diff --git a/api/sixtyfps-cpp/include/sixtyfps.h b/api/sixtyfps-cpp/include/sixtyfps.h index bb97d8deb..4ddf66be5 100644 --- a/api/sixtyfps-cpp/include/sixtyfps.h +++ b/api/sixtyfps-cpp/include/sixtyfps.h @@ -249,6 +249,12 @@ struct Repeater const auto &x = data.at(i); return { &C::component_type, x.get() }; } + + void compute_layout() const { + for (auto &x : data) { + x->compute_layout({ &C::component_type, x.get() }); + } + } }; Flickable::Flickable() diff --git a/api/sixtyfps-rs/repeater.rs b/api/sixtyfps-rs/repeater.rs index 8e205b50a..6f4e78058 100644 --- a/api/sixtyfps-rs/repeater.rs +++ b/api/sixtyfps-rs/repeater.rs @@ -81,4 +81,11 @@ where pub fn borrow_item_vec(&self) -> core::cell::Ref>>> { self.components.borrow() } + + /// Recompute the layout of each chile elements + pub fn compute_layout(&self) { + for c in self.components.borrow().iter() { + c.as_ref().compute_layout(); + } + } } diff --git a/sixtyfps_compiler/generator/cpp.rs b/sixtyfps_compiler/generator/cpp.rs index 1cd9df9c5..44a7f2f26 100644 --- a/sixtyfps_compiler/generator/cpp.rs +++ b/sixtyfps_compiler/generator/cpp.rs @@ -367,6 +367,7 @@ fn handle_repeater( init: &mut Vec, children_visitor_cases: &mut Vec, repeated_input_branch: &mut Vec, + layout_repeater_code: &mut Vec, diag: &mut BuildDiagnostics, ) { let parent_element = base_component.parent_element.upgrade().unwrap(); @@ -420,6 +421,7 @@ fn handle_repeater( i = repeater_count, id = repeater_id, )); + layout_repeater_code.push(format!("self->{}.compute_layout();", repeater_id)); component_struct.members.push(( Access::Private, @@ -659,6 +661,7 @@ fn generate_component( let mut children_visitor_cases = vec![]; let mut repeated_input_branch = vec![]; + let mut repeater_layout_code = vec![]; let mut tree_array = vec![]; let mut repeater_count = 0; super::build_array_helper(component, |item_rc, children_offset, is_flickable_rect| { @@ -691,6 +694,7 @@ fn generate_component( &mut init, &mut children_visitor_cases, &mut repeated_input_branch, + &mut repeater_layout_code, diag, ); repeater_count += 1; @@ -807,7 +811,7 @@ fn generate_component( name: "compute_layout".into(), signature: "(sixtyfps::private_api::ComponentRef component) -> void".into(), is_static: true, - statements: Some(compute_layout(component)), + statements: Some(compute_layout(component, &mut repeater_layout_code)), ..Default::default() }), )); @@ -1415,7 +1419,10 @@ impl<'a> LayoutTreeItem<'a> { } } -fn compute_layout(component: &Rc) -> Vec { +fn compute_layout( + component: &Rc, + repeater_layout_code: &mut Vec, +) -> Vec { let mut res = vec![]; res.push(format!( @@ -1440,6 +1447,8 @@ fn compute_layout(component: &Rc) -> Vec { res.push(" }".into()); }); + res.append(repeater_layout_code); + res } diff --git a/sixtyfps_compiler/generator/rust.rs b/sixtyfps_compiler/generator/rust.rs index dda019b61..fde400fc0 100644 --- a/sixtyfps_compiler/generator/rust.rs +++ b/sixtyfps_compiler/generator/rust.rs @@ -17,7 +17,7 @@ use crate::expression_tree::{ use crate::layout::{gen::LayoutItemCodeGen, Layout, LayoutElement}; use crate::object_tree::{Component, ElementRc}; use crate::typeregister::Type; -use proc_macro2::TokenStream; +use proc_macro2::{Ident, TokenStream}; use quote::quote; use std::rc::Rc; @@ -352,7 +352,7 @@ fn generate_component( Vec::new() }; - let layouts = compute_layout(component); + let layouts = compute_layout(component, &repeated_element_names); let mut visibility = None; let mut parent_component_type = None; if let Some(parent_element) = component.parent_element.upgrade() { @@ -1183,7 +1183,7 @@ impl<'a> LayoutTreeItem<'a> { } } -fn compute_layout(component: &Rc) -> TokenStream { +fn compute_layout(component: &Rc, repeated_element_names: &[Ident]) -> TokenStream { let mut layouts = vec![]; component.layout_constraints.borrow().iter().for_each(|layout| { let mut inverse_layout_tree = Vec::new(); @@ -1212,6 +1212,8 @@ fn compute_layout(component: &Rc) -> TokenStream { let _self = self; #(#layouts)* + + #(self.#repeated_element_names.compute_layout();)* } } } diff --git a/sixtyfps_runtime/interpreter/dynamic_component.rs b/sixtyfps_runtime/interpreter/dynamic_component.rs index c67fa6043..4dc74df17 100644 --- a/sixtyfps_runtime/interpreter/dynamic_component.rs +++ b/sixtyfps_runtime/interpreter/dynamic_component.rs @@ -1059,6 +1059,15 @@ extern "C" fn compute_layout(component: ComponentRefPin) { layout.solve(instance_ref); }); }); + + for rep_in_comp in &instance_ref.component_type.repeater { + generativity::make_guard!(guard); + let rep_in_comp = rep_in_comp.unerase(guard); + let vec = rep_in_comp.offset.apply(instance_ref.as_ref()).borrow(); + for c in vec.iter() { + c.borrow().as_ref().compute_layout(); + } + } } /// Get the component description from a ComponentRef diff --git a/tests/cases/grid_layout_within_for.60 b/tests/cases/grid_layout_within_for.60 index 4197d3418..094d42201 100644 --- a/tests/cases/grid_layout_within_for.60 +++ b/tests/cases/grid_layout_within_for.60 @@ -34,3 +34,34 @@ TestCase := Rectangle { } } } + + +/* +```cpp +TestCase instance; +TestCase::compute_layout({&TestCase::component_type, &instance }); + +sixtyfps::testing::send_mouse_click(instance, 190., 190.); +assert(instance.get_value() == 1+1); + +sixtyfps::testing::send_mouse_click(instance, 5., 290.); +assert(instance.get_value() == 1+1+2); +``` + + +```rust +let instance = TestCase::new(); +let instance = instance.as_ref(); +use sixtyfps::re_exports::Component; +instance.compute_layout(); + +sixtyfps::testing::send_mouse_click(instance, 190., 190.); +assert_eq!(instance.get_value(), 1+1); + +sixtyfps::testing::send_mouse_click(instance, 5., 290.); +assert_eq!(instance.get_value(), 1+1+2); + +``` + +// FIXME: JS test because layout are not computed +*/