1use crate::erased::{ErasedItemRc, SubComponentCallback, SubComponentProperty};
8use crate::globals::GlobalStorage;
9use crate::item_registry::ItemRegistry;
10use i_slint_compiler::llr::{
11 self, CompilationUnit, ItemInstanceIdx, RepeatedElementIdx, SubComponentIdx,
12 SubComponentInstanceIdx,
13};
14use i_slint_core::item_tree::{ItemTreeNode, ItemTreeVTable};
15use i_slint_core::model::{Conditional, Repeater};
16use i_slint_core::properties::ChangeTracker;
17use i_slint_core::window::WindowAdapterRc;
18use i_slint_core::{Callback, Property};
19use std::cell::{OnceCell, RefCell};
20use std::pin::Pin;
21use std::rc::{Rc, Weak};
22use typed_index_collections::TiVec;
23use vtable::{VRc, VWeak};
24
25pub enum RepeaterOrConditional {
30 Repeater(Pin<Box<Repeater<Instance>>>),
31 Conditional(Pin<Box<Conditional<Instance>>>),
32}
33
34impl RepeaterOrConditional {
35 pub fn visit(
36 &self,
37 order: i_slint_core::item_tree::TraversalOrder,
38 visitor: i_slint_core::item_tree::ItemVisitorRefMut<'_>,
39 ) -> i_slint_core::item_tree::VisitChildrenResult {
40 match self {
41 Self::Repeater(r) => Pin::as_ref(r).visit(order, visitor),
42 Self::Conditional(c) => Pin::as_ref(c).visit(order, visitor),
43 }
44 }
45
46 pub fn range(&self) -> core::ops::Range<usize> {
47 match self {
48 Self::Repeater(r) => r.range(),
49 Self::Conditional(c) => c.range(),
50 }
51 }
52
53 pub fn instance_at(&self, subindex: usize) -> Option<VRc<ItemTreeVTable, Instance>> {
54 match self {
55 Self::Repeater(r) => r.instance_at(subindex),
56 Self::Conditional(c) => c.instance_at(subindex),
57 }
58 }
59
60 pub fn instances_vec(&self) -> Vec<VRc<ItemTreeVTable, Instance>> {
61 match self {
62 Self::Repeater(r) => r.instances_vec(),
63 Self::Conditional(c) => c.instances_vec(),
64 }
65 }
66
67 pub fn track_instance_changes(&self) {
72 match self {
73 Self::Repeater(r) => Pin::as_ref(r).track_instance_changes(),
74 Self::Conditional(c) => Pin::as_ref(c).track_instance_changes(),
75 }
76 }
77
78 pub fn ensure_updated(
82 &self,
83 init: impl Fn() -> VRc<ItemTreeVTable, Instance> + 'static,
84 ) -> bool {
85 match self {
86 Self::Repeater(r) => Pin::as_ref(r).ensure_updated(init),
87 Self::Conditional(c) => Pin::as_ref(c).ensure_updated(init),
88 }
89 }
90
91 pub fn ensure_updated_listview_callback(
98 &self,
99 init: impl Fn() -> VRc<ItemTreeVTable, Instance> + 'static,
100 props: &dyn i_slint_core::model::ListViewProperties,
101 listview_width: i_slint_core::lengths::LogicalLength,
102 listview_height: i_slint_core::lengths::LogicalLength,
103 ) -> bool {
104 match self {
105 Self::Repeater(r) => Pin::as_ref(r).ensure_updated_listview_callback(
106 init,
107 props,
108 listview_width,
109 listview_height,
110 ),
111 Self::Conditional(_) => unreachable!("listview on a conditional element"),
112 }
113 }
114
115 pub fn set_model_binding(
117 &self,
118 binding: impl Fn() -> i_slint_core::model::ModelRc<crate::Value> + 'static,
119 ) {
120 match self {
121 Self::Repeater(r) => Pin::as_ref(r).set_model_binding(binding),
122 Self::Conditional(_) => unreachable!("set_model_binding on conditional"),
123 }
124 }
125
126 pub fn set_condition_binding(&self, binding: impl Fn() -> bool + 'static) {
128 match self {
129 Self::Conditional(c) => c.set_model_binding(binding),
130 Self::Repeater(_) => unreachable!("set_condition_binding on repeater"),
131 }
132 }
133
134 pub fn model_set_row_data(&self, row: usize, data: crate::Value) {
136 match self {
137 Self::Repeater(r) => Pin::as_ref(r).model_set_row_data(row, data),
138 Self::Conditional(_) => {} }
140 }
141
142 pub fn is_conditional(&self) -> bool {
143 matches!(self, Self::Conditional(_))
144 }
145}
146
147pub struct SubComponentInstance {
151 pub compilation_unit: Rc<CompilationUnit>,
152 pub sub_component_idx: SubComponentIdx,
153 pub properties: TiVec<llr::PropertyIdx, SubComponentProperty>,
154 pub callbacks: TiVec<llr::CallbackIdx, SubComponentCallback>,
155 pub callback_trackers: TiVec<llr::CallbackIdx, Option<Pin<Rc<Property<()>>>>>,
160 pub items: TiVec<ItemInstanceIdx, ErasedItemRc>,
161 pub sub_components: TiVec<SubComponentInstanceIdx, Pin<Rc<SubComponentInstance>>>,
162 pub repeaters: TiVec<RepeatedElementIdx, RepeaterOrConditional>,
167 pub parent: Weak<SubComponentInstance>,
169 pub root: OnceCell<VWeak<ItemTreeVTable, Instance>>,
171 pub change_trackers: Vec<ChangeTracker>,
174 pub timers: Vec<i_slint_core::timers::Timer>,
179 pub popup_ids: Vec<std::cell::Cell<Option<std::num::NonZeroU32>>>,
184 pub repeated_in: OnceCell<(Weak<SubComponentInstance>, RepeatedElementIdx)>,
188 pub menubar: RefCell<Option<vtable::VRc<i_slint_core::menus::MenuVTable>>>,
191}
192
193pub struct Instance {
195 pub root_sub_component: Pin<Rc<SubComponentInstance>>,
196 pub tree_nodes: Box<[ItemTreeNode]>,
198 pub dynamic_table: Box<[Option<(Box<[SubComponentInstanceIdx]>, RepeatedElementIdx)>]>,
202 pub item_table: Box<[Option<(Box<[SubComponentInstanceIdx]>, ItemInstanceIdx)>]>,
206 pub globals: Rc<GlobalStorage>,
207 pub self_weak: OnceCell<VWeak<ItemTreeVTable, Instance>>,
208 pub parent_instance: Weak<SubComponentInstance>,
211 pub public_component_index: Option<usize>,
215 pub window_adapter: OnceCell<WindowAdapterRc>,
218 window_adapter_error: OnceCell<String>,
222 pub window_attached: OnceCell<()>,
227 pub bindings_installed: OnceCell<()>,
230 pub init_code_run: OnceCell<()>,
236 pub embedded_in: OnceCell<(VWeak<ItemTreeVTable>, u32)>,
242 pub type_loaders: crate::component::TypeLoaders,
247}
248
249impl Drop for Instance {
250 fn drop(&mut self) {
251 let Some(adapter) = self.window_adapter.get().cloned().or_else(|| {
261 let mut parent = self.parent_instance.upgrade();
262 while let Some(sub) = parent {
263 let root = sub.root.get().and_then(|w| w.upgrade())?;
264 if let Some(a) = root.window_adapter.get() {
265 return Some(a.clone());
266 }
267 parent = root.parent_instance.upgrade();
268 }
269 None
270 }) else {
271 return;
272 };
273 vtable::new_vref!(let item_tree_ref : VRef<i_slint_core::item_tree::ItemTreeVTable> for i_slint_core::item_tree::ItemTree = self);
274 let items = collect_item_refs(&self.root_sub_component);
275 for item in &items {
280 item.as_ref().deinit(&adapter);
281 }
282 let _ =
283 adapter.renderer().free_graphics_resources(item_tree_ref, &mut items.iter().copied());
284 if let Some(internal) = adapter.internal(i_slint_core::InternalToken) {
285 internal.unregister_item_tree(item_tree_ref, &mut items.iter().copied());
286 }
287 let window_inner = i_slint_core::window::WindowInner::from_pub(adapter.window());
288 let to_close_popups = window_inner
289 .active_popups()
290 .iter()
291 .filter_map(|p| p.parent_item.upgrade().is_none().then_some(p.popup_id))
292 .collect::<Vec<_>>();
293 for popup_id in to_close_popups {
294 window_inner.close_popup(popup_id);
295 }
296 }
297}
298
299fn collect_item_refs<'a>(
302 sub: &'a Pin<Rc<SubComponentInstance>>,
303) -> Vec<Pin<vtable::VRef<'a, i_slint_core::items::ItemVTable>>> {
304 let mut out = Vec::new();
305 fn walk<'a>(
306 sub: &'a Pin<Rc<SubComponentInstance>>,
307 out: &mut Vec<Pin<vtable::VRef<'a, i_slint_core::items::ItemVTable>>>,
308 ) {
309 for item in &sub.items {
310 out.push(Pin::as_ref(item).as_item_ref());
311 }
312 for nested in &sub.sub_components {
313 walk(nested, out);
314 }
315 }
316 walk(sub, &mut out);
317 out
318}
319
320impl Instance {
321 pub fn window_adapter_or_default(&self) -> Option<WindowAdapterRc> {
324 self.try_window_adapter().ok()
325 }
326
327 pub fn try_window_adapter(&self) -> Result<WindowAdapterRc, i_slint_core::api::PlatformError> {
343 if let Some(a) = self.window_adapter.get() {
344 return Ok(a.clone());
345 }
346 if let Some((outer_weak, _)) = self.embedded_in.get()
352 && let Some(outer) = outer_weak.upgrade()
353 {
354 let mut result = None;
355 vtable::VRc::borrow_pin(&outer).as_ref().window_adapter(true, &mut result);
356 if let Some(a) = result {
357 let _ = self.window_adapter.set(a.clone());
358 return Ok(a);
359 }
360 }
361 let mut outermost_root = None;
364 let mut parent_sub = self.parent_instance.upgrade();
365 while let Some(sub) = parent_sub {
366 let Some(root_vrc) = sub.root.get().and_then(|w| w.upgrade()) else { break };
367 if let Some(a) = root_vrc.window_adapter.get() {
368 let cloned = a.clone();
369 let _ = self.window_adapter.set(cloned.clone());
372 return Ok(cloned);
373 }
374 parent_sub = root_vrc.parent_instance.upgrade();
375 outermost_root = Some(root_vrc);
376 }
377 if let Some(e) = self
378 .window_adapter_error
379 .get()
380 .or_else(|| outermost_root.as_ref().and_then(|root| root.window_adapter_error.get()))
381 {
382 return Err(i_slint_core::api::PlatformError::Other(e.clone()));
383 }
384 let adapter = i_slint_backend_selector::with_platform(|p| p.create_window_adapter())
385 .inspect_err(|e| {
386 let msg = e.to_string();
387 if let Some(root) = &outermost_root {
388 let _ = root.window_adapter_error.set(msg.clone());
389 }
390 let _ = self.window_adapter_error.set(msg);
391 })?;
392 adapter.renderer().set_window_adapter(&adapter);
396 if let Some(root) = outermost_root {
400 let _ = root.window_adapter.set(adapter.clone());
401 }
402 let _ = self.window_adapter.set(adapter.clone());
403 Ok(adapter)
404 }
405
406 pub fn attach_to_window(&self) {
415 if self.window_attached.get().is_some() {
416 return;
417 }
418 let Some(adapter) = self.window_adapter_or_default() else { return };
419 let Some(self_rc) = self.self_weak.get().and_then(|w| w.upgrade()) else { return };
420 let _ = self.window_attached.set(());
421 i_slint_core::window::WindowInner::from_pub(adapter.window())
422 .set_component(&vtable::VRc::into_dyn(self_rc));
423 }
424}
425
426pub(crate) fn component_container_item(
432 sub: &Pin<Rc<SubComponentInstance>>,
433 rep_idx: RepeatedElementIdx,
434) -> Option<Pin<&i_slint_core::items::ComponentContainer>> {
435 let sc = &sub.compilation_unit.sub_components[sub.sub_component_idx];
436 let cc_item_idx = sc.repeated.get(rep_idx)?.container_item_index?;
437 let item = sub.items.get(cc_item_idx)?;
438 i_slint_core::items::ItemRef::downcast_pin::<i_slint_core::items::ComponentContainer>(
439 Pin::as_ref(item).as_item_ref(),
440 )
441}
442
443impl Instance {
444 pub fn dynamic_at(
448 &self,
449 tree_index: u32,
450 ) -> Option<(Pin<Rc<SubComponentInstance>>, RepeatedElementIdx)> {
451 let entry = self.dynamic_table.get(tree_index as usize)?.as_ref()?;
452 let mut current = self.root_sub_component.clone();
453 for &idx in entry.0.iter() {
454 let next = current.sub_components[idx].clone();
455 current = next;
456 }
457 Some((current, entry.1))
458 }
459
460 pub fn ensure_updated(&self, tree_index: u32) -> bool {
471 let Some((sub, rep_idx)) = self.dynamic_at(tree_index) else { return false };
472 if let Some(cc) = component_container_item(&sub, rep_idx) {
473 return cc.ensure_updated();
474 }
475 let cu = sub.compilation_unit.clone();
476 let sc_idx = sub.sub_component_idx;
477 let sub_weak = Rc::downgrade(&Pin::into_inner(sub.clone()));
478 let globals = self.globals.clone();
479 let repeated = &cu.sub_components[sc_idx].repeated[rep_idx];
480 let listview_factory = repeated.listview.is_some();
481 let listview_info = repeated.listview.clone();
482 let factory = move || {
483 let item_tree = &cu.sub_components[sc_idx].repeated[rep_idx].sub_tree;
484 let vrc = Instance::new_repeated(
485 cu.clone(),
486 item_tree,
487 sub_weak.clone(),
488 rep_idx,
489 globals.clone(),
490 );
491 if listview_factory {
492 install_bindings_for_repeated_row(&vrc);
497 }
498 vrc
499 };
500 let repeater = &sub.repeaters[rep_idx];
501 if let Some(lv) = listview_info.as_ref() {
502 let listview_width = read_logical_length(&sub, &lv.listview_width);
503 let listview_height = read_logical_length(&sub, &lv.listview_height);
504 if listview_height.get() <= 0.0 {
509 return false;
510 }
511 let props = ValueListViewProps {
512 content_y: lv.content_y.clone(),
513 content_width: lv.content_width.clone(),
514 content_height: lv.content_height.clone(),
515 ctx_sub: sub.clone(),
516 };
517 repeater.ensure_updated_listview_callback(
518 factory,
519 &props,
520 listview_width,
521 listview_height,
522 )
523 } else {
524 repeater.ensure_updated(factory)
525 }
526 }
527
528 pub fn ensure_instantiated(&self) -> bool {
533 let mut changed = false;
534 for idx in 0..self.dynamic_table.len() {
535 if self.dynamic_table[idx].is_some() {
536 changed |= self.ensure_updated(idx as u32);
537 }
538 }
539 changed
540 }
541
542 pub fn visit_dynamic_children(
550 self: Pin<&Self>,
551 dyn_index: u32,
552 order: i_slint_core::item_tree::TraversalOrder,
553 visitor: vtable::VRefMut<'_, i_slint_core::item_tree::ItemVisitorVTable>,
554 ) -> i_slint_core::item_tree::VisitChildrenResult {
555 let Some((sub, rep_idx)) = self.get_ref().dynamic_at(dyn_index) else {
556 return i_slint_core::item_tree::VisitChildrenResult::CONTINUE;
557 };
558 if let Some(cc) = component_container_item(&sub, rep_idx) {
559 return cc.visit_children_item(-1, order, visitor);
560 }
561 let repeater = &sub.repeaters[rep_idx];
565 let sc = &sub.compilation_unit.sub_components[sub.sub_component_idx];
566 if let (Some(lv), RepeaterOrConditional::Repeater(r)) =
567 (sc.repeated[rep_idx].listview.as_ref(), repeater)
568 {
569 let props = ValueListViewProps {
570 content_y: lv.content_y.clone(),
571 content_width: lv.content_width.clone(),
572 content_height: lv.content_height.clone(),
573 ctx_sub: sub.clone(),
574 };
575 let listview_width = read_logical_length(&sub, &lv.listview_width);
576 let _ = read_logical_length(&sub, &lv.listview_height);
577 Pin::as_ref(r).track_changes_listview_callback(&props, listview_width);
578 }
579 repeater.visit(order, visitor)
580 }
581
582 pub fn new(
587 compilation_unit: Rc<CompilationUnit>,
588 public_component_index: usize,
589 ) -> VRc<ItemTreeVTable, Instance> {
590 Self::new_with_window(compilation_unit, public_component_index, None, Default::default())
591 }
592
593 pub fn new_with_window(
597 compilation_unit: Rc<CompilationUnit>,
598 public_component_index: usize,
599 window_adapter: Option<i_slint_core::window::WindowAdapterRc>,
600 type_loaders: crate::component::TypeLoaders,
601 ) -> VRc<ItemTreeVTable, Instance> {
602 Self::new_with_options(
603 compilation_unit,
604 public_component_index,
605 window_adapter,
606 type_loaders,
607 None,
608 )
609 }
610
611 pub fn new_embedded(
616 compilation_unit: Rc<CompilationUnit>,
617 public_component_index: usize,
618 type_loaders: crate::component::TypeLoaders,
619 parent: vtable::VWeak<ItemTreeVTable>,
620 parent_item_tree_index: u32,
621 ) -> VRc<ItemTreeVTable, Instance> {
622 Self::new_with_options(
623 compilation_unit,
624 public_component_index,
625 None,
626 type_loaders,
627 Some((parent, parent_item_tree_index)),
628 )
629 }
630
631 fn new_with_options(
632 compilation_unit: Rc<CompilationUnit>,
633 public_component_index: usize,
634 window_adapter: Option<i_slint_core::window::WindowAdapterRc>,
635 type_loaders: crate::component::TypeLoaders,
636 embedded_in: Option<(vtable::VWeak<ItemTreeVTable>, u32)>,
637 ) -> VRc<ItemTreeVTable, Instance> {
638 let public = &compilation_unit.public_components[public_component_index];
639 let globals = Rc::new(GlobalStorage::new(&compilation_unit));
640 let item_tree = &public.item_tree;
641 let vrc = build_instance(
642 &compilation_unit,
643 item_tree,
644 Weak::new(),
645 globals,
646 Some(public_component_index),
647 type_loaders,
648 );
649 if let Some(adapter) = window_adapter {
650 let _ = vrc.window_adapter.set(adapter);
651 }
652 if let Some((parent, idx)) = embedded_in {
656 let _ = vrc.embedded_in.set((parent, idx));
657 }
658 finalize_instance(&vrc);
659 vrc
660 }
661
662 pub fn new_repeated(
667 compilation_unit: Rc<CompilationUnit>,
668 item_tree: &llr::ItemTree,
669 parent: Weak<SubComponentInstance>,
670 repeater_idx: RepeatedElementIdx,
671 globals: Rc<GlobalStorage>,
672 ) -> VRc<ItemTreeVTable, Instance> {
673 let vrc = build_instance(
674 &compilation_unit,
675 item_tree,
676 parent.clone(),
677 globals,
678 None,
679 Default::default(),
680 );
681 let _ = vrc.root_sub_component.repeated_in.set((parent, repeater_idx));
682 vrc
683 }
684
685 pub fn new_popup(
689 compilation_unit: Rc<CompilationUnit>,
690 item_tree: &llr::ItemTree,
691 parent: Weak<SubComponentInstance>,
692 globals: Rc<GlobalStorage>,
693 ) -> VRc<ItemTreeVTable, Instance> {
694 build_instance(&compilation_unit, item_tree, parent, globals, None, Default::default())
695 }
696}
697
698fn build_instance(
706 compilation_unit: &Rc<CompilationUnit>,
707 item_tree: &llr::ItemTree,
708 parent: Weak<SubComponentInstance>,
709 globals: Rc<GlobalStorage>,
710 public_component_index: Option<usize>,
711 type_loaders: crate::component::TypeLoaders,
712) -> VRc<ItemTreeVTable, Instance> {
713 let parent_for_root = parent.clone();
714 let root_sub_component =
715 build_sub_component_instance(compilation_unit, item_tree.root, parent_for_root);
716 let (tree_nodes, dynamic_table, item_table) = build_tree_nodes(&item_tree.tree);
717
718 let vrc = VRc::new(Instance {
719 root_sub_component,
720 tree_nodes: tree_nodes.into_boxed_slice(),
721 dynamic_table: dynamic_table.into_boxed_slice(),
722 item_table: item_table.into_boxed_slice(),
723 globals,
724 self_weak: OnceCell::new(),
725 parent_instance: parent,
726 public_component_index,
727 window_adapter: OnceCell::new(),
728 window_adapter_error: OnceCell::new(),
729 window_attached: OnceCell::new(),
730 bindings_installed: OnceCell::new(),
731 init_code_run: OnceCell::new(),
732 embedded_in: OnceCell::new(),
733 type_loaders,
734 });
735 let weak = VRc::downgrade(&vrc);
736 let _ = vrc.self_weak.set(weak.clone());
737 let _ = vrc.globals.root.set(weak.clone());
739 propagate_root(&vrc.root_sub_component, &weak);
740 vrc
741}
742
743pub(crate) fn finalize_instance(vrc: &VRc<ItemTreeVTable, Instance>) {
753 install_bindings_for_repeated_row(vrc);
754 if vrc.init_code_run.get().is_some() {
755 return;
756 }
757 let _ = vrc.init_code_run.set(());
758 if vrc.public_component_index.is_some() && vrc.embedded_in.get().is_none() {
766 vrc.attach_to_window();
767 }
768 {
775 let dyn_rc = vtable::VRc::into_dyn(vrc.self_weak.get().unwrap().upgrade().unwrap());
776 let adapter = vrc.window_adapter_or_default();
777 i_slint_core::item_tree::register_item_tree(&dyn_rc, adapter);
778 }
779 crate::bindings::run_init_code_for_instance(vrc);
780}
781
782pub(crate) fn install_bindings_for_repeated_row(vrc: &VRc<ItemTreeVTable, Instance>) {
787 if vrc.bindings_installed.get().is_some() {
788 return;
789 }
790 let _ = vrc.bindings_installed.set(());
791 let is_root = vrc.parent_instance.upgrade().is_none();
792 if is_root {
793 crate::globals::install_global_bindings(&vrc.globals);
794 }
795 crate::bindings::install_bindings_only(vrc);
796}
797
798fn propagate_root(sub: &Pin<Rc<SubComponentInstance>>, weak: &VWeak<ItemTreeVTable, Instance>) {
800 let _ = sub.root.set(weak.clone());
801 for nested in &sub.sub_components {
802 propagate_root(nested, weak);
803 }
804}
805
806fn build_sub_component_instance(
808 cu: &Rc<CompilationUnit>,
809 sub_idx: SubComponentIdx,
810 parent: Weak<SubComponentInstance>,
811) -> Pin<Rc<SubComponentInstance>> {
812 let sc = &cu.sub_components[sub_idx];
813 let registry = ItemRegistry::global();
814
815 let properties = sc
816 .properties
817 .iter()
818 .map(|p| Rc::pin(Property::new(crate::eval::default_value_for_type(&p.ty))))
819 .collect();
820 let callbacks = sc.callbacks.iter().map(|_| Rc::pin(Callback::default())).collect();
821 let callback_trackers =
822 sc.callbacks.iter().map(|c| c.needs_tracker.then(|| Rc::pin(Property::new(())))).collect();
823 let items =
824 sc.items
825 .iter()
826 .map(|item| {
827 registry.factory(&item.ty.class_name).unwrap_or_else(|| {
828 panic!("native item `{}` is not registered", item.ty.class_name)
829 })()
830 })
831 .collect();
832 let repeaters = sc
833 .repeated
834 .iter()
835 .map(|rep| {
836 if rep.data_prop.is_none() {
837 RepeaterOrConditional::Conditional(Box::pin(Conditional::default()))
838 } else {
839 RepeaterOrConditional::Repeater(Box::pin(Repeater::default()))
840 }
841 })
842 .collect();
843
844 let rc = Rc::new_cyclic(|weak_self: &Weak<SubComponentInstance>| {
848 let sub_components = sc
849 .sub_components
850 .iter()
851 .map(|nested| build_sub_component_instance(cu, nested.ty, weak_self.clone()))
852 .collect();
853 SubComponentInstance {
854 compilation_unit: cu.clone(),
855 sub_component_idx: sub_idx,
856 properties,
857 callbacks,
858 callback_trackers,
859 items,
860 sub_components,
861 repeaters,
862 parent,
863 root: OnceCell::new(),
864 change_trackers: std::iter::repeat_with(ChangeTracker::default)
865 .take(2 * sc.timers.len() + sc.change_callbacks.len())
866 .collect(),
867 timers: std::iter::repeat_with(Default::default).take(sc.timers.len()).collect(),
868 popup_ids: vec![std::cell::Cell::new(None); sc.popup_windows.len()],
869 repeated_in: OnceCell::new(),
870 menubar: RefCell::new(None),
871 }
872 });
873 Pin::new(rc)
874}
875
876fn read_logical_length(
880 sub: &Pin<Rc<SubComponentInstance>>,
881 mr: &llr::MemberReference,
882) -> i_slint_core::lengths::LogicalLength {
883 let mut ctx = crate::eval::EvalContext::new(sub.clone());
884 let v = crate::eval::load_property(&ctx, mr);
885 let _ = &mut ctx;
886 let n: f64 = v.try_into().unwrap_or(0.0);
887 i_slint_core::lengths::LogicalLength::new(n as f32)
888}
889
890struct ValueListViewProps {
896 content_y: llr::MemberReference,
897 content_width: Option<llr::MemberReference>,
900 content_height: Option<llr::MemberReference>,
901 ctx_sub: Pin<Rc<SubComponentInstance>>,
902}
903
904impl i_slint_core::model::ListViewProperties for ValueListViewProps {
905 fn content_y_get(&self) -> i_slint_core::lengths::LogicalLength {
906 read_logical_length(&self.ctx_sub, &self.content_y)
907 }
908 fn content_y_get_internal(&self) -> i_slint_core::lengths::LogicalLength {
909 read_logical_length(&self.ctx_sub, &self.content_y)
913 }
914 fn content_y_set(&self, value: i_slint_core::lengths::LogicalLength) {
915 let ctx = crate::eval::EvalContext::new(self.ctx_sub.clone());
916 crate::eval::store_property(
917 &ctx,
918 &self.content_y,
919 crate::Value::Number(value.get() as f64),
920 );
921 }
922 fn content_y_has_binding(&self) -> bool {
923 false
927 }
928 fn computes_content_height(&self) -> bool {
929 self.content_height.is_some()
930 }
931 fn content_width_set(&self, value: i_slint_core::lengths::LogicalLength) {
932 let Some(content_width) = &self.content_width else { return };
933 let ctx = crate::eval::EvalContext::new(self.ctx_sub.clone());
934 crate::eval::store_property(&ctx, content_width, crate::Value::Number(value.get() as f64));
935 }
936 fn content_height_set(&self, value: i_slint_core::lengths::LogicalLength) {
937 let Some(content_height) = &self.content_height else { return };
938 let ctx = crate::eval::EvalContext::new(self.ctx_sub.clone());
939 crate::eval::store_property(&ctx, content_height, crate::Value::Number(value.get() as f64));
940 }
941 fn register_as_dependencies(&self) {
942 if let Some(content_width) = &self.content_width {
945 let _ = read_logical_length(&self.ctx_sub, content_width);
946 }
947 if let Some(content_height) = &self.content_height {
948 let _ = read_logical_length(&self.ctx_sub, content_height);
949 }
950 let _ = read_logical_length(&self.ctx_sub, &self.content_y);
951 }
952}
953
954type DynamicEntry = Option<(Box<[SubComponentInstanceIdx]>, RepeatedElementIdx)>;
955type ItemEntry = Option<(Box<[SubComponentInstanceIdx]>, ItemInstanceIdx)>;
956
957fn build_tree_nodes(
965 root: &llr::TreeNode,
966) -> (Vec<ItemTreeNode>, Vec<DynamicEntry>, Vec<ItemEntry>) {
967 use itertools::Either;
968
969 let mut out = Vec::new();
970 let mut dyn_table: Vec<DynamicEntry> = Vec::new();
971 let mut item_table: Vec<ItemEntry> = Vec::new();
972 root.visit_in_array(&mut |node, children_offset, parent_index| {
973 let parent_index = parent_index as u32;
974 let (entry, dyn_entry, item_entry) = match node.item_index {
975 Either::Left(item_idx) => (
976 ItemTreeNode::Item {
977 is_accessible: node.is_accessible,
978 children_count: node.children.len() as u32,
979 children_index: children_offset as u32,
980 parent_index,
981 item_array_index: out.len() as u32,
984 },
985 None,
986 Some((node.sub_component_path.clone().into_boxed_slice(), item_idx)),
987 ),
988 Either::Right(dynamic_index) => (
989 ItemTreeNode::DynamicTree { index: out.len() as u32, parent_index },
997 Some((
998 node.sub_component_path.clone().into_boxed_slice(),
999 (dynamic_index as usize).into(),
1000 )),
1001 None,
1002 ),
1003 };
1004 out.push(entry);
1005 dyn_table.push(dyn_entry);
1006 item_table.push(item_entry);
1007 });
1008 (out, dyn_table, item_table)
1009}
1010
1011impl i_slint_core::model::RepeatedItemTree for Instance {
1016 type Data = crate::Value;
1017
1018 fn update(&self, index: usize, data: Self::Data) {
1019 let sc_idx = self.root_sub_component.sub_component_idx;
1020 let cu = self.root_sub_component.compilation_unit.clone();
1021 let sc = &cu.sub_components[sc_idx];
1022 for (idx, prop) in sc.properties.iter_enumerated() {
1027 let target = &self.root_sub_component.properties[idx];
1028 match prop.name.as_str() {
1029 "model_data" => Pin::as_ref(target).set(data.clone()),
1030 "model_index" => Pin::as_ref(target).set(crate::Value::Number(index as f64)),
1031 _ => {}
1032 }
1033 }
1034 }
1035
1036 fn init(&self) {
1037 if let Some(weak) = self.self_weak.get()
1043 && let Some(vrc) = weak.upgrade()
1044 {
1045 finalize_instance(&vrc);
1046 }
1047 }
1048
1049 fn listview_layout(
1050 self: Pin<&Self>,
1051 offset_y: &mut i_slint_core::lengths::LogicalLength,
1052 ) -> i_slint_core::lengths::LogicalLength {
1053 use i_slint_core::item_tree::ItemTree as _;
1054 use i_slint_core::lengths::LogicalLength;
1055 let this = self.get_ref();
1059 let Some((parent_weak, rep_idx)) = this.root_sub_component.repeated_in.get() else {
1060 return LogicalLength::default();
1061 };
1062 let Some(parent_sub) = parent_weak.upgrade() else { return LogicalLength::default() };
1063 let parent_sub = Pin::new(parent_sub);
1064 let parent_cu = parent_sub.compilation_unit.clone();
1065 let parent_sc = &parent_cu.sub_components[parent_sub.sub_component_idx];
1066 let Some(lv) = parent_sc.repeated[*rep_idx].listview.as_ref() else {
1067 return LogicalLength::default();
1068 };
1069
1070 let row_sub = this.root_sub_component.clone();
1074 let ctx = crate::eval::EvalContext::new(row_sub.clone());
1075 crate::eval::store_property(&ctx, &lv.prop_y, crate::Value::Number(offset_y.get() as f64));
1076 let height_v = crate::eval::load_property(&ctx, &lv.prop_height);
1077 let height: f64 = height_v.try_into().unwrap_or(0.0);
1078 *offset_y += LogicalLength::new(height as f32);
1079 let info = self.layout_info(i_slint_core::items::Orientation::Horizontal);
1080 LogicalLength::new(info.min)
1081 }
1082
1083 fn layout_item_info(
1084 self: Pin<&Self>,
1085 orientation: i_slint_core::items::Orientation,
1086 child_index: Option<usize>,
1087 ) -> i_slint_core::layout::LayoutItemInfo {
1088 let this = self.get_ref();
1097 let cu = this.root_sub_component.compilation_unit.clone();
1098 let sc_idx = this.root_sub_component.sub_component_idx;
1099 let sc = &cu.sub_components[sc_idx];
1100
1101 if let (Some(index), true, Some(templates)) =
1102 (child_index, sc.is_repeated_row, sc.row_child_templates.as_ref())
1103 {
1104 return row_child_layout_item_info(this, sc, templates, orientation, index);
1105 }
1106
1107 let expr = match orientation {
1108 i_slint_core::items::Orientation::Horizontal => sc.layout_info_h.borrow(),
1109 i_slint_core::items::Orientation::Vertical => sc.layout_info_v.borrow(),
1110 };
1111 let mut ctx = crate::eval::EvalContext::new(this.root_sub_component.clone());
1112 let constraint =
1113 crate::eval::eval_expression(&mut ctx, &expr).try_into().unwrap_or_default();
1114 i_slint_core::layout::LayoutItemInfo { constraint }
1115 }
1116
1117 fn flexbox_layout_item_info(
1118 self: Pin<&Self>,
1119 orientation: i_slint_core::items::Orientation,
1120 child_index: Option<usize>,
1121 ) -> i_slint_core::layout::FlexboxLayoutItemInfo {
1122 let cu = self.root_sub_component.compilation_unit.clone();
1126 let sc_idx = self.root_sub_component.sub_component_idx;
1127 let sc = &cu.sub_components[sc_idx];
1128 if let Some(expr) = &sc.flexbox_layout_item_info_for_repeated {
1129 let expr = expr.borrow();
1130 let mut ctx = crate::eval::EvalContext::new(self.root_sub_component.clone());
1131 let value = crate::eval::eval_expression(&mut ctx, &expr);
1132 let mut info = value_to_flexbox_layout_item_info(value, orientation, self);
1133 if matches!(orientation, i_slint_core::items::Orientation::Vertical)
1139 && child_index.is_none()
1140 && let Some(v_expr) = &sc.layout_info_v_constrained_for_repeated
1141 {
1142 let mut ctx = crate::eval::EvalContext::new(self.root_sub_component.clone());
1143 info.constraint = crate::eval::eval_expression(&mut ctx, &v_expr.borrow())
1144 .try_into()
1145 .unwrap_or_default();
1146 return info;
1147 }
1148 if matches!(orientation, i_slint_core::items::Orientation::Horizontal)
1152 && child_index.is_none()
1153 && let Some(h_expr) = &sc.layout_info_h_constrained_for_repeated
1154 {
1155 let mut ctx = crate::eval::EvalContext::new(self.root_sub_component.clone());
1156 info.constraint = crate::eval::eval_expression(&mut ctx, &h_expr.borrow())
1157 .try_into()
1158 .unwrap_or_default();
1159 return info;
1160 }
1161 info.constraint = self.layout_item_info(orientation, child_index).constraint;
1164 return info;
1165 }
1166 let info = self.layout_item_info(orientation, None);
1167 info.into()
1168 }
1169}
1170
1171impl Instance {
1172 pub fn flexbox_layout_item_info_at_cross_width(
1176 self: Pin<&Self>,
1177 flex_cross_width: f32,
1178 ) -> i_slint_core::layout::FlexboxLayoutItemInfo {
1179 use i_slint_core::items::Orientation;
1180 use i_slint_core::model::RepeatedItemTree;
1181 let mut info =
1182 RepeatedItemTree::flexbox_layout_item_info(self, Orientation::Vertical, None);
1183 let cu = self.root_sub_component.compilation_unit.clone();
1184 let sc = &cu.sub_components[self.root_sub_component.sub_component_idx];
1185 if let Some(v_expr) = &sc.layout_info_v_at_cross_width_for_repeated {
1186 let mut ctx = crate::eval::EvalContext::new(self.root_sub_component.clone());
1187 ctx.locals.insert(
1188 i_slint_compiler::llr::lower_layout_expression::FLEX_CROSS_WIDTH_LOCAL.into(),
1189 crate::Value::Number(flex_cross_width as f64),
1190 );
1191 info.constraint = crate::eval::eval_expression(&mut ctx, &v_expr.borrow())
1192 .try_into()
1193 .unwrap_or_default();
1194 }
1195 info
1196 }
1197
1198 pub fn flexbox_layout_item_info_at_cross_height(
1202 self: Pin<&Self>,
1203 flex_cross_height: f32,
1204 ) -> i_slint_core::layout::FlexboxLayoutItemInfo {
1205 use i_slint_core::items::Orientation;
1206 use i_slint_core::model::RepeatedItemTree;
1207 let mut info =
1208 RepeatedItemTree::flexbox_layout_item_info(self, Orientation::Horizontal, None);
1209 let cu = self.root_sub_component.compilation_unit.clone();
1210 let sc = &cu.sub_components[self.root_sub_component.sub_component_idx];
1211 if let Some(h_expr) = &sc.layout_info_h_at_cross_height_for_repeated {
1212 let mut ctx = crate::eval::EvalContext::new(self.root_sub_component.clone());
1213 ctx.locals.insert(
1214 i_slint_compiler::llr::lower_layout_expression::FLEX_CROSS_HEIGHT_LOCAL.into(),
1215 crate::Value::Number(flex_cross_height as f64),
1216 );
1217 info.constraint = crate::eval::eval_expression(&mut ctx, &h_expr.borrow())
1218 .try_into()
1219 .unwrap_or_default();
1220 }
1221 info
1222 }
1223}
1224
1225fn row_child_layout_item_info(
1229 this: &Instance,
1230 sc: &i_slint_compiler::llr::SubComponent,
1231 templates: &[i_slint_compiler::llr::RowChildTemplateInfo],
1232 orientation: i_slint_core::items::Orientation,
1233 mut index: usize,
1234) -> i_slint_core::layout::LayoutItemInfo {
1235 use i_slint_compiler::llr::RowChildTemplateInfo;
1236 use i_slint_core::model::RepeatedItemTree;
1237 for entry in templates {
1238 match entry {
1239 RowChildTemplateInfo::Static { child_index } => {
1240 if index == 0 {
1241 let child = &sc.grid_layout_children[*child_index];
1242 let expr = match orientation {
1243 i_slint_core::items::Orientation::Horizontal => {
1244 child.layout_info_h.borrow()
1245 }
1246 i_slint_core::items::Orientation::Vertical => child.layout_info_v.borrow(),
1247 };
1248 let mut ctx = crate::eval::EvalContext::new(this.root_sub_component.clone());
1249 let constraint = crate::eval::eval_expression(&mut ctx, &expr)
1250 .try_into()
1251 .unwrap_or_default();
1252 return i_slint_core::layout::LayoutItemInfo { constraint };
1253 }
1254 index -= 1;
1255 }
1256 RowChildTemplateInfo::Repeated { repeater_index } => {
1257 let repeater = &this.root_sub_component.repeaters[*repeater_index];
1258 repeater.track_instance_changes();
1259 let count = repeater.range().len();
1260 if index < count {
1261 if let Some(inner) = repeater.instance_at(index) {
1262 return RepeatedItemTree::layout_item_info(
1263 inner.as_pin_ref(),
1264 orientation,
1265 None,
1266 );
1267 }
1268 return i_slint_core::layout::LayoutItemInfo::default();
1269 }
1270 index -= count;
1271 }
1272 }
1273 }
1274 i_slint_core::layout::LayoutItemInfo::default()
1275}
1276
1277fn value_to_flexbox_layout_item_info(
1278 v: crate::Value,
1279 orientation: i_slint_core::items::Orientation,
1280 instance: Pin<&Instance>,
1281) -> i_slint_core::layout::FlexboxLayoutItemInfo {
1282 use i_slint_core::model::RepeatedItemTree;
1283 let crate::Value::Struct(s) = v else {
1284 let info = RepeatedItemTree::layout_item_info(instance, orientation, None);
1285 return info.into();
1286 };
1287 crate::eval_layout::flexbox_item_info_from_struct(&s)
1288}