mirror of
				https://github.com/slint-ui/slint.git
				synced 2025-11-03 21:24:17 +00:00 
			
		
		
		
	Component container subcomponent (#4355)
This changes the component containers away from using a "MAGIC" index in the placeholder dynamic item tree node it creates. These are hard to integrate across sub-components. Use index numbers right after the index numbers used by repeaters and "extend" the repeater offset by the number of component containers in the sub-component. This way we can piggy-back on the forwarding of repeaters. This has one annoying side-effect: We do have indices in our item tree that are out of range for a repeater. But I think that is acceptable considering that we never materialize that array anyway.
This commit is contained in:
		
							parent
							
								
									ca881ea5d9
								
							
						
					
					
						commit
						382b5486ca
					
				
					 7 changed files with 186 additions and 74 deletions
				
			
		| 
						 | 
					@ -115,6 +115,7 @@ pub trait ItemTreeBuilder {
 | 
				
			||||||
    fn push_component_placeholder_item(
 | 
					    fn push_component_placeholder_item(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        item: &crate::object_tree::ElementRc,
 | 
					        item: &crate::object_tree::ElementRc,
 | 
				
			||||||
 | 
					        container_count: u32, // Must start at repeater.len()!
 | 
				
			||||||
        parent_index: u32,
 | 
					        parent_index: u32,
 | 
				
			||||||
        component_state: &Self::SubComponentState,
 | 
					        component_state: &Self::SubComponentState,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
| 
						 | 
					@ -163,7 +164,17 @@ pub fn build_item_tree<T: ItemTreeBuilder>(
 | 
				
			||||||
        build_item_tree::<T>(sub_component, &sub_compo_state, builder);
 | 
					        build_item_tree::<T>(sub_component, &sub_compo_state, builder);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        let mut repeater_count = 0;
 | 
					        let mut repeater_count = 0;
 | 
				
			||||||
        visit_item(initial_state, &root_component.root_element, 1, &mut repeater_count, 0, builder);
 | 
					        let mut container_count =
 | 
				
			||||||
 | 
					            repeater_count_in_sub_component(&root_component.root_element) as u32;
 | 
				
			||||||
 | 
					        visit_item(
 | 
				
			||||||
 | 
					            initial_state,
 | 
				
			||||||
 | 
					            &root_component.root_element,
 | 
				
			||||||
 | 
					            1,
 | 
				
			||||||
 | 
					            &mut repeater_count,
 | 
				
			||||||
 | 
					            &mut container_count,
 | 
				
			||||||
 | 
					            0,
 | 
				
			||||||
 | 
					            builder,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        visit_children(
 | 
					        visit_children(
 | 
				
			||||||
            initial_state,
 | 
					            initial_state,
 | 
				
			||||||
| 
						 | 
					@ -175,6 +186,7 @@ pub fn build_item_tree<T: ItemTreeBuilder>(
 | 
				
			||||||
            1,
 | 
					            1,
 | 
				
			||||||
            1,
 | 
					            1,
 | 
				
			||||||
            &mut repeater_count,
 | 
					            &mut repeater_count,
 | 
				
			||||||
 | 
					            &mut container_count,
 | 
				
			||||||
            builder,
 | 
					            builder,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -193,6 +205,15 @@ pub fn build_item_tree<T: ItemTreeBuilder>(
 | 
				
			||||||
        count
 | 
					        count
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Number of repeaters in this sub component
 | 
				
			||||||
 | 
					    fn repeater_count_in_sub_component(e: &ElementRc) -> usize {
 | 
				
			||||||
 | 
					        let mut count = if e.borrow().repeated.is_some() { 0 } else { 1 };
 | 
				
			||||||
 | 
					        for i in &e.borrow().children {
 | 
				
			||||||
 | 
					            count += repeater_count_in_sub_component(i);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        count
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn visit_children<T: ItemTreeBuilder>(
 | 
					    fn visit_children<T: ItemTreeBuilder>(
 | 
				
			||||||
        state: &T::SubComponentState,
 | 
					        state: &T::SubComponentState,
 | 
				
			||||||
        children: &[ElementRc],
 | 
					        children: &[ElementRc],
 | 
				
			||||||
| 
						 | 
					@ -203,6 +224,7 @@ pub fn build_item_tree<T: ItemTreeBuilder>(
 | 
				
			||||||
        children_offset: u32,
 | 
					        children_offset: u32,
 | 
				
			||||||
        relative_children_offset: u32,
 | 
					        relative_children_offset: u32,
 | 
				
			||||||
        repeater_count: &mut u32,
 | 
					        repeater_count: &mut u32,
 | 
				
			||||||
 | 
					        container_count: &mut u32,
 | 
				
			||||||
        builder: &mut T,
 | 
					        builder: &mut T,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        debug_assert_eq!(
 | 
					        debug_assert_eq!(
 | 
				
			||||||
| 
						 | 
					@ -241,6 +263,7 @@ pub fn build_item_tree<T: ItemTreeBuilder>(
 | 
				
			||||||
                    children_offset,
 | 
					                    children_offset,
 | 
				
			||||||
                    relative_children_offset,
 | 
					                    relative_children_offset,
 | 
				
			||||||
                    repeater_count,
 | 
					                    repeater_count,
 | 
				
			||||||
 | 
					                    container_count,
 | 
				
			||||||
                    builder,
 | 
					                    builder,
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
| 
						 | 
					@ -260,12 +283,21 @@ pub fn build_item_tree<T: ItemTreeBuilder>(
 | 
				
			||||||
                    &sub_component.root_element,
 | 
					                    &sub_component.root_element,
 | 
				
			||||||
                    offset,
 | 
					                    offset,
 | 
				
			||||||
                    repeater_count,
 | 
					                    repeater_count,
 | 
				
			||||||
 | 
					                    container_count,
 | 
				
			||||||
                    parent_index,
 | 
					                    parent_index,
 | 
				
			||||||
                    builder,
 | 
					                    builder,
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
                sub_component_states.push_back(sub_component_state);
 | 
					                sub_component_states.push_back(sub_component_state);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                visit_item(state, child, offset, repeater_count, parent_index, builder);
 | 
					                visit_item(
 | 
				
			||||||
 | 
					                    state,
 | 
				
			||||||
 | 
					                    child,
 | 
				
			||||||
 | 
					                    offset,
 | 
				
			||||||
 | 
					                    repeater_count,
 | 
				
			||||||
 | 
					                    container_count,
 | 
				
			||||||
 | 
					                    parent_index,
 | 
				
			||||||
 | 
					                    builder,
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            offset += item_sub_tree_size(child) as u32;
 | 
					            offset += item_sub_tree_size(child) as u32;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -289,6 +321,7 @@ pub fn build_item_tree<T: ItemTreeBuilder>(
 | 
				
			||||||
                    offset,
 | 
					                    offset,
 | 
				
			||||||
                    1,
 | 
					                    1,
 | 
				
			||||||
                    repeater_count,
 | 
					                    repeater_count,
 | 
				
			||||||
 | 
					                    container_count,
 | 
				
			||||||
                    builder,
 | 
					                    builder,
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
| 
						 | 
					@ -302,6 +335,7 @@ pub fn build_item_tree<T: ItemTreeBuilder>(
 | 
				
			||||||
                    offset,
 | 
					                    offset,
 | 
				
			||||||
                    relative_offset,
 | 
					                    relative_offset,
 | 
				
			||||||
                    repeater_count,
 | 
					                    repeater_count,
 | 
				
			||||||
 | 
					                    container_count,
 | 
				
			||||||
                    builder,
 | 
					                    builder,
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -319,11 +353,17 @@ pub fn build_item_tree<T: ItemTreeBuilder>(
 | 
				
			||||||
        item: &ElementRc,
 | 
					        item: &ElementRc,
 | 
				
			||||||
        children_offset: u32,
 | 
					        children_offset: u32,
 | 
				
			||||||
        repeater_count: &mut u32,
 | 
					        repeater_count: &mut u32,
 | 
				
			||||||
 | 
					        container_count: &mut u32,
 | 
				
			||||||
        parent_index: u32,
 | 
					        parent_index: u32,
 | 
				
			||||||
        builder: &mut T,
 | 
					        builder: &mut T,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        if item.borrow().is_component_placeholder {
 | 
					        if item.borrow().is_component_placeholder {
 | 
				
			||||||
            builder.push_component_placeholder_item(item, parent_index, component_state);
 | 
					            builder.push_component_placeholder_item(
 | 
				
			||||||
 | 
					                item,
 | 
				
			||||||
 | 
					                *container_count,
 | 
				
			||||||
 | 
					                parent_index,
 | 
				
			||||||
 | 
					                component_state,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
        } else if item.borrow().repeated.is_some() {
 | 
					        } else if item.borrow().repeated.is_some() {
 | 
				
			||||||
            builder.push_repeated_item(item, *repeater_count, parent_index, component_state);
 | 
					            builder.push_repeated_item(item, *repeater_count, parent_index, component_state);
 | 
				
			||||||
            *repeater_count += 1;
 | 
					            *repeater_count += 1;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -743,9 +743,10 @@ fn generate_sub_component(
 | 
				
			||||||
        repeated_element_components.push(rep_inner_component_id);
 | 
					        repeated_element_components.push(rep_inner_component_id);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for container in component.component_containers.iter() {
 | 
					    // Use ids following the real repeaters to piggyback on their forwarding through sub-components!
 | 
				
			||||||
 | 
					    for (idx, container) in component.component_containers.iter().enumerate() {
 | 
				
			||||||
 | 
					        let idx = (component.repeated.len() + idx) as u32;
 | 
				
			||||||
        let items_index = container.component_container_items_index;
 | 
					        let items_index = container.component_container_items_index;
 | 
				
			||||||
        let repeater_index = container.component_container_item_tree_index.as_repeater_index();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let embed_item = access_member(
 | 
					        let embed_item = access_member(
 | 
				
			||||||
            &llr::PropertyReference::InNativeItem {
 | 
					            &llr::PropertyReference::InNativeItem {
 | 
				
			||||||
| 
						 | 
					@ -763,19 +764,19 @@ fn generate_sub_component(
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        repeated_visit_branch.push(quote!(
 | 
					        repeated_visit_branch.push(quote!(
 | 
				
			||||||
            #repeater_index => {
 | 
					            #idx => {
 | 
				
			||||||
                #ensure_updated
 | 
					                #ensure_updated
 | 
				
			||||||
                #embed_item.visit_children_item(-1, order, visitor)
 | 
					                #embed_item.visit_children_item(-1, order, visitor)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        ));
 | 
					        ));
 | 
				
			||||||
        repeated_subtree_ranges.push(quote!(
 | 
					        repeated_subtree_ranges.push(quote!(
 | 
				
			||||||
            #repeater_index => {
 | 
					            #idx => {
 | 
				
			||||||
                #ensure_updated
 | 
					                #ensure_updated
 | 
				
			||||||
               #embed_item.subtree_range()
 | 
					                #embed_item.subtree_range()
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        ));
 | 
					        ));
 | 
				
			||||||
        repeated_subtree_components.push(quote!(
 | 
					        repeated_subtree_components.push(quote!(
 | 
				
			||||||
            #repeater_index => {
 | 
					            #idx => {
 | 
				
			||||||
                #ensure_updated
 | 
					                #ensure_updated
 | 
				
			||||||
                if subtree_index == 0 {
 | 
					                if subtree_index == 0 {
 | 
				
			||||||
                    *result = #embed_item.subtree_component()
 | 
					                    *result = #embed_item.subtree_component()
 | 
				
			||||||
| 
						 | 
					@ -1350,7 +1351,7 @@ fn generate_item_tree(
 | 
				
			||||||
    sub_tree.tree.visit_in_array(&mut |node, children_offset, parent_index| {
 | 
					    sub_tree.tree.visit_in_array(&mut |node, children_offset, parent_index| {
 | 
				
			||||||
        let parent_index = parent_index as u32;
 | 
					        let parent_index = parent_index as u32;
 | 
				
			||||||
        let (path, component) = follow_sub_component_path(&sub_tree.root, &node.sub_component_path);
 | 
					        let (path, component) = follow_sub_component_path(&sub_tree.root, &node.sub_component_path);
 | 
				
			||||||
        if node.repeated {
 | 
					        if node.repeated || node.component_container {
 | 
				
			||||||
            assert_eq!(node.children.len(), 0);
 | 
					            assert_eq!(node.children.len(), 0);
 | 
				
			||||||
            let mut repeater_index = node.item_index;
 | 
					            let mut repeater_index = node.item_index;
 | 
				
			||||||
            let mut sub_component = &sub_tree.root;
 | 
					            let mut sub_component = &sub_tree.root;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -142,47 +142,10 @@ pub struct RepeatedElement {
 | 
				
			||||||
    pub listview: Option<ListViewInfo>,
 | 
					    pub listview: Option<ListViewInfo>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Debug)]
 | 
					 | 
				
			||||||
pub struct ComponentContainerIndex(u32);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl From<u32> for ComponentContainerIndex {
 | 
					 | 
				
			||||||
    fn from(value: u32) -> Self {
 | 
					 | 
				
			||||||
        assert!(value < ComponentContainerIndex::MAGIC);
 | 
					 | 
				
			||||||
        ComponentContainerIndex(value + ComponentContainerIndex::MAGIC)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl ComponentContainerIndex {
 | 
					 | 
				
			||||||
    // Choose a MAGIC value that is big enough so we can have lots of repeaters
 | 
					 | 
				
			||||||
    // (repeater_index must be < MAGIC), but small enough to leave room for
 | 
					 | 
				
			||||||
    // lots of embeddings (which will use item_index + MAGIC as its
 | 
					 | 
				
			||||||
    // repeater_index).
 | 
					 | 
				
			||||||
    // Also pick a MAGIC that works on 32bit as well as 64bit systems.
 | 
					 | 
				
			||||||
    const MAGIC: u32 = (u32::MAX / 2) + 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn as_item_tree_index(&self) -> u32 {
 | 
					 | 
				
			||||||
        assert!(self.0 >= ComponentContainerIndex::MAGIC);
 | 
					 | 
				
			||||||
        self.0 - ComponentContainerIndex::MAGIC
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn as_repeater_index(&self) -> u32 {
 | 
					 | 
				
			||||||
        assert!(self.0 >= ComponentContainerIndex::MAGIC);
 | 
					 | 
				
			||||||
        self.0
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn try_from_repeater_index(index: u32) -> Option<Self> {
 | 
					 | 
				
			||||||
        if index >= ComponentContainerIndex::MAGIC {
 | 
					 | 
				
			||||||
            Some(ComponentContainerIndex(index))
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            None
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct ComponentContainerElement {
 | 
					pub struct ComponentContainerElement {
 | 
				
			||||||
    /// The item tree index of the `ComponentContainer` item node, controlling this Placeholder
 | 
					    /// The index of the `ComponentContainer` in the enclosing components `item_tree` array
 | 
				
			||||||
    pub component_container_item_tree_index: ComponentContainerIndex,
 | 
					    pub component_container_item_tree_index: u32,
 | 
				
			||||||
    /// The index of the `ComponentContainer` item in the enclosing components `items` array
 | 
					    /// The index of the `ComponentContainer` item in the enclosing components `items` array
 | 
				
			||||||
    pub component_container_items_index: u32,
 | 
					    pub component_container_items_index: u32,
 | 
				
			||||||
    /// The index to a dynamic tree node where the component is supposed to be embedded at
 | 
					    /// The index to a dynamic tree node where the component is supposed to be embedded at
 | 
				
			||||||
| 
						 | 
					@ -209,9 +172,10 @@ impl std::fmt::Debug for Item {
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct TreeNode {
 | 
					pub struct TreeNode {
 | 
				
			||||||
    pub sub_component_path: Vec<usize>,
 | 
					    pub sub_component_path: Vec<usize>,
 | 
				
			||||||
    /// Either an index in the items or repeater, depending on repeated
 | 
					    /// Either an index in the items or repeater, depending on (repeated || component_container)
 | 
				
			||||||
    pub item_index: u32,
 | 
					    pub item_index: u32,
 | 
				
			||||||
    pub repeated: bool,
 | 
					    pub repeated: bool,
 | 
				
			||||||
 | 
					    pub component_container: bool,
 | 
				
			||||||
    pub children: Vec<TreeNode>,
 | 
					    pub children: Vec<TreeNode>,
 | 
				
			||||||
    pub is_accessible: bool,
 | 
					    pub is_accessible: bool,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -301,7 +265,7 @@ pub struct PropAnalysis {
 | 
				
			||||||
impl SubComponent {
 | 
					impl SubComponent {
 | 
				
			||||||
    /// total count of repeater, including in sub components
 | 
					    /// total count of repeater, including in sub components
 | 
				
			||||||
    pub fn repeater_count(&self) -> u32 {
 | 
					    pub fn repeater_count(&self) -> u32 {
 | 
				
			||||||
        let mut count = self.repeated.len() as u32;
 | 
					        let mut count = (self.repeated.len() + self.component_containers.len()) as u32;
 | 
				
			||||||
        for x in self.sub_components.iter() {
 | 
					        for x in self.sub_components.iter() {
 | 
				
			||||||
            count += x.ty.repeater_count();
 | 
					            count += x.ty.repeater_count();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,13 +62,15 @@ pub enum LoweredElement {
 | 
				
			||||||
    SubComponent { sub_component_index: usize },
 | 
					    SubComponent { sub_component_index: usize },
 | 
				
			||||||
    NativeItem { item_index: u32 },
 | 
					    NativeItem { item_index: u32 },
 | 
				
			||||||
    Repeated { repeated_index: u32 },
 | 
					    Repeated { repeated_index: u32 },
 | 
				
			||||||
    ComponentPlaceholder { component_container_index: ComponentContainerIndex },
 | 
					    ComponentPlaceholder { repeated_index: u32 },
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Default, Debug, Clone)]
 | 
					#[derive(Default, Debug, Clone)]
 | 
				
			||||||
pub struct LoweredSubComponentMapping {
 | 
					pub struct LoweredSubComponentMapping {
 | 
				
			||||||
    pub element_mapping: HashMap<ByAddress<ElementRc>, LoweredElement>,
 | 
					    pub element_mapping: HashMap<ByAddress<ElementRc>, LoweredElement>,
 | 
				
			||||||
    pub property_mapping: HashMap<NamedReference, PropertyReference>,
 | 
					    pub property_mapping: HashMap<NamedReference, PropertyReference>,
 | 
				
			||||||
 | 
					    pub repeater_count: u32,
 | 
				
			||||||
 | 
					    pub container_count: u32,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl LoweredSubComponentMapping {
 | 
					impl LoweredSubComponentMapping {
 | 
				
			||||||
| 
						 | 
					@ -259,11 +261,13 @@ fn lower_sub_component(
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if elem.is_component_placeholder {
 | 
					        if elem.is_component_placeholder {
 | 
				
			||||||
            let index = parent.as_ref().unwrap().borrow().item_index.get().copied().unwrap();
 | 
					 | 
				
			||||||
            mapping.element_mapping.insert(
 | 
					            mapping.element_mapping.insert(
 | 
				
			||||||
                element.clone().into(),
 | 
					                element.clone().into(),
 | 
				
			||||||
                LoweredElement::ComponentPlaceholder { component_container_index: index.into() },
 | 
					                LoweredElement::ComponentPlaceholder {
 | 
				
			||||||
 | 
					                    repeated_index: component_container_data.len() as u32,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
 | 
					            mapping.container_count += 1;
 | 
				
			||||||
            component_container_data.push(parent.as_ref().unwrap().clone());
 | 
					            component_container_data.push(parent.as_ref().unwrap().clone());
 | 
				
			||||||
            return None;
 | 
					            return None;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -273,6 +277,7 @@ fn lower_sub_component(
 | 
				
			||||||
                LoweredElement::Repeated { repeated_index: repeated.len() as u32 },
 | 
					                LoweredElement::Repeated { repeated_index: repeated.len() as u32 },
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            repeated.push(element.clone());
 | 
					            repeated.push(element.clone());
 | 
				
			||||||
 | 
					            mapping.repeater_count += 1;
 | 
				
			||||||
            return None;
 | 
					            return None;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        match &elem.base_type {
 | 
					        match &elem.base_type {
 | 
				
			||||||
| 
						 | 
					@ -391,7 +396,8 @@ fn lower_sub_component(
 | 
				
			||||||
    sub_component.repeated =
 | 
					    sub_component.repeated =
 | 
				
			||||||
        repeated.into_iter().map(|elem| lower_repeated_component(&elem, &ctx)).collect();
 | 
					        repeated.into_iter().map(|elem| lower_repeated_component(&elem, &ctx)).collect();
 | 
				
			||||||
    for s in &mut sub_component.sub_components {
 | 
					    for s in &mut sub_component.sub_components {
 | 
				
			||||||
        s.repeater_offset += sub_component.repeated.len() as u32;
 | 
					        s.repeater_offset +=
 | 
				
			||||||
 | 
					            (sub_component.repeated.len() + sub_component.component_containers.len()) as u32;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    sub_component.component_containers = component_container_data
 | 
					    sub_component.component_containers = component_container_data
 | 
				
			||||||
        .into_iter()
 | 
					        .into_iter()
 | 
				
			||||||
| 
						 | 
					@ -563,10 +569,12 @@ fn lower_component_container(
 | 
				
			||||||
) -> ComponentContainerElement {
 | 
					) -> ComponentContainerElement {
 | 
				
			||||||
    let c = container.borrow();
 | 
					    let c = container.borrow();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let component_container_index: ComponentContainerIndex = (*c.item_index.get().unwrap()).into();
 | 
					    let component_container_index = *c.item_index.get().unwrap();
 | 
				
			||||||
    let ti = component_container_index.as_item_tree_index();
 | 
					    let component_container_items_index = sub_component
 | 
				
			||||||
    let component_container_items_index =
 | 
					        .items
 | 
				
			||||||
        sub_component.items.iter().position(|i| i.index_in_tree == ti).unwrap() as u32;
 | 
					        .iter()
 | 
				
			||||||
 | 
					        .position(|i| i.index_in_tree == component_container_index)
 | 
				
			||||||
 | 
					        .unwrap() as u32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ComponentContainerElement {
 | 
					    ComponentContainerElement {
 | 
				
			||||||
        component_container_item_tree_index: component_container_index,
 | 
					        component_container_item_tree_index: component_container_index,
 | 
				
			||||||
| 
						 | 
					@ -738,6 +746,7 @@ fn make_tree(
 | 
				
			||||||
) -> TreeNode {
 | 
					) -> TreeNode {
 | 
				
			||||||
    let e = element.borrow();
 | 
					    let e = element.borrow();
 | 
				
			||||||
    let children = e.children.iter().map(|c| make_tree(state, c, component, sub_component_path));
 | 
					    let children = e.children.iter().map(|c| make_tree(state, c, component, sub_component_path));
 | 
				
			||||||
 | 
					    let repeater_count = component.mapping.repeater_count;
 | 
				
			||||||
    match component.mapping.element_mapping.get(&ByAddress(element.clone())).unwrap() {
 | 
					    match component.mapping.element_mapping.get(&ByAddress(element.clone())).unwrap() {
 | 
				
			||||||
        LoweredElement::SubComponent { sub_component_index } => {
 | 
					        LoweredElement::SubComponent { sub_component_index } => {
 | 
				
			||||||
            let sub_component = e.sub_component().unwrap();
 | 
					            let sub_component = e.sub_component().unwrap();
 | 
				
			||||||
| 
						 | 
					@ -762,6 +771,7 @@ fn make_tree(
 | 
				
			||||||
            item_index: *item_index,
 | 
					            item_index: *item_index,
 | 
				
			||||||
            children: children.collect(),
 | 
					            children: children.collect(),
 | 
				
			||||||
            repeated: false,
 | 
					            repeated: false,
 | 
				
			||||||
 | 
					            component_container: false,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        LoweredElement::Repeated { repeated_index } => TreeNode {
 | 
					        LoweredElement::Repeated { repeated_index } => TreeNode {
 | 
				
			||||||
            is_accessible: false,
 | 
					            is_accessible: false,
 | 
				
			||||||
| 
						 | 
					@ -769,13 +779,15 @@ fn make_tree(
 | 
				
			||||||
            item_index: *repeated_index,
 | 
					            item_index: *repeated_index,
 | 
				
			||||||
            children: vec![],
 | 
					            children: vec![],
 | 
				
			||||||
            repeated: true,
 | 
					            repeated: true,
 | 
				
			||||||
 | 
					            component_container: false,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        LoweredElement::ComponentPlaceholder { component_container_index } => TreeNode {
 | 
					        LoweredElement::ComponentPlaceholder { repeated_index } => TreeNode {
 | 
				
			||||||
            is_accessible: false,
 | 
					            is_accessible: false,
 | 
				
			||||||
            sub_component_path: sub_component_path.into(),
 | 
					            sub_component_path: sub_component_path.into(),
 | 
				
			||||||
            item_index: component_container_index.as_repeater_index(),
 | 
					            item_index: *repeated_index + repeater_count,
 | 
				
			||||||
            children: vec![],
 | 
					            children: vec![],
 | 
				
			||||||
            repeated: true,
 | 
					            repeated: false,
 | 
				
			||||||
 | 
					            component_container: true,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,6 +69,7 @@ impl crate::generator::ItemTreeBuilder for Helper {
 | 
				
			||||||
    fn push_component_placeholder_item(
 | 
					    fn push_component_placeholder_item(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        item: &crate::object_tree::ElementRc,
 | 
					        item: &crate::object_tree::ElementRc,
 | 
				
			||||||
 | 
					        _container_count: u32,
 | 
				
			||||||
        _parent_index: u32,
 | 
					        _parent_index: u32,
 | 
				
			||||||
        component_state: &Self::SubComponentState,
 | 
					        component_state: &Self::SubComponentState,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,6 @@ use dynamic_type::{Instance, InstanceBox};
 | 
				
			||||||
use i_slint_compiler::diagnostics::SourceFileVersion;
 | 
					use i_slint_compiler::diagnostics::SourceFileVersion;
 | 
				
			||||||
use i_slint_compiler::expression_tree::{Expression, NamedReference};
 | 
					use i_slint_compiler::expression_tree::{Expression, NamedReference};
 | 
				
			||||||
use i_slint_compiler::langtype::{ElementType, Type};
 | 
					use i_slint_compiler::langtype::{ElementType, Type};
 | 
				
			||||||
use i_slint_compiler::llr::ComponentContainerIndex;
 | 
					 | 
				
			||||||
use i_slint_compiler::object_tree::ElementRc;
 | 
					use i_slint_compiler::object_tree::ElementRc;
 | 
				
			||||||
use i_slint_compiler::*;
 | 
					use i_slint_compiler::*;
 | 
				
			||||||
use i_slint_compiler::{diagnostics::BuildDiagnostics, object_tree::PropertyDeclaration};
 | 
					use i_slint_compiler::{diagnostics::BuildDiagnostics, object_tree::PropertyDeclaration};
 | 
				
			||||||
| 
						 | 
					@ -673,8 +672,8 @@ extern "C" fn visit_children_item(
 | 
				
			||||||
        order,
 | 
					        order,
 | 
				
			||||||
        v,
 | 
					        v,
 | 
				
			||||||
        |_, order, visitor, index| {
 | 
					        |_, order, visitor, index| {
 | 
				
			||||||
            if let Some(_) = ComponentContainerIndex::try_from_repeater_index(index) {
 | 
					            if index as usize >= instance_ref.description.repeater.len() {
 | 
				
			||||||
                // Do nothing: Our parent already did all the work!
 | 
					                // Do nothing: We are ComponentContainer and Our parent already did all the work!
 | 
				
			||||||
                VisitChildrenResult::CONTINUE
 | 
					                VisitChildrenResult::CONTINUE
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                // `ensure_updated` needs a 'static lifetime so we must call get_untagged.
 | 
					                // `ensure_updated` needs a 'static lifetime so we must call get_untagged.
 | 
				
			||||||
| 
						 | 
					@ -895,14 +894,12 @@ pub(crate) fn generate_item_tree<'id>(
 | 
				
			||||||
        fn push_component_placeholder_item(
 | 
					        fn push_component_placeholder_item(
 | 
				
			||||||
            &mut self,
 | 
					            &mut self,
 | 
				
			||||||
            item: &i_slint_compiler::object_tree::ElementRc,
 | 
					            item: &i_slint_compiler::object_tree::ElementRc,
 | 
				
			||||||
 | 
					            container_count: u32,
 | 
				
			||||||
            parent_index: u32,
 | 
					            parent_index: u32,
 | 
				
			||||||
            _component_state: &Self::SubComponentState,
 | 
					            _component_state: &Self::SubComponentState,
 | 
				
			||||||
        ) {
 | 
					        ) {
 | 
				
			||||||
            let component_index = ComponentContainerIndex::from(parent_index);
 | 
					            self.tree_array
 | 
				
			||||||
            self.tree_array.push(ItemTreeNode::DynamicTree {
 | 
					                .push(ItemTreeNode::DynamicTree { index: container_count, parent_index });
 | 
				
			||||||
                index: component_index.as_repeater_index(),
 | 
					 | 
				
			||||||
                parent_index,
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
            self.original_elements.push(item.clone());
 | 
					            self.original_elements.push(item.clone());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1647,8 +1644,16 @@ unsafe extern "C" fn get_item_ref(component: ItemTreeRefPin, index: u32) -> Pin<
 | 
				
			||||||
extern "C" fn get_subtree_range(component: ItemTreeRefPin, index: u32) -> IndexRange {
 | 
					extern "C" fn get_subtree_range(component: ItemTreeRefPin, index: u32) -> IndexRange {
 | 
				
			||||||
    generativity::make_guard!(guard);
 | 
					    generativity::make_guard!(guard);
 | 
				
			||||||
    let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };
 | 
					    let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };
 | 
				
			||||||
    if let Some(container_index) = ComponentContainerIndex::try_from_repeater_index(index) {
 | 
					    if index as usize >= instance_ref.description.repeater.len() {
 | 
				
			||||||
        let container = component.as_ref().get_item_ref(container_index.as_item_tree_index());
 | 
					        let container_index = {
 | 
				
			||||||
 | 
					            let tree_node = &component.as_ref().get_item_tree()[index as usize];
 | 
				
			||||||
 | 
					            if let ItemTreeNode::DynamicTree { parent_index, .. } = tree_node {
 | 
				
			||||||
 | 
					                *parent_index
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                u32::MAX
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let container = component.as_ref().get_item_ref(container_index);
 | 
				
			||||||
        let container = i_slint_core::items::ItemRef::downcast_pin::<
 | 
					        let container = i_slint_core::items::ItemRef::downcast_pin::<
 | 
				
			||||||
            i_slint_core::items::ComponentContainer,
 | 
					            i_slint_core::items::ComponentContainer,
 | 
				
			||||||
        >(container)
 | 
					        >(container)
 | 
				
			||||||
| 
						 | 
					@ -1673,8 +1678,16 @@ extern "C" fn get_subtree(
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    generativity::make_guard!(guard);
 | 
					    generativity::make_guard!(guard);
 | 
				
			||||||
    let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };
 | 
					    let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };
 | 
				
			||||||
    if let Some(container_index) = ComponentContainerIndex::try_from_repeater_index(index) {
 | 
					    if index as usize >= instance_ref.description.repeater.len() {
 | 
				
			||||||
        let container = component.as_ref().get_item_ref(container_index.as_item_tree_index());
 | 
					        let container_index = {
 | 
				
			||||||
 | 
					            let tree_node = &component.as_ref().get_item_tree()[index as usize];
 | 
				
			||||||
 | 
					            if let ItemTreeNode::DynamicTree { parent_index, .. } = tree_node {
 | 
				
			||||||
 | 
					                *parent_index
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                u32::MAX
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let container = component.as_ref().get_item_ref(container_index);
 | 
				
			||||||
        let container = i_slint_core::items::ItemRef::downcast_pin::<
 | 
					        let container = i_slint_core::items::ItemRef::downcast_pin::<
 | 
				
			||||||
            i_slint_core::items::ComponentContainer,
 | 
					            i_slint_core::items::ComponentContainer,
 | 
				
			||||||
        >(container)
 | 
					        >(container)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										81
									
								
								tests/cases/elements/component_container_component.slint
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								tests/cases/elements/component_container_component.slint
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,81 @@
 | 
				
			||||||
 | 
					// Copyright © SixtyFPS GmbH <info@slint.dev>
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FIXME: Skip embedding test on C++ and NodeJS since ComponentFactory is not
 | 
				
			||||||
 | 
					// implemented there!
 | 
				
			||||||
 | 
					//ignore: cpp,js
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { Button } from "std-widgets.slint";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					component Container {
 | 
				
			||||||
 | 
					    in property<component-factory> c1 <=> cont1.component-factory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cont1 := ComponentContainer { }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export component TestCase inherits Rectangle {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    in property<component-factory> c1;
 | 
				
			||||||
 | 
					    out property<bool> outside-focus <=> outside.has-focus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    outside := Button { text: "Outside button"; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Container {
 | 
				
			||||||
 | 
					        c1 <=> root.c1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					```cpp
 | 
				
			||||||
 | 
					// ComponentFactory not supported yet!
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```rust
 | 
				
			||||||
 | 
					let factory = slint::ComponentFactory::new(|ctx| {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut compiler = slint_interpreter::ComponentCompiler::new();
 | 
				
			||||||
 | 
					    let e = spin_on::spin_on(compiler.build_from_source(
 | 
				
			||||||
 | 
					        r#"import { Button } from "std-widgets.slint";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export component E1 inherits Rectangle {
 | 
				
			||||||
 | 
					    background: Colors.red;
 | 
				
			||||||
 | 
					    forward-focus: b;
 | 
				
			||||||
 | 
					    b := Button {
 | 
				
			||||||
 | 
					        text: "red";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}"#.into(),
 | 
				
			||||||
 | 
					        std::path::PathBuf::from("embedded.slint"),
 | 
				
			||||||
 | 
					     )).unwrap();
 | 
				
			||||||
 | 
					     e.create_embedded(ctx).ok()
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let instance = TestCase::new().unwrap();
 | 
				
			||||||
 | 
					assert!(!instance.get_outside_focus()); // Nothing has focus be default
 | 
				
			||||||
 | 
					slint_testing::send_keyboard_string_sequence(&instance, "\t");
 | 
				
			||||||
 | 
					assert!(instance.get_outside_focus()); // The outside button is the only thing
 | 
				
			||||||
 | 
					                                       // accepting focus at this point.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					instance.set_c1(factory);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					assert!(instance.get_outside_focus()); // embedding does not move the focus
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// focus the two embedded buttons:
 | 
				
			||||||
 | 
					slint_testing::send_keyboard_string_sequence(&instance, "\t");
 | 
				
			||||||
 | 
					assert!(!instance.get_outside_focus());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Go back to outside button
 | 
				
			||||||
 | 
					slint_testing::send_keyboard_string_sequence(&instance, "\t");
 | 
				
			||||||
 | 
					assert!(instance.get_outside_focus());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Focus backwards over the embedded buttons
 | 
				
			||||||
 | 
					slint_testing::send_keyboard_string_sequence(&instance, "\u{0019}");
 | 
				
			||||||
 | 
					assert!(!instance.get_outside_focus());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					slint_testing::send_keyboard_string_sequence(&instance, "\u{0019}");
 | 
				
			||||||
 | 
					assert!(instance.get_outside_focus());
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```js
 | 
				
			||||||
 | 
					var _instance = new slint.TestCase();
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue