Traverse item front to back for input events

This commit is contained in:
Olivier Goffart 2020-08-10 10:44:28 +02:00
parent d9c776eb57
commit 36243ccdf7
12 changed files with 97 additions and 47 deletions

View file

@ -31,6 +31,7 @@ using internal::ComponentVTable;
using ItemTreeNode = internal::ItemTreeNode<uint8_t>; using ItemTreeNode = internal::ItemTreeNode<uint8_t>;
using ComponentRef = VRef<ComponentVTable>; using ComponentRef = VRef<ComponentVTable>;
using ItemVisitorRefMut = VRefMut<internal::ItemVisitorVTable>; using ItemVisitorRefMut = VRefMut<internal::ItemVisitorVTable>;
using internal::TraversalOrder;
using internal::EasingCurve; using internal::EasingCurve;
using internal::TextHorizontalAlignment; using internal::TextHorizontalAlignment;
using internal::TextVerticalAlignment; using internal::TextVerticalAlignment;
@ -177,12 +178,13 @@ struct Repeater
} }
} }
intptr_t visit(ItemVisitorRefMut visitor) const intptr_t visit(TraversalOrder order, ItemVisitorRefMut visitor) const
{ {
for (std::size_t i = 0; i < data.size(); ++i) { for (std::size_t i = 0; i < data.size(); ++i) {
VRef<ComponentVTable> ref = item_at(i); int index = order == TraversalOrder::BackToFront ? i : data.size() - 1 - i;
if (ref.vtable->visit_children_item(ref, -1, visitor) != -1) { VRef<ComponentVTable> ref = item_at(index);
return i; if (ref.vtable->visit_children_item(ref, -1, order, visitor) != -1) {
return index;
} }
} }
return -1; return -1;

View file

@ -87,7 +87,7 @@ pub mod re_exports {
}; };
pub use sixtyfps_corelib::item_tree::{ pub use sixtyfps_corelib::item_tree::{
item_offset, visit_item_tree, ItemTreeNode, ItemVisitorRefMut, ItemVisitorVTable, item_offset, visit_item_tree, ItemTreeNode, ItemVisitorRefMut, ItemVisitorVTable,
VisitChildrenResult, TraversalOrder, VisitChildrenResult,
}; };
pub use sixtyfps_corelib::items::*; pub use sixtyfps_corelib::items::*;
pub use sixtyfps_corelib::layout::LayoutInfo; pub use sixtyfps_corelib::layout::LayoutInfo;

View file

@ -43,10 +43,11 @@ where
/// Call the visitor for each component /// Call the visitor for each component
pub fn visit( pub fn visit(
&self, &self,
order: sixtyfps_corelib::item_tree::TraversalOrder,
mut visitor: sixtyfps_corelib::item_tree::ItemVisitorRefMut, mut visitor: sixtyfps_corelib::item_tree::ItemVisitorRefMut,
) -> sixtyfps_corelib::item_tree::VisitChildrenResult { ) -> sixtyfps_corelib::item_tree::VisitChildrenResult {
for (i, c) in self.components.borrow().iter().enumerate() { for (i, c) in self.components.borrow().iter().enumerate() {
if c.as_ref().visit_children_item(-1, visitor.borrow_mut()).has_aborted() { if c.as_ref().visit_children_item(-1, order, visitor.borrow_mut()).has_aborted() {
return sixtyfps_corelib::item_tree::VisitChildrenResult::abort(i, 0); return sixtyfps_corelib::item_tree::VisitChildrenResult::abort(i, 0);
} }
} }

View file

@ -146,8 +146,6 @@ MainWindow := Rectangle {
clicked => { clicked => {
if (root.active_page == 0) { if (root.active_page == 0) {
root.active_page = idx + 1; root.active_page = idx + 1;
} else {
root.active_page = 0;
} }
} }
} }

View file

@ -356,7 +356,7 @@ fn handle_repeater(
repeater_count: i32, repeater_count: i32,
component_struct: &mut Struct, component_struct: &mut Struct,
init: &mut Vec<String>, init: &mut Vec<String>,
children_repeater_cases: &mut Vec<String>, children_visitor_cases: &mut Vec<String>,
repeated_input_branch: &mut Vec<String>, repeated_input_branch: &mut Vec<String>,
) { ) {
let repeater_id = let repeater_id =
@ -372,8 +372,8 @@ fn handle_repeater(
}; };
if repeated.model.is_constant() { if repeated.model.is_constant() {
children_repeater_cases.push(format!( children_visitor_cases.push(format!(
"\n case {i}: return self->{id}.visit(visitor);", "\n case {i}: return self->{id}.visit(order, visitor);",
id = repeater_id, id = repeater_id,
i = repeater_count i = repeater_count
)); ));
@ -392,14 +392,14 @@ fn handle_repeater(
init: None, init: None,
}), }),
)); ));
children_repeater_cases.push(format!( children_visitor_cases.push(format!(
"\n case {i}: {{ "\n case {i}: {{
if (self->model_{i}.is_dirty()) {{ if (self->model_{i}.is_dirty()) {{
self->model_{i}.evaluate([&] {{ self->model_{i}.evaluate([&] {{
self->{id}.update_model({model}, self); self->{id}.update_model({model}, self);
}}); }});
}} }}
self->{id}.visit(visitor); self->{id}.visit(order, visitor);
break; break;
}}", }}",
id = repeater_id, id = repeater_id,
@ -667,7 +667,7 @@ fn generate_component(
)); ));
} }
let mut children_visitor_case = vec![]; let mut children_visitor_cases = vec![];
let mut repeated_input_branch = vec![]; let mut repeated_input_branch = vec![];
let mut tree_array = vec![]; let mut tree_array = vec![];
let mut repeater_count = 0; let mut repeater_count = 0;
@ -699,7 +699,7 @@ fn generate_component(
repeater_count, repeater_count,
&mut component_struct, &mut component_struct,
&mut init, &mut init,
&mut children_visitor_case, &mut children_visitor_cases,
&mut repeated_input_branch, &mut repeated_input_branch,
); );
repeater_count += 1; repeater_count += 1;
@ -731,15 +731,14 @@ fn generate_component(
Access::Private, Access::Private,
Declaration::Function(Function { Declaration::Function(Function {
name: "visit_children".into(), name: "visit_children".into(),
signature: "(sixtyfps::ComponentRef component, intptr_t index, sixtyfps::ItemVisitorRefMut visitor) -> intptr_t".into(), signature: "(sixtyfps::ComponentRef component, intptr_t index, sixtyfps::TraversalOrder order, sixtyfps::ItemVisitorRefMut visitor) -> intptr_t".into(),
is_static: true, is_static: true,
statements: Some(vec![ statements: Some(vec![
"static const auto dyn_visit = [] (const uint8_t *base, [[maybe_unused]] sixtyfps::ItemVisitorRefMut visitor, uintptr_t dyn_index) -> int64_t {".to_owned(), "static const auto dyn_visit = [] (const uint8_t *base, sixtyfps::TraversalOrder order, [[maybe_unused]] sixtyfps::ItemVisitorRefMut visitor, uintptr_t dyn_index) -> int64_t {".to_owned(),
format!(" [[maybe_unused]] auto self = reinterpret_cast<const {}*>(base);", component_id), format!(" [[maybe_unused]] auto self = reinterpret_cast<const {}*>(base);", component_id),
// Fixme: this is not the root component format!(" switch(dyn_index) {{ {} }};", children_visitor_cases.join("")),
format!(" switch(dyn_index) {{ {} }};", children_visitor_case.join("")),
" return -1; //should not happen\n};".to_owned(), " return -1; //should not happen\n};".to_owned(),
"return sixtyfps::sixtyfps_visit_item_tree(component, item_tree() , index, visitor, dyn_visit);".to_owned(), "return sixtyfps::sixtyfps_visit_item_tree(component, item_tree() , index, order, visitor, dyn_visit);".to_owned(),
]), ]),
..Default::default() ..Default::default()
}), }),

View file

@ -230,7 +230,7 @@ fn generate_component(
}); });
}); });
repeated_visit_branch.push(quote!( repeated_visit_branch.push(quote!(
#repeater_index => self_pinned.#repeater_id.visit(visitor), #repeater_index => self_pinned.#repeater_id.visit(order, visitor),
)); ));
} else { } else {
let model_name = quote::format_ident!("model_{}", repeater_index); let model_name = quote::format_ident!("model_{}", repeater_index);
@ -244,7 +244,7 @@ fn generate_component(
}); });
}); });
} }
self_pinned.#repeater_id.visit(visitor) self_pinned.#repeater_id.visit(order, visitor)
} }
)); ));
repeated_dynmodel_names.push(model_name); repeated_dynmodel_names.push(model_name);
@ -438,13 +438,13 @@ fn generate_component(
} }
impl sixtyfps::re_exports::Component for #component_id { impl sixtyfps::re_exports::Component for #component_id {
fn visit_children_item(self: ::core::pin::Pin<&Self>, index: isize, visitor: sixtyfps::re_exports::ItemVisitorRefMut) fn visit_children_item(self: ::core::pin::Pin<&Self>, index: isize, order: sixtyfps::re_exports::TraversalOrder, visitor: sixtyfps::re_exports::ItemVisitorRefMut)
-> sixtyfps::re_exports::VisitChildrenResult -> sixtyfps::re_exports::VisitChildrenResult
{ {
use sixtyfps::re_exports::*; use sixtyfps::re_exports::*;
return sixtyfps::re_exports::visit_item_tree(self, VRef::new_pin(self), Self::item_tree(), index, visitor, visit_dynamic); return sixtyfps::re_exports::visit_item_tree(self, VRef::new_pin(self), Self::item_tree(), index, order, visitor, visit_dynamic);
#[allow(unused)] #[allow(unused)]
fn visit_dynamic(self_pinned: ::core::pin::Pin<&#component_id>, visitor: ItemVisitorRefMut, dyn_index: usize) -> VisitChildrenResult { fn visit_dynamic(self_pinned: ::core::pin::Pin<&#component_id>, order: sixtyfps::re_exports::TraversalOrder, visitor: ItemVisitorRefMut, dyn_index: usize) -> VisitChildrenResult {
match dyn_index { match dyn_index {
#(#repeated_visit_branch)* #(#repeated_visit_branch)*
_ => panic!("invalid dyn_index {}", dyn_index), _ => panic!("invalid dyn_index {}", dyn_index),

View file

@ -5,7 +5,7 @@ use vtable::*;
use crate::graphics::{HighLevelRenderingPrimitive, Rect, RenderingVariable}; use crate::graphics::{HighLevelRenderingPrimitive, Rect, RenderingVariable};
use crate::input::{InputEventResult, MouseEvent}; use crate::input::{InputEventResult, MouseEvent};
use crate::item_rendering::CachedRenderingData; use crate::item_rendering::CachedRenderingData;
use crate::item_tree::{ItemVisitorVTable, VisitChildrenResult}; use crate::item_tree::{ItemVisitorVTable, TraversalOrder, VisitChildrenResult};
use crate::{layout::LayoutInfo, SharedArray}; use crate::{layout::LayoutInfo, SharedArray};
/// A Component is representing an unit that is allocated together /// A Component is representing an unit that is allocated together
@ -18,6 +18,7 @@ pub struct ComponentVTable {
pub visit_children_item: extern "C" fn( pub visit_children_item: extern "C" fn(
core::pin::Pin<VRef<ComponentVTable>>, core::pin::Pin<VRef<ComponentVTable>>,
index: isize, index: isize,
order: TraversalOrder,
visitor: VRefMut<ItemVisitorVTable>, visitor: VRefMut<ItemVisitorVTable>,
) -> VisitChildrenResult, ) -> VisitChildrenResult,

View file

@ -416,6 +416,7 @@ impl<Backend: GraphicsBackend> crate::eventloop::GenericWindow for GraphicsWindo
// Generate cached rendering data once // Generate cached rendering data once
crate::item_tree::visit_items( crate::item_tree::visit_items(
component, component,
crate::item_tree::TraversalOrder::BackToFront,
|_, item, _| { |_, item, _| {
crate::item_rendering::update_item_rendering_data( crate::item_rendering::update_item_rendering_data(
item, item,

View file

@ -66,6 +66,7 @@ pub fn process_ungrabbed_mouse_event(
let mut result = InputEventResult::EventIgnored; let mut result = InputEventResult::EventIgnored;
let item_index = crate::item_tree::visit_items( let item_index = crate::item_tree::visit_items(
component, component,
crate::item_tree::TraversalOrder::FrontToBack,
|_, item, offset| -> ItemVisitorResult<Vector2D<f32>> { |_, item, offset| -> ItemVisitorResult<Vector2D<f32>> {
let geom = item.as_ref().geometry(); let geom = item.as_ref().geometry();
let geom = geom.translate(*offset); let geom = geom.translate(*offset);

View file

@ -49,6 +49,7 @@ pub(crate) fn render_component_items<Backend: GraphicsBackend>(
crate::item_tree::visit_items( crate::item_tree::visit_items(
component, component,
crate::item_tree::TraversalOrder::BackToFront,
|_, item, transform| { |_, item, transform| {
let origin = item.as_ref().geometry().origin; let origin = item.as_ref().geometry().origin;
let transform = let transform =

View file

@ -3,6 +3,13 @@ use crate::ComponentRefPin;
use core::pin::Pin; use core::pin::Pin;
use vtable::*; use vtable::*;
#[repr(u8)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TraversalOrder {
BackToFront,
FrontToBack,
}
/// The return value of the Component::visit_children_item function /// The return value of the Component::visit_children_item function
/// ///
/// Represents something like `enum { Continue, Aborted{aborted_at_item: isize} }`. /// Represents something like `enum { Continue, Aborted{aborted_at_item: isize} }`.
@ -114,29 +121,31 @@ pub enum ItemVisitorResult<State> {
/// Returns the index of the item that cancelled, or -1 if nobody cancelled /// Returns the index of the item that cancelled, or -1 if nobody cancelled
pub fn visit_items<State>( pub fn visit_items<State>(
component: ComponentRefPin, component: ComponentRefPin,
order: TraversalOrder,
mut visitor: impl FnMut(ComponentRefPin, Pin<ItemRef>, &State) -> ItemVisitorResult<State>, mut visitor: impl FnMut(ComponentRefPin, Pin<ItemRef>, &State) -> ItemVisitorResult<State>,
state: State, state: State,
) -> VisitChildrenResult { ) -> VisitChildrenResult {
visit_internal(component, &mut visitor, -1, &state) visit_internal(component, order, &mut visitor, -1, &state)
} }
fn visit_internal<State>( fn visit_internal<State>(
component: ComponentRefPin, component: ComponentRefPin,
order: TraversalOrder,
visitor: &mut impl FnMut(ComponentRefPin, Pin<ItemRef>, &State) -> ItemVisitorResult<State>, visitor: &mut impl FnMut(ComponentRefPin, Pin<ItemRef>, &State) -> ItemVisitorResult<State>,
index: isize, index: isize,
state: &State, state: &State,
) -> VisitChildrenResult { ) -> VisitChildrenResult {
let mut actual_visitor = |component: ComponentRefPin, let mut actual_visitor =
index: isize, |component: ComponentRefPin, index: isize, item: Pin<ItemRef>| -> VisitChildrenResult {
item: Pin<ItemRef>| match visitor(component, item, state) {
-> VisitChildrenResult { ItemVisitorResult::Continue(state) => {
match visitor(component, item, state) { visit_internal(component, order, visitor, index, &state)
ItemVisitorResult::Continue(state) => visit_internal(component, visitor, index, &state), }
ItemVisitorResult::Abort => VisitChildrenResult::abort(index as usize, 0), ItemVisitorResult::Abort => VisitChildrenResult::abort(index as usize, 0),
} }
}; };
vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor); vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
component.as_ref().visit_children_item(index, actual_visitor) component.as_ref().visit_children_item(index, order, actual_visitor)
} }
/// Visit the children within an array of ItemTreeNode /// Visit the children within an array of ItemTreeNode
@ -152,8 +161,14 @@ pub fn visit_item_tree<Base>(
component: ComponentRefPin, component: ComponentRefPin,
item_tree: &[ItemTreeNode<Base>], item_tree: &[ItemTreeNode<Base>],
index: isize, index: isize,
order: TraversalOrder,
mut visitor: vtable::VRefMut<ItemVisitorVTable>, mut visitor: vtable::VRefMut<ItemVisitorVTable>,
visit_dynamic: impl Fn(Pin<&Base>, vtable::VRefMut<ItemVisitorVTable>, usize) -> VisitChildrenResult, visit_dynamic: impl Fn(
Pin<&Base>,
TraversalOrder,
vtable::VRefMut<ItemVisitorVTable>,
usize,
) -> VisitChildrenResult,
) -> VisitChildrenResult { ) -> VisitChildrenResult {
let mut visit_at_index = |idx: usize| -> VisitChildrenResult { let mut visit_at_index = |idx: usize| -> VisitChildrenResult {
match &item_tree[idx] { match &item_tree[idx] {
@ -162,7 +177,7 @@ pub fn visit_item_tree<Base>(
} }
ItemTreeNode::DynamicTree { index } => { ItemTreeNode::DynamicTree { index } => {
if let Some(sub_idx) = if let Some(sub_idx) =
visit_dynamic(base, visitor.borrow_mut(), *index).aborted_index() visit_dynamic(base, order, visitor.borrow_mut(), *index).aborted_index()
{ {
VisitChildrenResult::abort(idx, sub_idx) VisitChildrenResult::abort(idx, sub_idx)
} else { } else {
@ -176,8 +191,12 @@ pub fn visit_item_tree<Base>(
} else { } else {
match &item_tree[index as usize] { match &item_tree[index as usize] {
ItemTreeNode::Item { children_index, chilren_count, .. } => { ItemTreeNode::Item { children_index, chilren_count, .. } => {
for c in *children_index..(*children_index + *chilren_count) { for c in 0..*chilren_count {
let maybe_abort_index = visit_at_index(c as usize); let idx = match order {
TraversalOrder::BackToFront => (*children_index + c),
TraversalOrder::FrontToBack => (*children_index + *chilren_count - c - 1),
} as usize;
let maybe_abort_index = visit_at_index(idx);
if maybe_abort_index.has_aborted() { if maybe_abort_index.has_aborted() {
return maybe_abort_index; return maybe_abort_index;
} }
@ -228,9 +247,11 @@ pub(crate) mod ffi {
component: Pin<VRef<ComponentVTable>>, component: Pin<VRef<ComponentVTable>>,
item_tree: Slice<ItemTreeNode<u8>>, item_tree: Slice<ItemTreeNode<u8>>,
index: isize, index: isize,
order: TraversalOrder,
visitor: VRefMut<ItemVisitorVTable>, visitor: VRefMut<ItemVisitorVTable>,
visit_dynamic: extern "C" fn( visit_dynamic: extern "C" fn(
base: &u8, base: &u8,
order: TraversalOrder,
visitor: vtable::VRefMut<ItemVisitorVTable>, visitor: vtable::VRefMut<ItemVisitorVTable>,
dyn_index: usize, dyn_index: usize,
) -> VisitChildrenResult, ) -> VisitChildrenResult,
@ -240,8 +261,9 @@ pub(crate) mod ffi {
component, component,
item_tree.as_slice(), item_tree.as_slice(),
index, index,
order,
visitor, visitor,
|a, b, c| visit_dynamic(a.get_ref(), b, c), |a, b, c, d| visit_dynamic(a.get_ref(), b, c, d),
) )
} }

View file

@ -9,7 +9,9 @@ use sixtyfps_compilerlib::typeregister::Type;
use sixtyfps_compilerlib::*; use sixtyfps_compilerlib::*;
use sixtyfps_corelib::abi::datastructures::{ComponentVTable, ItemVTable, WindowProperties}; use sixtyfps_corelib::abi::datastructures::{ComponentVTable, ItemVTable, WindowProperties};
use sixtyfps_corelib::graphics::Resource; use sixtyfps_corelib::graphics::Resource;
use sixtyfps_corelib::item_tree::{ItemTreeNode, ItemVisitorRefMut, VisitChildrenResult}; use sixtyfps_corelib::item_tree::{
ItemTreeNode, ItemVisitorRefMut, TraversalOrder, VisitChildrenResult,
};
use sixtyfps_corelib::items::{Flickable, PropertyAnimation, Rectangle}; use sixtyfps_corelib::items::{Flickable, PropertyAnimation, Rectangle};
use sixtyfps_corelib::layout::LayoutInfo; use sixtyfps_corelib::layout::LayoutInfo;
use sixtyfps_corelib::properties::{InterpolatedPropertyValue, PropertyListenerScope}; use sixtyfps_corelib::properties::{InterpolatedPropertyValue, PropertyListenerScope};
@ -157,6 +159,7 @@ pub struct ComponentDescription {
unsafe extern "C" fn visit_children_item( unsafe extern "C" fn visit_children_item(
component: ComponentRefPin, component: ComponentRefPin,
index: isize, index: isize,
order: TraversalOrder,
v: ItemVisitorRefMut, v: ItemVisitorRefMut,
) -> VisitChildrenResult { ) -> VisitChildrenResult {
let component_type = let component_type =
@ -167,8 +170,9 @@ unsafe extern "C" fn visit_children_item(
component, component,
item_tree.as_slice().into(), item_tree.as_slice().into(),
index, index,
order,
v, v,
|_, mut visitor, index| { |_, order, mut visitor, index| {
let rep_in_comp = &component_type.repeater[index]; let rep_in_comp = &component_type.repeater[index];
let vec = &mut *(component.as_ptr().add(rep_in_comp.offset) as *mut RepeaterVec); let vec = &mut *(component.as_ptr().add(rep_in_comp.offset) as *mut RepeaterVec);
if let Some(listener_offset) = rep_in_comp.listener { if let Some(listener_offset) = rep_in_comp.listener {
@ -205,11 +209,31 @@ unsafe extern "C" fn visit_children_item(
}); });
} }
} }
for (i, x) in vec.iter().enumerate() { match order {
if x.borrow().as_ref().visit_children_item(-1, visitor.borrow_mut()).has_aborted() { TraversalOrder::FrontToBack => {
return VisitChildrenResult::abort(i, 0); for (i, x) in vec.iter().enumerate() {
if x.borrow()
.as_ref()
.visit_children_item(-1, order, visitor.borrow_mut())
.has_aborted()
{
return VisitChildrenResult::abort(i, 0);
}
}
}
TraversalOrder::BackToFront => {
for (i, x) in vec.iter().enumerate().rev() {
if x.borrow()
.as_ref()
.visit_children_item(-1, order, visitor.borrow_mut())
.has_aborted()
{
return VisitChildrenResult::abort(i, 0);
}
}
} }
} }
VisitChildrenResult::CONTINUE VisitChildrenResult::CONTINUE
}, },
) )