mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 06:11:16 +00:00
Add ability to get the parent item from the vtable
(still untested)
This commit is contained in:
parent
1fda2e1c99
commit
c2982d9ab3
10 changed files with 356 additions and 209 deletions
|
@ -65,6 +65,7 @@ using cbindgen_private::ItemVTable;
|
||||||
using ComponentRef = vtable::VRef<private_api::ComponentVTable>;
|
using ComponentRef = vtable::VRef<private_api::ComponentVTable>;
|
||||||
using ItemRef = vtable::VRef<private_api::ItemVTable>;
|
using ItemRef = vtable::VRef<private_api::ItemVTable>;
|
||||||
using ItemVisitorRefMut = vtable::VRefMut<cbindgen_private::ItemVisitorVTable>;
|
using ItemVisitorRefMut = vtable::VRefMut<cbindgen_private::ItemVisitorVTable>;
|
||||||
|
using cbindgen_private::ItemWeak;
|
||||||
}
|
}
|
||||||
using cbindgen_private::ComponentRc;
|
using cbindgen_private::ComponentRc;
|
||||||
using cbindgen_private::EasingCurve;
|
using cbindgen_private::EasingCurve;
|
||||||
|
@ -165,16 +166,17 @@ using cbindgen_private::NativeStyleMetrics;
|
||||||
namespace private_api {
|
namespace private_api {
|
||||||
constexpr inline ItemTreeNode make_item_node(std::uintptr_t offset,
|
constexpr inline ItemTreeNode make_item_node(std::uintptr_t offset,
|
||||||
const cbindgen_private::ItemVTable *vtable,
|
const cbindgen_private::ItemVTable *vtable,
|
||||||
uint32_t child_count, uint32_t child_index)
|
uint32_t child_count, uint32_t child_index,
|
||||||
|
uint parent_index)
|
||||||
{
|
{
|
||||||
return ItemTreeNode { ItemTreeNode::Item_Body {
|
return ItemTreeNode { ItemTreeNode::Item_Body {
|
||||||
ItemTreeNode::Tag::Item, { vtable, offset }, child_count, child_index } };
|
ItemTreeNode::Tag::Item, { vtable, offset }, child_count, child_index, parent_index } };
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr inline ItemTreeNode make_dyn_node(std::uintptr_t offset)
|
constexpr inline ItemTreeNode make_dyn_node(std::uintptr_t offset, std::uint32_t parent_index)
|
||||||
{
|
{
|
||||||
return ItemTreeNode { ItemTreeNode::DynamicTree_Body { ItemTreeNode::Tag::DynamicTree,
|
return ItemTreeNode { ItemTreeNode::DynamicTree_Body {
|
||||||
offset } };
|
ItemTreeNode::Tag::DynamicTree, offset, parent_index } };
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ItemRef get_item_ref(ComponentRef component, Slice<ItemTreeNode> item_tree, int index)
|
inline ItemRef get_item_ref(ComponentRef component, Slice<ItemTreeNode> item_tree, int index)
|
||||||
|
@ -183,6 +185,17 @@ inline ItemRef get_item_ref(ComponentRef component, Slice<ItemTreeNode> item_tre
|
||||||
return ItemRef { item.vtable, reinterpret_cast<char *>(component.instance) + item.offset };
|
return ItemRef { item.vtable, reinterpret_cast<char *>(component.instance) + item.offset };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline ItemWeak parent_item(cbindgen_private::ComponentWeak component,
|
||||||
|
Slice<ItemTreeNode> item_tree, int index)
|
||||||
|
{
|
||||||
|
const auto &node = item_tree.ptr[index];
|
||||||
|
if (node.tag == ItemTreeNode::Tag::Item) {
|
||||||
|
return { component, node.item.parent_index };
|
||||||
|
} else {
|
||||||
|
return { component, node.dynamic_tree.parent_index };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using cbindgen_private::FocusEvent;
|
using cbindgen_private::FocusEvent;
|
||||||
|
|
|
@ -167,6 +167,8 @@ public:
|
||||||
inner->strong_ref++;
|
inner->strong_ref++;
|
||||||
return { VRc<VTable, X>(inner) };
|
return { VRc<VTable, X>(inner) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VWeak<VTable, Dyn> into_dyn() const { return *reinterpret_cast<const VWeak<VTable, Dyn> *>(this); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -88,14 +88,18 @@ pub fn generate(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Visit each item in order in which they should appear in the children tree array.
|
/// Visit each item in order in which they should appear in the children tree array.
|
||||||
/// The parameter of the visitor are the item, and the first_children_offset, and wether this is the flickable rectangle
|
/// The parameter of the visitor are
|
||||||
|
/// 1. the item
|
||||||
|
/// 2. the first_children_offset,
|
||||||
|
/// 3. the parent index
|
||||||
|
/// 4. wether this is the flickable rectangle
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn build_array_helper(
|
pub fn build_array_helper(
|
||||||
component: &Component,
|
component: &Component,
|
||||||
mut visit_item: impl FnMut(&ElementRc, u32, bool),
|
mut visit_item: impl FnMut(&ElementRc, u32, u32, bool),
|
||||||
) {
|
) {
|
||||||
visit_item(&component.root_element, 1, false);
|
visit_item(&component.root_element, 1, 0, false);
|
||||||
visit_children(&component.root_element, 1, &mut visit_item);
|
visit_children(&component.root_element, &mut 0, 1, &mut visit_item);
|
||||||
|
|
||||||
fn sub_children_count(e: &ElementRc) -> usize {
|
fn sub_children_count(e: &ElementRc) -> usize {
|
||||||
let mut count = e.borrow().children.len();
|
let mut count = e.borrow().children.len();
|
||||||
|
@ -110,29 +114,33 @@ pub fn build_array_helper(
|
||||||
|
|
||||||
fn visit_children(
|
fn visit_children(
|
||||||
item: &ElementRc,
|
item: &ElementRc,
|
||||||
|
index: &mut u32,
|
||||||
children_offset: u32,
|
children_offset: u32,
|
||||||
visit_item: &mut impl FnMut(&ElementRc, u32, bool),
|
visit_item: &mut impl FnMut(&ElementRc, u32, u32, bool),
|
||||||
) {
|
) {
|
||||||
let mut offset = children_offset + item.borrow().children.len() as u32;
|
let mut offset = children_offset + item.borrow().children.len() as u32;
|
||||||
|
|
||||||
if is_flickable(item) {
|
if is_flickable(item) {
|
||||||
visit_item(item, offset, true);
|
visit_item(item, offset, *index, true);
|
||||||
offset += 1;
|
offset += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in &item.borrow().children {
|
for i in &item.borrow().children {
|
||||||
visit_item(i, offset, false);
|
visit_item(i, offset, *index, false);
|
||||||
offset += sub_children_count(i) as u32;
|
offset += sub_children_count(i) as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*index += 1;
|
||||||
|
|
||||||
let mut offset = children_offset + item.borrow().children.len() as u32;
|
let mut offset = children_offset + item.borrow().children.len() as u32;
|
||||||
|
|
||||||
if is_flickable(item) {
|
if is_flickable(item) {
|
||||||
offset += 1;
|
offset += 1;
|
||||||
|
*index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for e in &item.borrow().children {
|
for e in &item.borrow().children {
|
||||||
visit_children(e, offset, visit_item);
|
visit_children(e, index, offset, visit_item);
|
||||||
offset += sub_children_count(e) as u32;
|
offset += sub_children_count(e) as u32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1003,59 +1003,67 @@ fn generate_component(
|
||||||
let mut tree_array = vec![];
|
let mut tree_array = vec![];
|
||||||
let mut item_names_and_vt_symbols = vec![];
|
let mut item_names_and_vt_symbols = vec![];
|
||||||
let mut repeater_count = 0;
|
let mut repeater_count = 0;
|
||||||
super::build_array_helper(component, |item_rc, children_offset, is_flickable_rect| {
|
super::build_array_helper(
|
||||||
let item = item_rc.borrow();
|
component,
|
||||||
if is_flickable_rect {
|
|item_rc, children_offset, parent_index, is_flickable_rect| {
|
||||||
tree_array.push(format!(
|
let item = item_rc.borrow();
|
||||||
"sixtyfps::private_api::make_item_node(offsetof({}, {}) + offsetof(sixtyfps::Flickable, viewport), &sixtyfps::private_api::RectangleVTable, {}, {})",
|
if is_flickable_rect {
|
||||||
|
tree_array.push(format!(
|
||||||
|
"sixtyfps::private_api::make_item_node(offsetof({}, {}) + offsetof(sixtyfps::Flickable, viewport), &sixtyfps::private_api::RectangleVTable, {}, {}, {})",
|
||||||
&component_id,
|
&component_id,
|
||||||
item.id,
|
item.id,
|
||||||
item.children.len(),
|
item.children.len(),
|
||||||
tree_array.len() + 1,
|
tree_array.len() + 1,
|
||||||
|
parent_index,
|
||||||
));
|
));
|
||||||
} else if item.base_type == Type::Void {
|
} else if item.base_type == Type::Void {
|
||||||
assert!(component.is_global());
|
assert!(component.is_global());
|
||||||
for (prop_name, binding_expression) in &item.bindings {
|
for (prop_name, binding_expression) in &item.bindings {
|
||||||
handle_property_binding(item_rc, prop_name, binding_expression, &mut init);
|
handle_property_binding(item_rc, prop_name, binding_expression, &mut init);
|
||||||
|
}
|
||||||
|
} else if let Some(repeated) = &item.repeated {
|
||||||
|
tree_array.push(format!(
|
||||||
|
"sixtyfps::private_api::make_dyn_node({}, {})",
|
||||||
|
repeater_count, parent_index
|
||||||
|
));
|
||||||
|
let base_component = item.base_type.as_component();
|
||||||
|
let mut friends = Vec::new();
|
||||||
|
generate_component(file, base_component, diag, Some(&mut friends));
|
||||||
|
if let Some(sub_components) = sub_components.as_mut() {
|
||||||
|
sub_components.extend_from_slice(friends.as_slice());
|
||||||
|
sub_components.push(self::component_id(base_component))
|
||||||
|
}
|
||||||
|
component_struct.friends.append(&mut friends);
|
||||||
|
component_struct.friends.push(self::component_id(base_component));
|
||||||
|
handle_repeater(
|
||||||
|
repeated,
|
||||||
|
base_component,
|
||||||
|
component,
|
||||||
|
repeater_count,
|
||||||
|
&mut component_struct,
|
||||||
|
&mut init,
|
||||||
|
&mut children_visitor_cases,
|
||||||
|
&mut repeated_input_branch,
|
||||||
|
&mut repeater_layout_code,
|
||||||
|
diag,
|
||||||
|
);
|
||||||
|
repeater_count += 1;
|
||||||
|
} else {
|
||||||
|
tree_array.push(format!(
|
||||||
|
"sixtyfps::private_api::make_item_node(offsetof({}, {}), &sixtyfps::private_api::{}, {}, {}, {})",
|
||||||
|
component_id,
|
||||||
|
item.id,
|
||||||
|
item.base_type.as_native().vtable_symbol,
|
||||||
|
if super::is_flickable(item_rc) { 1 } else { item.children.len() },
|
||||||
|
children_offset,
|
||||||
|
parent_index,
|
||||||
|
));
|
||||||
|
handle_item(item_rc, &mut component_struct, &mut init);
|
||||||
|
item_names_and_vt_symbols
|
||||||
|
.push((item.id.clone(), item.base_type.as_native().vtable_symbol.clone()));
|
||||||
}
|
}
|
||||||
} else if let Some(repeated) = &item.repeated {
|
},
|
||||||
tree_array.push(format!("sixtyfps::private_api::make_dyn_node({})", repeater_count,));
|
);
|
||||||
let base_component = item.base_type.as_component();
|
|
||||||
let mut friends = Vec::new();
|
|
||||||
generate_component(file, base_component, diag, Some(&mut friends));
|
|
||||||
if let Some(sub_components) = sub_components.as_mut() {
|
|
||||||
sub_components.extend_from_slice(friends.as_slice());
|
|
||||||
sub_components.push(self::component_id(base_component))
|
|
||||||
}
|
|
||||||
component_struct.friends.append(&mut friends);
|
|
||||||
component_struct.friends.push(self::component_id(base_component));
|
|
||||||
handle_repeater(
|
|
||||||
repeated,
|
|
||||||
base_component,
|
|
||||||
component,
|
|
||||||
repeater_count,
|
|
||||||
&mut component_struct,
|
|
||||||
&mut init,
|
|
||||||
&mut children_visitor_cases,
|
|
||||||
&mut repeated_input_branch,
|
|
||||||
&mut repeater_layout_code,
|
|
||||||
diag,
|
|
||||||
);
|
|
||||||
repeater_count += 1;
|
|
||||||
} else {
|
|
||||||
tree_array.push(format!(
|
|
||||||
"sixtyfps::private_api::make_item_node(offsetof({}, {}), &sixtyfps::private_api::{}, {}, {})",
|
|
||||||
component_id,
|
|
||||||
item.id,
|
|
||||||
item.base_type.as_native().vtable_symbol,
|
|
||||||
if super::is_flickable(item_rc) { 1 } else { item.children.len() },
|
|
||||||
children_offset,
|
|
||||||
));
|
|
||||||
handle_item(item_rc, &mut component_struct, &mut init);
|
|
||||||
item_names_and_vt_symbols
|
|
||||||
.push((item.id.clone(), item.base_type.as_native().vtable_symbol.clone()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if !component.is_global() {
|
if !component.is_global() {
|
||||||
component_struct
|
component_struct
|
||||||
|
@ -1139,6 +1147,31 @@ fn generate_component(
|
||||||
}),
|
}),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
let parent_item_from_parent_component = if let Some(parent_index) =
|
||||||
|
component.parent_element.upgrade().and_then(|e| e.borrow().item_index.get().map(|x| *x))
|
||||||
|
{
|
||||||
|
format!(" return {{ self->parent->self_weak.into_dyn(), {} }};", parent_index)
|
||||||
|
} else {
|
||||||
|
" return {};".to_owned()
|
||||||
|
};
|
||||||
|
|
||||||
|
component_struct.members.push((
|
||||||
|
Access::Private,
|
||||||
|
Declaration::Function(Function {
|
||||||
|
name: "parent_item".into(),
|
||||||
|
signature: "(sixtyfps::private_api::ComponentRef component, uintptr_t index) -> sixtyfps::private_api::ItemWeak".into(),
|
||||||
|
is_static: true,
|
||||||
|
statements: Some(vec![
|
||||||
|
format!("auto self = reinterpret_cast<const {}*>(component.instance);", component_id),
|
||||||
|
"if (index == 0) {".into(),
|
||||||
|
parent_item_from_parent_component,
|
||||||
|
"}".into(),
|
||||||
|
"return sixtyfps::private_api::parent_item(self->self_weak.into_dyn(), item_tree(), index);".into(),
|
||||||
|
]),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
|
||||||
component_struct.members.push((
|
component_struct.members.push((
|
||||||
Access::Private,
|
Access::Private,
|
||||||
Declaration::Function(Function {
|
Declaration::Function(Function {
|
||||||
|
@ -1232,7 +1265,7 @@ fn generate_component(
|
||||||
ty: "const sixtyfps::private_api::ComponentVTable".to_owned(),
|
ty: "const sixtyfps::private_api::ComponentVTable".to_owned(),
|
||||||
name: format!("{}::static_vtable", component_id),
|
name: format!("{}::static_vtable", component_id),
|
||||||
init: Some(format!(
|
init: Some(format!(
|
||||||
"{{ visit_children, get_item_ref, layouting_info, apply_layout, sixtyfps::private_api::drop_in_place<{}>, sixtyfps::private_api::dealloc }}",
|
"{{ visit_children, get_item_ref, parent_item, layouting_info, apply_layout, sixtyfps::private_api::drop_in_place<{}>, sixtyfps::private_api::dealloc }}",
|
||||||
component_id)
|
component_id)
|
||||||
),
|
),
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -373,38 +373,42 @@ fn generate_component(
|
||||||
let mut init = Vec::new();
|
let mut init = Vec::new();
|
||||||
let mut window_field_init = None;
|
let mut window_field_init = None;
|
||||||
let mut window_parent_param = None;
|
let mut window_parent_param = None;
|
||||||
super::build_array_helper(component, |item_rc, children_index, is_flickable_rect| {
|
super::build_array_helper(
|
||||||
let item = item_rc.borrow();
|
component,
|
||||||
if is_flickable_rect {
|
|item_rc, children_index, parent_index, is_flickable_rect| {
|
||||||
let field_name = format_ident!("{}", item.id);
|
let parent_index = parent_index as u32;
|
||||||
let children_count = item.children.len() as u32;
|
let item = item_rc.borrow();
|
||||||
let children_index = item_tree_array.len() as u32 + 1;
|
if is_flickable_rect {
|
||||||
|
let field_name = format_ident!("{}", item.id);
|
||||||
|
let children_count = item.children.len() as u32;
|
||||||
|
let children_index = item_tree_array.len() as u32 + 1;
|
||||||
|
|
||||||
item_tree_array.push(quote!(
|
item_tree_array.push(quote!(
|
||||||
sixtyfps::re_exports::ItemTreeNode::Item{
|
sixtyfps::re_exports::ItemTreeNode::Item{
|
||||||
item: VOffset::new(#inner_component_id::FIELD_OFFSETS.#field_name + sixtyfps::re_exports::Flickable::FIELD_OFFSETS.viewport),
|
item: VOffset::new(#inner_component_id::FIELD_OFFSETS.#field_name + sixtyfps::re_exports::Flickable::FIELD_OFFSETS.viewport),
|
||||||
chilren_count: #children_count,
|
chilren_count: #children_count,
|
||||||
children_index: #children_index,
|
children_index: #children_index,
|
||||||
|
parent_index: #parent_index
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
} else if item.base_type == Type::Void {
|
} else if item.base_type == Type::Void {
|
||||||
assert!(component.is_global());
|
assert!(component.is_global());
|
||||||
for (k, binding_expression) in &item.bindings {
|
for (k, binding_expression) in &item.bindings {
|
||||||
handle_property_binding(component, item_rc, k, binding_expression, &mut init);
|
handle_property_binding(component, item_rc, k, binding_expression, &mut init);
|
||||||
}
|
}
|
||||||
} else if let Some(repeated) = &item.repeated {
|
} else if let Some(repeated) = &item.repeated {
|
||||||
let base_component = item.base_type.as_component();
|
let base_component = item.base_type.as_component();
|
||||||
let repeater_index = repeated_element_names.len();
|
let repeater_index = repeated_element_names.len();
|
||||||
let repeater_id = format_ident!("repeater_{}", item.id);
|
let repeater_id = format_ident!("repeater_{}", item.id);
|
||||||
let rep_inner_component_id = self::inner_component_id(&*base_component);
|
let rep_inner_component_id = self::inner_component_id(&*base_component);
|
||||||
|
|
||||||
extra_components.push(generate_component(&*base_component, diag).unwrap_or_else(
|
extra_components.push(generate_component(&*base_component, diag).unwrap_or_else(
|
||||||
|| {
|
|| {
|
||||||
assert!(diag.has_error());
|
assert!(diag.has_error());
|
||||||
Default::default()
|
Default::default()
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
extra_components.push(if repeated.is_conditional_element {
|
extra_components.push(if repeated.is_conditional_element {
|
||||||
quote! {
|
quote! {
|
||||||
impl sixtyfps::re_exports::RepeatedComponent for #rep_inner_component_id {
|
impl sixtyfps::re_exports::RepeatedComponent for #rep_inner_component_id {
|
||||||
type Data = ();
|
type Data = ();
|
||||||
|
@ -472,54 +476,54 @@ fn generate_component(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut model = compile_expression(&repeated.model, component);
|
let mut model = compile_expression(&repeated.model, component);
|
||||||
if repeated.is_conditional_element {
|
if repeated.is_conditional_element {
|
||||||
model =
|
model = quote!(sixtyfps::re_exports::ModelHandle::new(std::rc::Rc::<bool>::new(#model)))
|
||||||
quote!(sixtyfps::re_exports::ModelHandle::new(std::rc::Rc::<bool>::new(#model)))
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: there could be an optimization if `repeated.model.is_constant()`, we don't need a binding
|
// FIXME: there could be an optimization if `repeated.model.is_constant()`, we don't need a binding
|
||||||
init.push(quote! {
|
init.push(quote! {
|
||||||
self_pinned.#repeater_id.set_model_binding({
|
self_pinned.#repeater_id.set_model_binding({
|
||||||
let self_weak = sixtyfps::re_exports::VRc::downgrade(&self_pinned);
|
let self_weak = sixtyfps::re_exports::VRc::downgrade(&self_pinned);
|
||||||
move || {
|
move || {
|
||||||
let self_pinned = self_weak.upgrade().unwrap();
|
let self_pinned = self_weak.upgrade().unwrap();
|
||||||
let _self = self_pinned.as_pin_ref();
|
let _self = self_pinned.as_pin_ref();
|
||||||
(#model) as _
|
(#model) as _
|
||||||
}
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(listview) = &repeated.is_listview {
|
if let Some(listview) = &repeated.is_listview {
|
||||||
let vp_y = access_named_reference(&listview.viewport_y, component, quote!(_self));
|
let vp_y =
|
||||||
let vp_h =
|
access_named_reference(&listview.viewport_y, component, quote!(_self));
|
||||||
access_named_reference(&listview.viewport_height, component, quote!(_self));
|
let vp_h =
|
||||||
let lv_h =
|
access_named_reference(&listview.viewport_height, component, quote!(_self));
|
||||||
access_named_reference(&listview.listview_height, component, quote!(_self));
|
let lv_h =
|
||||||
let vp_w =
|
access_named_reference(&listview.listview_height, component, quote!(_self));
|
||||||
access_named_reference(&listview.viewport_width, component, quote!(_self));
|
let vp_w =
|
||||||
let lv_w =
|
access_named_reference(&listview.viewport_width, component, quote!(_self));
|
||||||
access_named_reference(&listview.listview_width, component, quote!(_self));
|
let lv_w =
|
||||||
|
access_named_reference(&listview.listview_width, component, quote!(_self));
|
||||||
|
|
||||||
let ensure_updated = quote! {
|
let ensure_updated = quote! {
|
||||||
#inner_component_id::FIELD_OFFSETS.#repeater_id.apply_pin(self_pinned).ensure_updated_listview(
|
#inner_component_id::FIELD_OFFSETS.#repeater_id.apply_pin(self_pinned).ensure_updated_listview(
|
||||||
|| { #rep_inner_component_id::new(self_pinned.self_weak.get().unwrap().clone(), &self_pinned.window).into() },
|
|| { #rep_inner_component_id::new(self_pinned.self_weak.get().unwrap().clone(), &self_pinned.window).into() },
|
||||||
#vp_w, #vp_h, #vp_y, #lv_w.get(), #lv_h
|
#vp_w, #vp_h, #vp_y, #lv_w.get(), #lv_h
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
repeated_visit_branch.push(quote!(
|
repeated_visit_branch.push(quote!(
|
||||||
#repeater_index => {
|
#repeater_index => {
|
||||||
|
#ensure_updated
|
||||||
|
self_pinned.#repeater_id.visit(order, visitor)
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
repeated_element_layouts.push(quote!(
|
||||||
#ensure_updated
|
#ensure_updated
|
||||||
self_pinned.#repeater_id.visit(order, visitor)
|
));
|
||||||
}
|
} else {
|
||||||
));
|
repeated_visit_branch.push(quote!(
|
||||||
|
|
||||||
repeated_element_layouts.push(quote!(
|
|
||||||
#ensure_updated
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
repeated_visit_branch.push(quote!(
|
|
||||||
#repeater_index => {
|
#repeater_index => {
|
||||||
#inner_component_id::FIELD_OFFSETS.#repeater_id.apply_pin(self_pinned).ensure_updated(
|
#inner_component_id::FIELD_OFFSETS.#repeater_id.apply_pin(self_pinned).ensure_updated(
|
||||||
|| { #rep_inner_component_id::new(self_pinned.self_weak.get().unwrap().clone(), &self_pinned.window).into() }
|
|| { #rep_inner_component_id::new(self_pinned.self_weak.get().unwrap().clone(), &self_pinned.window).into() }
|
||||||
|
@ -528,42 +532,45 @@ fn generate_component(
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
repeated_element_layouts.push(quote!(
|
repeated_element_layouts.push(quote!(
|
||||||
self_pinned.#repeater_id.compute_layout();
|
self_pinned.#repeater_id.compute_layout();
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
repeated_input_branch.push(quote!(
|
||||||
|
#repeater_index => self.#repeater_id.input_event(rep_index, event, window),
|
||||||
));
|
));
|
||||||
}
|
|
||||||
|
|
||||||
repeated_input_branch.push(quote!(
|
item_tree_array.push(quote!(
|
||||||
#repeater_index => self.#repeater_id.input_event(rep_index, event, window),
|
sixtyfps::re_exports::ItemTreeNode::DynamicTree {
|
||||||
));
|
index: #repeater_index,
|
||||||
|
parent_index: #parent_index,
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
item_tree_array.push(quote!(
|
repeated_element_names.push(repeater_id);
|
||||||
sixtyfps::re_exports::ItemTreeNode::DynamicTree {
|
repeated_element_components.push(rep_inner_component_id);
|
||||||
index: #repeater_index,
|
} else {
|
||||||
|
let field_name = format_ident!("{}", item.id);
|
||||||
|
let children_count =
|
||||||
|
if super::is_flickable(item_rc) { 1 } else { item.children.len() as u32 };
|
||||||
|
|
||||||
|
item_tree_array.push(quote!(
|
||||||
|
sixtyfps::re_exports::ItemTreeNode::Item{
|
||||||
|
item: VOffset::new(#inner_component_id::FIELD_OFFSETS.#field_name),
|
||||||
|
chilren_count: #children_count,
|
||||||
|
children_index: #children_index,
|
||||||
|
parent_index: #parent_index,
|
||||||
|
}
|
||||||
|
));
|
||||||
|
for (k, binding_expression) in &item.bindings {
|
||||||
|
handle_property_binding(component, item_rc, k, binding_expression, &mut init);
|
||||||
}
|
}
|
||||||
));
|
item_names.push(field_name);
|
||||||
|
item_types.push(format_ident!("{}", item.base_type.as_native().class_name));
|
||||||
repeated_element_names.push(repeater_id);
|
|
||||||
repeated_element_components.push(rep_inner_component_id);
|
|
||||||
} else {
|
|
||||||
let field_name = format_ident!("{}", item.id);
|
|
||||||
let children_count =
|
|
||||||
if super::is_flickable(item_rc) { 1 } else { item.children.len() as u32 };
|
|
||||||
|
|
||||||
item_tree_array.push(quote!(
|
|
||||||
sixtyfps::re_exports::ItemTreeNode::Item{
|
|
||||||
item: VOffset::new(#inner_component_id::FIELD_OFFSETS.#field_name),
|
|
||||||
chilren_count: #children_count,
|
|
||||||
children_index: #children_index,
|
|
||||||
}
|
|
||||||
));
|
|
||||||
for (k, binding_expression) in &item.bindings {
|
|
||||||
handle_property_binding(component, item_rc, k, binding_expression, &mut init);
|
|
||||||
}
|
}
|
||||||
item_names.push(field_name);
|
},
|
||||||
item_types.push(format_ident!("{}", item.base_type.as_native().class_name));
|
);
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let resource_symbols: Vec<proc_macro2::TokenStream> = component
|
let resource_symbols: Vec<proc_macro2::TokenStream> = component
|
||||||
.embedded_file_resources
|
.embedded_file_resources
|
||||||
|
@ -661,6 +668,11 @@ fn generate_component(
|
||||||
(None, None)
|
(None, None)
|
||||||
} else {
|
} else {
|
||||||
let item_tree_array_len = item_tree_array.len();
|
let item_tree_array_len = item_tree_array.len();
|
||||||
|
let parent_item_index = component
|
||||||
|
.parent_element
|
||||||
|
.upgrade()
|
||||||
|
.and_then(|e| e.borrow().item_index.get().map(|x| *x));
|
||||||
|
let parent_item_index = parent_item_index.iter();
|
||||||
init.insert(0, quote!(sixtyfps::re_exports::init_component_items(_self, Self::item_tree(), &_self.window);));
|
init.insert(0, quote!(sixtyfps::re_exports::init_component_items(_self, Self::item_tree(), &_self.window);));
|
||||||
(
|
(
|
||||||
Some(quote! {
|
Some(quote! {
|
||||||
|
@ -700,6 +712,23 @@ fn generate_component(
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parent_item(self: ::core::pin::Pin<&Self>, index: usize) -> sixtyfps::re_exports::ItemWeak {
|
||||||
|
if index == 0 {
|
||||||
|
#(
|
||||||
|
if let Some(parent) = self.parent.clone().into_dyn().upgrade() {
|
||||||
|
return sixtyfps::re_exports::ItemRc::new(parent, #parent_item_index).downgrade();
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
return sixtyfps::re_exports::ItemWeak::default();
|
||||||
|
}
|
||||||
|
let parent_index = match &Self::item_tree()[index] {
|
||||||
|
ItemTreeNode::Item { parent_index, .. } => *parent_index,
|
||||||
|
ItemTreeNode::DynamicTree { parent_index, .. } => *parent_index,
|
||||||
|
};
|
||||||
|
let self_rc = self.self_weak.get().unwrap().clone().into_dyn().upgrade().unwrap();
|
||||||
|
ItemRc::new(self_rc, parent_index as _).downgrade()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
|
@ -190,19 +190,22 @@ pub async fn run_passes(
|
||||||
|
|
||||||
fn generate_item_indices(component: &Rc<object_tree::Component>) {
|
fn generate_item_indices(component: &Rc<object_tree::Component>) {
|
||||||
let mut current_item_index: usize = 0;
|
let mut current_item_index: usize = 0;
|
||||||
generator::build_array_helper(&component, move |item_rc, _, is_flickable_rect| {
|
generator::build_array_helper(&component, move |item_rc, _, _, is_flickable_rect| {
|
||||||
let item = item_rc.borrow();
|
let item = item_rc.borrow();
|
||||||
if is_flickable_rect {
|
if is_flickable_rect {
|
||||||
current_item_index += 1;
|
current_item_index += 1;
|
||||||
} else if item.base_type == crate::langtype::Type::Void {
|
} else if item.base_type == crate::langtype::Type::Void {
|
||||||
} else if item.repeated.is_some() {
|
|
||||||
generate_item_indices(&*item.base_type.as_component());
|
|
||||||
current_item_index += 1;
|
|
||||||
} else {
|
} else {
|
||||||
|
if let langtype::Type::Component(c) = &item.base_type {
|
||||||
|
generate_item_indices(c);
|
||||||
|
}
|
||||||
item.item_index.set(current_item_index).unwrap();
|
item.item_index.set(current_item_index).unwrap();
|
||||||
current_item_index += 1;
|
current_item_index += 1;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
for p in component.popup_windows.borrow().iter() {
|
||||||
|
generate_item_indices(&p.component)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
generate_item_indices(&doc.root_component);
|
generate_item_indices(&doc.root_component);
|
||||||
|
|
|
@ -13,7 +13,7 @@ LICENSE END */
|
||||||
|
|
||||||
use crate::graphics::Rect;
|
use crate::graphics::Rect;
|
||||||
use crate::item_tree::{ItemVisitorVTable, TraversalOrder, VisitChildrenResult};
|
use crate::item_tree::{ItemVisitorVTable, TraversalOrder, VisitChildrenResult};
|
||||||
use crate::items::ItemVTable;
|
use crate::items::{ItemVTable, ItemWeak};
|
||||||
use crate::layout::LayoutInfo;
|
use crate::layout::LayoutInfo;
|
||||||
use crate::window::ComponentWindow;
|
use crate::window::ComponentWindow;
|
||||||
use vtable::*;
|
use vtable::*;
|
||||||
|
@ -38,6 +38,10 @@ pub struct ComponentVTable {
|
||||||
index: usize,
|
index: usize,
|
||||||
) -> core::pin::Pin<VRef<ItemVTable>>,
|
) -> core::pin::Pin<VRef<ItemVTable>>,
|
||||||
|
|
||||||
|
/// Return the parent item. The return value is an item weak because it can be null if
|
||||||
|
/// there is no parent
|
||||||
|
pub parent_item: extern "C" fn(core::pin::Pin<VRef<ComponentVTable>>, index: usize) -> ItemWeak,
|
||||||
|
|
||||||
/// Returns the layout info for this component
|
/// Returns the layout info for this component
|
||||||
pub layout_info: extern "C" fn(core::pin::Pin<VRef<ComponentVTable>>) -> LayoutInfo,
|
pub layout_info: extern "C" fn(core::pin::Pin<VRef<ComponentVTable>>) -> LayoutInfo,
|
||||||
|
|
||||||
|
|
|
@ -84,12 +84,18 @@ pub enum ItemTreeNode<T> {
|
||||||
|
|
||||||
/// index of the first children within the item tree
|
/// index of the first children within the item tree
|
||||||
children_index: u32,
|
children_index: u32,
|
||||||
|
|
||||||
|
/// The index of the parent item (not valid for the root)
|
||||||
|
parent_index: u32,
|
||||||
},
|
},
|
||||||
/// A placeholder for many instance of item in their own component which
|
/// A placeholder for many instance of item in their own component which
|
||||||
/// are instantiated according to a model.
|
/// are instantiated according to a model.
|
||||||
DynamicTree {
|
DynamicTree {
|
||||||
/// the undex which is passed in the visit_dynamic callback.
|
/// the undex which is passed in the visit_dynamic callback.
|
||||||
index: usize,
|
index: usize,
|
||||||
|
|
||||||
|
/// The index of the parent item (not valid for the root)
|
||||||
|
parent_index: u32,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +236,7 @@ pub fn visit_item_tree<Base>(
|
||||||
ItemTreeNode::Item { item, .. } => {
|
ItemTreeNode::Item { item, .. } => {
|
||||||
visitor.visit_item(component, idx, item.apply_pin(base))
|
visitor.visit_item(component, idx, item.apply_pin(base))
|
||||||
}
|
}
|
||||||
ItemTreeNode::DynamicTree { index } => {
|
ItemTreeNode::DynamicTree { index, .. } => {
|
||||||
if let Some(sub_idx) =
|
if let Some(sub_idx) =
|
||||||
visit_dynamic(base, order, visitor.borrow_mut(), *index).aborted_index()
|
visit_dynamic(base, order, visitor.borrow_mut(), *index).aborted_index()
|
||||||
{
|
{
|
||||||
|
|
|
@ -132,6 +132,7 @@ impl ItemRc {
|
||||||
|
|
||||||
/// A Weak reference to an item that can be constructed from an ItemRc.
|
/// A Weak reference to an item that can be constructed from an ItemRc.
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct ItemWeak {
|
pub struct ItemWeak {
|
||||||
component: crate::component::ComponentWeak,
|
component: crate::component::ComponentWeak,
|
||||||
index: usize,
|
index: usize,
|
||||||
|
|
|
@ -23,7 +23,9 @@ use sixtyfps_corelib::graphics::{Rect, Resource};
|
||||||
use sixtyfps_corelib::item_tree::{
|
use sixtyfps_corelib::item_tree::{
|
||||||
ItemTreeNode, ItemVisitorRefMut, ItemVisitorVTable, TraversalOrder, VisitChildrenResult,
|
ItemTreeNode, ItemVisitorRefMut, ItemVisitorVTable, TraversalOrder, VisitChildrenResult,
|
||||||
};
|
};
|
||||||
use sixtyfps_corelib::items::{Flickable, ItemRef, ItemVTable, PropertyAnimation, Rectangle};
|
use sixtyfps_corelib::items::{
|
||||||
|
Flickable, ItemRc, ItemRef, ItemVTable, ItemWeak, PropertyAnimation, Rectangle,
|
||||||
|
};
|
||||||
use sixtyfps_corelib::layout::{LayoutInfo, Padding};
|
use sixtyfps_corelib::layout::{LayoutInfo, Padding};
|
||||||
use sixtyfps_corelib::model::RepeatedComponent;
|
use sixtyfps_corelib::model::RepeatedComponent;
|
||||||
use sixtyfps_corelib::model::Repeater;
|
use sixtyfps_corelib::model::Repeater;
|
||||||
|
@ -209,6 +211,9 @@ impl Component for ErasedComponentBox {
|
||||||
// indirection and call our implementation directly.
|
// indirection and call our implementation directly.
|
||||||
unsafe { get_item_ref(self.get_ref().borrow(), index) }
|
unsafe { get_item_ref(self.get_ref().borrow(), index) }
|
||||||
}
|
}
|
||||||
|
fn parent_item(self: Pin<&Self>, index: usize) -> ItemWeak {
|
||||||
|
self.borrow().as_ref().parent_item(index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sixtyfps_corelib::ComponentVTable_static!(static COMPONENT_BOX_VT for ErasedComponentBox);
|
sixtyfps_corelib::ComponentVTable_static!(static COMPONENT_BOX_VT for ErasedComponentBox);
|
||||||
|
@ -517,50 +522,55 @@ fn generate_component<'id>(
|
||||||
let mut repeater = vec![];
|
let mut repeater = vec![];
|
||||||
let mut repeater_names = HashMap::new();
|
let mut repeater_names = HashMap::new();
|
||||||
|
|
||||||
generator::build_array_helper(component, |rc_item, child_offset, is_flickable_rect| {
|
generator::build_array_helper(
|
||||||
let item = rc_item.borrow();
|
component,
|
||||||
if is_flickable_rect {
|
|rc_item, child_offset, parent_index, is_flickable_rect| {
|
||||||
use vtable::HasStaticVTable;
|
let item = rc_item.borrow();
|
||||||
let offset =
|
if is_flickable_rect {
|
||||||
items_types[&item.id].offset + Flickable::FIELD_OFFSETS.viewport.get_byte_offset();
|
use vtable::HasStaticVTable;
|
||||||
tree_array.push(ItemTreeNode::Item {
|
let offset = items_types[&item.id].offset
|
||||||
item: unsafe { vtable::VOffset::from_raw(Rectangle::static_vtable(), offset) },
|
+ Flickable::FIELD_OFFSETS.viewport.get_byte_offset();
|
||||||
children_index: tree_array.len() as u32 + 1,
|
tree_array.push(ItemTreeNode::Item {
|
||||||
chilren_count: item.children.len() as _,
|
item: unsafe { vtable::VOffset::from_raw(Rectangle::static_vtable(), offset) },
|
||||||
});
|
children_index: tree_array.len() as u32 + 1,
|
||||||
} else if let Some(repeated) = &item.repeated {
|
chilren_count: item.children.len() as _,
|
||||||
tree_array.push(ItemTreeNode::DynamicTree { index: repeater.len() });
|
parent_index,
|
||||||
let base_component = item.base_type.as_component();
|
});
|
||||||
repeater_names.insert(item.id.clone(), repeater.len());
|
} else if let Some(repeated) = &item.repeated {
|
||||||
generativity::make_guard!(guard);
|
tree_array.push(ItemTreeNode::DynamicTree { index: repeater.len(), parent_index });
|
||||||
repeater.push(
|
let base_component = item.base_type.as_component();
|
||||||
RepeaterWithinComponent {
|
repeater_names.insert(item.id.clone(), repeater.len());
|
||||||
component_to_repeat: generate_component(base_component, guard),
|
generativity::make_guard!(guard);
|
||||||
offset: builder.add_field_type::<Repeater<ErasedComponentBox>>(),
|
repeater.push(
|
||||||
model: repeated.model.clone(),
|
RepeaterWithinComponent {
|
||||||
}
|
component_to_repeat: generate_component(base_component, guard),
|
||||||
.into(),
|
offset: builder.add_field_type::<Repeater<ErasedComponentBox>>(),
|
||||||
);
|
model: repeated.model.clone(),
|
||||||
} else {
|
}
|
||||||
let rt = rtti.get(&*item.base_type.as_native().class_name).unwrap_or_else(|| {
|
.into(),
|
||||||
panic!("Native type not registered: {}", item.base_type.as_native().class_name)
|
);
|
||||||
});
|
} else {
|
||||||
let offset = builder.add_field(rt.type_info);
|
let rt = rtti.get(&*item.base_type.as_native().class_name).unwrap_or_else(|| {
|
||||||
tree_array.push(ItemTreeNode::Item {
|
panic!("Native type not registered: {}", item.base_type.as_native().class_name)
|
||||||
item: unsafe { vtable::VOffset::from_raw(rt.vtable, offset) },
|
});
|
||||||
children_index: child_offset,
|
let offset = builder.add_field(rt.type_info);
|
||||||
chilren_count: if generator::is_flickable(rc_item) {
|
tree_array.push(ItemTreeNode::Item {
|
||||||
1
|
item: unsafe { vtable::VOffset::from_raw(rt.vtable, offset) },
|
||||||
} else {
|
children_index: child_offset,
|
||||||
item.children.len() as _
|
chilren_count: if generator::is_flickable(rc_item) {
|
||||||
},
|
1
|
||||||
});
|
} else {
|
||||||
items_types.insert(
|
item.children.len() as _
|
||||||
item.id.clone(),
|
},
|
||||||
ItemWithinComponent { offset, rtti: rt.clone(), elem: rc_item.clone() },
|
parent_index,
|
||||||
);
|
});
|
||||||
}
|
items_types.insert(
|
||||||
});
|
item.id.clone(),
|
||||||
|
ItemWithinComponent { offset, rtti: rt.clone(), elem: rc_item.clone() },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let mut custom_properties = HashMap::new();
|
let mut custom_properties = HashMap::new();
|
||||||
let mut custom_callbacks = HashMap::new();
|
let mut custom_callbacks = HashMap::new();
|
||||||
|
@ -672,6 +682,7 @@ fn generate_component<'id>(
|
||||||
layout_info,
|
layout_info,
|
||||||
apply_layout,
|
apply_layout,
|
||||||
get_item_ref,
|
get_item_ref,
|
||||||
|
parent_item,
|
||||||
drop_in_place,
|
drop_in_place,
|
||||||
dealloc,
|
dealloc,
|
||||||
};
|
};
|
||||||
|
@ -1479,6 +1490,43 @@ unsafe extern "C" fn get_item_ref(component: ComponentRefPin, index: usize) -> P
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn parent_item(component: ComponentRefPin, index: usize) -> ItemWeak {
|
||||||
|
generativity::make_guard!(guard);
|
||||||
|
let instance_ref = InstanceRef::from_pin_ref(component, guard);
|
||||||
|
if index == 0 {
|
||||||
|
let parent_item_index = instance_ref
|
||||||
|
.component_type
|
||||||
|
.original
|
||||||
|
.parent_element
|
||||||
|
.upgrade()
|
||||||
|
.and_then(|e| e.borrow().item_index.get().map(|x| *x));
|
||||||
|
if let (Some(parent_offset), Some(parent_index)) =
|
||||||
|
(instance_ref.component_type.parent_component_offset, parent_item_index)
|
||||||
|
{
|
||||||
|
if let Some(parent) = parent_offset.apply(instance_ref.as_ref()) {
|
||||||
|
generativity::make_guard!(new_guard);
|
||||||
|
let parent_instance = InstanceRef::from_pin_ref(*parent, new_guard);
|
||||||
|
let parent_rc = parent_instance
|
||||||
|
.self_weak()
|
||||||
|
.get()
|
||||||
|
.unwrap()
|
||||||
|
.clone()
|
||||||
|
.into_dyn()
|
||||||
|
.upgrade()
|
||||||
|
.unwrap();
|
||||||
|
return ItemRc::new(parent_rc, parent_index).downgrade();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return ItemWeak::default();
|
||||||
|
}
|
||||||
|
let parent_index = match &instance_ref.component_type.item_tree.as_slice()[index] {
|
||||||
|
ItemTreeNode::Item { parent_index, .. } => parent_index,
|
||||||
|
ItemTreeNode::DynamicTree { parent_index, .. } => parent_index,
|
||||||
|
};
|
||||||
|
let self_rc = instance_ref.self_weak().get().unwrap().clone().into_dyn().upgrade().unwrap();
|
||||||
|
ItemRc::new(self_rc, *parent_index as _).downgrade()
|
||||||
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn drop_in_place(component: vtable::VRefMut<ComponentVTable>) -> vtable::Layout {
|
unsafe extern "C" fn drop_in_place(component: vtable::VRefMut<ComponentVTable>) -> vtable::Layout {
|
||||||
let instance_ptr = component.as_ptr() as *mut Instance<'static>;
|
let instance_ptr = component.as_ptr() as *mut Instance<'static>;
|
||||||
let layout = (*instance_ptr).type_info().layout();
|
let layout = (*instance_ptr).type_info().layout();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue