Skip to content

Commit 70e6c49

Browse files
committed
Allow rowspan and colspan to be expressions
ChangeLog: the row, col, rowspan and colspan properties can now be expressions rather than having to be constants. The layout adapts when the value of the expression changes.
1 parent d60dddd commit 70e6c49

File tree

6 files changed

+42
-66
lines changed

6 files changed

+42
-66
lines changed

internal/compiler/layout.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -281,16 +281,16 @@ pub struct GridLayoutElement {
281281
pub new_row: bool,
282282
pub col_expr: Option<Expression>,
283283
pub row_expr: Option<Expression>,
284-
pub colspan: u16,
285-
pub rowspan: u16,
284+
pub colspan_expr: Option<Expression>,
285+
pub rowspan_expr: Option<Expression>,
286286
pub item: LayoutItem,
287287
}
288288

289289
impl GridLayoutElement {
290-
pub fn span(&self, orientation: Orientation) -> u16 {
290+
pub fn span(&self, orientation: Orientation) -> &Option<Expression> {
291291
match orientation {
292-
Orientation::Horizontal => self.colspan,
293-
Orientation::Vertical => self.rowspan,
292+
Orientation::Horizontal => &self.colspan_expr,
293+
Orientation::Vertical => &self.rowspan_expr,
294294
}
295295
}
296296
}

internal/compiler/llr/lower_expression.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -860,18 +860,20 @@ fn grid_layout_cell_data(
860860
.elems
861861
.iter()
862862
.map(|c| {
863-
let span = c.span(orientation);
864863
let layout_info =
865864
get_layout_info(&c.item.element, ctx, &c.item.constraints, orientation);
866865

867-
let mut lower_expr_or_auto = |expr: &Option<crate::expression_tree::Expression>| {
868-
expr.as_ref().map_or_else(
869-
|| llr_Expression::NumberLiteral(u16::MAX.into()), // MAX means "auto", see to_layout_data()
870-
|e| lower_expression(e, ctx),
871-
)
872-
};
873-
let row_expr = lower_expr_or_auto(&c.row_expr);
874-
let col_expr = lower_expr_or_auto(&c.col_expr);
866+
let mut lower_expr_or_default =
867+
|expr: &Option<crate::expression_tree::Expression>, default: u16| {
868+
expr.as_ref().map_or_else(
869+
|| llr_Expression::NumberLiteral(default.into()),
870+
|e| lower_expression(e, ctx),
871+
)
872+
};
873+
// MAX means "auto", see to_layout_data()
874+
let row_expr = lower_expr_or_default(&c.row_expr, u16::MAX);
875+
let col_expr = lower_expr_or_default(&c.col_expr, u16::MAX);
876+
let span_expr = lower_expr_or_default(&c.span(orientation), 1);
875877

876878
make_struct(
877879
"GridLayoutCellData",
@@ -887,7 +889,7 @@ fn grid_layout_cell_data(
887889
},
888890
),
889891
("row", Type::Int32, row_expr),
890-
("span", Type::Int32, llr_Expression::NumberLiteral(span as _)),
892+
("span", Type::Int32, span_expr),
891893
],
892894
)
893895
})

internal/compiler/passes/lower_layout.rs

Lines changed: 10 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -274,17 +274,6 @@ impl GridLayout {
274274
layout_cache_prop_v: &NamedReference,
275275
diag: &mut BuildDiagnostics,
276276
) {
277-
let mut get_const_value = |name: &str| {
278-
item_element
279-
.borrow_mut()
280-
.bindings
281-
.get(name)
282-
.and_then(|e| eval_const_expr(&e.borrow().expression, name, &*e.borrow(), diag))
283-
};
284-
let colspan = get_const_value("colspan").unwrap_or(1);
285-
let rowspan = get_const_value("rowspan").unwrap_or(1);
286-
287-
// TODO: use get_expr for colspan/rowspan too
288277
let mut get_expr = |name: &str| {
289278
item_element.borrow_mut().bindings.get(name).map(|e| {
290279
let expr = &e.borrow().expression;
@@ -295,12 +284,14 @@ impl GridLayout {
295284

296285
let row_expr = get_expr("row");
297286
let col_expr = get_expr("col");
287+
let rowspan_expr = get_expr("rowspan");
288+
let colspan_expr = get_expr("colspan");
298289

299290
self.add_element_with_coord_as_expr(
300291
item_element,
301292
new_row,
302293
(&row_expr, &col_expr),
303-
(rowspan, colspan),
294+
(&rowspan_expr, &colspan_expr),
304295
layout_cache_prop_h,
305296
layout_cache_prop_v,
306297
diag,
@@ -323,7 +314,10 @@ impl GridLayout {
323314
&Some(Expression::NumberLiteral(row as _, Unit::None)),
324315
&Some(Expression::NumberLiteral(col as _, Unit::None)),
325316
),
326-
(rowspan, colspan),
317+
(
318+
&Some(Expression::NumberLiteral(rowspan as _, Unit::None)),
319+
&Some(Expression::NumberLiteral(colspan as _, Unit::None)),
320+
),
327321
layout_cache_prop_h,
328322
layout_cache_prop_v,
329323
diag,
@@ -335,7 +329,7 @@ impl GridLayout {
335329
item_element: &ElementRc,
336330
new_row: bool,
337331
(row_expr, col_expr): (&Option<Expression>, &Option<Expression>),
338-
(rowspan, colspan): (u16, u16),
332+
(rowspan_expr, colspan_expr): (&Option<Expression>, &Option<Expression>),
339333
layout_cache_prop_h: &NamedReference,
340334
layout_cache_prop_v: &NamedReference,
341335
diag: &mut BuildDiagnostics,
@@ -373,8 +367,8 @@ impl GridLayout {
373367
new_row,
374368
col_expr: col_expr.clone(),
375369
row_expr: row_expr.clone(),
376-
colspan,
377-
rowspan,
370+
colspan_expr: colspan_expr.clone(),
371+
rowspan_expr: rowspan_expr.clone(),
378372
item: layout_item.item.clone(),
379373
});
380374
}
@@ -839,29 +833,6 @@ fn set_prop_from_cache(
839833
}
840834
}
841835

842-
fn eval_const_expr(
843-
expression: &Expression,
844-
name: &str,
845-
span: &dyn crate::diagnostics::Spanned,
846-
diag: &mut BuildDiagnostics,
847-
) -> Option<u16> {
848-
match super::ignore_debug_hooks(expression) {
849-
Expression::NumberLiteral(v, Unit::None) => {
850-
if *v < 0. || *v > u16::MAX as f64 || !v.trunc().approx_eq(v) {
851-
diag.push_error(format!("'{name}' must be a positive integer"), span);
852-
None
853-
} else {
854-
Some(*v as u16)
855-
}
856-
}
857-
Expression::Cast { from, .. } => eval_const_expr(from, name, span, diag),
858-
_ => {
859-
diag.push_error(format!("'{name}' must be an integer literal"), span);
860-
None
861-
}
862-
}
863-
}
864-
865836
// If it's a number literal, it must be a positive integer
866837
// But also allow any other kind of expression
867838
fn check_number_literal_is_positive_integer(

internal/compiler/tests/syntax/basic/layout2.slint

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ export X := Rectangle {
1313
text: lay.foo + parent.width;
1414
// ^error{Element 'Row' does not have a property 'width'}
1515
colspan: 1 + 1;
16-
// ^error{'colspan' must be an integer literal}
1716
rowspan: 2;
1817
}
1918
Text {
@@ -22,6 +21,8 @@ export X := Rectangle {
2221
// ^error{'col' must be a positive integer}
2322
rowspan: 2.2;
2423
// ^error{'rowspan' must be a positive integer}
24+
colspan: -1;
25+
// ^error{'colspan' must be a positive integer}
2526
y: 0;
2627
// ^error{The property 'y' cannot be set for elements placed in this layout, because the layout is already setting it}
2728

internal/interpreter/eval_layout.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,8 @@ fn grid_layout_data(
180180
&expr_eval,
181181
);
182182
let span = cell.span(orientation);
183-
let mut eval_or_auto = |expr: &Option<Expression>| match expr {
184-
None => u16::MAX, // auto
183+
let mut eval_or_default = |expr: &Option<Expression>, default: u16| match expr {
184+
None => default,
185185
Some(e) => {
186186
let value = eval_expression(e, local_context);
187187
match value {
@@ -193,8 +193,9 @@ fn grid_layout_data(
193193
}
194194
}
195195
};
196-
let row = eval_or_auto(&cell.row_expr);
197-
let col = eval_or_auto(&cell.col_expr);
196+
let row = eval_or_default(&cell.row_expr, u16::MAX);
197+
let col = eval_or_default(&cell.col_expr, u16::MAX);
198+
let span = eval_or_default(&span, 1);
198199
core_layout::GridLayoutCellData {
199200
new_row: cell.new_row,
200201
col_or_row: match orientation {

tests/cases/layout/grid_variable_row_col.slint

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
export component TestCase inherits Window {
55
property <int> blue_row: 1;
6+
property <int> blue_colspan: 2;
67
property <int> green_col: 1;
78
property <int> red_row: 0;
89
property <int> red_col: 0;
@@ -17,8 +18,7 @@ export component TestCase inherits Window {
1718
background: blue;
1819
row: blue_row;
1920
col: 0;
20-
colspan: 1;
21-
width: 40phx;
21+
colspan: blue_colspan;
2222
height: 40phx;
2323
}
2424
rg := Rectangle {
@@ -39,23 +39,24 @@ export component TestCase inherits Window {
3939
}
4040
}
4141
out property <bool> initial_grid_ok: {
42-
// red is at (0, 0), green is at (row=0, col=1), blue is at (row=1, col=0)
42+
// red is at (0, 0), green is at (row=0, col=1), blue is at (row=1, col=0) with colspan 2
4343
rr.x == 50phx && rr.y == 50phx && rr.colspan == 1 &&
4444
rg.x == 100phx && rg.y == 50phx && rg.colspan == 1 &&
45-
rb.x == 50phx && rb.y == 100phx && rb.colspan == 1
45+
rb.x == 50phx && rb.y == 100phx && rb.width == 90phx && rb.colspan == 2
4646
}
4747

4848
public function change_grid() {
4949
green_col = 0;
5050
red_row = 1;
5151
blue_row = 2;
52+
blue_colspan = 1;
5253
}
5354

5455
out property <bool> final_grid_ok: {
5556
// now they are all at col 0, and in the order green, red, blue
56-
rr.x == 50phx && rr.y == 100phx && rr.colspan == 1 &&
57-
rg.x == 50phx && rg.y == 50phx && rg.colspan == 1 &&
58-
rb.x == 50phx && rb.y == 150phx && rb.colspan == 1
57+
rr.x == 50phx && rr.y == 100phx && rr.width == 40phx && rr.colspan == 1 &&
58+
rg.x == 50phx && rg.y == 50phx && rg.width == 40phx && rg.colspan == 1 &&
59+
rb.x == 50phx && rb.y == 150phx && rb.width == 40phx && rb.colspan == 1
5960
}
6061

6162
init => {

0 commit comments

Comments
 (0)