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() || self.embedded_in.get().is_some() {
418 return;
419 }
420 let Some(adapter) = self.window_adapter_or_default() else { return };
421 let Some(self_rc) = self.self_weak.get().and_then(|w| w.upgrade()) else { return };
422 let _ = self.window_attached.set(());
423 i_slint_core::window::WindowInner::from_pub(adapter.window())
424 .set_component(&vtable::VRc::into_dyn(self_rc));
425 }
426}
427
428pub(crate) fn component_container_item(
434 sub: &Pin<Rc<SubComponentInstance>>,
435 rep_idx: RepeatedElementIdx,
436) -> Option<Pin<&i_slint_core::items::ComponentContainer>> {
437 let sc = &sub.compilation_unit.sub_components[sub.sub_component_idx];
438 let cc_item_idx = sc.repeated.get(rep_idx)?.container_item_index?;
439 let item = sub.items.get(cc_item_idx)?;
440 i_slint_core::items::ItemRef::downcast_pin::<i_slint_core::items::ComponentContainer>(
441 Pin::as_ref(item).as_item_ref(),
442 )
443}
444
445impl Instance {
446 pub fn dynamic_at(
450 &self,
451 tree_index: u32,
452 ) -> Option<(Pin<Rc<SubComponentInstance>>, RepeatedElementIdx)> {
453 let entry = self.dynamic_table.get(tree_index as usize)?.as_ref()?;
454 let mut current = self.root_sub_component.clone();
455 for &idx in entry.0.iter() {
456 let next = current.sub_components[idx].clone();
457 current = next;
458 }
459 Some((current, entry.1))
460 }
461
462 pub fn ensure_updated(&self, tree_index: u32) -> bool {
473 let Some((sub, rep_idx)) = self.dynamic_at(tree_index) else { return false };
474 if let Some(cc) = component_container_item(&sub, rep_idx) {
475 return cc.ensure_updated();
476 }
477 let cu = sub.compilation_unit.clone();
478 let sc_idx = sub.sub_component_idx;
479 let sub_weak = Rc::downgrade(&Pin::into_inner(sub.clone()));
480 let globals = self.globals.clone();
481 let repeated = &cu.sub_components[sc_idx].repeated[rep_idx];
482 let listview_factory = repeated.listview.is_some();
483 let listview_info = repeated.listview.clone();
484 let factory = move || {
485 let item_tree = &cu.sub_components[sc_idx].repeated[rep_idx].sub_tree;
486 let vrc = Instance::new_repeated(
487 cu.clone(),
488 item_tree,
489 sub_weak.clone(),
490 rep_idx,
491 globals.clone(),
492 );
493 if listview_factory {
494 install_bindings_for_repeated_row(&vrc);
499 }
500 vrc
501 };
502 let repeater = &sub.repeaters[rep_idx];
503 if let Some(lv) = listview_info.as_ref() {
504 let listview_width = read_logical_length(&sub, &lv.listview_width);
505 let listview_height = read_logical_length(&sub, &lv.listview_height);
506 if listview_height.get() <= 0.0 {
511 return false;
512 }
513 let props = ValueListViewProps {
514 content_y: lv.content_y.clone(),
515 content_width: lv.content_width.clone(),
516 content_height: lv.content_height.clone(),
517 ctx_sub: sub.clone(),
518 };
519 repeater.ensure_updated_listview_callback(
520 factory,
521 &props,
522 listview_width,
523 listview_height,
524 )
525 } else {
526 repeater.ensure_updated(factory)
527 }
528 }
529
530 pub fn ensure_instantiated(&self) -> bool {
535 let mut changed = false;
536 for idx in 0..self.dynamic_table.len() {
537 if self.dynamic_table[idx].is_some() {
538 changed |= self.ensure_updated(idx as u32);
539 }
540 }
541 changed
542 }
543
544 pub fn visit_dynamic_children(
552 self: Pin<&Self>,
553 dyn_index: u32,
554 order: i_slint_core::item_tree::TraversalOrder,
555 visitor: vtable::VRefMut<'_, i_slint_core::item_tree::ItemVisitorVTable>,
556 ) -> i_slint_core::item_tree::VisitChildrenResult {
557 let Some((sub, rep_idx)) = self.get_ref().dynamic_at(dyn_index) else {
558 return i_slint_core::item_tree::VisitChildrenResult::CONTINUE;
559 };
560 if let Some(cc) = component_container_item(&sub, rep_idx) {
561 return cc.visit_children_item(-1, order, visitor);
562 }
563 let repeater = &sub.repeaters[rep_idx];
567 let sc = &sub.compilation_unit.sub_components[sub.sub_component_idx];
568 if let (Some(lv), RepeaterOrConditional::Repeater(r)) =
569 (sc.repeated[rep_idx].listview.as_ref(), repeater)
570 {
571 let props = ValueListViewProps {
572 content_y: lv.content_y.clone(),
573 content_width: lv.content_width.clone(),
574 content_height: lv.content_height.clone(),
575 ctx_sub: sub.clone(),
576 };
577 let listview_width = read_logical_length(&sub, &lv.listview_width);
578 let _ = read_logical_length(&sub, &lv.listview_height);
579 Pin::as_ref(r).track_changes_listview_callback(&props, listview_width);
580 }
581 repeater.visit(order, visitor)
582 }
583
584 pub fn new(
589 compilation_unit: Rc<CompilationUnit>,
590 public_component_index: usize,
591 ) -> VRc<ItemTreeVTable, Instance> {
592 Self::new_with_window(compilation_unit, public_component_index, None, Default::default())
593 }
594
595 pub fn new_with_window(
599 compilation_unit: Rc<CompilationUnit>,
600 public_component_index: usize,
601 window_adapter: Option<i_slint_core::window::WindowAdapterRc>,
602 type_loaders: crate::component::TypeLoaders,
603 ) -> VRc<ItemTreeVTable, Instance> {
604 Self::new_with_options(
605 compilation_unit,
606 public_component_index,
607 window_adapter,
608 type_loaders,
609 None,
610 )
611 }
612
613 pub fn new_embedded(
618 compilation_unit: Rc<CompilationUnit>,
619 public_component_index: usize,
620 type_loaders: crate::component::TypeLoaders,
621 parent: vtable::VWeak<ItemTreeVTable>,
622 parent_item_tree_index: u32,
623 ) -> VRc<ItemTreeVTable, Instance> {
624 Self::new_with_options(
625 compilation_unit,
626 public_component_index,
627 None,
628 type_loaders,
629 Some((parent, parent_item_tree_index)),
630 )
631 }
632
633 fn new_with_options(
634 compilation_unit: Rc<CompilationUnit>,
635 public_component_index: usize,
636 window_adapter: Option<i_slint_core::window::WindowAdapterRc>,
637 type_loaders: crate::component::TypeLoaders,
638 embedded_in: Option<(vtable::VWeak<ItemTreeVTable>, u32)>,
639 ) -> VRc<ItemTreeVTable, Instance> {
640 let public = &compilation_unit.public_components[public_component_index];
641 let globals = Rc::new(GlobalStorage::new(&compilation_unit));
642 let item_tree = &public.item_tree;
643 let vrc = build_instance(
644 &compilation_unit,
645 item_tree,
646 Weak::new(),
647 globals,
648 Some(public_component_index),
649 type_loaders,
650 );
651 if let Some(adapter) = window_adapter {
652 let _ = vrc.window_adapter.set(adapter);
653 }
654 if let Some((parent, idx)) = embedded_in {
658 let _ = vrc.embedded_in.set((parent, idx));
659 }
660 finalize_instance(&vrc);
661 vrc
662 }
663
664 pub fn new_repeated(
669 compilation_unit: Rc<CompilationUnit>,
670 item_tree: &llr::ItemTree,
671 parent: Weak<SubComponentInstance>,
672 repeater_idx: RepeatedElementIdx,
673 globals: Rc<GlobalStorage>,
674 ) -> VRc<ItemTreeVTable, Instance> {
675 let vrc = build_instance(
676 &compilation_unit,
677 item_tree,
678 parent.clone(),
679 globals,
680 None,
681 Default::default(),
682 );
683 let _ = vrc.root_sub_component.repeated_in.set((parent, repeater_idx));
684 vrc
685 }
686
687 pub fn new_popup(
691 compilation_unit: Rc<CompilationUnit>,
692 item_tree: &llr::ItemTree,
693 parent: Weak<SubComponentInstance>,
694 globals: Rc<GlobalStorage>,
695 ) -> VRc<ItemTreeVTable, Instance> {
696 build_instance(&compilation_unit, item_tree, parent, globals, None, Default::default())
697 }
698}
699
700fn build_instance(
708 compilation_unit: &Rc<CompilationUnit>,
709 item_tree: &llr::ItemTree,
710 parent: Weak<SubComponentInstance>,
711 globals: Rc<GlobalStorage>,
712 public_component_index: Option<usize>,
713 type_loaders: crate::component::TypeLoaders,
714) -> VRc<ItemTreeVTable, Instance> {
715 let parent_for_root = parent.clone();
716 let root_sub_component =
717 build_sub_component_instance(compilation_unit, item_tree.root, parent_for_root);
718 let (tree_nodes, dynamic_table, item_table) = build_tree_nodes(&item_tree.tree);
719
720 let vrc = VRc::new(Instance {
721 root_sub_component,
722 tree_nodes: tree_nodes.into_boxed_slice(),
723 dynamic_table: dynamic_table.into_boxed_slice(),
724 item_table: item_table.into_boxed_slice(),
725 globals,
726 self_weak: OnceCell::new(),
727 parent_instance: parent,
728 public_component_index,
729 window_adapter: OnceCell::new(),
730 window_adapter_error: OnceCell::new(),
731 window_attached: OnceCell::new(),
732 bindings_installed: OnceCell::new(),
733 init_code_run: OnceCell::new(),
734 embedded_in: OnceCell::new(),
735 type_loaders,
736 });
737 let weak = VRc::downgrade(&vrc);
738 let _ = vrc.self_weak.set(weak.clone());
739 let _ = vrc.globals.root.set(weak.clone());
741 propagate_root(&vrc.root_sub_component, &weak);
742 vrc
743}
744
745pub(crate) fn finalize_instance(vrc: &VRc<ItemTreeVTable, Instance>) {
755 install_bindings_for_repeated_row(vrc);
756 if vrc.init_code_run.get().is_some() {
757 return;
758 }
759 let _ = vrc.init_code_run.set(());
760 if vrc.public_component_index.is_some() && vrc.embedded_in.get().is_none() {
768 vrc.attach_to_window();
769 }
770 {
777 let dyn_rc = vtable::VRc::into_dyn(vrc.self_weak.get().unwrap().upgrade().unwrap());
778 let adapter = vrc.window_adapter_or_default();
779 i_slint_core::item_tree::register_item_tree(&dyn_rc, adapter);
780 }
781 crate::bindings::run_init_code_for_instance(vrc);
782}
783
784pub(crate) fn install_bindings_for_repeated_row(vrc: &VRc<ItemTreeVTable, Instance>) {
789 if vrc.bindings_installed.get().is_some() {
790 return;
791 }
792 let _ = vrc.bindings_installed.set(());
793 let is_root = vrc.parent_instance.upgrade().is_none();
794 if is_root {
795 crate::globals::install_global_bindings(&vrc.globals);
796 }
797 crate::bindings::install_bindings_only(vrc);
798}
799
800fn propagate_root(sub: &Pin<Rc<SubComponentInstance>>, weak: &VWeak<ItemTreeVTable, Instance>) {
802 let _ = sub.root.set(weak.clone());
803 for nested in &sub.sub_components {
804 propagate_root(nested, weak);
805 }
806}
807
808fn build_sub_component_instance(
810 cu: &Rc<CompilationUnit>,
811 sub_idx: SubComponentIdx,
812 parent: Weak<SubComponentInstance>,
813) -> Pin<Rc<SubComponentInstance>> {
814 let sc = &cu.sub_components[sub_idx];
815 let registry = ItemRegistry::global();
816
817 let properties = sc
818 .properties
819 .iter()
820 .map(|p| Rc::pin(Property::new(crate::eval::default_value_for_type(&p.ty))))
821 .collect();
822 let callbacks = sc.callbacks.iter().map(|_| Rc::pin(Callback::default())).collect();
823 let callback_trackers =
824 sc.callbacks.iter().map(|c| c.needs_tracker.then(|| Rc::pin(Property::new(())))).collect();
825 let items =
826 sc.items
827 .iter()
828 .map(|item| {
829 registry.factory(&item.ty.class_name).unwrap_or_else(|| {
830 panic!("native item `{}` is not registered", item.ty.class_name)
831 })()
832 })
833 .collect();
834 let repeaters = sc
835 .repeated
836 .iter()
837 .map(|rep| {
838 if rep.data_prop.is_none() {
839 RepeaterOrConditional::Conditional(Box::pin(Conditional::default()))
840 } else {
841 RepeaterOrConditional::Repeater(Box::pin(Repeater::default()))
842 }
843 })
844 .collect();
845
846 let rc = Rc::new_cyclic(|weak_self: &Weak<SubComponentInstance>| {
850 let sub_components = sc
851 .sub_components
852 .iter()
853 .map(|nested| build_sub_component_instance(cu, nested.ty, weak_self.clone()))
854 .collect();
855 SubComponentInstance {
856 compilation_unit: cu.clone(),
857 sub_component_idx: sub_idx,
858 properties,
859 callbacks,
860 callback_trackers,
861 items,
862 sub_components,
863 repeaters,
864 parent,
865 root: OnceCell::new(),
866 change_trackers: std::iter::repeat_with(ChangeTracker::default)
867 .take(2 * sc.timers.len() + sc.change_callbacks.len())
868 .collect(),
869 timers: std::iter::repeat_with(Default::default).take(sc.timers.len()).collect(),
870 popup_ids: vec![std::cell::Cell::new(None); sc.popup_windows.len()],
871 repeated_in: OnceCell::new(),
872 menubar: RefCell::new(None),
873 }
874 });
875 Pin::new(rc)
876}
877
878fn read_logical_length(
882 sub: &Pin<Rc<SubComponentInstance>>,
883 mr: &llr::MemberReference,
884) -> i_slint_core::lengths::LogicalLength {
885 let mut ctx = crate::eval::EvalContext::new(sub.clone());
886 let v = crate::eval::load_property(&ctx, mr);
887 let _ = &mut ctx;
888 let n: f64 = v.try_into().unwrap_or(0.0);
889 i_slint_core::lengths::LogicalLength::new(n as f32)
890}
891
892struct ValueListViewProps {
898 content_y: llr::MemberReference,
899 content_width: Option<llr::MemberReference>,
902 content_height: Option<llr::MemberReference>,
903 ctx_sub: Pin<Rc<SubComponentInstance>>,
904}
905
906impl i_slint_core::model::ListViewProperties for ValueListViewProps {
907 fn content_y_get(&self) -> i_slint_core::lengths::LogicalLength {
908 read_logical_length(&self.ctx_sub, &self.content_y)
909 }
910 fn content_y_get_internal(&self) -> i_slint_core::lengths::LogicalLength {
911 read_logical_length(&self.ctx_sub, &self.content_y)
915 }
916 fn content_y_set(&self, value: i_slint_core::lengths::LogicalLength) {
917 let ctx = crate::eval::EvalContext::new(self.ctx_sub.clone());
918 crate::eval::store_property(
919 &ctx,
920 &self.content_y,
921 crate::Value::Number(value.get() as f64),
922 );
923 }
924 fn content_y_has_binding(&self) -> bool {
925 false
929 }
930 fn computes_content_height(&self) -> bool {
931 self.content_height.is_some()
932 }
933 fn content_width_set(&self, value: i_slint_core::lengths::LogicalLength) {
934 let Some(content_width) = &self.content_width else { return };
935 let ctx = crate::eval::EvalContext::new(self.ctx_sub.clone());
936 crate::eval::store_property(&ctx, content_width, crate::Value::Number(value.get() as f64));
937 }
938 fn content_height_set(&self, value: i_slint_core::lengths::LogicalLength) {
939 let Some(content_height) = &self.content_height else { return };
940 let ctx = crate::eval::EvalContext::new(self.ctx_sub.clone());
941 crate::eval::store_property(&ctx, content_height, crate::Value::Number(value.get() as f64));
942 }
943 fn register_as_dependencies(&self) {
944 if let Some(content_width) = &self.content_width {
947 let _ = read_logical_length(&self.ctx_sub, content_width);
948 }
949 if let Some(content_height) = &self.content_height {
950 let _ = read_logical_length(&self.ctx_sub, content_height);
951 }
952 let _ = read_logical_length(&self.ctx_sub, &self.content_y);
953 }
954}
955
956type DynamicEntry = Option<(Box<[SubComponentInstanceIdx]>, RepeatedElementIdx)>;
957type ItemEntry = Option<(Box<[SubComponentInstanceIdx]>, ItemInstanceIdx)>;
958
959fn build_tree_nodes(
967 root: &llr::TreeNode,
968) -> (Vec<ItemTreeNode>, Vec<DynamicEntry>, Vec<ItemEntry>) {
969 use itertools::Either;
970
971 let mut out = Vec::new();
972 let mut dyn_table: Vec<DynamicEntry> = Vec::new();
973 let mut item_table: Vec<ItemEntry> = Vec::new();
974 root.visit_in_array(&mut |node, children_offset, parent_index| {
975 let parent_index = parent_index as u32;
976 let (entry, dyn_entry, item_entry) = match node.item_index {
977 Either::Left(item_idx) => (
978 ItemTreeNode::Item {
979 is_accessible: node.is_accessible,
980 children_count: node.children.len() as u32,
981 children_index: children_offset as u32,
982 parent_index,
983 item_array_index: out.len() as u32,
986 },
987 None,
988 Some((node.sub_component_path.clone().into_boxed_slice(), item_idx)),
989 ),
990 Either::Right(dynamic_index) => (
991 ItemTreeNode::DynamicTree { index: out.len() as u32, parent_index },
999 Some((
1000 node.sub_component_path.clone().into_boxed_slice(),
1001 (dynamic_index as usize).into(),
1002 )),
1003 None,
1004 ),
1005 };
1006 out.push(entry);
1007 dyn_table.push(dyn_entry);
1008 item_table.push(item_entry);
1009 });
1010 (out, dyn_table, item_table)
1011}
1012
1013impl i_slint_core::model::RepeatedItemTree for Instance {
1018 type Data = crate::Value;
1019
1020 fn update(&self, index: usize, data: Self::Data) {
1021 let sc_idx = self.root_sub_component.sub_component_idx;
1022 let cu = self.root_sub_component.compilation_unit.clone();
1023 let sc = &cu.sub_components[sc_idx];
1024 for (idx, prop) in sc.properties.iter_enumerated() {
1029 let target = &self.root_sub_component.properties[idx];
1030 match prop.name.as_str() {
1031 "model_data" => Pin::as_ref(target).set(data.clone()),
1032 "model_index" => Pin::as_ref(target).set(crate::Value::Number(index as f64)),
1033 _ => {}
1034 }
1035 }
1036 }
1037
1038 fn init(&self) {
1039 if let Some(weak) = self.self_weak.get()
1045 && let Some(vrc) = weak.upgrade()
1046 {
1047 finalize_instance(&vrc);
1048 }
1049 }
1050
1051 fn listview_layout(
1052 self: Pin<&Self>,
1053 offset_y: &mut i_slint_core::lengths::LogicalLength,
1054 ) -> i_slint_core::lengths::LogicalLength {
1055 use i_slint_core::item_tree::ItemTree as _;
1056 use i_slint_core::lengths::LogicalLength;
1057 let this = self.get_ref();
1061 let Some((parent_weak, rep_idx)) = this.root_sub_component.repeated_in.get() else {
1062 return LogicalLength::default();
1063 };
1064 let Some(parent_sub) = parent_weak.upgrade() else { return LogicalLength::default() };
1065 let parent_sub = Pin::new(parent_sub);
1066 let parent_cu = parent_sub.compilation_unit.clone();
1067 let parent_sc = &parent_cu.sub_components[parent_sub.sub_component_idx];
1068 let Some(lv) = parent_sc.repeated[*rep_idx].listview.as_ref() else {
1069 return LogicalLength::default();
1070 };
1071
1072 let row_sub = this.root_sub_component.clone();
1076 let ctx = crate::eval::EvalContext::new(row_sub.clone());
1077 crate::eval::store_property(&ctx, &lv.prop_y, crate::Value::Number(offset_y.get() as f64));
1078 let height_v = crate::eval::load_property(&ctx, &lv.prop_height);
1079 let height: f64 = height_v.try_into().unwrap_or(0.0);
1080 *offset_y += LogicalLength::new(height as f32);
1081 let info = self.layout_info(i_slint_core::items::Orientation::Horizontal);
1082 LogicalLength::new(info.min)
1083 }
1084
1085 fn layout_item_info(
1086 self: Pin<&Self>,
1087 orientation: i_slint_core::items::Orientation,
1088 child_index: Option<usize>,
1089 ) -> i_slint_core::layout::LayoutItemInfo {
1090 let this = self.get_ref();
1099 let cu = this.root_sub_component.compilation_unit.clone();
1100 let sc_idx = this.root_sub_component.sub_component_idx;
1101 let sc = &cu.sub_components[sc_idx];
1102
1103 if let (Some(index), true, Some(templates)) =
1104 (child_index, sc.is_repeated_row, sc.row_child_templates.as_ref())
1105 {
1106 return row_child_layout_item_info(this, sc, templates, orientation, index);
1107 }
1108
1109 let expr = match orientation {
1110 i_slint_core::items::Orientation::Horizontal => sc.layout_info_h.borrow(),
1111 i_slint_core::items::Orientation::Vertical => sc.layout_info_v.borrow(),
1112 };
1113 let mut ctx = crate::eval::EvalContext::new(this.root_sub_component.clone());
1114 let constraint =
1115 crate::eval::eval_expression(&mut ctx, &expr).try_into().unwrap_or_default();
1116 let cross_axis_self_alignment = match &sc.cross_axis_self_alignment_for_repeated {
1119 Some((cross_o, align_expr))
1120 if crate::eval::llr_to_core_orientation(*cross_o) == orientation =>
1121 {
1122 crate::eval::eval_expression(&mut ctx, &align_expr.borrow())
1123 .try_into()
1124 .unwrap_or_default()
1125 }
1126 _ => Default::default(),
1127 };
1128 i_slint_core::layout::LayoutItemInfo { constraint, cross_axis_self_alignment }
1129 }
1130
1131 fn flexbox_layout_item_info(
1132 self: Pin<&Self>,
1133 orientation: i_slint_core::items::Orientation,
1134 child_index: Option<usize>,
1135 ) -> i_slint_core::layout::FlexboxLayoutItemInfo {
1136 let cu = self.root_sub_component.compilation_unit.clone();
1140 let sc_idx = self.root_sub_component.sub_component_idx;
1141 let sc = &cu.sub_components[sc_idx];
1142 if let Some(expr) = &sc.flexbox_layout_item_info_for_repeated {
1143 let expr = expr.borrow();
1144 let mut ctx = crate::eval::EvalContext::new(self.root_sub_component.clone());
1145 let value = crate::eval::eval_expression(&mut ctx, &expr);
1146 let mut info = value_to_flexbox_layout_item_info(value, orientation, self);
1147 if matches!(orientation, i_slint_core::items::Orientation::Vertical)
1153 && child_index.is_none()
1154 && let Some(v_expr) = &sc.layout_info_v_constrained_for_repeated
1155 {
1156 let mut ctx = crate::eval::EvalContext::new(self.root_sub_component.clone());
1157 info.constraint = crate::eval::eval_expression(&mut ctx, &v_expr.borrow())
1158 .try_into()
1159 .unwrap_or_default();
1160 return info;
1161 }
1162 if matches!(orientation, i_slint_core::items::Orientation::Horizontal)
1166 && child_index.is_none()
1167 && let Some(h_expr) = &sc.layout_info_h_constrained_for_repeated
1168 {
1169 let mut ctx = crate::eval::EvalContext::new(self.root_sub_component.clone());
1170 info.constraint = crate::eval::eval_expression(&mut ctx, &h_expr.borrow())
1171 .try_into()
1172 .unwrap_or_default();
1173 return info;
1174 }
1175 info.constraint = self.layout_item_info(orientation, child_index).constraint;
1178 return info;
1179 }
1180 let info = self.layout_item_info(orientation, None);
1181 info.into()
1182 }
1183}
1184
1185impl Instance {
1186 pub fn flexbox_layout_item_info_at_cross_width(
1190 self: Pin<&Self>,
1191 flex_cross_width: f32,
1192 ) -> i_slint_core::layout::FlexboxLayoutItemInfo {
1193 use i_slint_core::items::Orientation;
1194 use i_slint_core::model::RepeatedItemTree;
1195 let mut info =
1196 RepeatedItemTree::flexbox_layout_item_info(self, Orientation::Vertical, None);
1197 let cu = self.root_sub_component.compilation_unit.clone();
1198 let sc = &cu.sub_components[self.root_sub_component.sub_component_idx];
1199 if let Some(v_expr) = &sc.layout_info_v_at_cross_width_for_repeated {
1200 let mut ctx = crate::eval::EvalContext::new(self.root_sub_component.clone());
1201 ctx.locals.insert(
1202 i_slint_compiler::llr::lower_layout_expression::FLEX_CROSS_WIDTH_LOCAL.into(),
1203 crate::Value::Number(flex_cross_width as f64),
1204 );
1205 info.constraint = crate::eval::eval_expression(&mut ctx, &v_expr.borrow())
1206 .try_into()
1207 .unwrap_or_default();
1208 }
1209 info
1210 }
1211
1212 pub fn flexbox_layout_item_info_at_cross_height(
1216 self: Pin<&Self>,
1217 flex_cross_height: f32,
1218 ) -> i_slint_core::layout::FlexboxLayoutItemInfo {
1219 use i_slint_core::items::Orientation;
1220 use i_slint_core::model::RepeatedItemTree;
1221 let mut info =
1222 RepeatedItemTree::flexbox_layout_item_info(self, Orientation::Horizontal, None);
1223 let cu = self.root_sub_component.compilation_unit.clone();
1224 let sc = &cu.sub_components[self.root_sub_component.sub_component_idx];
1225 if let Some(h_expr) = &sc.layout_info_h_at_cross_height_for_repeated {
1226 let mut ctx = crate::eval::EvalContext::new(self.root_sub_component.clone());
1227 ctx.locals.insert(
1228 i_slint_compiler::llr::lower_layout_expression::FLEX_CROSS_HEIGHT_LOCAL.into(),
1229 crate::Value::Number(flex_cross_height as f64),
1230 );
1231 info.constraint = crate::eval::eval_expression(&mut ctx, &h_expr.borrow())
1232 .try_into()
1233 .unwrap_or_default();
1234 }
1235 info
1236 }
1237}
1238
1239fn row_child_layout_item_info(
1243 this: &Instance,
1244 sc: &i_slint_compiler::llr::SubComponent,
1245 templates: &[i_slint_compiler::llr::RowChildTemplateInfo],
1246 orientation: i_slint_core::items::Orientation,
1247 mut index: usize,
1248) -> i_slint_core::layout::LayoutItemInfo {
1249 use i_slint_compiler::llr::RowChildTemplateInfo;
1250 use i_slint_core::model::RepeatedItemTree;
1251 for entry in templates {
1252 match entry {
1253 RowChildTemplateInfo::Static { child_index } => {
1254 if index == 0 {
1255 let child = &sc.grid_layout_children[*child_index];
1256 let expr = match orientation {
1257 i_slint_core::items::Orientation::Horizontal => {
1258 child.layout_info_h.borrow()
1259 }
1260 i_slint_core::items::Orientation::Vertical => child.layout_info_v.borrow(),
1261 };
1262 let mut ctx = crate::eval::EvalContext::new(this.root_sub_component.clone());
1263 let constraint = crate::eval::eval_expression(&mut ctx, &expr)
1264 .try_into()
1265 .unwrap_or_default();
1266 return i_slint_core::layout::LayoutItemInfo {
1267 constraint,
1268 ..Default::default()
1269 };
1270 }
1271 index -= 1;
1272 }
1273 RowChildTemplateInfo::Repeated { repeater_index } => {
1274 let repeater = &this.root_sub_component.repeaters[*repeater_index];
1275 repeater.track_instance_changes();
1276 let count = repeater.range().len();
1277 if index < count {
1278 if let Some(inner) = repeater.instance_at(index) {
1279 return RepeatedItemTree::layout_item_info(
1280 inner.as_pin_ref(),
1281 orientation,
1282 None,
1283 );
1284 }
1285 return i_slint_core::layout::LayoutItemInfo::default();
1286 }
1287 index -= count;
1288 }
1289 }
1290 }
1291 i_slint_core::layout::LayoutItemInfo::default()
1292}
1293
1294fn value_to_flexbox_layout_item_info(
1295 v: crate::Value,
1296 orientation: i_slint_core::items::Orientation,
1297 instance: Pin<&Instance>,
1298) -> i_slint_core::layout::FlexboxLayoutItemInfo {
1299 use i_slint_core::model::RepeatedItemTree;
1300 let crate::Value::Struct(s) = v else {
1301 let info = RepeatedItemTree::layout_item_info(instance, orientation, None);
1302 return info.into();
1303 };
1304 crate::eval_layout::flexbox_item_info_from_struct(&s)
1305}