mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-02 06:41: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);
|
assert_eq!(reduce_to_second.class_name, second.class_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
pub struct PropertyLookupResult<'a> {
|
pub struct PropertyLookupResult<'a> {
|
||||||
pub resolved_name: std::borrow::Cow<'a, str>,
|
pub resolved_name: std::borrow::Cow<'a, str>,
|
||||||
pub property_type: Type,
|
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_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_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::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(
|
passes::apply_default_properties_from_style::apply_default_properties_from_style(
|
||||||
&doc.root_component,
|
&doc.root_component,
|
||||||
&mut type_loader,
|
&mut type_loader,
|
||||||
|
|
|
@ -12,6 +12,7 @@ LICENSE END */
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use crate::diagnostics::BuildDiagnostics;
|
||||||
use crate::langtype::DefaultSizeBinding;
|
use crate::langtype::DefaultSizeBinding;
|
||||||
use crate::langtype::Type;
|
use crate::langtype::Type;
|
||||||
use crate::object_tree::{Component, ElementRc};
|
use crate::object_tree::{Component, ElementRc};
|
||||||
|
@ -20,11 +21,14 @@ use crate::{
|
||||||
langtype::PropertyLookupResult,
|
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(
|
crate::object_tree::recurse_elem_including_sub_components(
|
||||||
&root_component,
|
&root_component,
|
||||||
&None,
|
&None,
|
||||||
&mut |elem: &ElementRc, parent: &Option<ElementRc>| {
|
&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();
|
let base_type = elem.borrow().base_type.clone();
|
||||||
if let (Some(parent), Type::Builtin(builtin_type)) = (parent, base_type) {
|
if let (Some(parent), Type::Builtin(builtin_type)) = (parent, base_type) {
|
||||||
match builtin_type.default_size_binding {
|
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) {
|
fn make_default_100(elem: &ElementRc, parent_element: &ElementRc, property: &str) {
|
||||||
let PropertyLookupResult { resolved_name, property_type } =
|
let PropertyLookupResult { resolved_name, property_type } =
|
||||||
parent_element.borrow().lookup_property(property);
|
parent_element.borrow().lookup_property(property);
|
||||||
|
|
|
@ -212,55 +212,6 @@ fn find_parent_element(e: &ElementRc) -> Option<ElementRc> {
|
||||||
recurse(&root, e)
|
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 {
|
impl Expression {
|
||||||
pub fn from_binding_expression_node(
|
pub fn from_binding_expression_node(
|
||||||
node: SyntaxNodeWithSourceFile,
|
node: SyntaxNodeWithSourceFile,
|
||||||
|
@ -275,7 +226,23 @@ impl Expression {
|
||||||
.map(|c| Self::from_codeblock_node(c.into(), ctx))
|
.map(|c| Self::from_codeblock_node(c.into(), ctx))
|
||||||
})
|
})
|
||||||
.unwrap_or(Self::Invalid);
|
.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)
|
e.maybe_convert_to(ctx.property_type.clone(), &node, &mut ctx.diag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ LICENSE END */
|
||||||
|
|
||||||
Foo := Rectangle {
|
Foo := Rectangle {
|
||||||
width: 30%;
|
width: 30%;
|
||||||
// ^error{Cannot find parent property to apply relative lenght}
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
height: 111%;
|
height: 111%;
|
||||||
|
|
|
@ -7,12 +7,21 @@
|
||||||
This file is also available under commercial licensing terms.
|
This file is also available under commercial licensing terms.
|
||||||
Please contact info@sixtyfps.io for more information.
|
Please contact info@sixtyfps.io for more information.
|
||||||
LICENSE END */
|
LICENSE END */
|
||||||
|
|
||||||
|
Sub := Rectangle {
|
||||||
|
width: 25%;
|
||||||
|
height: 35%;
|
||||||
|
}
|
||||||
|
|
||||||
TestCase := Rectangle {
|
TestCase := Rectangle {
|
||||||
width: 600phx;
|
width: 600phx;
|
||||||
inner_rect := Rectangle {
|
inner_rect := Rectangle {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
|
inner_inner := Sub { }
|
||||||
}
|
}
|
||||||
property<length> test_length: inner_rect.width;
|
property<length> test_length: inner_rect.width;
|
||||||
|
property<length> test_inner_inner_length: inner_inner.width;
|
||||||
|
|
||||||
|
|
||||||
height: 200phx;
|
height: 200phx;
|
||||||
property<percent> controller: 10%;
|
property<percent> controller: 10%;
|
||||||
|
@ -29,6 +38,7 @@ TestCase := Rectangle {
|
||||||
auto handle = TestCase::create();
|
auto handle = TestCase::create();
|
||||||
const TestCase &instance = *handle;
|
const TestCase &instance = *handle;
|
||||||
assert_eq(instance.get_test_length(), 300.);
|
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.);
|
assert_eq(instance.get_controlled_test_length(), 20.);
|
||||||
instance.set_controller(50);
|
instance.set_controller(50);
|
||||||
|
@ -40,6 +50,7 @@ assert_eq(instance.get_controlled_test_length(), 100.);
|
||||||
```rust
|
```rust
|
||||||
let instance = TestCase::new();
|
let instance = TestCase::new();
|
||||||
assert_eq!(instance.get_test_length(), 300.);
|
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.);
|
assert_eq!(instance.get_controlled_test_length(), 20.);
|
||||||
instance.set_controller(50.);
|
instance.set_controller(50.);
|
||||||
|
@ -49,6 +60,7 @@ assert_eq!(instance.get_controlled_test_length(), 100.);
|
||||||
```js
|
```js
|
||||||
var instance = new sixtyfps.TestCase({});
|
var instance = new sixtyfps.TestCase({});
|
||||||
assert.equal(instance.test_length, 300.);
|
assert.equal(instance.test_length, 300.);
|
||||||
|
assert.equal(instance.test_inner_inner_length, 300. / 4.);
|
||||||
|
|
||||||
assert.equal(instance.controlled_test_length, 20.);
|
assert.equal(instance.controlled_test_length, 20.);
|
||||||
instance.controller = 50.;
|
instance.controller = 50.;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue