mirror of
https://github.com/slint-ui/slint.git
synced 2025-11-01 12:24:16 +00:00
Component: Add information to stich together ItemTrees
Add accessors to the information necessary to stitch together the Component-wide ItemTrees (which include DynamicNodes) into one logical tree of Items.
This commit is contained in:
parent
c1bb22bd00
commit
ee68716d07
8 changed files with 368 additions and 17 deletions
|
|
@ -42,10 +42,12 @@ namespace slint {
|
|||
namespace private_api {
|
||||
using cbindgen_private::ComponentVTable;
|
||||
using cbindgen_private::ItemVTable;
|
||||
using ComponentRc = vtable::VRc<private_api::ComponentVTable>;
|
||||
using ComponentRef = vtable::VRef<private_api::ComponentVTable>;
|
||||
using IndexRange = cbindgen_private::IndexRange;
|
||||
using ItemRef = vtable::VRef<private_api::ItemVTable>;
|
||||
using ItemVisitorRefMut = vtable::VRefMut<cbindgen_private::ItemVisitorVTable>;
|
||||
using cbindgen_private::ComponentRc;
|
||||
using cbindgen_private::ComponentWeak;
|
||||
using cbindgen_private::ItemWeak;
|
||||
using cbindgen_private::TraversalOrder;
|
||||
}
|
||||
|
|
@ -846,6 +848,16 @@ public:
|
|||
return { &C::static_vtable, const_cast<C *>(&(**x.ptr)) };
|
||||
}
|
||||
|
||||
void component_at(int i, vtable::VWeak<private_api::ComponentVTable> *result) const
|
||||
{
|
||||
const auto &x = inner->data.at(i);
|
||||
*result = vtable::VWeak<private_api::ComponentVTable>{x.ptr->into_dyn()};
|
||||
}
|
||||
|
||||
private_api::IndexRange index_range() const {
|
||||
return private_api::IndexRange { 0, inner->data.size() };
|
||||
}
|
||||
|
||||
float compute_layout_listview(const private_api::Property<float> *viewport_width,
|
||||
float listview_width) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
||||
|
||||
// cSpell: ignore buildrs
|
||||
|
||||
/*!
|
||||
# Slint
|
||||
|
||||
|
|
@ -283,7 +285,7 @@ pub mod re_exports {
|
|||
pub use i_slint_core::callbacks::Callback;
|
||||
pub use i_slint_core::component::{
|
||||
free_component_item_graphics_resources, init_component_items, Component, ComponentRefPin,
|
||||
ComponentVTable,
|
||||
ComponentVTable, ComponentWeak, IndexRange,
|
||||
};
|
||||
pub use i_slint_core::graphics::*;
|
||||
pub use i_slint_core::input::{
|
||||
|
|
|
|||
|
|
@ -848,15 +848,25 @@ fn generate_item_tree(
|
|||
let mut visit_children_statements = vec![
|
||||
"static const auto dyn_visit = [] (const uint8_t *base, [[maybe_unused]] slint::private_api::TraversalOrder order, [[maybe_unused]] slint::private_api::ItemVisitorRefMut visitor, [[maybe_unused]] uintptr_t dyn_index) -> uint64_t {".to_owned(),
|
||||
format!(" [[maybe_unused]] auto self = reinterpret_cast<const {}*>(base);", item_tree_class_name)];
|
||||
let mut subtree_range_statement = vec![" std::abort();".into()];
|
||||
let mut subtree_component_statement = vec![" std::abort();".into()];
|
||||
|
||||
if target_struct.members.iter().any(|(_, declaration)| {
|
||||
matches!(&declaration, Declaration::Function(func @ Function { .. }) if func.name == "visit_dynamic_children")
|
||||
}) {
|
||||
visit_children_statements
|
||||
.push(" return self->visit_dynamic_children(dyn_index, order, visitor);".into());
|
||||
subtree_range_statement = vec![
|
||||
format!("auto self = reinterpret_cast<const {}*>(component.instance);", item_tree_class_name),
|
||||
"return self->subtree_range(dyn_index);".to_owned(),
|
||||
];
|
||||
subtree_component_statement = vec![
|
||||
format!("auto self = reinterpret_cast<const {}*>(component.instance);", item_tree_class_name),
|
||||
"self->subtree_component(dyn_index, subtree_index, result);".to_owned(),
|
||||
];
|
||||
} else {
|
||||
visit_children_statements.push(" std::abort();".into());
|
||||
}
|
||||
}
|
||||
|
||||
visit_children_statements.extend([
|
||||
"};".into(),
|
||||
|
|
@ -888,6 +898,28 @@ fn generate_item_tree(
|
|||
}),
|
||||
));
|
||||
|
||||
target_struct.members.push((
|
||||
Access::Private,
|
||||
Declaration::Function(Function {
|
||||
name: "get_subtree_range".into(),
|
||||
signature: "([[maybe_unused]] slint::private_api::ComponentRef component, [[maybe_unused]] uintptr_t dyn_index) -> slint::private_api::IndexRange".into(),
|
||||
is_static: true,
|
||||
statements: Some(subtree_range_statement),
|
||||
..Default::default()
|
||||
}),
|
||||
));
|
||||
|
||||
target_struct.members.push((
|
||||
Access::Private,
|
||||
Declaration::Function(Function {
|
||||
name: "get_subtree_component".into(),
|
||||
signature: "([[maybe_unused]] slint::private_api::ComponentRef component, [[maybe_unused]] uintptr_t dyn_index, [[maybe_unused]] uintptr_t subtree_index, [[maybe_unused]] slint::private_api::ComponentWeak *result) -> void".into(),
|
||||
is_static: true,
|
||||
statements: Some(subtree_component_statement),
|
||||
..Default::default()
|
||||
}),
|
||||
));
|
||||
|
||||
target_struct.members.push((
|
||||
Access::Private,
|
||||
Declaration::Function(Function {
|
||||
|
|
@ -910,7 +942,7 @@ fn generate_item_tree(
|
|||
format!(
|
||||
// that does not work when the parent is not a component with a ComponentVTable
|
||||
//" *result = slint::private_api::parent_item(self->parent->self_weak.into_dyn(), self->parent->get_item_tree(), {});",
|
||||
"self->parent->self_weak.vtable()->parent_item(self->parent->self_weak.lock()->borrow(), {}, result);",
|
||||
"*result = {{ self->parent->self_weak, {} }};",
|
||||
parent_index,
|
||||
)
|
||||
} else {
|
||||
|
|
@ -934,6 +966,17 @@ fn generate_item_tree(
|
|||
}),
|
||||
));
|
||||
|
||||
target_struct.members.push((
|
||||
Access::Private,
|
||||
Declaration::Function(Function {
|
||||
name: "subtree_index".into(),
|
||||
signature: "(slint::private_api::ComponentRef /* component */) -> uintptr_t".into(),
|
||||
is_static: true,
|
||||
statements: Some(vec!["/* unimplemented! */".to_owned(), "return 0;".into()]),
|
||||
..Default::default()
|
||||
}),
|
||||
));
|
||||
|
||||
target_struct.members.push((
|
||||
Access::Private,
|
||||
Declaration::Function(Function {
|
||||
|
|
@ -995,7 +1038,7 @@ fn generate_item_tree(
|
|||
ty: "const slint::private_api::ComponentVTable".to_owned(),
|
||||
name: format!("{}::static_vtable", item_tree_class_name),
|
||||
init: Some(format!(
|
||||
"{{ visit_children, get_item_ref, get_item_tree, parent_item, layout_info, slint::private_api::drop_in_place<{}>, slint::private_api::dealloc }}",
|
||||
"{{ visit_children, get_item_ref, get_subtree_range, get_subtree_component, get_item_tree, parent_item, subtree_index, layout_info, slint::private_api::drop_in_place<{}>, slint::private_api::dealloc }}",
|
||||
item_tree_class_name)
|
||||
),
|
||||
..Default::default()
|
||||
|
|
@ -1181,6 +1224,8 @@ fn generate_sub_component(
|
|||
}
|
||||
|
||||
let mut children_visitor_cases = Vec::new();
|
||||
let mut subtrees_ranges_cases = Vec::new();
|
||||
let mut subtrees_components_cases = Vec::new();
|
||||
|
||||
let mut subcomponent_init_code = Vec::new();
|
||||
for sub in &component.sub_components {
|
||||
|
|
@ -1223,6 +1268,23 @@ fn generate_sub_component(
|
|||
id = field_name,
|
||||
base = repeater_offset,
|
||||
));
|
||||
subtrees_ranges_cases.push(format!(
|
||||
"\n {case_code} {{
|
||||
return self->{id}.subtree_range(dyn_index - {base});
|
||||
}}",
|
||||
case_code = case_code,
|
||||
id = field_name,
|
||||
base = repeater_offset,
|
||||
));
|
||||
subtrees_components_cases.push(format!(
|
||||
"\n {case_code} {{
|
||||
self->{id}.subtree_component(dyn_index - {base}, subtree_index, result);
|
||||
return;
|
||||
}}",
|
||||
case_code = case_code,
|
||||
id = field_name,
|
||||
base = repeater_offset,
|
||||
));
|
||||
}
|
||||
|
||||
target_struct.members.push((
|
||||
|
|
@ -1321,6 +1383,25 @@ fn generate_sub_component(
|
|||
i = idx,
|
||||
e_u = ensure_updated,
|
||||
));
|
||||
subtrees_ranges_cases.push(format!(
|
||||
"\n case {i}: {{
|
||||
{e_u}
|
||||
return self->{id}.index_range();
|
||||
}}",
|
||||
i = idx,
|
||||
e_u = ensure_updated,
|
||||
id = repeater_id,
|
||||
));
|
||||
subtrees_components_cases.push(format!(
|
||||
"\n case {i}: {{
|
||||
{e_u}
|
||||
self->{id}.component_at(subtree_index, result);
|
||||
return;
|
||||
}}",
|
||||
i = idx,
|
||||
e_u = ensure_updated,
|
||||
id = repeater_id,
|
||||
));
|
||||
|
||||
target_struct.members.push((
|
||||
Access::Private,
|
||||
|
|
@ -1382,6 +1463,32 @@ fn generate_sub_component(
|
|||
..Default::default()
|
||||
}),
|
||||
));
|
||||
target_struct.members.push((
|
||||
field_access,
|
||||
Declaration::Function(Function {
|
||||
name: "subtree_range".into(),
|
||||
signature: "(uintptr_t dyn_index) const -> slint::private_api::IndexRange".into(),
|
||||
statements: Some(vec![
|
||||
"[[maybe_unused]] auto self = this;".to_owned(),
|
||||
format!(" switch(dyn_index) {{ {} }};", subtrees_ranges_cases.join("")),
|
||||
" std::abort();".to_owned(),
|
||||
]),
|
||||
..Default::default()
|
||||
}),
|
||||
));
|
||||
target_struct.members.push((
|
||||
field_access,
|
||||
Declaration::Function(Function {
|
||||
name: "subtree_component".into(),
|
||||
signature: "(uintptr_t dyn_index, [[maybe_unused]] uintptr_t subtree_index, [[maybe_unused]] slint::private_api::ComponentWeak *result) const -> void".into(),
|
||||
statements: Some(vec![
|
||||
"[[maybe_unused]] auto self = this;".to_owned(),
|
||||
format!(" switch(dyn_index) {{ {} }};", subtrees_components_cases.join("")),
|
||||
" std::abort();".to_owned(),
|
||||
]),
|
||||
..Default::default()
|
||||
}),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
||||
|
||||
// cSpell: ignore conv powf punct
|
||||
|
||||
/*! module for the Rust code generator
|
||||
|
||||
Some convention used in the generated code:
|
||||
|
|
@ -117,7 +119,7 @@ pub fn generate(doc: &Document) -> TokenStream {
|
|||
let sub_compos = llr
|
||||
.sub_components
|
||||
.iter()
|
||||
.map(|sub_compo| generate_sub_component(sub_compo, &llr, None, quote!()))
|
||||
.map(|sub_compo| generate_sub_component(sub_compo, &llr, None, quote!(), None))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let compo = generate_public_component(&llr);
|
||||
|
|
@ -243,7 +245,7 @@ fn generate_public_component(llr: &llr::PublicComponent) -> TokenStream {
|
|||
let global_container_id = format_ident!("Globals_{}", public_component_id);
|
||||
|
||||
let component =
|
||||
generate_item_tree(&llr.item_tree, llr, None, quote!(globals: #global_container_id));
|
||||
generate_item_tree(&llr.item_tree, llr, None, quote!(globals: #global_container_id), None);
|
||||
|
||||
let ctx = EvaluationContext {
|
||||
public_component: llr,
|
||||
|
|
@ -515,6 +517,7 @@ fn generate_sub_component(
|
|||
root: &llr::PublicComponent,
|
||||
parent_ctx: Option<ParentCtx>,
|
||||
extra_fields: TokenStream,
|
||||
index_property: Option<llr::PropertyIndex>,
|
||||
) -> TokenStream {
|
||||
let inner_component_id = inner_component_id(component);
|
||||
|
||||
|
|
@ -527,7 +530,9 @@ fn generate_sub_component(
|
|||
let mut extra_components = component
|
||||
.popup_windows
|
||||
.iter()
|
||||
.map(|c| generate_item_tree(c, root, Some(ParentCtx::new(&ctx, None)), quote!()))
|
||||
.map(|c| {
|
||||
generate_item_tree(c, root, Some(ParentCtx::new(&ctx, None)), quote!(), index_property)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut declared_property_vars = vec![];
|
||||
|
|
@ -592,6 +597,8 @@ fn generate_sub_component(
|
|||
let mut repeated_element_names: Vec<Ident> = vec![];
|
||||
let mut repeated_visit_branch: Vec<TokenStream> = vec![];
|
||||
let mut repeated_element_components: Vec<Ident> = vec![];
|
||||
let mut repeated_subtree_ranges: Vec<TokenStream> = vec![];
|
||||
let mut repeated_subtree_components: Vec<TokenStream> = vec![];
|
||||
|
||||
for (idx, repeated) in component.repeated.iter().enumerate() {
|
||||
extra_components.push(generate_repeated_component(
|
||||
|
|
@ -643,6 +650,19 @@ fn generate_sub_component(
|
|||
_self.#repeater_id.visit(order, visitor)
|
||||
}
|
||||
));
|
||||
repeated_subtree_ranges.push(quote!(
|
||||
#idx => {
|
||||
#ensure_updated
|
||||
let (start, end) = _self.#repeater_id.range();
|
||||
slint::re_exports::IndexRange { start, end }
|
||||
}
|
||||
));
|
||||
repeated_subtree_components.push(quote!(
|
||||
#idx => {
|
||||
#ensure_updated
|
||||
*result = vtable::VRc::downgrade(&vtable::VRc::into_dyn(_self.#repeater_id.component_at(subtree_index).unwrap()))
|
||||
}
|
||||
));
|
||||
repeated_element_names.push(repeater_id);
|
||||
repeated_element_components.push(rep_inner_component_id);
|
||||
}
|
||||
|
|
@ -687,6 +707,16 @@ fn generate_sub_component(
|
|||
#sub_compo_field.apply_pin(_self).visit_dynamic_children(dyn_index - #repeater_offset, order, visitor)
|
||||
}
|
||||
));
|
||||
repeated_subtree_ranges.push(quote!(
|
||||
#repeater_offset..=#last_repeater => {
|
||||
#sub_compo_field.apply_pin(_self).subtree_range(dyn_index - #repeater_offset)
|
||||
}
|
||||
));
|
||||
repeated_subtree_components.push(quote!(
|
||||
#repeater_offset..=#last_repeater => {
|
||||
#sub_compo_field.apply_pin(_self).subtree_component(dyn_index - #repeater_offset, subtree_index, result)
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
sub_component_names.push(field_name);
|
||||
|
|
@ -736,6 +766,18 @@ fn generate_sub_component(
|
|||
let visibility =
|
||||
core::ptr::eq(&root.item_tree.root as *const _, component as *const _).then(|| quote!(pub));
|
||||
|
||||
let access_prop = |&property_index| {
|
||||
access_member(
|
||||
&llr::PropertyReference::Local { sub_component_path: vec![], property_index },
|
||||
&ctx,
|
||||
)
|
||||
};
|
||||
let prop = index_property.iter().map(access_prop);
|
||||
let mut subtree_index_function = quote!(#(#prop.get() as usize)*);
|
||||
if subtree_index_function.is_empty() {
|
||||
subtree_index_function = quote!(core::usize::MAX);
|
||||
}
|
||||
|
||||
quote!(
|
||||
#[derive(slint::re_exports::FieldOffsets, Default)]
|
||||
#[const_field_offset(slint::re_exports::const_field_offset)]
|
||||
|
|
@ -796,6 +838,33 @@ fn generate_sub_component(
|
|||
slint::re_exports::Orientation::Vertical => #layout_info_v,
|
||||
}
|
||||
}
|
||||
|
||||
fn subtree_range(self: ::core::pin::Pin<&Self>, dyn_index: usize) -> slint::re_exports::IndexRange {
|
||||
#![allow(unused)]
|
||||
use slint::re_exports::*;
|
||||
let _self = self;
|
||||
match dyn_index {
|
||||
#(#repeated_subtree_ranges)*
|
||||
_ => panic!("invalid dyn_index {}", dyn_index),
|
||||
}
|
||||
}
|
||||
|
||||
fn subtree_component(self: ::core::pin::Pin<&Self>, dyn_index: usize, subtree_index: usize, result: &mut slint::re_exports::ComponentWeak) {
|
||||
#![allow(unused)]
|
||||
use slint::re_exports::*;
|
||||
let _self = self;
|
||||
match dyn_index {
|
||||
#(#repeated_subtree_components)*
|
||||
_ => panic!("invalid dyn_index {}", dyn_index),
|
||||
};
|
||||
}
|
||||
|
||||
fn index_property(self: ::core::pin::Pin<&Self>) -> usize {
|
||||
#![allow(unused)]
|
||||
use slint::re_exports::*;
|
||||
let _self = self;
|
||||
#subtree_index_function
|
||||
}
|
||||
}
|
||||
|
||||
#(#extra_components)*
|
||||
|
|
@ -923,8 +992,15 @@ fn generate_item_tree(
|
|||
root: &llr::PublicComponent,
|
||||
parent_ctx: Option<ParentCtx>,
|
||||
extra_fields: TokenStream,
|
||||
index_property: Option<llr::PropertyIndex>,
|
||||
) -> TokenStream {
|
||||
let sub_comp = generate_sub_component(&sub_tree.root, root, parent_ctx.clone(), extra_fields);
|
||||
let sub_comp = generate_sub_component(
|
||||
&sub_tree.root,
|
||||
root,
|
||||
parent_ctx.clone(),
|
||||
extra_fields,
|
||||
index_property,
|
||||
);
|
||||
let inner_component_id = self::inner_component_id(&sub_tree.root);
|
||||
let parent_component_type = parent_ctx.iter().map(|parent| {
|
||||
let parent_component_id = self::inner_component_id(parent.ctx.current_sub_component.unwrap());
|
||||
|
|
@ -1077,11 +1153,29 @@ fn generate_item_tree(
|
|||
Self::item_tree().into()
|
||||
}
|
||||
|
||||
fn get_subtree_range(
|
||||
self: ::core::pin::Pin<&Self>, index: usize) -> slint::re_exports::IndexRange
|
||||
{
|
||||
self.subtree_range(index)
|
||||
}
|
||||
|
||||
fn get_subtree_component(
|
||||
self: ::core::pin::Pin<&Self>, index: usize, subtree_index: usize, result: &mut slint::re_exports::ComponentWeak)
|
||||
{
|
||||
self.subtree_component(index, subtree_index, result);
|
||||
}
|
||||
|
||||
fn subtree_index(
|
||||
self: ::core::pin::Pin<&Self>) -> usize
|
||||
{
|
||||
self.index_property()
|
||||
}
|
||||
|
||||
fn parent_item(self: ::core::pin::Pin<&Self>, index: usize, result: &mut slint::re_exports::ItemWeak) {
|
||||
if index == 0 {
|
||||
#(
|
||||
if let Some(parent) = self.parent.clone().upgrade().map(|sc| VRcMapped::origin(&sc)) {
|
||||
*result = slint::re_exports::ItemRc::new(parent, #parent_item_index).parent_item();
|
||||
*result = slint::re_exports::ItemRc::new(parent, #parent_item_index).downgrade();
|
||||
}
|
||||
)*
|
||||
return;
|
||||
|
|
@ -1105,8 +1199,13 @@ fn generate_repeated_component(
|
|||
root: &llr::PublicComponent,
|
||||
parent_ctx: ParentCtx,
|
||||
) -> TokenStream {
|
||||
let component =
|
||||
generate_item_tree(&repeated.sub_tree, root, Some(parent_ctx.clone()), quote!());
|
||||
let component = generate_item_tree(
|
||||
&repeated.sub_tree,
|
||||
root,
|
||||
Some(parent_ctx.clone()),
|
||||
quote!(),
|
||||
repeated.index_prop,
|
||||
);
|
||||
|
||||
let ctx = EvaluationContext {
|
||||
public_component: root,
|
||||
|
|
@ -1120,7 +1219,7 @@ fn generate_repeated_component(
|
|||
let inner_component_id = self::inner_component_id(&repeated.sub_tree.root);
|
||||
|
||||
// let rep_inner_component_id = self::inner_component_id(&repeated.sub_tree.root.name);
|
||||
// let inner_component_id = self::inner_component_id(&parent_compo);
|
||||
// let inner_component_id = self::inner_component_id(&parent_compo);
|
||||
|
||||
let extra_fn = if let Some(listview) = &repeated.listview {
|
||||
let p_y = access_member(&listview.prop_y, &ctx);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
||||
|
||||
// cSpell: ignore dealloc
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
//! This module contains the basic datastructures that are exposed to the C API
|
||||
|
|
@ -12,6 +14,15 @@ use crate::slice::Slice;
|
|||
use crate::window::WindowRc;
|
||||
use vtable::*;
|
||||
|
||||
#[repr(C)]
|
||||
/// A range of indices
|
||||
pub struct IndexRange {
|
||||
/// Start index
|
||||
pub start: usize,
|
||||
/// Index one past the last index
|
||||
pub end: usize,
|
||||
}
|
||||
|
||||
/// A Component is representing an unit that is allocated together
|
||||
#[vtable]
|
||||
#[repr(C)]
|
||||
|
|
@ -32,17 +43,35 @@ pub struct ComponentVTable {
|
|||
index: usize,
|
||||
) -> core::pin::Pin<VRef<ItemVTable>>,
|
||||
|
||||
/// Return the range of indices below the dynamic `ItemTreeNode` at `index`
|
||||
pub get_subtree_range:
|
||||
extern "C" fn(core::pin::Pin<VRef<ComponentVTable>>, index: usize) -> IndexRange,
|
||||
|
||||
/// Return the `ComponentRc` at `subindex` below the dynamic `ItemTreeNode` at `index`
|
||||
pub get_subtree_component: extern "C" fn(
|
||||
core::pin::Pin<VRef<ComponentVTable>>,
|
||||
index: usize,
|
||||
subindex: usize,
|
||||
result: &mut vtable::VWeak<ComponentVTable, Dyn>,
|
||||
),
|
||||
|
||||
/// Return the item tree that is defined by this `Component`.
|
||||
/// The return value is an item weak because it can be null if there is no parent.
|
||||
/// And the return value is passed by &mut because ItemWeak has a destructor
|
||||
pub get_item_tree: extern "C" fn(core::pin::Pin<VRef<ComponentVTable>>) -> Slice<ItemTreeNode>,
|
||||
|
||||
// FIXME: This does return an invalid ItemWeak now that points to the parent repeater!
|
||||
// FIXME: Get rid of the index and make this always return the "Item" that connects this component
|
||||
// to its parent-component?
|
||||
/// Return the parent item.
|
||||
/// The return value is an item weak because it can be null if there is no parent.
|
||||
/// And the return value is passed by &mut because ItemWeak has a destructor
|
||||
pub parent_item:
|
||||
extern "C" fn(core::pin::Pin<VRef<ComponentVTable>>, index: usize, result: &mut ItemWeak),
|
||||
|
||||
/// Return the index of the current subtree or usize::MAX if this is not a subtree
|
||||
pub subtree_index: extern "C" fn(core::pin::Pin<VRef<ComponentVTable>>) -> usize,
|
||||
|
||||
/// Returns the layout info for this component
|
||||
pub layout_info:
|
||||
extern "C" fn(core::pin::Pin<VRef<ComponentVTable>>, Orientation) -> LayoutInfo,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
||||
|
||||
// cSpell: ignore dealloc nesw
|
||||
|
||||
/*!
|
||||
This module contains the builtin items, either in this file or in sub-modules.
|
||||
|
||||
|
|
@ -177,6 +179,7 @@ impl ItemRc {
|
|||
pub fn new(component: vtable::VRc<ComponentVTable>, index: usize) -> Self {
|
||||
Self { component, index }
|
||||
}
|
||||
|
||||
/// Return a `Pin<ItemRef<'a>>`
|
||||
pub fn borrow<'a>(&'a self) -> Pin<ItemRef<'a>> {
|
||||
let comp_ref_pin = vtable::VRc::borrow_pin(&self.component);
|
||||
|
|
@ -185,15 +188,29 @@ impl ItemRc {
|
|||
// lifetime of the component, which is 'a. Pin::as_ref removes the lifetime, but we can just put it back.
|
||||
unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'a>>>(result) }
|
||||
}
|
||||
|
||||
pub fn downgrade(&self) -> ItemWeak {
|
||||
ItemWeak { component: VRc::downgrade(&self.component), index: self.index }
|
||||
}
|
||||
|
||||
/// Return the parent Item in the item tree.
|
||||
/// This is weak because it can be null if there is no parent
|
||||
pub fn parent_item(&self) -> ItemWeak {
|
||||
let comp_ref_pin = vtable::VRc::borrow_pin(&self.component);
|
||||
let item_tree = crate::item_tree::ComponentItemTree::new(
|
||||
comp_ref_pin.as_ref().get_item_tree().as_slice(),
|
||||
);
|
||||
|
||||
if let Some(parent_index) = item_tree.parent(self.index) {
|
||||
return ItemRc::new(self.component.clone(), parent_index).downgrade();
|
||||
}
|
||||
|
||||
let mut r = ItemWeak::default();
|
||||
comp_ref_pin.as_ref().parent_item(self.index, &mut r);
|
||||
// parent_item returns the repeater node, go up one more level!
|
||||
if let Some(rc) = r.upgrade() {
|
||||
r = rc.parent_item();
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
||||
|
||||
// cSpell: ignore vecmodel
|
||||
|
||||
//! Model and Repeater
|
||||
|
||||
// Safety: we use pointer to Repeater in the DependencyList, bue the Drop of the Repeater
|
||||
// will remove them from the list so it will not be accessed after it is dropped
|
||||
#![allow(unsafe_code)]
|
||||
|
||||
use crate::component::ComponentVTable;
|
||||
use crate::item_tree::TraversalOrder;
|
||||
use crate::items::ItemRef;
|
||||
use crate::layout::Orientation;
|
||||
|
|
@ -567,7 +570,9 @@ impl<T> Model for ModelRc<T> {
|
|||
}
|
||||
|
||||
/// Component that can be instantiated by a repeater.
|
||||
pub trait RepeatedComponent: crate::component::Component {
|
||||
pub trait RepeatedComponent:
|
||||
crate::component::Component + vtable::HasStaticVTable<ComponentVTable> + 'static
|
||||
{
|
||||
/// The data corresponding to the model
|
||||
type Data: 'static;
|
||||
|
||||
|
|
@ -615,6 +620,7 @@ impl<C: RepeatedComponent> Default for RepeaterInner<C> {
|
|||
RepeaterInner { components: Default::default(), offset: 0, cached_item_height: 0. }
|
||||
}
|
||||
}
|
||||
|
||||
trait ErasedRepeater {
|
||||
fn row_changed(&self, row: usize);
|
||||
fn row_added(&self, index: usize, count: usize);
|
||||
|
|
@ -968,7 +974,24 @@ impl<C: RepeatedComponent> Repeater<C> {
|
|||
self.inner.borrow().components.len()
|
||||
}
|
||||
|
||||
/// Return true if the Repeater is empty
|
||||
/// Return the range of indices used by this Repeater.
|
||||
///
|
||||
/// Two values are necessary here since the Repeater can start to insert the data from its
|
||||
/// model at an offset.
|
||||
pub fn range(&self) -> (usize, usize) {
|
||||
let inner = self.inner.borrow();
|
||||
(inner.offset, inner.offset + inner.components.len())
|
||||
}
|
||||
|
||||
pub fn component_at(&self, index: usize) -> Option<ComponentRc<C>> {
|
||||
self.inner
|
||||
.borrow()
|
||||
.components
|
||||
.get(index)
|
||||
.map(|c| c.1.clone().expect("That was updated before!"))
|
||||
}
|
||||
|
||||
/// Return true if the Repeater as empty
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
||||
|
||||
// cSpell: ignore dealloc refcell unerase
|
||||
|
||||
use crate::{api::Value, dynamic_type, eval};
|
||||
|
||||
use core::convert::TryInto;
|
||||
|
|
@ -12,7 +14,9 @@ use i_slint_compiler::object_tree::ElementRc;
|
|||
use i_slint_compiler::*;
|
||||
use i_slint_compiler::{diagnostics::BuildDiagnostics, object_tree::PropertyDeclaration};
|
||||
use i_slint_core::api::Window;
|
||||
use i_slint_core::component::{Component, ComponentRef, ComponentRefPin, ComponentVTable};
|
||||
use i_slint_core::component::{
|
||||
Component, ComponentRef, ComponentRefPin, ComponentVTable, ComponentWeak, IndexRange,
|
||||
};
|
||||
use i_slint_core::item_tree::{
|
||||
ItemTreeNode, ItemVisitorRefMut, ItemVisitorVTable, TraversalOrder, VisitChildrenResult,
|
||||
};
|
||||
|
|
@ -174,9 +178,26 @@ impl Component for ErasedComponentBox {
|
|||
unsafe { get_item_ref(self.get_ref().borrow(), index) }
|
||||
}
|
||||
|
||||
fn get_subtree_range(self: Pin<&Self>, index: usize) -> IndexRange {
|
||||
self.borrow().as_ref().get_subtree_range(index)
|
||||
}
|
||||
|
||||
fn get_subtree_component(
|
||||
self: Pin<&Self>,
|
||||
index: usize,
|
||||
subindex: usize,
|
||||
result: &mut ComponentWeak,
|
||||
) {
|
||||
self.borrow().as_ref().get_subtree_component(index, subindex, result);
|
||||
}
|
||||
|
||||
fn parent_item(self: Pin<&Self>, index: usize, result: &mut ItemWeak) {
|
||||
self.borrow().as_ref().parent_item(index, result)
|
||||
}
|
||||
|
||||
fn subtree_index(self: Pin<&Self>) -> usize {
|
||||
self.borrow().as_ref().subtree_index()
|
||||
}
|
||||
}
|
||||
|
||||
i_slint_core::ComponentVTable_static!(static COMPONENT_BOX_VT for ErasedComponentBox);
|
||||
|
|
@ -1030,7 +1051,10 @@ pub(crate) fn generate_component<'id>(
|
|||
layout_info,
|
||||
get_item_ref,
|
||||
get_item_tree,
|
||||
get_subtree_range,
|
||||
get_subtree_component,
|
||||
parent_item,
|
||||
subtree_index,
|
||||
drop_in_place,
|
||||
dealloc,
|
||||
};
|
||||
|
|
@ -1518,6 +1542,34 @@ unsafe extern "C" fn get_item_ref(component: ComponentRefPin, index: usize) -> P
|
|||
}
|
||||
}
|
||||
|
||||
extern "C" fn get_subtree_range(component: ComponentRefPin, index: usize) -> IndexRange {
|
||||
generativity::make_guard!(guard);
|
||||
let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };
|
||||
let rep_in_comp = unsafe { instance_ref.component_type.repeater[index].get_untagged() };
|
||||
ensure_repeater_updated(instance_ref, rep_in_comp);
|
||||
|
||||
let repeater = rep_in_comp.offset.apply(&instance_ref.instance);
|
||||
let (start, end) = repeater.range();
|
||||
IndexRange { start, end }
|
||||
}
|
||||
|
||||
extern "C" fn get_subtree_component(
|
||||
component: ComponentRefPin,
|
||||
index: usize,
|
||||
subtree_index: usize,
|
||||
result: &mut ComponentWeak,
|
||||
) {
|
||||
generativity::make_guard!(guard);
|
||||
let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };
|
||||
let rep_in_comp = unsafe { instance_ref.component_type.repeater[index].get_untagged() };
|
||||
ensure_repeater_updated(instance_ref, rep_in_comp);
|
||||
|
||||
let repeater = rep_in_comp.offset.apply(&instance_ref.instance);
|
||||
*result = vtable::VRc::downgrade(&vtable::VRc::into_dyn(
|
||||
repeater.component_at(subtree_index).unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
extern "C" fn get_item_tree(component: ComponentRefPin) -> Slice<ItemTreeNode> {
|
||||
generativity::make_guard!(guard);
|
||||
let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };
|
||||
|
|
@ -1525,6 +1577,16 @@ extern "C" fn get_item_tree(component: ComponentRefPin) -> Slice<ItemTreeNode> {
|
|||
unsafe { core::mem::transmute::<&[ItemTreeNode], &[ItemTreeNode]>(tree) }.into()
|
||||
}
|
||||
|
||||
extern "C" fn subtree_index(component: ComponentRefPin) -> usize {
|
||||
generativity::make_guard!(guard);
|
||||
let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };
|
||||
if let Ok(value) = instance_ref.component_type.get_property(component, "index") {
|
||||
value.try_into().unwrap()
|
||||
} else {
|
||||
core::usize::MAX
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn parent_item(component: ComponentRefPin, index: usize, result: &mut ItemWeak) {
|
||||
generativity::make_guard!(guard);
|
||||
let instance_ref = InstanceRef::from_pin_ref(component, guard);
|
||||
|
|
@ -1549,7 +1611,7 @@ unsafe extern "C" fn parent_item(component: ComponentRefPin, index: usize, resul
|
|||
.into_dyn()
|
||||
.upgrade()
|
||||
.unwrap();
|
||||
*result = ItemRc::new(parent_rc, parent_index).parent_item();
|
||||
*result = ItemRc::new(parent_rc, parent_index).downgrade();
|
||||
};
|
||||
}
|
||||
return;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue