Skip to content

Commit 01a4193

Browse files
dfaure-kdabogoffart
authored andcommitted
compiler: allow setting the row/col property from the outside
1 parent 8983907 commit 01a4193

File tree

7 files changed

+135
-95
lines changed

7 files changed

+135
-95
lines changed

internal/compiler/layout.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -275,19 +275,25 @@ impl LayoutConstraints {
275275
}
276276
}
277277

278+
#[derive(Debug, Clone)]
279+
pub enum RowColExpr {
280+
Named(NamedReference),
281+
Literal(u16),
282+
}
283+
278284
/// An element in a GridLayout
279285
#[derive(Debug, Clone)]
280286
pub struct GridLayoutElement {
281287
pub new_row: bool,
282-
pub col_expr: Option<Expression>,
283-
pub row_expr: Option<Expression>,
284-
pub colspan_expr: Option<Expression>,
285-
pub rowspan_expr: Option<Expression>,
288+
pub col_expr: RowColExpr,
289+
pub row_expr: RowColExpr,
290+
pub colspan_expr: RowColExpr,
291+
pub rowspan_expr: RowColExpr,
286292
pub item: LayoutItem,
287293
}
288294

289295
impl GridLayoutElement {
290-
pub fn span(&self, orientation: Orientation) -> &Option<Expression> {
296+
pub fn span(&self, orientation: Orientation) -> &RowColExpr {
291297
match orientation {
292298
Orientation::Horizontal => &self.colspan_expr,
293299
Orientation::Vertical => &self.rowspan_expr,
@@ -426,7 +432,7 @@ fn find_binding<R>(
426432
}
427433

428434
/// Return a named reference to a property if a binding is set on that property
429-
fn binding_reference(element: &ElementRc, name: &'static str) -> Option<NamedReference> {
435+
pub fn binding_reference(element: &ElementRc, name: &'static str) -> Option<NamedReference> {
430436
find_binding(element, name, |_, _, _| NamedReference::new(element, SmolStr::new_static(name)))
431437
}
432438

@@ -468,6 +474,18 @@ impl GridLayout {
468474
pub fn visit_named_references(&mut self, visitor: &mut impl FnMut(&mut NamedReference)) {
469475
for cell in &mut self.elems {
470476
cell.item.constraints.visit_named_references(visitor);
477+
if let RowColExpr::Named(ref mut e) = cell.col_expr {
478+
visitor(e);
479+
}
480+
if let RowColExpr::Named(ref mut e) = cell.row_expr {
481+
visitor(e);
482+
}
483+
if let RowColExpr::Named(ref mut e) = cell.colspan_expr {
484+
visitor(e);
485+
}
486+
if let RowColExpr::Named(ref mut e) = cell.rowspan_expr {
487+
visitor(e);
488+
}
471489
}
472490
self.geometry.visit_named_references(visitor);
473491
}

internal/compiler/llr/lower_expression.rs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use super::lower_to_item_tree::{LoweredElement, LoweredSubComponentMapping, Lowe
1212
use super::{Animation, LocalMemberReference, MemberReference, PropertyIdx, RepeatedElementIdx};
1313
use crate::expression_tree::{BuiltinFunction, Callable, Expression as tree_Expression};
1414
use crate::langtype::{BuiltinPrivateStruct, EnumerationValue, Struct, StructName, Type};
15-
use crate::layout::Orientation;
15+
use crate::layout::{Orientation, RowColExpr};
1616
use crate::llr::Expression as llr_Expression;
1717
use crate::namedreference::NamedReference;
1818
use crate::object_tree::{Element, ElementRc, PropertyAnimation};
@@ -891,18 +891,16 @@ fn grid_layout_input_data(
891891
.elems
892892
.iter()
893893
.map(|c| {
894-
let mut lower_expr_or_default =
895-
|expr: &Option<crate::expression_tree::Expression>, default: u16| {
896-
expr.as_ref().map_or_else(
897-
|| llr_Expression::NumberLiteral(default.into()),
898-
|e| lower_expression(e, ctx),
899-
)
900-
};
901-
// MAX means "auto", see to_layout_data()
902-
let row_expr = lower_expr_or_default(&c.row_expr, u16::MAX);
903-
let col_expr = lower_expr_or_default(&c.col_expr, u16::MAX);
904-
let rowspan_expr = lower_expr_or_default(&c.rowspan_expr, 1);
905-
let colspan_expr = lower_expr_or_default(&c.colspan_expr, 1);
894+
let propref_or_default = |named_ref: &RowColExpr| match named_ref {
895+
RowColExpr::Literal(n) => llr_Expression::NumberLiteral((*n).into()),
896+
RowColExpr::Named(e) => {
897+
llr_Expression::PropertyReference(ctx.map_property_reference(e))
898+
}
899+
};
900+
let row_expr = propref_or_default(&c.row_expr);
901+
let col_expr = propref_or_default(&c.col_expr);
902+
let rowspan_expr = propref_or_default(&c.rowspan_expr);
903+
let colspan_expr = propref_or_default(&c.colspan_expr);
906904

907905
make_struct(
908906
BuiltinPrivateStruct::GridLayoutInputData,

internal/compiler/passes/lower_layout.rs

Lines changed: 74 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -340,21 +340,66 @@ impl GridLayout {
340340
numbering_type: &mut Option<RowColExpressionType>,
341341
diag: &mut BuildDiagnostics,
342342
) {
343-
let mut get_expr = |name: &str| {
344-
let mut is_number_literal = false;
345-
let expr = item_element.borrow_mut().bindings.get(name).map(|e| {
346-
let expr = &e.borrow().expression;
347-
is_number_literal =
348-
check_number_literal_is_positive_integer(expr, name, &*e.borrow(), diag);
349-
expr.clone()
350-
});
351-
(expr, is_number_literal)
343+
// Some compile-time checks
344+
{
345+
let mut check_expr = |name: &str| {
346+
let mut is_number_literal = false;
347+
let expr = item_element.borrow_mut().bindings.get(name).map(|e| {
348+
let expr = &e.borrow().expression;
349+
is_number_literal =
350+
check_number_literal_is_positive_integer(expr, name, &*e.borrow(), diag);
351+
expr.clone()
352+
});
353+
(expr, is_number_literal)
354+
};
355+
356+
let (row_expr, row_is_number_literal) = check_expr("row");
357+
let (col_expr, col_is_number_literal) = check_expr("col");
358+
check_expr("rowspan");
359+
check_expr("colspan");
360+
361+
let mut check_numbering_consistency =
362+
|expr_type: RowColExpressionType, prop_name: &str| {
363+
if !matches!(expr_type, RowColExpressionType::Literal) {
364+
if let Some(current_numbering_type) = numbering_type {
365+
if *current_numbering_type != expr_type {
366+
let element_ref = item_element.borrow();
367+
let span: &dyn Spanned =
368+
if let Some(binding) = element_ref.bindings.get(prop_name) {
369+
&*binding.borrow()
370+
} else {
371+
&*element_ref
372+
};
373+
diag.push_error(
374+
format!("Cannot mix auto-numbering and runtime expressions for the '{prop_name}' property"),
375+
span,
376+
);
377+
}
378+
} else {
379+
// Store the first auto or runtime expression case we see
380+
*numbering_type = Some(expr_type);
381+
}
382+
}
383+
};
384+
385+
let row_expr_type =
386+
RowColExpressionType::from_option_expr(&row_expr, row_is_number_literal);
387+
check_numbering_consistency(row_expr_type, "row");
388+
389+
let col_expr_type =
390+
RowColExpressionType::from_option_expr(&col_expr, col_is_number_literal);
391+
check_numbering_consistency(col_expr_type, "col");
392+
}
393+
394+
let propref_or_default = |name: &'static str| -> Option<RowColExpr> {
395+
crate::layout::binding_reference(item_element, &name).map(|nr| RowColExpr::Named(nr))
352396
};
353397

354-
let (row_expr, row_is_number_literal) = get_expr("row");
355-
let (col_expr, col_is_number_literal) = get_expr("col");
356-
let (rowspan_expr, _) = get_expr("rowspan");
357-
let (colspan_expr, _) = get_expr("colspan");
398+
// MAX means "auto", see to_layout_data()
399+
let row_expr = propref_or_default("row");
400+
let col_expr = propref_or_default("col");
401+
let rowspan_expr = propref_or_default("rowspan");
402+
let colspan_expr = propref_or_default("colspan");
358403

359404
self.add_element_with_coord_as_expr(
360405
item_element,
@@ -366,32 +411,6 @@ impl GridLayout {
366411
organized_data_prop,
367412
diag,
368413
);
369-
370-
let mut check_numbering_consistency = |expr_type: RowColExpressionType, prop_name: &str| {
371-
if !matches!(expr_type, RowColExpressionType::Literal) {
372-
if let Some(current_numbering_type) = numbering_type {
373-
if *current_numbering_type != expr_type {
374-
item_element.borrow_mut().bindings.get(prop_name).map(|binding| {
375-
diag.push_error(
376-
format!("Cannot mix auto-numbering and runtime expressions for the '{prop_name}' property"),
377-
&*binding.borrow(),
378-
);
379-
});
380-
}
381-
} else {
382-
// Store the first auto or runtime expression case we see
383-
*numbering_type = Some(expr_type);
384-
}
385-
}
386-
};
387-
388-
let row_expr_type =
389-
RowColExpressionType::from_option_expr(&row_expr, row_is_number_literal);
390-
check_numbering_consistency(row_expr_type, "row");
391-
392-
let col_expr_type =
393-
RowColExpressionType::from_option_expr(&col_expr, col_is_number_literal);
394-
check_numbering_consistency(col_expr_type, "col");
395414
}
396415

397416
fn add_element_with_coord(
@@ -407,14 +426,8 @@ impl GridLayout {
407426
self.add_element_with_coord_as_expr(
408427
item_element,
409428
false, // new_row
410-
(
411-
&Some(Expression::NumberLiteral(row as _, Unit::None)),
412-
&Some(Expression::NumberLiteral(col as _, Unit::None)),
413-
),
414-
(
415-
&Some(Expression::NumberLiteral(rowspan as _, Unit::None)),
416-
&Some(Expression::NumberLiteral(colspan as _, Unit::None)),
417-
),
429+
(&Some(RowColExpr::Literal(row)), &Some(RowColExpr::Literal(col))),
430+
(&Some(RowColExpr::Literal(rowspan)), &Some(RowColExpr::Literal(colspan))),
418431
layout_cache_prop_h,
419432
layout_cache_prop_v,
420433
organized_data_prop,
@@ -426,8 +439,8 @@ impl GridLayout {
426439
&mut self,
427440
item_element: &ElementRc,
428441
new_row: bool,
429-
(row_expr, col_expr): (&Option<Expression>, &Option<Expression>),
430-
(rowspan_expr, colspan_expr): (&Option<Expression>, &Option<Expression>),
442+
(row_expr, col_expr): (&Option<RowColExpr>, &Option<RowColExpr>),
443+
(rowspan_expr, colspan_expr): (&Option<RowColExpr>, &Option<RowColExpr>),
431444
layout_cache_prop_h: &NamedReference,
432445
layout_cache_prop_v: &NamedReference,
433446
organized_data_prop: &NamedReference,
@@ -463,12 +476,20 @@ impl GridLayout {
463476
set_prop_from_cache(e, "row", organized_data_prop, org_index + 2, &None, diag);
464477
}
465478

479+
let expr_or_default = |expr: &Option<RowColExpr>, default: u16| -> RowColExpr {
480+
match expr {
481+
Some(RowColExpr::Literal(v)) => RowColExpr::Literal(*v),
482+
Some(RowColExpr::Named(nr)) => RowColExpr::Named(nr.clone()),
483+
None => RowColExpr::Literal(default),
484+
}
485+
};
486+
466487
self.elems.push(GridLayoutElement {
467488
new_row,
468-
col_expr: col_expr.clone(),
469-
row_expr: row_expr.clone(),
470-
colspan_expr: colspan_expr.clone(),
471-
rowspan_expr: rowspan_expr.clone(),
489+
col_expr: expr_or_default(col_expr, u16::MAX), // MAX means "auto"
490+
row_expr: expr_or_default(row_expr, u16::MAX),
491+
colspan_expr: expr_or_default(colspan_expr, 1),
492+
rowspan_expr: expr_or_default(rowspan_expr, 1),
472493
item: layout_item.item.clone(),
473494
});
474495
}

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ export X := Rectangle {
3030

3131
init => {
3232
self.colspan = 45;
33-
// ^error{The property must be known at compile time and cannot be changed at runtime}
3433
}
3534
}
3635
}
@@ -49,25 +48,25 @@ export X := Rectangle {
4948
}
5049

5150
lay2 := GridLayout {
52-
// ^error{Cannot mix auto-numbering and runtime expressions for the 'col' property}
5351
property<int> negative: -5;
5452
property<int> last_row: 4;
5553
Text {
5654
row: lay2.last_row;
5755
col: -lay2.negative; // check that a unary minus isn't necessary an error
5856
}
5957
Text {
58+
// ^error{Cannot mix auto-numbering and runtime expressions for the 'col' property}
6059
row: 0; // mixing runtime expr and literal is ok
6160
}
6261
}
6362

6463
lay3 := GridLayout {
65-
// ^error{Cannot mix auto-numbering and runtime expressions for the 'row' property}
6664
Text {
6765
row: lay2.last_row;
6866
col: lay2.last_row;
6967
}
7068
Text {
69+
// ^error{Cannot mix auto-numbering and runtime expressions for the 'row' property}
7170
col: 1;
7271
}
7372
}

internal/compiler/typeregister.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ pub fn reserved_properties() -> impl Iterator<Item = (&'static str, Type, Proper
247247
.chain(
248248
RESERVED_GRIDLAYOUT_PROPERTIES
249249
.iter()
250-
.map(|(k, v)| (*k, v.clone(), PropertyVisibility::Constexpr)),
250+
.map(|(k, v)| (*k, v.clone(), PropertyVisibility::Input)),
251251
)
252252
.chain(IntoIterator::into_iter([
253253
("absolute-position", logical_point_type().into(), PropertyVisibility::Output),

internal/interpreter/eval_layout.rs

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
33

44
use crate::dynamic_item_tree::InstanceRef;
5-
use crate::eval::{self, eval_expression, EvalLocalContext};
5+
use crate::eval::{self, EvalLocalContext};
66
use crate::Value;
77
use i_slint_compiler::expression_tree::Expression;
88
use i_slint_compiler::langtype::Type;
99
use i_slint_compiler::layout::{
10-
GridLayout, Layout, LayoutConstraints, LayoutGeometry, Orientation,
10+
GridLayout, Layout, LayoutConstraints, LayoutGeometry, Orientation, RowColExpr,
1111
};
1212
use i_slint_compiler::namedreference::NamedReference;
1313
use i_slint_compiler::object_tree::ElementRc;
@@ -92,7 +92,11 @@ pub(crate) fn organize_grid_layout(
9292
layout: &GridLayout,
9393
local_context: &mut EvalLocalContext,
9494
) -> Value {
95-
let cells = grid_layout_input_data(layout, local_context);
95+
let component = local_context.component_instance;
96+
let expr_eval = |nr: &NamedReference| -> f32 {
97+
eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
98+
};
99+
let cells = grid_layout_input_data(layout, &expr_eval);
96100

97101
if let Some(buttons_roles) = &layout.dialog_button_roles {
98102
let roles = buttons_roles
@@ -197,29 +201,30 @@ fn padding_and_spacing(
197201

198202
fn grid_layout_input_data(
199203
grid_layout: &i_slint_compiler::layout::GridLayout,
200-
local_context: &mut EvalLocalContext,
204+
expr_eval: &impl Fn(&NamedReference) -> f32,
201205
) -> Vec<core_layout::GridLayoutInputData> {
202206
grid_layout
203207
.elems
204208
.iter()
205209
.map(|cell| {
206-
let mut eval_or_default = |expr: &Option<Expression>, default: u16| match expr {
207-
None => default,
208-
Some(e) => {
209-
let value = eval_expression(e, local_context);
210-
match value {
211-
Value::Number(n) if n >= 0.0 && n <= u16::MAX as f64 => n as u16,
212-
_ => panic!(
210+
let eval_or_default = |expr: &RowColExpr| match expr {
211+
RowColExpr::Literal(value) => *value,
212+
RowColExpr::Named(e) => {
213+
let value = expr_eval(e);
214+
if value >= 0.0 && value <= u16::MAX as f32 {
215+
value as u16
216+
} else {
217+
panic!(
213218
"Expected a positive integer, but got {:?} while evaluating {:?}",
214219
value, e
215-
),
220+
);
216221
}
217222
}
218223
};
219-
let row = eval_or_default(&cell.row_expr, u16::MAX);
220-
let col = eval_or_default(&cell.col_expr, u16::MAX);
221-
let rowspan = eval_or_default(&cell.rowspan_expr, 1);
222-
let colspan = eval_or_default(&cell.colspan_expr, 1);
224+
let row = eval_or_default(&cell.row_expr);
225+
let col = eval_or_default(&cell.col_expr);
226+
let rowspan = eval_or_default(&cell.rowspan_expr);
227+
let colspan = eval_or_default(&cell.colspan_expr);
223228
core_layout::GridLayoutInputData { new_row: cell.new_row, col, row, colspan, rowspan }
224229
})
225230
.collect()

0 commit comments

Comments
 (0)