1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
3
4use crate::Cli;
5use i_slint_compiler::expression_tree::Expression;
6use i_slint_compiler::langtype::Type;
7use i_slint_compiler::object_tree::ElementRc;
8use i_slint_compiler::parser::{SyntaxKind, SyntaxNode};
9use std::io::Write;
10
11pub(crate) fn fold_node(
12 node: &SyntaxNode,
13 file: &mut impl Write,
14 state: &mut crate::State,
15 args: &Cli,
16) -> std::io::Result<bool> {
17 let kind = node.kind();
18 if kind == SyntaxKind::Element {
19 if state.lookup_change.scope.len() >= 2 {
20 let elem = &state.lookup_change.scope[state.lookup_change.scope.len() - 1];
21 let parent = &state.lookup_change.scope[state.lookup_change.scope.len() - 2];
22
23 if !is_layout_base(parent) && !is_path(elem) && elem.borrow().is_legacy_syntax {
24 let extend = elem.borrow().builtin_type().map_or(false, |b| {
25 b.default_size_binding
26 != i_slint_compiler::langtype::DefaultSizeBinding::ImplicitSize
27 });
28
29 let new_props = format!(
30 "{}{}",
31 new_geometry_binding(elem, "x", "width", extend),
32 new_geometry_binding(elem, "y", "height", extend)
33 );
34 if !new_props.is_empty() {
35 let mut seen_brace = false;
36 for c in node.children_with_tokens() {
37 if seen_brace {
38 if c.kind() == SyntaxKind::Whitespace {
39 crate::visit_node_or_token(c.clone(), file, state, args)?;
40 }
41 write!(file, "{new_props}")?;
42 seen_brace = false;
43 } else if c.kind() == SyntaxKind::LBrace {
44 seen_brace = true;
45 }
46 crate::visit_node_or_token(c, file, state, args)?;
47 }
48 return Ok(true);
49 }
50 }
51 }
52 }
53 Ok(false)
54}
55
56fn new_geometry_binding(elem: &ElementRc, pos_prop: &str, size_prop: &str, extend: bool) -> String {
57 if elem.borrow().lookup_property(name:pos_prop).property_type != Type::LogicalLength {
58 return String::default();
59 }
60 if elem.borrow().is_binding_set(property_name:pos_prop, need_explicit:false) {
61 return String::default();
62 }
63 if extend && !elem.borrow().is_binding_set(property_name:size_prop, need_explicit:false) {
64 return String::default();
65 }
66 if let Some(b: &RefCell) = elem.borrow().bindings.get(key:size_prop) {
67 if let Expression::Uncompiled(x: &SyntaxNode) = &b.borrow().expression {
68 let s = x.to_string();
69 if s.trim() == "100%;" || s.trim() == format!("parent.{size_prop};") {
70 return String::default();
71 }
72 }
73 }
74
75 format!("{pos_prop}:0;")
76}
77
78fn is_layout_base(elem: &ElementRc) -> bool {
79 match &elem.borrow().base_type {
80 i_slint_compiler::langtype::ElementType::Builtin(b: &Rc) => {
81 return matches!(
82 b.name.as_str(),
83 "GridLayout" | "HorizontalLayout" | "VerticalLayout" | "Row" | "Path" | "Dialog"
84 );
85 }
86 i_slint_compiler::langtype::ElementType::Component(c: &Rc) => {
87 if c.id == "ListView" {
88 return true;
89 }
90 if let Some(ins: &(Rc>, ChildrenPlaceholder)) = &*c.child_insertion_point.borrow() {
91 return is_layout_base(&ins.0);
92 } else {
93 return is_layout_base(&c.root_element);
94 }
95 }
96 _ => return false,
97 };
98}
99
100fn is_path(elem: &ElementRc) -> bool {
101 // Path's children are still considered in the Path for some reason, so just don't touch path
102 elem.borrow().base_type.to_string() == "Path"
103}
104