mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 06:11:16 +00:00
Make the viewport element of the flickable a real Element in the object_tree
This commit is contained in:
parent
7589a301f2
commit
a712f515fa
11 changed files with 430 additions and 437 deletions
|
@ -92,13 +92,9 @@ pub fn generate(
|
||||||
/// 1. the item
|
/// 1. the item
|
||||||
/// 2. the first_children_offset,
|
/// 2. the first_children_offset,
|
||||||
/// 3. the parent index
|
/// 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, mut visit_item: impl FnMut(&ElementRc, u32, u32)) {
|
||||||
component: &Component,
|
visit_item(&component.root_element, 1, 0);
|
||||||
mut visit_item: impl FnMut(&ElementRc, u32, u32, bool),
|
|
||||||
) {
|
|
||||||
visit_item(&component.root_element, 1, 0, false);
|
|
||||||
visit_children(&component.root_element, &mut 0, 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 {
|
||||||
|
@ -106,9 +102,6 @@ pub fn build_array_helper(
|
||||||
for i in &e.borrow().children {
|
for i in &e.borrow().children {
|
||||||
count += sub_children_count(i);
|
count += sub_children_count(i);
|
||||||
}
|
}
|
||||||
if is_flickable(e) {
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
count
|
count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,17 +109,12 @@ pub fn build_array_helper(
|
||||||
item: &ElementRc,
|
item: &ElementRc,
|
||||||
index: &mut u32,
|
index: &mut u32,
|
||||||
children_offset: u32,
|
children_offset: u32,
|
||||||
visit_item: &mut impl FnMut(&ElementRc, u32, u32, bool),
|
visit_item: &mut impl FnMut(&ElementRc, u32, u32),
|
||||||
) {
|
) {
|
||||||
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) {
|
|
||||||
visit_item(item, offset, *index, true);
|
|
||||||
offset += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in &item.borrow().children {
|
for i in &item.borrow().children {
|
||||||
visit_item(i, offset, *index, false);
|
visit_item(i, offset, *index);
|
||||||
offset += sub_children_count(i) as u32;
|
offset += sub_children_count(i) as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,27 +122,9 @@ pub fn build_array_helper(
|
||||||
|
|
||||||
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) {
|
|
||||||
offset += 1;
|
|
||||||
*index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for e in &item.borrow().children {
|
for e in &item.borrow().children {
|
||||||
visit_children(e, index, offset, visit_item);
|
visit_children(e, index, offset, visit_item);
|
||||||
offset += sub_children_count(e) as u32;
|
offset += sub_children_count(e) as u32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_flickable(e: &ElementRc) -> bool {
|
|
||||||
matches!(&e.borrow().base_type, crate::langtype::Type::Native(n) if n.class_name == "Flickable")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the element is a Flickable and the property is the property of the viewport, returns the property with the prefix stipped
|
|
||||||
pub fn as_flickable_viewport_property<'a>(e: &ElementRc, name: &'a str) -> Option<&'a str> {
|
|
||||||
if is_flickable(e) {
|
|
||||||
name.strip_prefix("viewport_")
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -332,25 +332,29 @@ fn handle_property_binding(
|
||||||
) {
|
) {
|
||||||
let item = elem.borrow();
|
let item = elem.borrow();
|
||||||
let component = item.enclosing_component.upgrade().unwrap();
|
let component = item.enclosing_component.upgrade().unwrap();
|
||||||
let id = &item.id;
|
let accessor_prefix = if item.property_declarations.contains_key(prop_name) {
|
||||||
|
String::new()
|
||||||
|
} else if item.is_flickable_viewport {
|
||||||
|
format!(
|
||||||
|
"{id}.viewport.",
|
||||||
|
id = crate::object_tree::find_parent_element(elem).unwrap().borrow().id
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
format!("{id}.", id = item.id)
|
||||||
|
};
|
||||||
let prop_type = item.lookup_property(prop_name).property_type;
|
let prop_type = item.lookup_property(prop_name).property_type;
|
||||||
if let Type::Callback { args, .. } = &prop_type {
|
if let Type::Callback { args, .. } = &prop_type {
|
||||||
let callback_accessor_prefix = if item.property_declarations.contains_key(prop_name) {
|
|
||||||
String::new()
|
|
||||||
} else {
|
|
||||||
format!("{id}.", id = id.clone())
|
|
||||||
};
|
|
||||||
let mut params = args.iter().enumerate().map(|(i, ty)| {
|
let mut params = args.iter().enumerate().map(|(i, ty)| {
|
||||||
format!("[[maybe_unused]] {} arg_{}", ty.cpp_type().unwrap_or_default(), i)
|
format!("[[maybe_unused]] {} arg_{}", ty.cpp_type().unwrap_or_default(), i)
|
||||||
});
|
});
|
||||||
|
|
||||||
init.push(format!(
|
init.push(format!(
|
||||||
"{callback_accessor_prefix}{prop}.set_handler(
|
"{accessor_prefix}{prop}.set_handler(
|
||||||
[this]({params}) {{
|
[this]({params}) {{
|
||||||
[[maybe_unused]] auto self = this;
|
[[maybe_unused]] auto self = this;
|
||||||
return {code};
|
return {code};
|
||||||
}});",
|
}});",
|
||||||
callback_accessor_prefix = callback_accessor_prefix,
|
accessor_prefix = accessor_prefix,
|
||||||
prop = prop_name,
|
prop = prop_name,
|
||||||
params = params.join(", "),
|
params = params.join(", "),
|
||||||
code = compile_expression_wrap_return(binding_expression, &component)
|
code = compile_expression_wrap_return(binding_expression, &component)
|
||||||
|
@ -366,20 +370,10 @@ fn handle_property_binding(
|
||||||
handle_property_binding(elem, prop_name, next, init)
|
handle_property_binding(elem, prop_name, next, init)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let accessor_prefix = if item.property_declarations.contains_key(prop_name) {
|
|
||||||
String::new()
|
|
||||||
} else {
|
|
||||||
format!("{id}.", id = id.clone())
|
|
||||||
};
|
|
||||||
|
|
||||||
let component = &item.enclosing_component.upgrade().unwrap();
|
let component = &item.enclosing_component.upgrade().unwrap();
|
||||||
|
|
||||||
let init_expr = compile_expression_wrap_return(binding_expression, component);
|
let init_expr = compile_expression_wrap_return(binding_expression, component);
|
||||||
let cpp_prop = if let Some(vp) = super::as_flickable_viewport_property(elem, prop_name) {
|
let cpp_prop = format!("{}{}", accessor_prefix, prop_name);
|
||||||
format!("{}viewport.{}", accessor_prefix, vp,)
|
|
||||||
} else {
|
|
||||||
format!("{}{}", accessor_prefix, prop_name,)
|
|
||||||
};
|
|
||||||
|
|
||||||
init.push(if binding_expression.is_constant() {
|
init.push(if binding_expression.is_constant() {
|
||||||
format!("{}.set({});", cpp_prop, init_expr)
|
format!("{}.set({});", cpp_prop, init_expr)
|
||||||
|
@ -1005,67 +999,66 @@ 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(
|
super::build_array_helper(component, |item_rc, children_offset, parent_index| {
|
||||||
component,
|
let item = item_rc.borrow();
|
||||||
|item_rc, children_offset, parent_index, is_flickable_rect| {
|
if item.base_type == Type::Void {
|
||||||
let item = item_rc.borrow();
|
assert!(component.is_global());
|
||||||
if is_flickable_rect {
|
for (prop_name, binding_expression) in &item.bindings {
|
||||||
tree_array.push(format!(
|
handle_property_binding(item_rc, prop_name, binding_expression, &mut init);
|
||||||
"sixtyfps::private_api::make_item_node(offsetof({}, {}) + offsetof(sixtyfps::Flickable, viewport), &sixtyfps::private_api::RectangleVTable, {}, {}, {})",
|
}
|
||||||
&component_id,
|
} else if let Some(repeated) = &item.repeated {
|
||||||
item.id,
|
tree_array.push(format!(
|
||||||
item.children.len(),
|
"sixtyfps::private_api::make_dyn_node({}, {})",
|
||||||
tree_array.len() + 1,
|
repeater_count, parent_index
|
||||||
parent_index,
|
|
||||||
));
|
));
|
||||||
} else if item.base_type == Type::Void {
|
let base_component = item.base_type.as_component();
|
||||||
assert!(component.is_global());
|
let mut friends = Vec::new();
|
||||||
for (prop_name, binding_expression) in &item.bindings {
|
generate_component(file, base_component, diag, Some(&mut friends));
|
||||||
handle_property_binding(item_rc, prop_name, binding_expression, &mut init);
|
if let Some(sub_components) = sub_components.as_mut() {
|
||||||
}
|
sub_components.extend_from_slice(friends.as_slice());
|
||||||
} else if let Some(repeated) = &item.repeated {
|
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 {
|
||||||
|
if item.is_flickable_viewport {
|
||||||
tree_array.push(format!(
|
tree_array.push(format!(
|
||||||
"sixtyfps::private_api::make_dyn_node({}, {})",
|
"sixtyfps::private_api::make_item_node(offsetof({}, {}) + offsetof(sixtyfps::Flickable, viewport), &sixtyfps::private_api::RectangleVTable, {}, {}, {})",
|
||||||
repeater_count, parent_index
|
&component_id,
|
||||||
|
crate::object_tree::find_parent_element(item_rc).unwrap().borrow().id,
|
||||||
|
item.children.len(),
|
||||||
|
children_offset,
|
||||||
|
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 {
|
} else {
|
||||||
tree_array.push(format!(
|
tree_array.push(format!(
|
||||||
"sixtyfps::private_api::make_item_node(offsetof({}, {}), &sixtyfps::private_api::{}, {}, {}, {})",
|
"sixtyfps::private_api::make_item_node(offsetof({}, {}), &sixtyfps::private_api::{}, {}, {}, {})",
|
||||||
component_id,
|
component_id,
|
||||||
item.id,
|
item.id,
|
||||||
item.base_type.as_native().vtable_symbol,
|
item.base_type.as_native().vtable_symbol,
|
||||||
if super::is_flickable(item_rc) { 1 } else { item.children.len() },
|
item.children.len(),
|
||||||
children_offset,
|
children_offset,
|
||||||
parent_index,
|
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()));
|
|
||||||
}
|
}
|
||||||
},
|
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
|
||||||
|
@ -1327,8 +1320,13 @@ fn access_member(
|
||||||
if Rc::ptr_eq(component, &enclosing_component) {
|
if Rc::ptr_eq(component, &enclosing_component) {
|
||||||
if e.property_declarations.contains_key(name) || name == "" || component.is_global() {
|
if e.property_declarations.contains_key(name) || name == "" || component.is_global() {
|
||||||
format!("{}->{}", component_cpp, name)
|
format!("{}->{}", component_cpp, name)
|
||||||
} else if let Some(vp) = super::as_flickable_viewport_property(element, name) {
|
} else if e.is_flickable_viewport {
|
||||||
format!("{}->{}.viewport.{}", component_cpp, e.id.as_str(), vp)
|
format!(
|
||||||
|
"{}->{}.viewport.{}",
|
||||||
|
component_cpp,
|
||||||
|
crate::object_tree::find_parent_element(element).unwrap().borrow().id,
|
||||||
|
name
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
format!("{}->{}.{}", component_cpp, e.id.as_str(), name)
|
format!("{}->{}.{}", component_cpp, e.id.as_str(), name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -377,228 +377,228 @@ 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(
|
super::build_array_helper(component, |item_rc, children_index, parent_index| {
|
||||||
component,
|
let parent_index = parent_index as u32;
|
||||||
|item_rc, children_index, parent_index, is_flickable_rect| {
|
let item = item_rc.borrow();
|
||||||
let parent_index = parent_index as u32;
|
if item.base_type == Type::Void {
|
||||||
let item = item_rc.borrow();
|
assert!(component.is_global());
|
||||||
if is_flickable_rect {
|
for (k, binding_expression) in &item.bindings {
|
||||||
let field_name = format_ident!("{}", item.id);
|
handle_property_binding(component, item_rc, k, binding_expression, &mut init);
|
||||||
let children_count = item.children.len() as u32;
|
}
|
||||||
let children_index = item_tree_array.len() as u32 + 1;
|
} else if let Some(repeated) = &item.repeated {
|
||||||
|
let base_component = item.base_type.as_component();
|
||||||
|
let repeater_index = repeated_element_names.len();
|
||||||
|
let repeater_id = format_ident!("repeater_{}", item.id);
|
||||||
|
let rep_inner_component_id = self::inner_component_id(&*base_component);
|
||||||
|
|
||||||
item_tree_array.push(quote!(
|
extra_components.push(generate_component(&*base_component, diag).unwrap_or_else(
|
||||||
sixtyfps::re_exports::ItemTreeNode::Item{
|
|| {
|
||||||
item: VOffset::new(#inner_component_id::FIELD_OFFSETS.#field_name + sixtyfps::re_exports::Flickable::FIELD_OFFSETS.viewport),
|
assert!(diag.has_error());
|
||||||
chilren_count: #children_count,
|
Default::default()
|
||||||
children_index: #children_index,
|
},
|
||||||
parent_index: #parent_index
|
));
|
||||||
|
|
||||||
|
let extra_fn = if repeated.is_listview.is_some() {
|
||||||
|
let am = |prop| {
|
||||||
|
access_member(
|
||||||
|
&base_component.root_element,
|
||||||
|
prop,
|
||||||
|
base_component,
|
||||||
|
quote!(self),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let p_y = am("y");
|
||||||
|
let p_height = am("height");
|
||||||
|
let p_width = am("width");
|
||||||
|
quote! {
|
||||||
|
fn listview_layout(
|
||||||
|
self: core::pin::Pin<&Self>,
|
||||||
|
offset_y: &mut f32,
|
||||||
|
viewport_width: core::pin::Pin<&sixtyfps::re_exports::Property<f32>>,
|
||||||
|
) {
|
||||||
|
use sixtyfps::re_exports::*;
|
||||||
|
let vp_w = viewport_width.get();
|
||||||
|
self.apply_layout(Rect::new(Point::new(0., *offset_y), Size::new(vp_w, 0.)));
|
||||||
|
#p_y.set(*offset_y);
|
||||||
|
*offset_y += #p_height.get();
|
||||||
|
let w = #p_width.get();
|
||||||
|
if vp_w < w {
|
||||||
|
viewport_width.set(w);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
));
|
|
||||||
} else if item.base_type == Type::Void {
|
|
||||||
assert!(component.is_global());
|
|
||||||
for (k, binding_expression) in &item.bindings {
|
|
||||||
handle_property_binding(component, item_rc, k, binding_expression, &mut init);
|
|
||||||
}
|
}
|
||||||
} else if let Some(repeated) = &item.repeated {
|
} else {
|
||||||
let base_component = item.base_type.as_component();
|
// TODO: we could generate this code only if we know that this component is in a box layout
|
||||||
let repeater_index = repeated_element_names.len();
|
let root_id = format_ident!("{}", base_component.root_element.borrow().id);
|
||||||
let repeater_id = format_ident!("repeater_{}", item.id);
|
let root_c = &base_component.layouts.borrow().root_constraints;
|
||||||
let rep_inner_component_id = self::inner_component_id(&*base_component);
|
let width = if root_c.fixed_width {
|
||||||
|
quote!(None)
|
||||||
extra_components.push(generate_component(&*base_component, diag).unwrap_or_else(
|
|
||||||
|| {
|
|
||||||
assert!(diag.has_error());
|
|
||||||
Default::default()
|
|
||||||
},
|
|
||||||
));
|
|
||||||
|
|
||||||
let extra_fn = if repeated.is_listview.is_some() {
|
|
||||||
let am = |prop| {
|
|
||||||
access_member(
|
|
||||||
&base_component.root_element,
|
|
||||||
prop,
|
|
||||||
base_component,
|
|
||||||
quote!(self),
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let p_y = am("y");
|
|
||||||
let p_height = am("height");
|
|
||||||
let p_width = am("width");
|
|
||||||
quote! {
|
|
||||||
fn listview_layout(
|
|
||||||
self: core::pin::Pin<&Self>,
|
|
||||||
offset_y: &mut f32,
|
|
||||||
viewport_width: core::pin::Pin<&sixtyfps::re_exports::Property<f32>>,
|
|
||||||
) {
|
|
||||||
use sixtyfps::re_exports::*;
|
|
||||||
let vp_w = viewport_width.get();
|
|
||||||
self.apply_layout(Rect::new(Point::new(0., *offset_y), Size::new(vp_w, 0.)));
|
|
||||||
#p_y.set(*offset_y);
|
|
||||||
*offset_y += #p_height.get();
|
|
||||||
let w = #p_width.get();
|
|
||||||
if vp_w < w {
|
|
||||||
viewport_width.set(w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// TODO: we could generate this code only if we know that this component is in a box layout
|
quote!(Some(&self.get_ref().#root_id.width))
|
||||||
let root_id = format_ident!("{}", base_component.root_element.borrow().id);
|
};
|
||||||
let root_c = &base_component.layouts.borrow().root_constraints;
|
let height = if root_c.fixed_height {
|
||||||
let width = if root_c.fixed_width {
|
quote!(None)
|
||||||
quote!(None)
|
} else {
|
||||||
} else {
|
quote!(Some(&self.get_ref().#root_id.height))
|
||||||
quote!(Some(&self.get_ref().#root_id.width))
|
};
|
||||||
};
|
quote! {
|
||||||
let height = if root_c.fixed_height {
|
fn box_layout_data<'a>(self: ::core::pin::Pin<&'a Self>) -> sixtyfps::re_exports::BoxLayoutCellData<'a> {
|
||||||
quote!(None)
|
use sixtyfps::re_exports::*;
|
||||||
} else {
|
BoxLayoutCellData {
|
||||||
quote!(Some(&self.get_ref().#root_id.height))
|
constraint: self.layout_info(),
|
||||||
};
|
x: Some(&self.get_ref().#root_id.x),
|
||||||
quote! {
|
y: Some(&self.get_ref().#root_id.y),
|
||||||
fn box_layout_data<'a>(self: ::core::pin::Pin<&'a Self>) -> sixtyfps::re_exports::BoxLayoutCellData<'a> {
|
width: #width,
|
||||||
use sixtyfps::re_exports::*;
|
height: #height,
|
||||||
BoxLayoutCellData {
|
|
||||||
constraint: self.layout_info(),
|
|
||||||
x: Some(&self.get_ref().#root_id.x),
|
|
||||||
y: Some(&self.get_ref().#root_id.y),
|
|
||||||
width: #width,
|
|
||||||
height: #height,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
extra_components.push(if repeated.is_conditional_element {
|
||||||
|
quote! {
|
||||||
|
impl sixtyfps::re_exports::RepeatedComponent for #rep_inner_component_id {
|
||||||
|
type Data = ();
|
||||||
|
fn update(&self, _: usize, _: Self::Data) { }
|
||||||
|
#extra_fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let data_type = get_rust_type(
|
||||||
|
&Expression::RepeaterModelReference { element: Rc::downgrade(item_rc) }.ty(),
|
||||||
|
&item.node.as_ref().map(|x| x.to_source_location()),
|
||||||
|
diag,
|
||||||
|
);
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
impl sixtyfps::re_exports::RepeatedComponent for #rep_inner_component_id {
|
||||||
|
type Data = #data_type;
|
||||||
|
fn update(&self, index: usize, data: Self::Data) {
|
||||||
|
self.index.set(index);
|
||||||
|
self.model_data.set(data);
|
||||||
|
}
|
||||||
|
#extra_fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut model = compile_expression(&repeated.model, component);
|
||||||
|
if repeated.is_conditional_element {
|
||||||
|
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
|
||||||
|
init.push(quote! {
|
||||||
|
_self.#repeater_id.set_model_binding({
|
||||||
|
let self_weak = sixtyfps::re_exports::VRc::downgrade(&self_rc);
|
||||||
|
move || {
|
||||||
|
let self_rc = self_weak.upgrade().unwrap();
|
||||||
|
let _self = self_rc.as_pin_ref();
|
||||||
|
(#model) as _
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(listview) = &repeated.is_listview {
|
||||||
|
let vp_y = access_named_reference(&listview.viewport_y, component, quote!(_self));
|
||||||
|
let vp_h =
|
||||||
|
access_named_reference(&listview.viewport_height, component, quote!(_self));
|
||||||
|
let lv_h =
|
||||||
|
access_named_reference(&listview.listview_height, component, quote!(_self));
|
||||||
|
let vp_w =
|
||||||
|
access_named_reference(&listview.viewport_width, component, quote!(_self));
|
||||||
|
let lv_w =
|
||||||
|
access_named_reference(&listview.listview_width, component, quote!(_self));
|
||||||
|
|
||||||
|
let ensure_updated = quote! {
|
||||||
|
#inner_component_id::FIELD_OFFSETS.#repeater_id.apply_pin(_self).ensure_updated_listview(
|
||||||
|
|| { #rep_inner_component_id::new(_self.self_weak.get().unwrap().clone(), &_self.window).into() },
|
||||||
|
#vp_w, #vp_h, #vp_y, #lv_w.get(), #lv_h
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
extra_components.push(if repeated.is_conditional_element {
|
repeated_visit_branch.push(quote!(
|
||||||
quote! {
|
#repeater_index => {
|
||||||
impl sixtyfps::re_exports::RepeatedComponent for #rep_inner_component_id {
|
|
||||||
type Data = ();
|
|
||||||
fn update(&self, _: usize, _: Self::Data) { }
|
|
||||||
#extra_fn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let data_type = get_rust_type(
|
|
||||||
&Expression::RepeaterModelReference { element: Rc::downgrade(item_rc) }
|
|
||||||
.ty(),
|
|
||||||
&item.node.as_ref().map(|x| x.to_source_location()),
|
|
||||||
diag,
|
|
||||||
);
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
impl sixtyfps::re_exports::RepeatedComponent for #rep_inner_component_id {
|
|
||||||
type Data = #data_type;
|
|
||||||
fn update(&self, index: usize, data: Self::Data) {
|
|
||||||
self.index.set(index);
|
|
||||||
self.model_data.set(data);
|
|
||||||
}
|
|
||||||
#extra_fn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut model = compile_expression(&repeated.model, component);
|
|
||||||
if repeated.is_conditional_element {
|
|
||||||
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
|
|
||||||
init.push(quote! {
|
|
||||||
_self.#repeater_id.set_model_binding({
|
|
||||||
let self_weak = sixtyfps::re_exports::VRc::downgrade(&self_rc);
|
|
||||||
move || {
|
|
||||||
let self_rc = self_weak.upgrade().unwrap();
|
|
||||||
let _self = self_rc.as_pin_ref();
|
|
||||||
(#model) as _
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(listview) = &repeated.is_listview {
|
|
||||||
let vp_y =
|
|
||||||
access_named_reference(&listview.viewport_y, component, quote!(_self));
|
|
||||||
let vp_h =
|
|
||||||
access_named_reference(&listview.viewport_height, component, quote!(_self));
|
|
||||||
let lv_h =
|
|
||||||
access_named_reference(&listview.listview_height, component, quote!(_self));
|
|
||||||
let vp_w =
|
|
||||||
access_named_reference(&listview.viewport_width, component, quote!(_self));
|
|
||||||
let lv_w =
|
|
||||||
access_named_reference(&listview.listview_width, component, quote!(_self));
|
|
||||||
|
|
||||||
let ensure_updated = quote! {
|
|
||||||
#inner_component_id::FIELD_OFFSETS.#repeater_id.apply_pin(_self).ensure_updated_listview(
|
|
||||||
|| { #rep_inner_component_id::new(_self.self_weak.get().unwrap().clone(), &_self.window).into() },
|
|
||||||
#vp_w, #vp_h, #vp_y, #lv_w.get(), #lv_h
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
repeated_visit_branch.push(quote!(
|
|
||||||
#repeater_index => {
|
|
||||||
#ensure_updated
|
|
||||||
_self.#repeater_id.visit(order, visitor)
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
repeated_element_layouts.push(quote!(
|
|
||||||
#ensure_updated
|
#ensure_updated
|
||||||
));
|
_self.#repeater_id.visit(order, visitor)
|
||||||
} else {
|
|
||||||
let ensure_updated = quote! {
|
|
||||||
#inner_component_id::FIELD_OFFSETS.#repeater_id.apply_pin(_self).ensure_updated(
|
|
||||||
|| { #rep_inner_component_id::new(_self.self_weak.get().unwrap().clone(), &_self.window).into() }
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
repeated_visit_branch.push(quote!(
|
|
||||||
#repeater_index => {
|
|
||||||
#ensure_updated
|
|
||||||
_self.#repeater_id.visit(order, visitor)
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
repeated_element_layouts.push(quote!(
|
|
||||||
#ensure_updated
|
|
||||||
_self.#repeater_id.compute_layout();
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
repeated_input_branch.push(quote!(
|
|
||||||
#repeater_index => self.#repeater_id.input_event(rep_index, event, window),
|
|
||||||
));
|
|
||||||
|
|
||||||
item_tree_array.push(quote!(
|
|
||||||
sixtyfps::re_exports::ItemTreeNode::DynamicTree {
|
|
||||||
index: #repeater_index,
|
|
||||||
parent_index: #parent_index,
|
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
repeated_element_names.push(repeater_id);
|
repeated_element_layouts.push(quote!(
|
||||||
repeated_element_components.push(rep_inner_component_id);
|
#ensure_updated
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
let field_name = format_ident!("{}", item.id);
|
let ensure_updated = quote! {
|
||||||
let children_count =
|
#inner_component_id::FIELD_OFFSETS.#repeater_id.apply_pin(_self).ensure_updated(
|
||||||
if super::is_flickable(item_rc) { 1 } else { item.children.len() as u32 };
|
|| { #rep_inner_component_id::new(_self.self_weak.get().unwrap().clone(), &_self.window).into() }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
item_tree_array.push(quote!(
|
repeated_visit_branch.push(quote!(
|
||||||
sixtyfps::re_exports::ItemTreeNode::Item{
|
#repeater_index => {
|
||||||
item: VOffset::new(#inner_component_id::FIELD_OFFSETS.#field_name),
|
#ensure_updated
|
||||||
chilren_count: #children_count,
|
_self.#repeater_id.visit(order, visitor)
|
||||||
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);
|
repeated_element_layouts.push(quote!(
|
||||||
}
|
#ensure_updated
|
||||||
item_names.push(field_name);
|
_self.#repeater_id.compute_layout();
|
||||||
item_types.push(format_ident!("{}", item.base_type.as_native().class_name));
|
));
|
||||||
}
|
}
|
||||||
},
|
|
||||||
);
|
repeated_input_branch.push(quote!(
|
||||||
|
#repeater_index => self.#repeater_id.input_event(rep_index, event, window),
|
||||||
|
));
|
||||||
|
|
||||||
|
item_tree_array.push(quote!(
|
||||||
|
sixtyfps::re_exports::ItemTreeNode::DynamicTree {
|
||||||
|
index: #repeater_index,
|
||||||
|
parent_index: #parent_index,
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
repeated_element_names.push(repeater_id);
|
||||||
|
repeated_element_components.push(rep_inner_component_id);
|
||||||
|
} else if item.is_flickable_viewport {
|
||||||
|
let field_name = format_ident!(
|
||||||
|
"{}",
|
||||||
|
crate::object_tree::find_parent_element(item_rc).unwrap().borrow().id
|
||||||
|
);
|
||||||
|
let children_count = 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 + sixtyfps::re_exports::Flickable::FIELD_OFFSETS.viewport),
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let field_name = format_ident!("{}", item.id);
|
||||||
|
let children_count = 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));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let resource_symbols: Vec<proc_macro2::TokenStream> = component
|
let resource_symbols: Vec<proc_macro2::TokenStream> = component
|
||||||
.embedded_file_resources
|
.embedded_file_resources
|
||||||
|
@ -976,9 +976,11 @@ fn access_member(
|
||||||
let name_ident = format_ident!("{}", name);
|
let name_ident = format_ident!("{}", name);
|
||||||
if e.property_declarations.contains_key(name) || is_special || component.is_global() {
|
if e.property_declarations.contains_key(name) || is_special || component.is_global() {
|
||||||
quote!(#inner_component_id::FIELD_OFFSETS.#name_ident.apply_pin(#component_rust))
|
quote!(#inner_component_id::FIELD_OFFSETS.#name_ident.apply_pin(#component_rust))
|
||||||
} else if let Some(vp) = super::as_flickable_viewport_property(element, name) {
|
} else if e.is_flickable_viewport {
|
||||||
let name_ident = format_ident!("{}", vp);
|
let elem_ident = format_ident!(
|
||||||
let elem_ident = format_ident!("{}", e.id);
|
"{}",
|
||||||
|
crate::object_tree::find_parent_element(element).unwrap().borrow().id
|
||||||
|
);
|
||||||
|
|
||||||
quote!((#inner_component_id::FIELD_OFFSETS.#elem_ident
|
quote!((#inner_component_id::FIELD_OFFSETS.#elem_ident
|
||||||
+ sixtyfps::re_exports::Flickable::FIELD_OFFSETS.viewport
|
+ sixtyfps::re_exports::Flickable::FIELD_OFFSETS.viewport
|
||||||
|
|
|
@ -50,6 +50,7 @@ mod passes {
|
||||||
pub mod deduplicate_property_read;
|
pub mod deduplicate_property_read;
|
||||||
pub mod default_geometry;
|
pub mod default_geometry;
|
||||||
pub mod embed_resources;
|
pub mod embed_resources;
|
||||||
|
pub mod flickable;
|
||||||
pub mod focus_item;
|
pub mod focus_item;
|
||||||
pub mod generate_item_indices;
|
pub mod generate_item_indices;
|
||||||
pub mod inlining;
|
pub mod inlining;
|
||||||
|
@ -160,6 +161,10 @@ pub async fn run_passes(
|
||||||
passes::focus_item::resolve_element_reference_in_set_focus_calls(&doc.root_component, diag);
|
passes::focus_item::resolve_element_reference_in_set_focus_calls(&doc.root_component, diag);
|
||||||
passes::focus_item::determine_initial_focus_item(&doc.root_component, diag);
|
passes::focus_item::determine_initial_focus_item(&doc.root_component, diag);
|
||||||
passes::focus_item::erase_forward_focus_properties(&doc.root_component);
|
passes::focus_item::erase_forward_focus_properties(&doc.root_component);
|
||||||
|
passes::flickable::handle_flickable(
|
||||||
|
&doc.root_component,
|
||||||
|
&type_loader.global_type_registry.borrow(),
|
||||||
|
);
|
||||||
passes::materialize_fake_properties::materialize_fake_properties(&doc.root_component);
|
passes::materialize_fake_properties::materialize_fake_properties(&doc.root_component);
|
||||||
if compiler_config.embed_resources {
|
if compiler_config.embed_resources {
|
||||||
passes::embed_resources::embed_resources(&doc.root_component);
|
passes::embed_resources::embed_resources(&doc.root_component);
|
||||||
|
|
|
@ -287,6 +287,9 @@ pub struct Element {
|
||||||
/// true when this item's geometry is handled by a layout
|
/// true when this item's geometry is handled by a layout
|
||||||
pub child_of_layout: bool,
|
pub child_of_layout: bool,
|
||||||
|
|
||||||
|
/// true if this Element is the fake Flickable viewport
|
||||||
|
pub is_flickable_viewport: bool,
|
||||||
|
|
||||||
/// This is the component-local index of this item in the item tree array.
|
/// This is the component-local index of this item in the item tree array.
|
||||||
/// It is generated after the last pass and before the generators run.
|
/// It is generated after the last pass and before the generators run.
|
||||||
pub item_index: once_cell::unsync::OnceCell<usize>,
|
pub item_index: once_cell::unsync::OnceCell<usize>,
|
||||||
|
@ -1017,6 +1020,28 @@ fn find_element_by_id(e: &ElementRc, name: &str) -> Option<ElementRc> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Find the parent element to a given element.
|
||||||
|
/// (since there is no parent mapping we need to fo an exhaustive search)
|
||||||
|
pub fn find_parent_element(e: &ElementRc) -> Option<ElementRc> {
|
||||||
|
fn recurse(base: &ElementRc, e: &ElementRc) -> Option<ElementRc> {
|
||||||
|
for child in &base.borrow().children {
|
||||||
|
if Rc::ptr_eq(child, e) {
|
||||||
|
return Some(base.clone());
|
||||||
|
}
|
||||||
|
if let Some(x) = recurse(child, e) {
|
||||||
|
return Some(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
let root = e.borrow().enclosing_component.upgrade().unwrap().root_element.clone();
|
||||||
|
if Rc::ptr_eq(&root, e) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
recurse(&root, e)
|
||||||
|
}
|
||||||
|
|
||||||
/// Call the visitor for each children of the element recursively, starting with the element itself
|
/// Call the visitor for each children of the element recursively, starting with the element itself
|
||||||
///
|
///
|
||||||
/// The state returned by the visitor is passed to the children
|
/// The state returned by the visitor is passed to the children
|
||||||
|
|
72
sixtyfps_compiler/passes/flickable.rs
Normal file
72
sixtyfps_compiler/passes/flickable.rs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
/* LICENSE BEGIN
|
||||||
|
This file is part of the SixtyFPS Project -- https://sixtyfps.io
|
||||||
|
Copyright (c) 2020 Olivier Goffart <olivier.goffart@sixtyfps.io>
|
||||||
|
Copyright (c) 2020 Simon Hausmann <simon.hausmann@sixtyfps.io>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
This file is also available under commercial licensing terms.
|
||||||
|
Please contact info@sixtyfps.io for more information.
|
||||||
|
LICENSE END */
|
||||||
|
|
||||||
|
//! Flickable pass
|
||||||
|
//!
|
||||||
|
//! The Flickable element is special in the sense that it has a viewport
|
||||||
|
//! which is not exposed. This passes create the viewport and fixes all property access
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use crate::expression_tree::{Expression, NamedReference};
|
||||||
|
use crate::langtype::Type;
|
||||||
|
use crate::object_tree::{Component, Element, ElementRc};
|
||||||
|
use crate::typeregister::TypeRegister;
|
||||||
|
|
||||||
|
pub fn handle_flickable(root_component: &Rc<Component>, tr: &TypeRegister) -> () {
|
||||||
|
let mut native_rect = tr.lookup("Rectangle").as_builtin().native_class.clone();
|
||||||
|
while let Some(p) = native_rect.parent.clone() {
|
||||||
|
native_rect = p;
|
||||||
|
}
|
||||||
|
crate::object_tree::recurse_elem_including_sub_components(
|
||||||
|
&root_component,
|
||||||
|
&(),
|
||||||
|
&mut |elem: &ElementRc, _| {
|
||||||
|
if !matches!(elem.borrow().native_class(), Some(n) if n.class_name == "Flickable") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut flickable = elem.borrow_mut();
|
||||||
|
let flickable = &mut *flickable;
|
||||||
|
|
||||||
|
let viewport = Rc::new(RefCell::new(Element {
|
||||||
|
id: format!("{}_viewport", flickable.id),
|
||||||
|
base_type: Type::Native(native_rect.clone()),
|
||||||
|
children: std::mem::take(&mut flickable.children),
|
||||||
|
enclosing_component: flickable.enclosing_component.clone(),
|
||||||
|
is_flickable_viewport: true,
|
||||||
|
..Element::default()
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Create aliases. All these aliases should be removed by the alias optimisation pass
|
||||||
|
for (prop, ty) in &flickable.base_type.as_builtin().properties {
|
||||||
|
if let Some(vp_prop) = prop.strip_prefix("viewport_") {
|
||||||
|
let nr = NamedReference::new(&viewport, vp_prop);
|
||||||
|
flickable.property_declarations.insert(prop.to_owned(), ty.clone().into());
|
||||||
|
match flickable.bindings.entry(prop.to_owned()) {
|
||||||
|
std::collections::hash_map::Entry::Occupied(entry) => {
|
||||||
|
let entry = entry.into_mut();
|
||||||
|
entry.expression = Expression::TwoWayBinding(
|
||||||
|
nr,
|
||||||
|
Some(Box::new(std::mem::take(&mut entry.expression))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
std::collections::hash_map::Entry::Vacant(entry) => {
|
||||||
|
entry.insert(Expression::TwoWayBinding(nr, None).into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flickable.children.push(viewport);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
|
@ -10,11 +10,9 @@ LICENSE END */
|
||||||
//! Assign the Element::item_index on each elements
|
//! Assign the Element::item_index on each elements
|
||||||
pub fn generate_item_indices(component: &std::rc::Rc<crate::object_tree::Component>) {
|
pub fn generate_item_indices(component: &std::rc::Rc<crate::object_tree::Component>) {
|
||||||
let mut current_item_index: usize = 0;
|
let mut current_item_index: usize = 0;
|
||||||
crate::generator::build_array_helper(&component, move |item_rc, _, _, is_flickable_rect| {
|
crate::generator::build_array_helper(&component, move |item_rc, _, _| {
|
||||||
let item = item_rc.borrow();
|
let item = item_rc.borrow();
|
||||||
if is_flickable_rect {
|
if item.base_type == crate::langtype::Type::Void {
|
||||||
current_item_index += 1;
|
|
||||||
} else if item.base_type == crate::langtype::Type::Void {
|
|
||||||
} else {
|
} else {
|
||||||
if let crate::langtype::Type::Component(c) = &item.base_type {
|
if let crate::langtype::Type::Component(c) = &item.base_type {
|
||||||
generate_item_indices(c);
|
generate_item_indices(c);
|
||||||
|
|
|
@ -184,6 +184,7 @@ fn duplicate_element_with_mapping(
|
||||||
child_of_layout: elem.child_of_layout,
|
child_of_layout: elem.child_of_layout,
|
||||||
named_references: Default::default(),
|
named_references: Default::default(),
|
||||||
item_index: Default::default(), // Not determined yet
|
item_index: Default::default(), // Not determined yet
|
||||||
|
is_flickable_viewport: elem.is_flickable_viewport,
|
||||||
}));
|
}));
|
||||||
mapping.insert(element_key(element.clone()), new.clone());
|
mapping.insert(element_key(element.clone()), new.clone());
|
||||||
new
|
new
|
||||||
|
|
|
@ -48,6 +48,7 @@ fn create_repeater_components(component: &Rc<Component>) {
|
||||||
states: std::mem::take(&mut elem.states),
|
states: std::mem::take(&mut elem.states),
|
||||||
transitions: std::mem::take(&mut elem.transitions),
|
transitions: std::mem::take(&mut elem.transitions),
|
||||||
child_of_layout: elem.child_of_layout,
|
child_of_layout: elem.child_of_layout,
|
||||||
|
is_flickable_viewport: elem.is_flickable_viewport,
|
||||||
item_index: Default::default(), // Not determined yet
|
item_index: Default::default(), // Not determined yet
|
||||||
})),
|
})),
|
||||||
parent_element,
|
parent_element,
|
||||||
|
|
|
@ -190,28 +190,6 @@ fn find_element_by_id(roots: &[ElementRc], name: &str) -> Option<ElementRc> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find the parent element to a given element.
|
|
||||||
/// (since there is no parent mapping we need to fo an exhaustive search)
|
|
||||||
fn find_parent_element(e: &ElementRc) -> Option<ElementRc> {
|
|
||||||
fn recurse(base: &ElementRc, e: &ElementRc) -> Option<ElementRc> {
|
|
||||||
for child in &base.borrow().children {
|
|
||||||
if Rc::ptr_eq(child, e) {
|
|
||||||
return Some(base.clone());
|
|
||||||
}
|
|
||||||
if let Some(x) = recurse(child, e) {
|
|
||||||
return Some(x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
let root = e.borrow().enclosing_component.upgrade().unwrap().root_element.clone();
|
|
||||||
if Rc::ptr_eq(&root, e) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
recurse(&root, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
pub fn from_binding_expression_node(
|
pub fn from_binding_expression_node(
|
||||||
node: SyntaxNodeWithSourceFile,
|
node: SyntaxNodeWithSourceFile,
|
||||||
|
|
|
@ -27,7 +27,7 @@ use sixtyfps_corelib::item_tree::{
|
||||||
ItemTreeNode, ItemVisitorRefMut, ItemVisitorVTable, TraversalOrder, VisitChildrenResult,
|
ItemTreeNode, ItemVisitorRefMut, ItemVisitorVTable, TraversalOrder, VisitChildrenResult,
|
||||||
};
|
};
|
||||||
use sixtyfps_corelib::items::{
|
use sixtyfps_corelib::items::{
|
||||||
Flickable, ItemRc, ItemRef, ItemVTable, ItemWeak, PropertyAnimation, Rectangle,
|
Flickable, ItemRc, ItemRef, ItemVTable, ItemWeak, PropertyAnimation,
|
||||||
};
|
};
|
||||||
use sixtyfps_corelib::layout::{LayoutInfo, Padding};
|
use sixtyfps_corelib::layout::{LayoutInfo, Padding};
|
||||||
use sixtyfps_corelib::model::RepeatedComponent;
|
use sixtyfps_corelib::model::RepeatedComponent;
|
||||||
|
@ -569,57 +569,6 @@ fn rtti_for<T: 'static + Default + rtti::BuiltinItem + vtable::HasStaticVTable<I
|
||||||
(T::name(), Rc::new(rtti))
|
(T::name(), Rc::new(rtti))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flickable is special because some of its property applies to the viewport.
|
|
||||||
/// This adds the viewport property in the flickable's property list
|
|
||||||
fn rtti_for_flickable() -> (&'static str, Rc<ItemRTTI>) {
|
|
||||||
let (name, mut rtti) = rtti_for::<Flickable>();
|
|
||||||
|
|
||||||
use rtti::BuiltinItem;
|
|
||||||
let rect_prop = &["viewport_x", "viewport_y", "viewport_width", "viewport_height"];
|
|
||||||
|
|
||||||
struct FlickableViewPortPropertyInfo(&'static dyn rtti::PropertyInfo<Rectangle, Value>);
|
|
||||||
fn viewport(flick: Pin<ItemRef>) -> Pin<&Rectangle> {
|
|
||||||
Flickable::FIELD_OFFSETS
|
|
||||||
.viewport
|
|
||||||
.apply_pin(ItemRef::downcast_pin::<Flickable>(flick).unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
impl eval::ErasedPropertyInfo for FlickableViewPortPropertyInfo {
|
|
||||||
fn get(&self, item: Pin<ItemRef>) -> Value {
|
|
||||||
(*self.0).get(viewport(item)).unwrap()
|
|
||||||
}
|
|
||||||
fn set(&self, item: Pin<ItemRef>, value: Value, animation: Option<PropertyAnimation>) {
|
|
||||||
(*self.0).set(viewport(item), value, animation).unwrap()
|
|
||||||
}
|
|
||||||
fn set_binding(
|
|
||||||
&self,
|
|
||||||
item: Pin<ItemRef>,
|
|
||||||
binding: Box<dyn Fn() -> Value>,
|
|
||||||
animation: AnimatedBindingKind,
|
|
||||||
) {
|
|
||||||
(*self.0).set_binding(viewport(item), binding, animation).unwrap();
|
|
||||||
}
|
|
||||||
fn offset(&self) -> usize {
|
|
||||||
(*self.0).offset() + Flickable::FIELD_OFFSETS.viewport.get_byte_offset()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn link_two_ways(&self, item: Pin<ItemRef>, property2: *const ()) {
|
|
||||||
(*self.0).link_two_ways(viewport(item), property2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rc::get_mut(&mut rtti).unwrap().properties.extend(
|
|
||||||
Rectangle::properties().into_iter().filter_map(|(k, v)| {
|
|
||||||
Some((
|
|
||||||
*rect_prop.iter().find(|x| x.ends_with(k))?,
|
|
||||||
Box::new(FlickableViewPortPropertyInfo(v)) as Box<dyn eval::ErasedPropertyInfo>,
|
|
||||||
))
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
(name, rtti)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a ComponentDescription from a source.
|
/// Create a ComponentDescription from a source.
|
||||||
/// The path corresponding to the source need to be passed as well (path is used for diagnostics
|
/// The path corresponding to the source need to be passed as well (path is used for diagnostics
|
||||||
/// and loading relative assets)
|
/// and loading relative assets)
|
||||||
|
@ -668,7 +617,7 @@ fn generate_component<'id>(
|
||||||
rtti_for::<TouchArea>(),
|
rtti_for::<TouchArea>(),
|
||||||
rtti_for::<FocusScope>(),
|
rtti_for::<FocusScope>(),
|
||||||
rtti_for::<Path>(),
|
rtti_for::<Path>(),
|
||||||
rtti_for_flickable(),
|
rtti_for::<Flickable>(),
|
||||||
rtti_for::<Window>(),
|
rtti_for::<Window>(),
|
||||||
rtti_for::<TextInput>(),
|
rtti_for::<TextInput>(),
|
||||||
rtti_for::<Clip>(),
|
rtti_for::<Clip>(),
|
||||||
|
@ -707,55 +656,49 @@ 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(
|
generator::build_array_helper(component, |rc_item, child_offset, parent_index| {
|
||||||
component,
|
let item = rc_item.borrow();
|
||||||
|rc_item, child_offset, parent_index, is_flickable_rect| {
|
if let Some(repeated) = &item.repeated {
|
||||||
let item = rc_item.borrow();
|
tree_array.push(ItemTreeNode::DynamicTree { index: repeater.len(), parent_index });
|
||||||
if is_flickable_rect {
|
let base_component = item.base_type.as_component();
|
||||||
use vtable::HasStaticVTable;
|
repeater_names.insert(item.id.clone(), repeater.len());
|
||||||
let offset = items_types[&item.id].offset
|
generativity::make_guard!(guard);
|
||||||
+ Flickable::FIELD_OFFSETS.viewport.get_byte_offset();
|
repeater.push(
|
||||||
tree_array.push(ItemTreeNode::Item {
|
RepeaterWithinComponent {
|
||||||
item: unsafe { vtable::VOffset::from_raw(Rectangle::static_vtable(), offset) },
|
component_to_repeat: generate_component(base_component, guard),
|
||||||
children_index: tree_array.len() as u32 + 1,
|
offset: builder.add_field_type::<Repeater<ErasedComponentBox>>(),
|
||||||
chilren_count: item.children.len() as _,
|
model: repeated.model.clone(),
|
||||||
parent_index,
|
}
|
||||||
});
|
.into(),
|
||||||
} else if let Some(repeated) = &item.repeated {
|
);
|
||||||
tree_array.push(ItemTreeNode::DynamicTree { index: repeater.len(), parent_index });
|
} else {
|
||||||
let base_component = item.base_type.as_component();
|
let rt = rtti.get(&*item.base_type.as_native().class_name).unwrap_or_else(|| {
|
||||||
repeater_names.insert(item.id.clone(), repeater.len());
|
panic!("Native type not registered: {}", item.base_type.as_native().class_name)
|
||||||
generativity::make_guard!(guard);
|
});
|
||||||
repeater.push(
|
|
||||||
RepeaterWithinComponent {
|
let offset = if item.is_flickable_viewport {
|
||||||
component_to_repeat: generate_component(base_component, guard),
|
let parent =
|
||||||
offset: builder.add_field_type::<Repeater<ErasedComponentBox>>(),
|
&items_types[&object_tree::find_parent_element(rc_item).unwrap().borrow().id];
|
||||||
model: repeated.model.clone(),
|
assert_eq!(
|
||||||
}
|
parent.elem.borrow().base_type.as_native().class_name.as_str(),
|
||||||
.into(),
|
"Flickable"
|
||||||
);
|
);
|
||||||
|
parent.offset + Flickable::FIELD_OFFSETS.viewport.get_byte_offset()
|
||||||
} else {
|
} else {
|
||||||
let rt = rtti.get(&*item.base_type.as_native().class_name).unwrap_or_else(|| {
|
builder.add_field(rt.type_info)
|
||||||
panic!("Native type not registered: {}", item.base_type.as_native().class_name)
|
};
|
||||||
});
|
tree_array.push(ItemTreeNode::Item {
|
||||||
let offset = builder.add_field(rt.type_info);
|
item: unsafe { vtable::VOffset::from_raw(rt.vtable, offset) },
|
||||||
tree_array.push(ItemTreeNode::Item {
|
children_index: child_offset,
|
||||||
item: unsafe { vtable::VOffset::from_raw(rt.vtable, offset) },
|
chilren_count: item.children.len() as u32,
|
||||||
children_index: child_offset,
|
parent_index,
|
||||||
chilren_count: if generator::is_flickable(rc_item) {
|
});
|
||||||
1
|
items_types.insert(
|
||||||
} else {
|
item.id.clone(),
|
||||||
item.children.len() as _
|
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();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue