i_slint_compiler/passes/
ensure_window.rs1use crate::diagnostics::BuildDiagnostics;
7use crate::expression_tree::{BindingExpression, Expression};
8use crate::langtype::Type;
9use crate::namedreference::NamedReference;
10use crate::object_tree::{Component, Element};
11use crate::typeregister::TypeRegister;
12use smol_str::SmolStr;
13use std::cell::RefCell;
14use std::collections::HashSet;
15use std::rc::Rc;
16
17pub fn ensure_window(
18 component: &Rc<Component>,
19 type_register: &TypeRegister,
20 style_metrics: &Rc<Component>,
21 diag: &mut BuildDiagnostics,
22) {
23 if component.inherits_popup_window.get() {
24 diag.push_error(
25 "PopupWindow cannot be the top level".into(),
26 &*component.root_element.borrow(),
27 );
28 }
29
30 if inherits_window(component) {
31 return; }
33
34 let window_type = type_register.lookup_builtin_element("Window").unwrap();
35
36 let win_elem = component.root_element.clone();
37
38 let mut win_elem_mut = win_elem.borrow_mut();
40 let new_root = Element {
41 id: std::mem::replace(&mut win_elem_mut.id, "root_window".into()),
42 base_type: std::mem::replace(&mut win_elem_mut.base_type, window_type),
43 bindings: Default::default(),
44 change_callbacks: Default::default(),
45 is_component_placeholder: false,
46 property_analysis: Default::default(),
47 children: std::mem::take(&mut win_elem_mut.children),
48 enclosing_component: win_elem_mut.enclosing_component.clone(),
49 property_declarations: Default::default(),
50 named_references: Default::default(),
51 repeated: Default::default(),
52 states: Default::default(),
53 transitions: Default::default(),
54 child_of_layout: false,
55 has_popup_child: false,
56 layout_info_prop: Default::default(),
57 default_fill_parent: Default::default(),
58 accessibility_props: Default::default(),
59 geometry_props: Default::default(),
60 is_flickable_viewport: false,
61 item_index: Default::default(),
62 item_index_of_first_children: Default::default(),
63 debug: std::mem::take(&mut win_elem_mut.debug),
64
65 inline_depth: 0,
66 is_legacy_syntax: false,
67 };
68 let new_root = new_root.make_rc();
69 win_elem_mut.children.push(new_root.clone());
70 drop(win_elem_mut);
71
72 let make_two_way = |name: &'static str| {
73 new_root.borrow_mut().bindings.insert(
74 name.into(),
75 RefCell::new(BindingExpression::new_two_way(NamedReference::new(
76 &win_elem,
77 SmolStr::new_static(name),
78 ))),
79 );
80 };
81 make_two_way("width");
82 make_two_way("height");
83
84 let mut must_update = HashSet::new();
85
86 let mut base_props: HashSet<SmolStr> =
87 new_root.borrow().base_type.property_list().into_iter().map(|x| x.0).collect();
88 base_props.extend(win_elem.borrow().bindings.keys().cloned());
89 for prop in base_props {
90 if prop == "width" || prop == "height" {
91 continue;
92 }
93
94 if win_elem.borrow().property_declarations.contains_key(&prop) {
95 continue;
96 }
97
98 must_update.insert(NamedReference::new(&win_elem, prop.clone()));
99
100 if let Some(b) = win_elem.borrow_mut().bindings.remove(&prop) {
101 new_root.borrow_mut().bindings.insert(prop.clone(), b);
102 }
103 if let Some(a) = win_elem.borrow().property_analysis.borrow_mut().remove(&prop) {
104 new_root.borrow().property_analysis.borrow_mut().insert(prop.clone(), a);
105 }
106 }
107
108 crate::object_tree::visit_all_named_references(component, &mut |nr| {
109 if must_update.contains(nr) {
110 *nr = NamedReference::new(&new_root, nr.name().clone());
111 }
112 });
113
114 let fixup_element_reference = |expr: &mut Expression| {
117 if let Expression::FunctionCall { arguments, .. } = expr {
118 for arg in arguments.iter_mut() {
119 if matches!(arg, Expression::ElementReference(elr) if elr.upgrade().is_some_and(|elemrc| Rc::ptr_eq(&elemrc, &win_elem)))
120 {
121 *arg = Expression::ElementReference(Rc::downgrade(&new_root))
122 }
123 }
124 }
125 };
126
127 crate::object_tree::visit_all_expressions(component, |expr, _| {
128 expr.visit_recursive_mut(&mut |expr| fixup_element_reference(expr));
129 fixup_element_reference(expr)
130 });
131
132 component.root_element.borrow_mut().set_binding_if_not_set("background".into(), || {
133 Expression::Cast {
134 from: Expression::PropertyReference(NamedReference::new(
135 &style_metrics.root_element,
136 SmolStr::new_static("window-background"),
137 ))
138 .into(),
139 to: Type::Brush,
140 }
141 });
142}
143
144pub fn inherits_window(component: &Rc<Component>) -> bool {
145 component.root_element.borrow().builtin_type().map_or(true, |b| {
146 matches!(b.name.as_str(), "Window" | "Dialog" | "WindowItem" | "PopupWindow")
147 })
148}