1use super::{Item, ItemConsts, ItemRc, RenderingResult};
11use crate::Coord;
12use crate::component_factory::{ComponentFactory, FactoryContext};
13use crate::input::{
14 FocusEvent, FocusEventResult, InputEventFilterResult, InputEventResult, InternalKeyEvent,
15 KeyEventResult, MouseEvent,
16};
17use crate::item_rendering::{CachedRenderingData, RenderRectangle};
18use crate::item_tree::{IndexRange, ItemTreeRc, ItemTreeWeak, ItemWeak};
19use crate::item_tree::{ItemTreeNode, ItemVisitorVTable, TraversalOrder, VisitChildrenResult};
20use crate::layout::{LayoutInfo, Orientation};
21use crate::lengths::{LogicalLength, LogicalRect, LogicalSize};
22use crate::properties::{Property, PropertyTracker};
23#[cfg(feature = "rtti")]
24use crate::rtti::*;
25use crate::window::WindowAdapter;
26use alloc::boxed::Box;
27use alloc::rc::Rc;
28use const_field_offset::FieldOffsets;
29use core::cell::RefCell;
30use core::pin::Pin;
31use i_slint_core_macros::*;
32use once_cell::unsync::OnceCell;
33
34#[repr(C)]
35#[derive(FieldOffsets, Default, SlintElement)]
36#[pin]
37pub struct ComponentContainer {
39 pub width: Property<LogicalLength>,
40 pub height: Property<LogicalLength>,
41 pub component_factory: Property<ComponentFactory>,
42 pub has_component: Property<bool>,
43
44 pub cached_rendering_data: CachedRenderingData,
45
46 component_tracker: OnceCell<Pin<Box<PropertyTracker>>>,
47 item_tree: RefCell<Option<ItemTreeRc>>,
48
49 my_component: OnceCell<ItemTreeWeak>,
50 embedding_item_tree_index: OnceCell<u32>,
51 self_weak: OnceCell<ItemWeak>,
52}
53
54impl ComponentContainer {
55 pub fn ensure_updated(self: Pin<&Self>) {
56 let factory = self
57 .component_tracker
58 .get()
59 .unwrap()
60 .as_ref()
61 .evaluate_if_dirty(|| self.component_factory());
62
63 let Some(factory) = factory else {
64 return;
65 };
66
67 let mut window = None;
68 if let Some(parent) = self.my_component.get().and_then(|x| x.upgrade()) {
69 vtable::VRc::borrow_pin(&parent).as_ref().window_adapter(false, &mut window);
70 }
71 let prevent_focus_change =
72 window.as_ref().is_some_and(|w| w.window().0.prevent_focus_change.replace(true));
73
74 let factory_context = FactoryContext {
75 parent_item_tree: self.my_component.get().unwrap().clone(),
76 parent_item_tree_index: *self.embedding_item_tree_index.get().unwrap(),
77 };
78
79 let product = factory.build(factory_context);
80
81 if let Some(w) = window {
82 w.window().0.prevent_focus_change.set(prevent_focus_change);
83 }
84
85 if let Some(item_tree) = product.clone() {
86 let item_tree = vtable::VRc::borrow_pin(&item_tree);
87 let root_item = item_tree.as_ref().get_item_ref(0);
88 if let Some(window_item) =
89 crate::items::ItemRef::downcast_pin::<crate::items::WindowItem>(root_item)
90 {
91 let weak = self.self_weak.get().unwrap().clone();
94 window_item.width.set_binding(Box::new(move || {
95 if let Some(self_rc) = weak.upgrade() {
96 let self_pin = self_rc.borrow();
97 if let Some(self_cc) = crate::items::ItemRef::downcast_pin::<Self>(self_pin)
98 {
99 return self_cc.width();
100 }
101 }
102 Default::default()
103 }));
104 let weak = self.self_weak.get().unwrap().clone();
105 window_item.height.set_binding(Box::new(move || {
106 if let Some(self_rc) = weak.upgrade() {
107 let self_pin = self_rc.borrow();
108 if let Some(self_cc) = crate::items::ItemRef::downcast_pin::<Self>(self_pin)
109 {
110 return self_cc.height();
111 }
112 }
113 Default::default()
114 }));
115 }
116 }
117
118 self.has_component.set(product.is_some());
119
120 self.item_tree.replace(product);
121 }
122
123 pub fn subtree_range(self: Pin<&Self>) -> IndexRange {
124 IndexRange { start: 0, end: if self.item_tree.borrow().is_some() { 1 } else { 0 } }
125 }
126
127 pub fn subtree_component(self: Pin<&Self>) -> ItemTreeWeak {
128 self.item_tree.borrow().as_ref().map_or(ItemTreeWeak::default(), vtable::VRc::downgrade)
129 }
130
131 pub fn visit_children_item(
132 self: Pin<&Self>,
133 _index: isize,
134 order: TraversalOrder,
135 visitor: vtable::VRefMut<ItemVisitorVTable>,
136 ) -> VisitChildrenResult {
137 let rc = self.item_tree.borrow().clone();
138 if let Some(rc) = &rc {
139 vtable::VRc::borrow_pin(rc).as_ref().visit_children_item(-1, order, visitor)
140 } else {
141 VisitChildrenResult::CONTINUE
142 }
143 }
144}
145
146impl Item for ComponentContainer {
147 fn init(self: Pin<&Self>, self_rc: &ItemRc) {
148 let rc = self_rc.item_tree();
149
150 self.my_component.set(vtable::VRc::downgrade(rc)).ok().unwrap();
151
152 let pin_rc = vtable::VRc::borrow_pin(rc);
154 let item_tree = pin_rc.as_ref().get_item_tree();
155 let ItemTreeNode::Item { children_index, children_count, .. } =
156 item_tree[self_rc.index() as usize]
157 else {
158 panic!("ComponentContainer not found in item tree");
159 };
160
161 assert_eq!(children_count, 1);
162 assert!(matches!(item_tree[children_index as usize], ItemTreeNode::DynamicTree { .. }));
163
164 self.embedding_item_tree_index.set(children_index).ok().unwrap();
165
166 self.component_tracker.set(Box::pin(PropertyTracker::default())).ok().unwrap();
167 self.self_weak.set(self_rc.downgrade()).ok().unwrap();
168 }
169
170 fn deinit(self: Pin<&Self>, _window_adapter: &Rc<dyn WindowAdapter>) {}
171
172 fn layout_info(
173 self: Pin<&Self>,
174 orientation: Orientation,
175 _cross_axis_constraint: Coord,
176 _window_adapter: &Rc<dyn WindowAdapter>,
177 _self_rc: &ItemRc,
178 ) -> LayoutInfo {
179 self.ensure_updated();
180 if let Some(rc) = self.item_tree.borrow().clone() {
181 vtable::VRc::borrow_pin(&rc).as_ref().layout_info(orientation)
182 } else {
183 Default::default()
184 }
185 }
186
187 fn input_event_filter_before_children(
188 self: Pin<&Self>,
189 _: &MouseEvent,
190 _window_adapter: &Rc<dyn WindowAdapter>,
191 _self_rc: &ItemRc,
192 _: &mut super::MouseCursor,
193 ) -> InputEventFilterResult {
194 InputEventFilterResult::ForwardAndIgnore
195 }
196
197 fn input_event(
198 self: Pin<&Self>,
199 _: &MouseEvent,
200 _window_adapter: &Rc<dyn WindowAdapter>,
201 _self_rc: &ItemRc,
202 _: &mut super::MouseCursor,
203 ) -> InputEventResult {
204 InputEventResult::EventIgnored
205 }
206
207 fn focus_event(
208 self: Pin<&Self>,
209 _: &FocusEvent,
210 _window_adapter: &Rc<dyn WindowAdapter>,
211 _self_rc: &ItemRc,
212 ) -> FocusEventResult {
213 FocusEventResult::FocusIgnored
214 }
215
216 fn capture_key_event(
217 self: Pin<&Self>,
218 _: &InternalKeyEvent,
219 _window_adapter: &Rc<dyn WindowAdapter>,
220 _self_rc: &ItemRc,
221 ) -> KeyEventResult {
222 KeyEventResult::EventIgnored
223 }
224
225 fn key_event(
226 self: Pin<&Self>,
227 _: &InternalKeyEvent,
228 _window_adapter: &Rc<dyn WindowAdapter>,
229 _self_rc: &ItemRc,
230 ) -> KeyEventResult {
231 KeyEventResult::EventIgnored
232 }
233
234 fn render(
235 self: Pin<&Self>,
236 backend: &mut super::ItemRendererRef,
237 item_rc: &ItemRc,
238 size: LogicalSize,
239 ) -> RenderingResult {
240 backend.draw_rectangle(self, item_rc, size, &self.cached_rendering_data);
241 RenderingResult::ContinueRenderingChildren
242 }
243
244 fn bounding_rect(
245 self: core::pin::Pin<&Self>,
246 _window_adapter: &Rc<dyn WindowAdapter>,
247 _self_rc: &ItemRc,
248 geometry: LogicalRect,
249 ) -> LogicalRect {
250 geometry
251 }
252
253 fn clips_children(self: core::pin::Pin<&Self>) -> bool {
254 false
255 }
256}
257
258impl RenderRectangle for ComponentContainer {
259 fn background(self: Pin<&Self>) -> crate::Brush {
260 self.item_tree
261 .borrow()
262 .clone()
263 .and_then(|item_tree| {
264 let item_tree = vtable::VRc::borrow_pin(&item_tree);
265 let root_item = item_tree.as_ref().get_item_ref(0);
266 crate::items::ItemRef::downcast_pin::<crate::items::WindowItem>(root_item)
267 .map(|window_item| window_item.background())
268 })
269 .unwrap_or_default()
270 }
271}
272
273impl ItemConsts for ComponentContainer {
274 const cached_rendering_data_offset: const_field_offset::FieldOffset<
275 ComponentContainer,
276 CachedRenderingData,
277 > = ComponentContainer::FIELD_OFFSETS.cached_rendering_data().as_unpinned_projection();
278}