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:
Tobias Hunger 2022-03-25 09:20:16 +01:00 committed by Tobias Hunger
parent c1bb22bd00
commit ee68716d07
8 changed files with 368 additions and 17 deletions

View file

@ -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
{

View file

@ -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::{

View file

@ -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()
}),
));
}
}

View file

@ -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);

View file

@ -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,

View file

@ -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
}

View file

@ -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
}

View file

@ -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;