mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-02 22:54:36 +00:00
Traverse item front to back for input events
This commit is contained in:
parent
d9c776eb57
commit
36243ccdf7
12 changed files with 97 additions and 47 deletions
|
@ -31,6 +31,7 @@ using internal::ComponentVTable;
|
|||
using ItemTreeNode = internal::ItemTreeNode<uint8_t>;
|
||||
using ComponentRef = VRef<ComponentVTable>;
|
||||
using ItemVisitorRefMut = VRefMut<internal::ItemVisitorVTable>;
|
||||
using internal::TraversalOrder;
|
||||
using internal::EasingCurve;
|
||||
using internal::TextHorizontalAlignment;
|
||||
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) {
|
||||
VRef<ComponentVTable> ref = item_at(i);
|
||||
if (ref.vtable->visit_children_item(ref, -1, visitor) != -1) {
|
||||
return i;
|
||||
int index = order == TraversalOrder::BackToFront ? i : data.size() - 1 - i;
|
||||
VRef<ComponentVTable> ref = item_at(index);
|
||||
if (ref.vtable->visit_children_item(ref, -1, order, visitor) != -1) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
|
|
|
@ -87,7 +87,7 @@ pub mod re_exports {
|
|||
};
|
||||
pub use sixtyfps_corelib::item_tree::{
|
||||
item_offset, visit_item_tree, ItemTreeNode, ItemVisitorRefMut, ItemVisitorVTable,
|
||||
VisitChildrenResult,
|
||||
TraversalOrder, VisitChildrenResult,
|
||||
};
|
||||
pub use sixtyfps_corelib::items::*;
|
||||
pub use sixtyfps_corelib::layout::LayoutInfo;
|
||||
|
|
|
@ -43,10 +43,11 @@ where
|
|||
/// Call the visitor for each component
|
||||
pub fn visit(
|
||||
&self,
|
||||
order: sixtyfps_corelib::item_tree::TraversalOrder,
|
||||
mut visitor: sixtyfps_corelib::item_tree::ItemVisitorRefMut,
|
||||
) -> sixtyfps_corelib::item_tree::VisitChildrenResult {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,8 +146,6 @@ MainWindow := Rectangle {
|
|||
clicked => {
|
||||
if (root.active_page == 0) {
|
||||
root.active_page = idx + 1;
|
||||
} else {
|
||||
root.active_page = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -356,7 +356,7 @@ fn handle_repeater(
|
|||
repeater_count: i32,
|
||||
component_struct: &mut Struct,
|
||||
init: &mut Vec<String>,
|
||||
children_repeater_cases: &mut Vec<String>,
|
||||
children_visitor_cases: &mut Vec<String>,
|
||||
repeated_input_branch: &mut Vec<String>,
|
||||
) {
|
||||
let repeater_id =
|
||||
|
@ -372,8 +372,8 @@ fn handle_repeater(
|
|||
};
|
||||
|
||||
if repeated.model.is_constant() {
|
||||
children_repeater_cases.push(format!(
|
||||
"\n case {i}: return self->{id}.visit(visitor);",
|
||||
children_visitor_cases.push(format!(
|
||||
"\n case {i}: return self->{id}.visit(order, visitor);",
|
||||
id = repeater_id,
|
||||
i = repeater_count
|
||||
));
|
||||
|
@ -392,14 +392,14 @@ fn handle_repeater(
|
|||
init: None,
|
||||
}),
|
||||
));
|
||||
children_repeater_cases.push(format!(
|
||||
children_visitor_cases.push(format!(
|
||||
"\n case {i}: {{
|
||||
if (self->model_{i}.is_dirty()) {{
|
||||
self->model_{i}.evaluate([&] {{
|
||||
self->{id}.update_model({model}, self);
|
||||
}});
|
||||
}}
|
||||
self->{id}.visit(visitor);
|
||||
self->{id}.visit(order, visitor);
|
||||
break;
|
||||
}}",
|
||||
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 tree_array = vec![];
|
||||
let mut repeater_count = 0;
|
||||
|
@ -699,7 +699,7 @@ fn generate_component(
|
|||
repeater_count,
|
||||
&mut component_struct,
|
||||
&mut init,
|
||||
&mut children_visitor_case,
|
||||
&mut children_visitor_cases,
|
||||
&mut repeated_input_branch,
|
||||
);
|
||||
repeater_count += 1;
|
||||
|
@ -731,15 +731,14 @@ fn generate_component(
|
|||
Access::Private,
|
||||
Declaration::Function(Function {
|
||||
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,
|
||||
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),
|
||||
// Fixme: this is not the root component
|
||||
format!(" switch(dyn_index) {{ {} }};", children_visitor_case.join("")),
|
||||
format!(" switch(dyn_index) {{ {} }};", children_visitor_cases.join("")),
|
||||
" 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()
|
||||
}),
|
||||
|
|
|
@ -230,7 +230,7 @@ fn generate_component(
|
|||
});
|
||||
});
|
||||
repeated_visit_branch.push(quote!(
|
||||
#repeater_index => self_pinned.#repeater_id.visit(visitor),
|
||||
#repeater_index => self_pinned.#repeater_id.visit(order, visitor),
|
||||
));
|
||||
} else {
|
||||
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);
|
||||
|
@ -438,13 +438,13 @@ fn generate_component(
|
|||
}
|
||||
|
||||
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
|
||||
{
|
||||
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)]
|
||||
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 {
|
||||
#(#repeated_visit_branch)*
|
||||
_ => panic!("invalid dyn_index {}", dyn_index),
|
||||
|
|
|
@ -5,7 +5,7 @@ use vtable::*;
|
|||
use crate::graphics::{HighLevelRenderingPrimitive, Rect, RenderingVariable};
|
||||
use crate::input::{InputEventResult, MouseEvent};
|
||||
use crate::item_rendering::CachedRenderingData;
|
||||
use crate::item_tree::{ItemVisitorVTable, VisitChildrenResult};
|
||||
use crate::item_tree::{ItemVisitorVTable, TraversalOrder, VisitChildrenResult};
|
||||
use crate::{layout::LayoutInfo, SharedArray};
|
||||
|
||||
/// A Component is representing an unit that is allocated together
|
||||
|
@ -18,6 +18,7 @@ pub struct ComponentVTable {
|
|||
pub visit_children_item: extern "C" fn(
|
||||
core::pin::Pin<VRef<ComponentVTable>>,
|
||||
index: isize,
|
||||
order: TraversalOrder,
|
||||
visitor: VRefMut<ItemVisitorVTable>,
|
||||
) -> VisitChildrenResult,
|
||||
|
||||
|
|
|
@ -416,6 +416,7 @@ impl<Backend: GraphicsBackend> crate::eventloop::GenericWindow for GraphicsWindo
|
|||
// Generate cached rendering data once
|
||||
crate::item_tree::visit_items(
|
||||
component,
|
||||
crate::item_tree::TraversalOrder::BackToFront,
|
||||
|_, item, _| {
|
||||
crate::item_rendering::update_item_rendering_data(
|
||||
item,
|
||||
|
|
|
@ -66,6 +66,7 @@ pub fn process_ungrabbed_mouse_event(
|
|||
let mut result = InputEventResult::EventIgnored;
|
||||
let item_index = crate::item_tree::visit_items(
|
||||
component,
|
||||
crate::item_tree::TraversalOrder::FrontToBack,
|
||||
|_, item, offset| -> ItemVisitorResult<Vector2D<f32>> {
|
||||
let geom = item.as_ref().geometry();
|
||||
let geom = geom.translate(*offset);
|
||||
|
|
|
@ -49,6 +49,7 @@ pub(crate) fn render_component_items<Backend: GraphicsBackend>(
|
|||
|
||||
crate::item_tree::visit_items(
|
||||
component,
|
||||
crate::item_tree::TraversalOrder::BackToFront,
|
||||
|_, item, transform| {
|
||||
let origin = item.as_ref().geometry().origin;
|
||||
let transform =
|
||||
|
|
|
@ -3,6 +3,13 @@ use crate::ComponentRefPin;
|
|||
use core::pin::Pin;
|
||||
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
|
||||
///
|
||||
/// 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
|
||||
pub fn visit_items<State>(
|
||||
component: ComponentRefPin,
|
||||
order: TraversalOrder,
|
||||
mut visitor: impl FnMut(ComponentRefPin, Pin<ItemRef>, &State) -> ItemVisitorResult<State>,
|
||||
state: State,
|
||||
) -> VisitChildrenResult {
|
||||
visit_internal(component, &mut visitor, -1, &state)
|
||||
visit_internal(component, order, &mut visitor, -1, &state)
|
||||
}
|
||||
|
||||
fn visit_internal<State>(
|
||||
component: ComponentRefPin,
|
||||
order: TraversalOrder,
|
||||
visitor: &mut impl FnMut(ComponentRefPin, Pin<ItemRef>, &State) -> ItemVisitorResult<State>,
|
||||
index: isize,
|
||||
state: &State,
|
||||
) -> VisitChildrenResult {
|
||||
let mut actual_visitor = |component: ComponentRefPin,
|
||||
index: isize,
|
||||
item: Pin<ItemRef>|
|
||||
-> VisitChildrenResult {
|
||||
let mut actual_visitor =
|
||||
|component: ComponentRefPin, index: isize, item: Pin<ItemRef>| -> VisitChildrenResult {
|
||||
match visitor(component, item, state) {
|
||||
ItemVisitorResult::Continue(state) => visit_internal(component, visitor, index, &state),
|
||||
ItemVisitorResult::Continue(state) => {
|
||||
visit_internal(component, order, visitor, index, &state)
|
||||
}
|
||||
ItemVisitorResult::Abort => VisitChildrenResult::abort(index as usize, 0),
|
||||
}
|
||||
};
|
||||
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
|
||||
|
@ -152,8 +161,14 @@ pub fn visit_item_tree<Base>(
|
|||
component: ComponentRefPin,
|
||||
item_tree: &[ItemTreeNode<Base>],
|
||||
index: isize,
|
||||
order: TraversalOrder,
|
||||
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 {
|
||||
let mut visit_at_index = |idx: usize| -> VisitChildrenResult {
|
||||
match &item_tree[idx] {
|
||||
|
@ -162,7 +177,7 @@ pub fn visit_item_tree<Base>(
|
|||
}
|
||||
ItemTreeNode::DynamicTree { index } => {
|
||||
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)
|
||||
} else {
|
||||
|
@ -176,8 +191,12 @@ pub fn visit_item_tree<Base>(
|
|||
} else {
|
||||
match &item_tree[index as usize] {
|
||||
ItemTreeNode::Item { children_index, chilren_count, .. } => {
|
||||
for c in *children_index..(*children_index + *chilren_count) {
|
||||
let maybe_abort_index = visit_at_index(c as usize);
|
||||
for c in 0..*chilren_count {
|
||||
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() {
|
||||
return maybe_abort_index;
|
||||
}
|
||||
|
@ -228,9 +247,11 @@ pub(crate) mod ffi {
|
|||
component: Pin<VRef<ComponentVTable>>,
|
||||
item_tree: Slice<ItemTreeNode<u8>>,
|
||||
index: isize,
|
||||
order: TraversalOrder,
|
||||
visitor: VRefMut<ItemVisitorVTable>,
|
||||
visit_dynamic: extern "C" fn(
|
||||
base: &u8,
|
||||
order: TraversalOrder,
|
||||
visitor: vtable::VRefMut<ItemVisitorVTable>,
|
||||
dyn_index: usize,
|
||||
) -> VisitChildrenResult,
|
||||
|
@ -240,8 +261,9 @@ pub(crate) mod ffi {
|
|||
component,
|
||||
item_tree.as_slice(),
|
||||
index,
|
||||
order,
|
||||
visitor,
|
||||
|a, b, c| visit_dynamic(a.get_ref(), b, c),
|
||||
|a, b, c, d| visit_dynamic(a.get_ref(), b, c, d),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,9 @@ use sixtyfps_compilerlib::typeregister::Type;
|
|||
use sixtyfps_compilerlib::*;
|
||||
use sixtyfps_corelib::abi::datastructures::{ComponentVTable, ItemVTable, WindowProperties};
|
||||
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::layout::LayoutInfo;
|
||||
use sixtyfps_corelib::properties::{InterpolatedPropertyValue, PropertyListenerScope};
|
||||
|
@ -157,6 +159,7 @@ pub struct ComponentDescription {
|
|||
unsafe extern "C" fn visit_children_item(
|
||||
component: ComponentRefPin,
|
||||
index: isize,
|
||||
order: TraversalOrder,
|
||||
v: ItemVisitorRefMut,
|
||||
) -> VisitChildrenResult {
|
||||
let component_type =
|
||||
|
@ -167,8 +170,9 @@ unsafe extern "C" fn visit_children_item(
|
|||
component,
|
||||
item_tree.as_slice().into(),
|
||||
index,
|
||||
order,
|
||||
v,
|
||||
|_, mut visitor, index| {
|
||||
|_, order, mut visitor, index| {
|
||||
let rep_in_comp = &component_type.repeater[index];
|
||||
let vec = &mut *(component.as_ptr().add(rep_in_comp.offset) as *mut RepeaterVec);
|
||||
if let Some(listener_offset) = rep_in_comp.listener {
|
||||
|
@ -205,11 +209,31 @@ unsafe extern "C" fn visit_children_item(
|
|||
});
|
||||
}
|
||||
}
|
||||
match order {
|
||||
TraversalOrder::FrontToBack => {
|
||||
for (i, x) in vec.iter().enumerate() {
|
||||
if x.borrow().as_ref().visit_children_item(-1, visitor.borrow_mut()).has_aborted() {
|
||||
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
|
||||
},
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue