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 | |
4 | use crate::Cli; |
5 | use i_slint_compiler::expression_tree::Expression; |
6 | use i_slint_compiler::langtype::Type; |
7 | use i_slint_compiler::object_tree::ElementRc; |
8 | use i_slint_compiler::parser::{SyntaxKind, SyntaxNode}; |
9 | use std::io::Write; |
10 | |
11 | pub(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 | |
56 | fn 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 | |
78 | fn 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 | |
100 | fn 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 | |