mirror of
https://github.com/slint-ui/slint.git
synced 2025-11-03 05:12:55 +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