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 visit_maybe_instance(
47 &self,
48 instance: Option<u32>,
49 order: i_slint_core::item_tree::TraversalOrder,
50 visitor: i_slint_core::item_tree::ItemVisitorRefMut<'_>,
51 ) -> i_slint_core::item_tree::VisitChildrenResult {
52 match self {
53 Self::Repeater(r) => Pin::as_ref(r).visit_maybe_instance(instance, order, visitor),
54 Self::Conditional(c) => Pin::as_ref(c).visit_maybe_instance(instance, order, visitor),
55 }
56 }
57
58 pub fn for_each_instance_z(&self, cb: &mut dyn FnMut(u32, f32)) {
61 match self {
62 Self::Repeater(r) => Pin::as_ref(r).for_each_instance_z(cb),
63 Self::Conditional(c) => Pin::as_ref(c).for_each_instance_z(cb),
64 }
65 }
66
67 pub fn range(&self) -> core::ops::Range<usize> {
68 match self {
69 Self::Repeater(r) => r.range(),
70 Self::Conditional(c) => c.range(),
71 }
72 }
73
74 pub fn instance_at(&self, subindex: usize) -> Option<VRc<ItemTreeVTable, Instance>> {
75 match self {
76 Self::Repeater(r) => r.instance_at(subindex),
77 Self::Conditional(c) => c.instance_at(subindex),
78 }
79 }
80
81 pub fn instances_vec(&self) -> Vec<VRc<ItemTreeVTable, Instance>> {
82 match self {
83 Self::Repeater(r) => r.instances_vec(),
84 Self::Conditional(c) => c.instances_vec(),
85 }
86 }
87
88 pub fn track_instance_changes(&self) {
93 match self {
94 Self::Repeater(r) => Pin::as_ref(r).track_instance_changes(),
95 Self::Conditional(c) => Pin::as_ref(c).track_instance_changes(),
96 }
97 }
98
99 pub fn ensure_updated(
103 &self,
104 init: impl Fn() -> VRc<ItemTreeVTable, Instance> + 'static,
105 ) -> bool {
106 match self {
107 Self::Repeater(r) => Pin::as_ref(r).ensure_updated(init),
108 Self::Conditional(c) => Pin::as_ref(c).ensure_updated(init),
109 }
110 }
111
112 pub fn ensure_updated_listview_callback(
119 &self,
120 init: impl Fn() -> VRc<ItemTreeVTable, Instance> + 'static,
121 props: &dyn i_slint_core::model::ListViewProperties,
122 listview_width: i_slint_core::lengths::LogicalLength,
123 listview_height: i_slint_core::lengths::LogicalLength,
124 ) -> bool {
125 match self {
126 Self::Repeater(r) => Pin::as_ref(r).ensure_updated_listview_callback(
127 init,
128 props,
129 listview_width,
130 listview_height,
131 ),
132 Self::Conditional(_) => unreachable!("listview on a conditional element"),
133 }
134 }
135
136 pub fn set_model_binding(
138 &self,
139 binding: impl Fn() -> i_slint_core::model::ModelRc<crate::Value> + 'static,
140 ) {
141 match self {
142 Self::Repeater(r) => Pin::as_ref(r).set_model_binding(binding),
143 Self::Conditional(_) => unreachable!("set_model_binding on conditional"),
144 }
145 }
146
147 pub fn set_condition_binding(&self, binding: impl Fn() -> bool + 'static) {
149 match self {
150 Self::Conditional(c) => c.set_model_binding(binding),
151 Self::Repeater(_) => unreachable!("set_condition_binding on repeater"),
152 }
153 }
154
155 pub fn model_set_row_data(&self, row: usize, data: crate::Value) {
157 match self {
158 Self::Repeater(r) => Pin::as_ref(r).model_set_row_data(row, data),
159 Self::Conditional(_) => {} }
161 }
162
163 pub fn is_conditional(&self) -> bool {
164 matches!(self, Self::Conditional(_))
165 }
166}
167
168pub struct SubComponentInstance {
172 pub compilation_unit: Rc<CompilationUnit>,
173 pub sub_component_idx: SubComponentIdx,
174 pub properties: TiVec<llr::PropertyIdx, SubComponentProperty>,
175 pub callbacks: TiVec<llr::CallbackIdx, SubComponentCallback>,
176 pub callback_trackers: TiVec<llr::CallbackIdx, Option<Pin<Rc<Property<()>>>>>,
181 pub items: TiVec<ItemInstanceIdx, ErasedItemRc>,
182 pub sub_components: TiVec<SubComponentInstanceIdx, Pin<Rc<SubComponentInstance>>>,
183 pub repeaters: TiVec<RepeatedElementIdx, RepeaterOrConditional>,
188 pub parent: Weak<SubComponentInstance>,
190 pub root: OnceCell<VWeak<ItemTreeVTable, Instance>>,
192 pub change_trackers: Vec<ChangeTracker>,
195 pub timers: Vec<i_slint_core::timers::Timer>,
200 pub popup_ids: Vec<std::cell::Cell<Option<std::num::NonZeroU32>>>,
205 pub repeated_in: OnceCell<(Weak<SubComponentInstance>, RepeatedElementIdx)>,
209 pub menubar: RefCell<Option<vtable::VRc<i_slint_core::menus::MenuVTable>>>,
212}
213
214pub struct Instance {
216 pub root_sub_component: Pin<Rc<SubComponentInstance>>,
217 pub tree_nodes: Box<[ItemTreeNode]>,
219 pub dynamic_table: Box<[Option<(Box<[SubComponentInstanceIdx]>, RepeatedElementIdx)>]>,
223 pub item_table: Box<[Option<(Box<[SubComponentInstanceIdx]>, ItemInstanceIdx)>]>,
227 pub z_sort_table: Box<[Option<Vec<llr::ZSource>>]>,
230 pub globals: Rc<GlobalStorage>,
231 pub self_weak: OnceCell<VWeak<ItemTreeVTable, Instance>>,
232 pub parent_instance: Weak<SubComponentInstance>,
235 pub public_component_index: Option<usize>,
239 pub window_adapter: OnceCell<WindowAdapterRc>,
242 window_adapter_error: OnceCell<String>,
246 pub window_attached: OnceCell<()>,
251 pub bindings_installed: OnceCell<()>,
254 pub init_code_run: OnceCell<()>,
260 pub embedded_in: OnceCell<(VWeak<ItemTreeVTable>, u32)>,
266 pub type_loaders: crate::component::TypeLoaders,
271}
272
273impl Drop for Instance {
274 fn drop(&mut self) {
275 let Some(adapter) = self.window_adapter.get().cloned().or_else(|| {
285 let mut parent = self.parent_instance.upgrade();
286 while let Some(sub) = parent {
287 let root = sub.root.get().and_then(|w| w.upgrade())?;
288 if let Some(a) = root.window_adapter.get() {
289 return Some(a.clone());
290 }
291 parent = root.parent_instance.upgrade();
292 }
293 None
294 }) else {
295 return;
296 };
297 vtable::new_vref!(let item_tree_ref : VRef<i_slint_core::item_tree::ItemTreeVTable> for i_slint_core::item_tree::ItemTree = self);
298 let items = collect_item_refs(&self.root_sub_component);
299 for item in &items {
304 item.as_ref().deinit(&adapter);
305 }
306 let _ =
307 adapter.renderer().free_graphics_resources(item_tree_ref, &mut items.iter().copied());
308 if let Some(internal) = adapter.internal(i_slint_core::InternalToken) {
309 internal.unregister_item_tree(item_tree_ref, &mut items.iter().copied());
310 }
311 let window_inner = i_slint_core::window::WindowInner::from_pub(adapter.window());
312 let to_close_popups = window_inner
313 .active_popups()
314 .iter()
315 .filter_map(|p| p.parent_item.upgrade().is_none().then_some(p.popup_id))
316 .collect::<Vec<_>>();
317 for popup_id in to_close_popups {
318 window_inner.close_popup(popup_id);
319 }
320 }
321}
322
323fn collect_item_refs<'a>(
326 sub: &'a Pin<Rc<SubComponentInstance>>,
327) -> Vec<Pin<vtable::VRef<'a, i_slint_core::items::ItemVTable>>> {
328 let mut out = Vec::new();
329 fn walk<'a>(
330 sub: &'a Pin<Rc<SubComponentInstance>>,
331 out: &mut Vec<Pin<vtable::VRef<'a, i_slint_core::items::ItemVTable>>>,
332 ) {
333 for item in &sub.items {
334 out.push(Pin::as_ref(item).as_item_ref());
335 }
336 for nested in &sub.sub_components {
337 walk(nested, out);
338 }
339 }
340 walk(sub, &mut out);
341 out
342}
343
344impl Instance {
345 pub fn window_adapter_or_default(&self) -> Option<WindowAdapterRc> {
348 self.try_window_adapter().ok()
349 }
350
351 pub fn try_window_adapter(&self) -> Result<WindowAdapterRc, i_slint_core::api::PlatformError> {
367 if let Some(a) = self.window_adapter.get() {
368 return Ok(a.clone());
369 }
370 if let Some((outer_weak, _)) = self.embedded_in.get()
376 && let Some(outer) = outer_weak.upgrade()
377 {
378 let mut result = None;
379 vtable::VRc::borrow_pin(&outer).as_ref().window_adapter(true, &mut result);
380 if let Some(a) = result {
381 let _ = self.window_adapter.set(a.clone());
382 return Ok(a);
383 }
384 }
385 let mut outermost_root = None;
388 let mut parent_sub = self.parent_instance.upgrade();
389 while let Some(sub) = parent_sub {
390 let Some(root_vrc) = sub.root.get().and_then(|w| w.upgrade()) else { break };
391 if let Some(a) = root_vrc.window_adapter.get() {
392 let cloned = a.clone();
393 let _ = self.window_adapter.set(cloned.clone());
396 return Ok(cloned);
397 }
398 parent_sub = root_vrc.parent_instance.upgrade();
399 outermost_root = Some(root_vrc);
400 }
401 if let Some(e) = self
402 .window_adapter_error
403 .get()
404 .or_else(|| outermost_root.as_ref().and_then(|root| root.window_adapter_error.get()))
405 {
406 return Err(i_slint_core::api::PlatformError::Other(e.clone()));
407 }
408 let adapter = i_slint_backend_selector::with_platform(|p| p.create_window_adapter())
409 .inspect_err(|e| {
410 let msg = e.to_string();
411 if let Some(root) = &outermost_root {
412 let _ = root.window_adapter_error.set(msg.clone());
413 }
414 let _ = self.window_adapter_error.set(msg);
415 })?;
416 adapter.renderer().set_window_adapter(&adapter);
420 if let Some(root) = outermost_root {
424 let _ = root.window_adapter.set(adapter.clone());
425 }
426 let _ = self.window_adapter.set(adapter.clone());
427 Ok(adapter)
428 }
429
430 pub fn attach_to_window(&self) {
439 if self.window_attached.get().is_some() || self.embedded_in.get().is_some() {
442 return;
443 }
444 let Some(adapter) = self.window_adapter_or_default() else { return };
445 let Some(self_rc) = self.self_weak.get().and_then(|w| w.upgrade()) else { return };
446 let _ = self.window_attached.set(());
447 i_slint_core::window::WindowInner::from_pub(adapter.window())
448 .set_component(&vtable::VRc::into_dyn(self_rc));
449 }
450}
451
452pub(crate) fn component_container_item(
458 sub: &Pin<Rc<SubComponentInstance>>,
459 rep_idx: RepeatedElementIdx,
460) -> Option<Pin<&i_slint_core::items::ComponentContainer>> {
461 let sc = &sub.compilation_unit.sub_components[sub.sub_component_idx];
462 let cc_item_idx = sc.repeated.get(rep_idx)?.container_item_index?;
463 let item = sub.items.get(cc_item_idx)?;
464 i_slint_core::items::ItemRef::downcast_pin::<i_slint_core::items::ComponentContainer>(
465 Pin::as_ref(item).as_item_ref(),
466 )
467}
468
469impl Instance {
470 pub fn dynamic_at(
474 &self,
475 tree_index: u32,
476 ) -> Option<(Pin<Rc<SubComponentInstance>>, RepeatedElementIdx)> {
477 let entry = self.dynamic_table.get(tree_index as usize)?.as_ref()?;
478 let mut current = self.root_sub_component.clone();
479 for &idx in entry.0.iter() {
480 let next = current.sub_components[idx].clone();
481 current = next;
482 }
483 Some((current, entry.1))
484 }
485
486 pub fn ensure_updated(&self, tree_index: u32) -> bool {
497 let Some((sub, rep_idx)) = self.dynamic_at(tree_index) else { return false };
498 if let Some(cc) = component_container_item(&sub, rep_idx) {
499 return cc.ensure_updated();
500 }
501 let cu = sub.compilation_unit.clone();
502 let sc_idx = sub.sub_component_idx;
503 let sub_weak = Rc::downgrade(&Pin::into_inner(sub.clone()));
504 let globals = self.globals.clone();
505 let repeated = &cu.sub_components[sc_idx].repeated[rep_idx];
506 let listview_factory = repeated.listview.is_some();
507 let listview_info = repeated.listview.clone();
508 let factory = move || {
509 let item_tree = &cu.sub_components[sc_idx].repeated[rep_idx].sub_tree;
510 let vrc = Instance::new_repeated(
511 cu.clone(),
512 item_tree,
513 sub_weak.clone(),
514 rep_idx,
515 globals.clone(),
516 );
517 if listview_factory {
518 install_bindings_for_repeated_row(&vrc);
523 }
524 vrc
525 };
526 let repeater = &sub.repeaters[rep_idx];
527 if let Some(lv) = listview_info.as_ref() {
528 let listview_width = read_logical_length(&sub, &lv.listview_width);
529 let listview_height = read_logical_length(&sub, &lv.listview_height);
530 if listview_height.get() <= 0.0 {
535 return false;
536 }
537 let props = ValueListViewProps {
538 content_y: lv.content_y.clone(),
539 content_width: lv.content_width.clone(),
540 content_height: lv.content_height.clone(),
541 ctx_sub: sub.clone(),
542 };
543 repeater.ensure_updated_listview_callback(
544 factory,
545 &props,
546 listview_width,
547 listview_height,
548 )
549 } else {
550 repeater.ensure_updated(factory)
551 }
552 }
553
554 pub fn ensure_instantiated(&self) -> bool {
559 let mut changed = false;
560 for idx in 0..self.dynamic_table.len() {
561 if self.dynamic_table[idx].is_some() {
562 changed |= self.ensure_updated(idx as u32);
563 }
564 }
565 changed
566 }
567
568 pub fn visit_dynamic_children(
576 self: Pin<&Self>,
577 dyn_index: u32,
578 order: i_slint_core::item_tree::TraversalOrder,
579 visitor: vtable::VRefMut<'_, i_slint_core::item_tree::ItemVisitorVTable>,
580 instance: Option<u32>,
581 ) -> i_slint_core::item_tree::VisitChildrenResult {
582 let Some((sub, rep_idx)) = self.get_ref().dynamic_at(dyn_index) else {
583 return i_slint_core::item_tree::VisitChildrenResult::CONTINUE;
584 };
585 if let Some(cc) = component_container_item(&sub, rep_idx) {
586 return cc.visit_children_item(-1, order, visitor);
587 }
588 let repeater = &sub.repeaters[rep_idx];
592 let sc = &sub.compilation_unit.sub_components[sub.sub_component_idx];
593 if let (Some(lv), RepeaterOrConditional::Repeater(r)) =
594 (sc.repeated[rep_idx].listview.as_ref(), repeater)
595 {
596 let props = ValueListViewProps {
597 content_y: lv.content_y.clone(),
598 content_width: lv.content_width.clone(),
599 content_height: lv.content_height.clone(),
600 ctx_sub: sub.clone(),
601 };
602 let listview_width = read_logical_length(&sub, &lv.listview_width);
603 let _ = read_logical_length(&sub, &lv.listview_height);
604 Pin::as_ref(r).track_changes_listview_callback(&props, listview_width);
605 }
606 repeater.visit_maybe_instance(instance, order, visitor)
607 }
608
609 pub fn compute_z_sorted_children(
612 self: Pin<&Self>,
613 index: isize,
614 ) -> Option<Vec<i_slint_core::item_tree::ZSortedChild>> {
615 use i_slint_core::item_tree::ZSortedChild;
616 if index < 0 {
617 return None;
618 }
619 let sources = self.z_sort_table.get(index as usize)?.as_ref()?;
620 let ItemTreeNode::Item { children_index, .. } = self.tree_nodes[index as usize] else {
621 return None;
622 };
623 let mut ctx = crate::eval::EvalContext::new(self.root_sub_component.clone());
624 let mut entries: Vec<ZSortedChild> = Vec::with_capacity(sources.len());
625 for (k, source) in sources.iter().enumerate() {
626 let child_offset = k as u32;
627 match source {
628 llr::ZSource::Expression(e) => {
629 let z: f64 = crate::eval::eval_expression(&mut ctx, &e.borrow())
630 .try_into()
631 .unwrap_or(0.0);
632 entries.push(ZSortedChild { z: z as f32, child_offset, instance: u32::MAX });
633 }
634 llr::ZSource::RepeaterInstances => {
635 if let Some((sub, rep_idx)) =
637 self.get_ref().dynamic_at(children_index + child_offset)
638 {
639 sub.repeaters[rep_idx].for_each_instance_z(&mut |instance, z| {
640 entries.push(ZSortedChild { z, child_offset, instance })
641 });
642 }
643 }
644 }
645 }
646 i_slint_core::item_tree::sort_z_entries(&mut entries);
647 Some(entries)
648 }
649
650 pub fn new(
655 compilation_unit: Rc<CompilationUnit>,
656 public_component_index: usize,
657 ) -> VRc<ItemTreeVTable, Instance> {
658 Self::new_with_window(compilation_unit, public_component_index, None, Default::default())
659 }
660
661 pub fn new_with_window(
665 compilation_unit: Rc<CompilationUnit>,
666 public_component_index: usize,
667 window_adapter: Option<i_slint_core::window::WindowAdapterRc>,
668 type_loaders: crate::component::TypeLoaders,
669 ) -> VRc<ItemTreeVTable, Instance> {
670 Self::new_with_options(
671 compilation_unit,
672 public_component_index,
673 window_adapter,
674 type_loaders,
675 None,
676 )
677 }
678
679 pub fn new_embedded(
684 compilation_unit: Rc<CompilationUnit>,
685 public_component_index: usize,
686 type_loaders: crate::component::TypeLoaders,
687 parent: vtable::VWeak<ItemTreeVTable>,
688 parent_item_tree_index: u32,
689 ) -> VRc<ItemTreeVTable, Instance> {
690 Self::new_with_options(
691 compilation_unit,
692 public_component_index,
693 None,
694 type_loaders,
695 Some((parent, parent_item_tree_index)),
696 )
697 }
698
699 fn new_with_options(
700 compilation_unit: Rc<CompilationUnit>,
701 public_component_index: usize,
702 window_adapter: Option<i_slint_core::window::WindowAdapterRc>,
703 type_loaders: crate::component::TypeLoaders,
704 embedded_in: Option<(vtable::VWeak<ItemTreeVTable>, u32)>,
705 ) -> VRc<ItemTreeVTable, Instance> {
706 let public = &compilation_unit.public_components[public_component_index];
707 let globals = Rc::new(GlobalStorage::new(&compilation_unit));
708 let item_tree = &public.item_tree;
709 let vrc = build_instance(
710 &compilation_unit,
711 item_tree,
712 Weak::new(),
713 globals,
714 Some(public_component_index),
715 type_loaders,
716 );
717 if let Some(adapter) = window_adapter {
718 let _ = vrc.window_adapter.set(adapter);
719 }
720 if let Some((parent, idx)) = embedded_in {
724 let _ = vrc.embedded_in.set((parent, idx));
725 }
726 finalize_instance(&vrc);
727 vrc
728 }
729
730 pub fn new_repeated(
735 compilation_unit: Rc<CompilationUnit>,
736 item_tree: &llr::ItemTree,
737 parent: Weak<SubComponentInstance>,
738 repeater_idx: RepeatedElementIdx,
739 globals: Rc<GlobalStorage>,
740 ) -> VRc<ItemTreeVTable, Instance> {
741 let vrc = build_instance(
742 &compilation_unit,
743 item_tree,
744 parent.clone(),
745 globals,
746 None,
747 Default::default(),
748 );
749 let _ = vrc.root_sub_component.repeated_in.set((parent, repeater_idx));
750 vrc
751 }
752
753 pub fn new_popup(
757 compilation_unit: Rc<CompilationUnit>,
758 item_tree: &llr::ItemTree,
759 parent: Weak<SubComponentInstance>,
760 globals: Rc<GlobalStorage>,
761 ) -> VRc<ItemTreeVTable, Instance> {
762 build_instance(&compilation_unit, item_tree, parent, globals, None, Default::default())
763 }
764}
765
766fn build_instance(
774 compilation_unit: &Rc<CompilationUnit>,
775 item_tree: &llr::ItemTree,
776 parent: Weak<SubComponentInstance>,
777 globals: Rc<GlobalStorage>,
778 public_component_index: Option<usize>,
779 type_loaders: crate::component::TypeLoaders,
780) -> VRc<ItemTreeVTable, Instance> {
781 let parent_for_root = parent.clone();
782 let root_sub_component =
783 build_sub_component_instance(compilation_unit, item_tree.root, parent_for_root);
784 let (tree_nodes, dynamic_table, item_table, z_sort_table) = build_tree_nodes(&item_tree.tree);
785
786 let vrc = VRc::new(Instance {
787 root_sub_component,
788 tree_nodes: tree_nodes.into_boxed_slice(),
789 dynamic_table: dynamic_table.into_boxed_slice(),
790 item_table: item_table.into_boxed_slice(),
791 z_sort_table: z_sort_table.into_boxed_slice(),
792 globals,
793 self_weak: OnceCell::new(),
794 parent_instance: parent,
795 public_component_index,
796 window_adapter: OnceCell::new(),
797 window_adapter_error: OnceCell::new(),
798 window_attached: OnceCell::new(),
799 bindings_installed: OnceCell::new(),
800 init_code_run: OnceCell::new(),
801 embedded_in: OnceCell::new(),
802 type_loaders,
803 });
804 let weak = VRc::downgrade(&vrc);
805 let _ = vrc.self_weak.set(weak.clone());
806 let _ = vrc.globals.root.set(weak.clone());
808 propagate_root(&vrc.root_sub_component, &weak);
809 vrc
810}
811
812pub(crate) fn finalize_instance(vrc: &VRc<ItemTreeVTable, Instance>) {
822 install_bindings_for_repeated_row(vrc);
823 if vrc.init_code_run.get().is_some() {
824 return;
825 }
826 let _ = vrc.init_code_run.set(());
827 if vrc.public_component_index.is_some() && vrc.embedded_in.get().is_none() {
835 vrc.attach_to_window();
836 }
837 {
844 let dyn_rc = vtable::VRc::into_dyn(vrc.self_weak.get().unwrap().upgrade().unwrap());
845 let adapter = vrc.window_adapter_or_default();
846 i_slint_core::item_tree::register_item_tree(&dyn_rc, adapter);
847 }
848 crate::bindings::run_init_code_for_instance(vrc);
849}
850
851pub(crate) fn install_bindings_for_repeated_row(vrc: &VRc<ItemTreeVTable, Instance>) {
856 if vrc.bindings_installed.get().is_some() {
857 return;
858 }
859 let _ = vrc.bindings_installed.set(());
860 let is_root = vrc.parent_instance.upgrade().is_none();
861 if is_root {
862 crate::globals::install_global_bindings(&vrc.globals);
863 }
864 crate::bindings::install_bindings_only(vrc);
865}
866
867fn propagate_root(sub: &Pin<Rc<SubComponentInstance>>, weak: &VWeak<ItemTreeVTable, Instance>) {
869 let _ = sub.root.set(weak.clone());
870 for nested in &sub.sub_components {
871 propagate_root(nested, weak);
872 }
873}
874
875fn build_sub_component_instance(
877 cu: &Rc<CompilationUnit>,
878 sub_idx: SubComponentIdx,
879 parent: Weak<SubComponentInstance>,
880) -> Pin<Rc<SubComponentInstance>> {
881 let sc = &cu.sub_components[sub_idx];
882 let registry = ItemRegistry::global();
883
884 let properties = sc
885 .properties
886 .iter()
887 .map(|p| Rc::pin(Property::new(crate::eval::default_value_for_type(&p.ty))))
888 .collect();
889 let callbacks = sc.callbacks.iter().map(|_| Rc::pin(Callback::default())).collect();
890 let callback_trackers =
891 sc.callbacks.iter().map(|c| c.needs_tracker.then(|| Rc::pin(Property::new(())))).collect();
892 let items =
893 sc.items
894 .iter()
895 .map(|item| {
896 registry.factory(&item.ty.class_name).unwrap_or_else(|| {
897 panic!("native item `{}` is not registered", item.ty.class_name)
898 })()
899 })
900 .collect();
901 let repeaters = sc
902 .repeated
903 .iter()
904 .map(|rep| {
905 if rep.data_prop.is_none() {
906 RepeaterOrConditional::Conditional(Box::pin(Conditional::default()))
907 } else {
908 RepeaterOrConditional::Repeater(Box::pin(Repeater::default()))
909 }
910 })
911 .collect();
912
913 let rc = Rc::new_cyclic(|weak_self: &Weak<SubComponentInstance>| {
917 let sub_components = sc
918 .sub_components
919 .iter()
920 .map(|nested| build_sub_component_instance(cu, nested.ty, weak_self.clone()))
921 .collect();
922 SubComponentInstance {
923 compilation_unit: cu.clone(),
924 sub_component_idx: sub_idx,
925 properties,
926 callbacks,
927 callback_trackers,
928 items,
929 sub_components,
930 repeaters,
931 parent,
932 root: OnceCell::new(),
933 change_trackers: std::iter::repeat_with(ChangeTracker::default)
934 .take(2 * sc.timers.len() + sc.change_callbacks.len())
935 .collect(),
936 timers: std::iter::repeat_with(Default::default).take(sc.timers.len()).collect(),
937 popup_ids: vec![std::cell::Cell::new(None); sc.popup_windows.len()],
938 repeated_in: OnceCell::new(),
939 menubar: RefCell::new(None),
940 }
941 });
942 Pin::new(rc)
943}
944
945fn read_logical_length(
949 sub: &Pin<Rc<SubComponentInstance>>,
950 mr: &llr::MemberReference,
951) -> i_slint_core::lengths::LogicalLength {
952 let mut ctx = crate::eval::EvalContext::new(sub.clone());
953 let v = crate::eval::load_property(&ctx, mr);
954 let _ = &mut ctx;
955 let n: f64 = v.try_into().unwrap_or(0.0);
956 i_slint_core::lengths::LogicalLength::new(n as f32)
957}
958
959struct ValueListViewProps {
965 content_y: llr::MemberReference,
966 content_width: Option<llr::MemberReference>,
969 content_height: Option<llr::MemberReference>,
970 ctx_sub: Pin<Rc<SubComponentInstance>>,
971}
972
973impl i_slint_core::model::ListViewProperties for ValueListViewProps {
974 fn content_y_get(&self) -> i_slint_core::lengths::LogicalLength {
975 read_logical_length(&self.ctx_sub, &self.content_y)
976 }
977 fn content_y_get_internal(&self) -> i_slint_core::lengths::LogicalLength {
978 read_logical_length(&self.ctx_sub, &self.content_y)
982 }
983 fn content_y_set(&self, value: i_slint_core::lengths::LogicalLength) {
984 let ctx = crate::eval::EvalContext::new(self.ctx_sub.clone());
985 crate::eval::store_property(
986 &ctx,
987 &self.content_y,
988 crate::Value::Number(value.get() as f64),
989 );
990 }
991 fn content_y_has_binding(&self) -> bool {
992 false
996 }
997 fn computes_content_height(&self) -> bool {
998 self.content_height.is_some()
999 }
1000 fn content_width_set(&self, value: i_slint_core::lengths::LogicalLength) {
1001 let Some(content_width) = &self.content_width else { return };
1002 let ctx = crate::eval::EvalContext::new(self.ctx_sub.clone());
1003 crate::eval::store_property(&ctx, content_width, crate::Value::Number(value.get() as f64));
1004 }
1005 fn content_height_set(&self, value: i_slint_core::lengths::LogicalLength) {
1006 let Some(content_height) = &self.content_height else { return };
1007 let ctx = crate::eval::EvalContext::new(self.ctx_sub.clone());
1008 crate::eval::store_property(&ctx, content_height, crate::Value::Number(value.get() as f64));
1009 }
1010 fn register_as_dependencies(&self) {
1011 if let Some(content_width) = &self.content_width {
1014 let _ = read_logical_length(&self.ctx_sub, content_width);
1015 }
1016 if let Some(content_height) = &self.content_height {
1017 let _ = read_logical_length(&self.ctx_sub, content_height);
1018 }
1019 let _ = read_logical_length(&self.ctx_sub, &self.content_y);
1020 }
1021}
1022
1023type DynamicEntry = Option<(Box<[SubComponentInstanceIdx]>, RepeatedElementIdx)>;
1024type ItemEntry = Option<(Box<[SubComponentInstanceIdx]>, ItemInstanceIdx)>;
1025type ZSortEntry = Option<Vec<llr::ZSource>>;
1026
1027fn build_tree_nodes(
1037 root: &llr::TreeNode,
1038) -> (Vec<ItemTreeNode>, Vec<DynamicEntry>, Vec<ItemEntry>, Vec<ZSortEntry>) {
1039 use itertools::Either;
1040
1041 let mut out = Vec::new();
1042 let mut dyn_table: Vec<DynamicEntry> = Vec::new();
1043 let mut item_table: Vec<ItemEntry> = Vec::new();
1044 let mut z_sort_table: Vec<ZSortEntry> = Vec::new();
1045 root.visit_in_array(&mut |node, children_offset, parent_index| {
1046 let parent_index = parent_index as u32;
1047 let (entry, dyn_entry, item_entry) = match node.item_index {
1048 Either::Left(item_idx) => (
1049 ItemTreeNode::Item {
1050 is_accessible: node.is_accessible,
1051 children_count: node.children.len() as u32,
1052 children_index: children_offset as u32,
1053 parent_index,
1054 item_array_index: out.len() as u32,
1057 },
1058 None,
1059 Some((node.sub_component_path.clone().into_boxed_slice(), item_idx)),
1060 ),
1061 Either::Right(dynamic_index) => (
1062 ItemTreeNode::DynamicTree { index: out.len() as u32, parent_index },
1070 Some((
1071 node.sub_component_path.clone().into_boxed_slice(),
1072 (dynamic_index as usize).into(),
1073 )),
1074 None,
1075 ),
1076 };
1077 out.push(entry);
1078 dyn_table.push(dyn_entry);
1079 item_table.push(item_entry);
1080 z_sort_table.push(node.z_sort_order_property.clone());
1081 });
1082 (out, dyn_table, item_table, z_sort_table)
1083}
1084
1085impl i_slint_core::model::RepeatedItemTree for Instance {
1090 type Data = crate::Value;
1091
1092 fn update(&self, index: usize, data: Self::Data) {
1093 let sc_idx = self.root_sub_component.sub_component_idx;
1094 let cu = self.root_sub_component.compilation_unit.clone();
1095 let sc = &cu.sub_components[sc_idx];
1096 for (idx, prop) in sc.properties.iter_enumerated() {
1101 let target = &self.root_sub_component.properties[idx];
1102 match prop.name.as_str() {
1103 "model_data" => Pin::as_ref(target).set(data.clone()),
1104 "model_index" => Pin::as_ref(target).set(crate::Value::Number(index as f64)),
1105 _ => {}
1106 }
1107 }
1108 }
1109
1110 fn init(&self) {
1111 if let Some(weak) = self.self_weak.get()
1117 && let Some(vrc) = weak.upgrade()
1118 {
1119 finalize_instance(&vrc);
1120 }
1121 }
1122
1123 fn z_order(self: Pin<&Self>) -> Option<f32> {
1124 let this = self.get_ref();
1127 let (parent_weak, rep_idx) = this.root_sub_component.repeated_in.get()?;
1128 let parent_sub = parent_weak.upgrade()?;
1129 let parent_sc = &parent_sub.compilation_unit.sub_components[parent_sub.sub_component_idx];
1130 let z_ref = parent_sc.repeated[*rep_idx].dynamic_z.as_ref()?;
1131 let ctx = crate::eval::EvalContext::new(this.root_sub_component.clone());
1132 let z: f64 = crate::eval::load_property(&ctx, z_ref).try_into().unwrap_or(0.0);
1133 Some(z as f32)
1134 }
1135
1136 fn listview_layout(
1137 self: Pin<&Self>,
1138 offset_y: &mut i_slint_core::lengths::LogicalLength,
1139 ) -> i_slint_core::lengths::LogicalLength {
1140 use i_slint_core::item_tree::ItemTree as _;
1141 use i_slint_core::lengths::LogicalLength;
1142 let this = self.get_ref();
1146 let Some((parent_weak, rep_idx)) = this.root_sub_component.repeated_in.get() else {
1147 return LogicalLength::default();
1148 };
1149 let Some(parent_sub) = parent_weak.upgrade() else { return LogicalLength::default() };
1150 let parent_sub = Pin::new(parent_sub);
1151 let parent_cu = parent_sub.compilation_unit.clone();
1152 let parent_sc = &parent_cu.sub_components[parent_sub.sub_component_idx];
1153 let Some(lv) = parent_sc.repeated[*rep_idx].listview.as_ref() else {
1154 return LogicalLength::default();
1155 };
1156
1157 let row_sub = this.root_sub_component.clone();
1161 let ctx = crate::eval::EvalContext::new(row_sub.clone());
1162 crate::eval::store_property(&ctx, &lv.prop_y, crate::Value::Number(offset_y.get() as f64));
1163 let height_v = crate::eval::load_property(&ctx, &lv.prop_height);
1164 let height: f64 = height_v.try_into().unwrap_or(0.0);
1165 *offset_y += LogicalLength::new(height as f32);
1166 let info = self.layout_info(i_slint_core::items::Orientation::Horizontal);
1167 LogicalLength::new(info.min)
1168 }
1169
1170 fn layout_item_info(
1171 self: Pin<&Self>,
1172 orientation: i_slint_core::items::Orientation,
1173 child_index: Option<usize>,
1174 ) -> i_slint_core::layout::LayoutItemInfo {
1175 let this = self.get_ref();
1184 let cu = this.root_sub_component.compilation_unit.clone();
1185 let sc_idx = this.root_sub_component.sub_component_idx;
1186 let sc = &cu.sub_components[sc_idx];
1187
1188 if let (Some(index), true, Some(templates)) =
1189 (child_index, sc.is_repeated_row, sc.row_child_templates.as_ref())
1190 {
1191 return row_child_layout_item_info(this, sc, templates, orientation, index);
1192 }
1193
1194 let expr = match orientation {
1195 i_slint_core::items::Orientation::Horizontal => sc.layout_info_h.borrow(),
1196 i_slint_core::items::Orientation::Vertical => sc.layout_info_v.borrow(),
1197 };
1198 let mut ctx = crate::eval::EvalContext::new(this.root_sub_component.clone());
1199 let constraint =
1200 crate::eval::eval_expression(&mut ctx, &expr).try_into().unwrap_or_default();
1201 let cross_axis_self_alignment = match &sc.cross_axis_self_alignment_for_repeated {
1204 Some((cross_o, align_expr))
1205 if crate::eval::llr_to_core_orientation(*cross_o) == orientation =>
1206 {
1207 crate::eval::eval_expression(&mut ctx, &align_expr.borrow())
1208 .try_into()
1209 .unwrap_or_default()
1210 }
1211 _ => Default::default(),
1212 };
1213 i_slint_core::layout::LayoutItemInfo { constraint, cross_axis_self_alignment }
1214 }
1215
1216 fn flexbox_layout_item_info(
1217 self: Pin<&Self>,
1218 orientation: i_slint_core::items::Orientation,
1219 child_index: Option<usize>,
1220 ) -> i_slint_core::layout::FlexboxLayoutItemInfo {
1221 let cu = self.root_sub_component.compilation_unit.clone();
1225 let sc_idx = self.root_sub_component.sub_component_idx;
1226 let sc = &cu.sub_components[sc_idx];
1227 if let Some(expr) = &sc.flexbox_layout_item_info_for_repeated {
1228 let expr = expr.borrow();
1229 let mut ctx = crate::eval::EvalContext::new(self.root_sub_component.clone());
1230 let value = crate::eval::eval_expression(&mut ctx, &expr);
1231 let mut info = value_to_flexbox_layout_item_info(value, orientation, self);
1232 if matches!(orientation, i_slint_core::items::Orientation::Vertical)
1238 && child_index.is_none()
1239 && let Some(v_expr) = &sc.layout_info_v_constrained_for_repeated
1240 {
1241 let mut ctx = crate::eval::EvalContext::new(self.root_sub_component.clone());
1242 info.constraint = crate::eval::eval_expression(&mut ctx, &v_expr.borrow())
1243 .try_into()
1244 .unwrap_or_default();
1245 return info;
1246 }
1247 if matches!(orientation, i_slint_core::items::Orientation::Horizontal)
1251 && child_index.is_none()
1252 && let Some(h_expr) = &sc.layout_info_h_constrained_for_repeated
1253 {
1254 let mut ctx = crate::eval::EvalContext::new(self.root_sub_component.clone());
1255 info.constraint = crate::eval::eval_expression(&mut ctx, &h_expr.borrow())
1256 .try_into()
1257 .unwrap_or_default();
1258 return info;
1259 }
1260 info.constraint = self.layout_item_info(orientation, child_index).constraint;
1263 return info;
1264 }
1265 let info = self.layout_item_info(orientation, None);
1266 info.into()
1267 }
1268}
1269
1270impl Instance {
1271 pub fn flexbox_layout_item_info_at_cross_width(
1275 self: Pin<&Self>,
1276 flex_cross_width: f32,
1277 ) -> i_slint_core::layout::FlexboxLayoutItemInfo {
1278 use i_slint_core::items::Orientation;
1279 use i_slint_core::model::RepeatedItemTree;
1280 let mut info =
1281 RepeatedItemTree::flexbox_layout_item_info(self, Orientation::Vertical, None);
1282 let cu = self.root_sub_component.compilation_unit.clone();
1283 let sc = &cu.sub_components[self.root_sub_component.sub_component_idx];
1284 if let Some(v_expr) = &sc.layout_info_v_at_cross_width_for_repeated {
1285 let mut ctx = crate::eval::EvalContext::new(self.root_sub_component.clone());
1286 ctx.locals.insert(
1287 i_slint_compiler::llr::lower_layout_expression::FLEX_CROSS_WIDTH_LOCAL.into(),
1288 crate::Value::Number(flex_cross_width as f64),
1289 );
1290 info.constraint = crate::eval::eval_expression(&mut ctx, &v_expr.borrow())
1291 .try_into()
1292 .unwrap_or_default();
1293 }
1294 info
1295 }
1296
1297 pub fn flexbox_layout_item_info_at_cross_height(
1301 self: Pin<&Self>,
1302 flex_cross_height: f32,
1303 ) -> i_slint_core::layout::FlexboxLayoutItemInfo {
1304 use i_slint_core::items::Orientation;
1305 use i_slint_core::model::RepeatedItemTree;
1306 let mut info =
1307 RepeatedItemTree::flexbox_layout_item_info(self, Orientation::Horizontal, None);
1308 let cu = self.root_sub_component.compilation_unit.clone();
1309 let sc = &cu.sub_components[self.root_sub_component.sub_component_idx];
1310 if let Some(h_expr) = &sc.layout_info_h_at_cross_height_for_repeated {
1311 let mut ctx = crate::eval::EvalContext::new(self.root_sub_component.clone());
1312 ctx.locals.insert(
1313 i_slint_compiler::llr::lower_layout_expression::FLEX_CROSS_HEIGHT_LOCAL.into(),
1314 crate::Value::Number(flex_cross_height as f64),
1315 );
1316 info.constraint = crate::eval::eval_expression(&mut ctx, &h_expr.borrow())
1317 .try_into()
1318 .unwrap_or_default();
1319 }
1320 info
1321 }
1322}
1323
1324fn row_child_layout_item_info(
1328 this: &Instance,
1329 sc: &i_slint_compiler::llr::SubComponent,
1330 templates: &[i_slint_compiler::llr::RowChildTemplateInfo],
1331 orientation: i_slint_core::items::Orientation,
1332 mut index: usize,
1333) -> i_slint_core::layout::LayoutItemInfo {
1334 use i_slint_compiler::llr::RowChildTemplateInfo;
1335 use i_slint_core::model::RepeatedItemTree;
1336 for entry in templates {
1337 match entry {
1338 RowChildTemplateInfo::Static { child_index } => {
1339 if index == 0 {
1340 let child = &sc.grid_layout_children[*child_index];
1341 let expr = match orientation {
1342 i_slint_core::items::Orientation::Horizontal => {
1343 child.layout_info_h.borrow()
1344 }
1345 i_slint_core::items::Orientation::Vertical => child.layout_info_v.borrow(),
1346 };
1347 let mut ctx = crate::eval::EvalContext::new(this.root_sub_component.clone());
1348 let constraint = crate::eval::eval_expression(&mut ctx, &expr)
1349 .try_into()
1350 .unwrap_or_default();
1351 return i_slint_core::layout::LayoutItemInfo {
1352 constraint,
1353 ..Default::default()
1354 };
1355 }
1356 index -= 1;
1357 }
1358 RowChildTemplateInfo::Repeated { repeater_index } => {
1359 let repeater = &this.root_sub_component.repeaters[*repeater_index];
1360 repeater.track_instance_changes();
1361 let count = repeater.range().len();
1362 if index < count {
1363 if let Some(inner) = repeater.instance_at(index) {
1364 return RepeatedItemTree::layout_item_info(
1365 inner.as_pin_ref(),
1366 orientation,
1367 None,
1368 );
1369 }
1370 return i_slint_core::layout::LayoutItemInfo::default();
1371 }
1372 index -= count;
1373 }
1374 }
1375 }
1376 i_slint_core::layout::LayoutItemInfo::default()
1377}
1378
1379fn value_to_flexbox_layout_item_info(
1380 v: crate::Value,
1381 orientation: i_slint_core::items::Orientation,
1382 instance: Pin<&Instance>,
1383) -> i_slint_core::layout::FlexboxLayoutItemInfo {
1384 use i_slint_core::model::RepeatedItemTree;
1385 let crate::Value::Struct(s) = v else {
1386 let info = RepeatedItemTree::layout_item_info(instance, orientation, None);
1387 return info.into();
1388 };
1389 crate::eval_layout::flexbox_item_info_from_struct(&s)
1390}