mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 22:31:14 +00:00
Delay the percentage size conversion to after the layouting phase
So we can see inthe layouting phase if the size was in percent
This commit is contained in:
parent
92218a8b6e
commit
0174db3679
6 changed files with 67 additions and 53 deletions
|
@ -628,6 +628,7 @@ fn test_select_minimal_class_based_on_property_usage() {
|
|||
assert_eq!(reduce_to_second.class_name, second.class_name);
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct PropertyLookupResult<'a> {
|
||||
pub resolved_name: std::borrow::Cow<'a, str>,
|
||||
pub property_type: Type,
|
||||
|
|
|
@ -182,7 +182,7 @@ pub async fn run_passes(
|
|||
passes::lower_popups::lower_popups(&doc.root_component, &doc.local_registry, diag);
|
||||
passes::lower_layout::lower_layouts(&doc.root_component, &mut type_loader, diag).await;
|
||||
passes::lower_shadows::lower_shadow_properties(&doc.root_component, &doc.local_registry, diag);
|
||||
passes::default_geometry::default_geometry(&doc.root_component);
|
||||
passes::default_geometry::default_geometry(&doc.root_component, diag);
|
||||
passes::apply_default_properties_from_style::apply_default_properties_from_style(
|
||||
&doc.root_component,
|
||||
&mut type_loader,
|
||||
|
|
|
@ -12,6 +12,7 @@ LICENSE END */
|
|||
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::diagnostics::BuildDiagnostics;
|
||||
use crate::langtype::DefaultSizeBinding;
|
||||
use crate::langtype::Type;
|
||||
use crate::object_tree::{Component, ElementRc};
|
||||
|
@ -20,11 +21,14 @@ use crate::{
|
|||
langtype::PropertyLookupResult,
|
||||
};
|
||||
|
||||
pub fn default_geometry(root_component: &Rc<Component>) {
|
||||
pub fn default_geometry(root_component: &Rc<Component>, diag: &mut BuildDiagnostics) {
|
||||
crate::object_tree::recurse_elem_including_sub_components(
|
||||
&root_component,
|
||||
&None,
|
||||
&mut |elem: &ElementRc, parent: &Option<ElementRc>| {
|
||||
fix_percent_size(elem, parent, "width", diag);
|
||||
fix_percent_size(elem, parent, "height", diag);
|
||||
|
||||
let base_type = elem.borrow().base_type.clone();
|
||||
if let (Some(parent), Type::Builtin(builtin_type)) = (parent, base_type) {
|
||||
match builtin_type.default_size_binding {
|
||||
|
@ -46,6 +50,37 @@ pub fn default_geometry(root_component: &Rc<Component>) {
|
|||
)
|
||||
}
|
||||
|
||||
/// Replace expression such as `"width: 30%;` with `width: 0.3 * parent.width;`
|
||||
fn fix_percent_size(
|
||||
elem: &ElementRc,
|
||||
parent: &Option<ElementRc>,
|
||||
property: &str,
|
||||
diag: &mut BuildDiagnostics,
|
||||
) {
|
||||
if !elem.borrow().bindings.get(property).map_or(false, |b| b.ty() == Type::Percent) {
|
||||
return;
|
||||
}
|
||||
let mut elem = elem.borrow_mut();
|
||||
let b = elem.bindings.get_mut(property).unwrap();
|
||||
if let Some(parent) = parent {
|
||||
debug_assert_eq!(
|
||||
parent.borrow().lookup_property(property),
|
||||
PropertyLookupResult { resolved_name: property.into(), property_type: Type::Length }
|
||||
);
|
||||
b.expression = Expression::BinaryExpression {
|
||||
lhs: Box::new(std::mem::take(&mut b.expression).maybe_convert_to(
|
||||
Type::Float32,
|
||||
&b.span,
|
||||
diag,
|
||||
)),
|
||||
rhs: Box::new(Expression::PropertyReference(NamedReference::new(parent, property))),
|
||||
op: '*',
|
||||
}
|
||||
} else {
|
||||
diag.push_error("Cannot find parent property to apply relative lenght".into(), &b.span);
|
||||
}
|
||||
}
|
||||
|
||||
fn make_default_100(elem: &ElementRc, parent_element: &ElementRc, property: &str) {
|
||||
let PropertyLookupResult { resolved_name, property_type } =
|
||||
parent_element.borrow().lookup_property(property);
|
||||
|
|
|
@ -212,55 +212,6 @@ fn find_parent_element(e: &ElementRc) -> Option<ElementRc> {
|
|||
recurse(&root, e)
|
||||
}
|
||||
|
||||
/// If the type of the expression is a percentage, and the current property evaluated is
|
||||
/// `width` or `height`, attempt to multiply by the parent `width` or `height`
|
||||
fn attempt_percent_conversion(
|
||||
ctx: &mut LookupCtx,
|
||||
e: Expression,
|
||||
node: &dyn SpannedWithSourceFile,
|
||||
) -> Expression {
|
||||
if ctx.property_type != Type::Length || e.ty() != Type::Percent {
|
||||
return e;
|
||||
}
|
||||
|
||||
const RELATIVE_TO_PARENT_PROPERTIES: [&str; 2] = ["width", "height"];
|
||||
let property_name = ctx.property_name.unwrap_or_default();
|
||||
if !RELATIVE_TO_PARENT_PROPERTIES.contains(&property_name) {
|
||||
ctx.diag.push_error(
|
||||
format!(
|
||||
"Automatic conversion from percentage to lenght is only possible for the properties {}",
|
||||
RELATIVE_TO_PARENT_PROPERTIES.join(" and ")
|
||||
),
|
||||
node
|
||||
);
|
||||
return Expression::Invalid;
|
||||
}
|
||||
|
||||
let mut parent = ctx.component_scope.last().and_then(find_parent_element);
|
||||
while let Some(p) = parent {
|
||||
let PropertyLookupResult { resolved_name, property_type } =
|
||||
p.borrow().lookup_property(property_name);
|
||||
if property_type == Type::Length {
|
||||
return Expression::BinaryExpression {
|
||||
lhs: Box::new(Expression::BinaryExpression {
|
||||
lhs: Box::new(e),
|
||||
rhs: Box::new(Expression::NumberLiteral(0.01, Unit::None)),
|
||||
op: '*',
|
||||
}),
|
||||
rhs: Box::new(Expression::PropertyReference(NamedReference {
|
||||
element: Rc::downgrade(&p),
|
||||
name: resolved_name.to_string(),
|
||||
})),
|
||||
op: '*',
|
||||
};
|
||||
}
|
||||
parent = find_parent_element(&p);
|
||||
}
|
||||
|
||||
ctx.diag.push_error("Cannot find parent property to apply relative lenght".into(), node);
|
||||
Expression::Invalid
|
||||
}
|
||||
|
||||
impl Expression {
|
||||
pub fn from_binding_expression_node(
|
||||
node: SyntaxNodeWithSourceFile,
|
||||
|
@ -275,7 +226,23 @@ impl Expression {
|
|||
.map(|c| Self::from_codeblock_node(c.into(), ctx))
|
||||
})
|
||||
.unwrap_or(Self::Invalid);
|
||||
let e = attempt_percent_conversion(ctx, e, &node);
|
||||
if ctx.property_type == Type::Length && e.ty() == Type::Percent {
|
||||
// See if a conversion from percentage to lenght is allowed
|
||||
const RELATIVE_TO_PARENT_PROPERTIES: [&str; 2] = ["width", "height"];
|
||||
let property_name = ctx.property_name.unwrap_or_default();
|
||||
if RELATIVE_TO_PARENT_PROPERTIES.contains(&property_name) {
|
||||
return e;
|
||||
} else {
|
||||
ctx.diag.push_error(
|
||||
format!(
|
||||
"Automatic conversion from percentage to lenght is only possible for the properties {}",
|
||||
RELATIVE_TO_PARENT_PROPERTIES.join(" and ")
|
||||
),
|
||||
&node
|
||||
);
|
||||
return Expression::Invalid;
|
||||
}
|
||||
};
|
||||
e.maybe_convert_to(ctx.property_type.clone(), &node, &mut ctx.diag)
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ LICENSE END */
|
|||
|
||||
Foo := Rectangle {
|
||||
width: 30%;
|
||||
// ^error{Cannot find parent property to apply relative lenght}
|
||||
|
||||
Rectangle {
|
||||
height: 111%;
|
||||
|
|
|
@ -7,12 +7,21 @@
|
|||
This file is also available under commercial licensing terms.
|
||||
Please contact info@sixtyfps.io for more information.
|
||||
LICENSE END */
|
||||
|
||||
Sub := Rectangle {
|
||||
width: 25%;
|
||||
height: 35%;
|
||||
}
|
||||
|
||||
TestCase := Rectangle {
|
||||
width: 600phx;
|
||||
inner_rect := Rectangle {
|
||||
width: 50%;
|
||||
inner_inner := Sub { }
|
||||
}
|
||||
property<length> test_length: inner_rect.width;
|
||||
property<length> test_inner_inner_length: inner_inner.width;
|
||||
|
||||
|
||||
height: 200phx;
|
||||
property<percent> controller: 10%;
|
||||
|
@ -29,6 +38,7 @@ TestCase := Rectangle {
|
|||
auto handle = TestCase::create();
|
||||
const TestCase &instance = *handle;
|
||||
assert_eq(instance.get_test_length(), 300.);
|
||||
assert_eq(instance.get_test_inner_inner_length(), 300. / 4.);
|
||||
|
||||
assert_eq(instance.get_controlled_test_length(), 20.);
|
||||
instance.set_controller(50);
|
||||
|
@ -40,6 +50,7 @@ assert_eq(instance.get_controlled_test_length(), 100.);
|
|||
```rust
|
||||
let instance = TestCase::new();
|
||||
assert_eq!(instance.get_test_length(), 300.);
|
||||
assert_eq!(instance.get_test_inner_inner_length(), 300. / 4.);
|
||||
|
||||
assert_eq!(instance.get_controlled_test_length(), 20.);
|
||||
instance.set_controller(50.);
|
||||
|
@ -49,6 +60,7 @@ assert_eq!(instance.get_controlled_test_length(), 100.);
|
|||
```js
|
||||
var instance = new sixtyfps.TestCase({});
|
||||
assert.equal(instance.test_length, 300.);
|
||||
assert.equal(instance.test_inner_inner_length, 300. / 4.);
|
||||
|
||||
assert.equal(instance.controlled_test_length, 20.);
|
||||
instance.controller = 50.;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue