Skip to content

Commit aef30ac

Browse files
dfaure-kdabogoffart
authored andcommitted
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 bf9031e commit aef30ac

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
@@ -857,18 +857,20 @@ fn grid_layout_cell_data(
857857
.elems
858858
.iter()
859859
.map(|c| {
860-
let span = c.span(orientation);
861860
let layout_info =
862861
get_layout_info(&c.item.element, ctx, &c.item.constraints, orientation);
863862

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

873875
make_struct(
874876
BuiltinPrivateStruct::GridLayoutCellData,
@@ -884,7 +886,7 @@ fn grid_layout_cell_data(
884886
},
885887
),
886888
("row", Type::Int32, row_expr),
887-
("span", Type::Int32, llr_Expression::NumberLiteral(span as _)),
889+
("span", Type::Int32, span_expr),
888890
],
889891
)
890892
})

internal/compiler/passes/lower_layout.rs

Lines changed: 10 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -280,17 +280,6 @@ impl GridLayout {
280280
layout_cache_prop_v: &NamedReference,
281281
diag: &mut BuildDiagnostics,
282282
) {
283-
let mut get_const_value = |name: &str| {
284-
item_element
285-
.borrow_mut()
286-
.bindings
287-
.get(name)
288-
.and_then(|e| eval_const_expr(&e.borrow().expression, name, &*e.borrow(), diag))
289-
};
290-
let colspan = get_const_value("colspan").unwrap_or(1);
291-
let rowspan = get_const_value("rowspan").unwrap_or(1);
292-
293-
// TODO: use get_expr for colspan/rowspan too
294283
let mut get_expr = |name: &str| {
295284
item_element.borrow_mut().bindings.get(name).map(|e| {
296285
let expr = &e.borrow().expression;
@@ -301,12 +290,14 @@ impl GridLayout {
301290

302291
let row_expr = get_expr("row");
303292
let col_expr = get_expr("col");
293+
let rowspan_expr = get_expr("rowspan");
294+
let colspan_expr = get_expr("colspan");
304295

305296
self.add_element_with_coord_as_expr(
306297
item_element,
307298
new_row,
308299
(&row_expr, &col_expr),
309-
(rowspan, colspan),
300+
(&rowspan_expr, &colspan_expr),
310301
layout_cache_prop_h,
311302
layout_cache_prop_v,
312303
diag,
@@ -329,7 +320,10 @@ impl GridLayout {
329320
&Some(Expression::NumberLiteral(row as _, Unit::None)),
330321
&Some(Expression::NumberLiteral(col as _, Unit::None)),
331322
),
332-
(rowspan, colspan),
323+
(
324+
&Some(Expression::NumberLiteral(rowspan as _, Unit::None)),
325+
&Some(Expression::NumberLiteral(colspan as _, Unit::None)),
326+
),
333327
layout_cache_prop_h,
334328
layout_cache_prop_v,
335329
diag,
@@ -341,7 +335,7 @@ impl GridLayout {
341335
item_element: &ElementRc,
342336
new_row: bool,
343337
(row_expr, col_expr): (&Option<Expression>, &Option<Expression>),
344-
(rowspan, colspan): (u16, u16),
338+
(rowspan_expr, colspan_expr): (&Option<Expression>, &Option<Expression>),
345339
layout_cache_prop_h: &NamedReference,
346340
layout_cache_prop_v: &NamedReference,
347341
diag: &mut BuildDiagnostics,
@@ -379,8 +373,8 @@ impl GridLayout {
379373
new_row,
380374
col_expr: col_expr.clone(),
381375
row_expr: row_expr.clone(),
382-
colspan,
383-
rowspan,
376+
colspan_expr: colspan_expr.clone(),
377+
rowspan_expr: rowspan_expr.clone(),
384378
item: layout_item.item.clone(),
385379
});
386380
}
@@ -845,29 +839,6 @@ fn set_prop_from_cache(
845839
}
846840
}
847841

848-
fn eval_const_expr(
849-
expression: &Expression,
850-
name: &str,
851-
span: &dyn crate::diagnostics::Spanned,
852-
diag: &mut BuildDiagnostics,
853-
) -> Option<u16> {
854-
match super::ignore_debug_hooks(expression) {
855-
Expression::NumberLiteral(v, Unit::None) => {
856-
if *v < 0. || *v > u16::MAX as f64 || !v.trunc().approx_eq(v) {
857-
diag.push_error(format!("'{name}' must be a positive integer"), span);
858-
None
859-
} else {
860-
Some(*v as u16)
861-
}
862-
}
863-
Expression::Cast { from, .. } => eval_const_expr(from, name, span, diag),
864-
_ => {
865-
diag.push_error(format!("'{name}' must be an integer literal"), span);
866-
None
867-
}
868-
}
869-
}
870-
871842
// If it's a number literal, it must be a positive integer
872843
// But also allow any other kind of expression
873844
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 {
@@ -23,6 +22,8 @@ export X := Rectangle {
2322
// ^error{'col' must be a positive integer}
2423
rowspan: 2.2;
2524
// ^error{'rowspan' must be a positive integer}
25+
colspan: -1;
26+
// ^error{'colspan' must be a positive integer}
2627
y: 0;
2728
// ^error{The property 'y' cannot be set for elements placed in this layout, because the layout is already setting it}
2829

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)