mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-02 14:51:15 +00:00
Mouse grab in rust
This commit is contained in:
parent
5aa7ee86fe
commit
0a56912d0f
9 changed files with 263 additions and 139 deletions
|
@ -73,6 +73,7 @@ pub(crate) mod repeater;
|
|||
pub mod re_exports {
|
||||
pub use crate::repeater::*;
|
||||
pub use const_field_offset::{self, FieldOffsets};
|
||||
pub use once_cell::sync::Lazy;
|
||||
pub use once_cell::unsync::OnceCell;
|
||||
pub use pin_weak::rc::*;
|
||||
pub use sixtyfps_corelib::abi::datastructures::*;
|
||||
|
@ -81,9 +82,12 @@ pub mod re_exports {
|
|||
pub use sixtyfps_corelib::graphics::{
|
||||
PathArcTo, PathData, PathElement, PathEvent, PathLineTo, Point, Rect, Size,
|
||||
};
|
||||
pub use sixtyfps_corelib::input::{InputEventResult, MouseEvent};
|
||||
pub use sixtyfps_corelib::input::{
|
||||
process_ungrabbed_mouse_event, InputEventResult, MouseEvent,
|
||||
};
|
||||
pub use sixtyfps_corelib::item_tree::{
|
||||
visit_item_tree, ItemTreeNode, ItemVisitorRefMut, ItemVisitorVTable, VisitChildrenResult,
|
||||
item_offset, visit_item_tree, ItemTreeNode, ItemVisitorRefMut, ItemVisitorVTable,
|
||||
VisitChildrenResult,
|
||||
};
|
||||
pub use sixtyfps_corelib::items::*;
|
||||
pub use sixtyfps_corelib::layout::LayoutInfo;
|
||||
|
|
|
@ -53,6 +53,15 @@ where
|
|||
sixtyfps_corelib::item_tree::VisitChildrenResult::CONTINUE
|
||||
}
|
||||
|
||||
/// Forward an input event to a particular item
|
||||
pub fn input_event(
|
||||
&self,
|
||||
idx: usize,
|
||||
event: sixtyfps_corelib::input::MouseEvent,
|
||||
) -> sixtyfps_corelib::input::InputEventResult {
|
||||
self.components.borrow()[idx].as_ref().input_event(event)
|
||||
}
|
||||
|
||||
/// Return the amount of item currently in the component
|
||||
pub fn len(&self) -> usize {
|
||||
self.components.borrow().len()
|
||||
|
|
|
@ -146,6 +146,8 @@ MainWindow := Rectangle {
|
|||
clicked => {
|
||||
if (root.active_page == 0) {
|
||||
root.active_page = idx + 1;
|
||||
} else {
|
||||
root.active_page = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ pub struct FieldOffset<T, U, PinFlag = NotPinnedFlag>(
|
|||
/// of.apply(foo)
|
||||
/// }
|
||||
/// ```
|
||||
PhantomData<(PhantomContra<T>, *const U, PinFlag)>,
|
||||
PhantomData<(PhantomContra<T>, U, PinFlag)>,
|
||||
);
|
||||
|
||||
/// Type that can be used in the `Flag` parameter of `FieldOffset` to specify that
|
||||
|
|
|
@ -460,6 +460,7 @@ impl<Base, T: ?Sized + VTableMeta, Flag> VOffset<Base, T, Flag> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new<X: HasStaticVTable<T>>(o: FieldOffset<Base, X, Flag>) -> Self {
|
||||
Self { vtable: X::static_vtable(), offset: o.get_byte_offset(), phantom: PhantomData }
|
||||
}
|
||||
|
@ -467,12 +468,14 @@ impl<Base, T: ?Sized + VTableMeta, Flag> VOffset<Base, T, Flag> {
|
|||
/// Create a new VOffset from raw data
|
||||
///
|
||||
/// Safety: there must be a field that matches the vtable at offset T in base
|
||||
#[inline]
|
||||
pub unsafe fn from_raw(vtable: &'static T::VTable, offset: usize) -> Self {
|
||||
Self { vtable, offset, phantom: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Base, T: ?Sized + VTableMeta> VOffset<Base, T, PinnedFlag> {
|
||||
#[inline]
|
||||
pub fn apply_pin<'a>(self, x: Pin<&'a Base>) -> Pin<VRef<'a, T>> {
|
||||
let ptr = x.get_ref() as *const Base as *mut u8;
|
||||
unsafe {
|
||||
|
|
|
@ -162,6 +162,7 @@ fn generate_component(
|
|||
let mut repeated_element_components = Vec::new();
|
||||
let mut repeated_dynmodel_names = Vec::new();
|
||||
let mut repeated_visit_branch = Vec::new();
|
||||
let mut repeated_input_branch = Vec::new();
|
||||
let mut init = Vec::new();
|
||||
super::build_array_helper(component, |item_rc, children_index, is_flickable_rect| {
|
||||
let item = item_rc.borrow();
|
||||
|
@ -249,6 +250,10 @@ fn generate_component(
|
|||
repeated_dynmodel_names.push(model_name);
|
||||
}
|
||||
|
||||
repeated_input_branch.push(quote!(
|
||||
#repeater_index => self.#repeater_id.input_event(rep_index, event),
|
||||
));
|
||||
|
||||
item_tree_array.push(quote!(
|
||||
sixtyfps::re_exports::ItemTreeNode::DynamicTree {
|
||||
index: #repeater_index,
|
||||
|
@ -408,6 +413,8 @@ fn generate_component(
|
|||
// Trick so we can use `#()` as a `if let Some` in `quote!`
|
||||
let parent_component_type = parent_component_type.iter().collect::<Vec<_>>();
|
||||
|
||||
let item_tree_array_len = item_tree_array.len();
|
||||
|
||||
if diag.has_error() {
|
||||
return None;
|
||||
}
|
||||
|
@ -427,6 +434,7 @@ fn generate_component(
|
|||
#(#repeated_dynmodel_names : sixtyfps::re_exports::PropertyListenerScope,)*
|
||||
self_weak: sixtyfps::re_exports::OnceCell<sixtyfps::re_exports::PinWeak<#component_id>>,
|
||||
#(parent : sixtyfps::re_exports::PinWeak<#parent_component_type>,)*
|
||||
mouse_grabber: ::core::cell::Cell<sixtyfps::re_exports::VisitChildrenResult>
|
||||
}
|
||||
|
||||
impl sixtyfps::re_exports::Component for #component_id {
|
||||
|
@ -434,8 +442,7 @@ fn generate_component(
|
|||
-> sixtyfps::re_exports::VisitChildrenResult
|
||||
{
|
||||
use sixtyfps::re_exports::*;
|
||||
let tree = &[#(#item_tree_array),*];
|
||||
return sixtyfps::re_exports::visit_item_tree(self, VRef::new_pin(self), tree, index, visitor, visit_dynamic);
|
||||
return sixtyfps::re_exports::visit_item_tree(self, VRef::new_pin(self), Self::item_tree(), index, visitor, visit_dynamic);
|
||||
#[allow(unused)]
|
||||
fn visit_dynamic(self_pinned: ::core::pin::Pin<&#component_id>, visitor: ItemVisitorRefMut, dyn_index: usize) -> VisitChildrenResult {
|
||||
match dyn_index {
|
||||
|
@ -445,8 +452,35 @@ fn generate_component(
|
|||
}
|
||||
}
|
||||
|
||||
fn input_event(self: ::core::pin::Pin<&Self>, _ : sixtyfps::re_exports::MouseEvent) -> sixtyfps::re_exports::InputEventResult {
|
||||
todo!()
|
||||
fn input_event(self: ::core::pin::Pin<&Self>, mouse_event : sixtyfps::re_exports::MouseEvent) -> sixtyfps::re_exports::InputEventResult {
|
||||
use sixtyfps::re_exports::*;
|
||||
let mouse_grabber = self.mouse_grabber.get();
|
||||
#[allow(unused)]
|
||||
let (status, new_grab) = if let Some((item_index, rep_index)) = mouse_grabber.aborted_indexes() {
|
||||
let tree = Self::item_tree();
|
||||
let offset = item_offset(self, tree, item_index);
|
||||
let mut event = mouse_event.clone();
|
||||
event.pos -= offset.to_vector();
|
||||
let res = match tree[item_index] {
|
||||
ItemTreeNode::Item { item, .. } => {
|
||||
item.apply_pin(self).as_ref().input_event(event)
|
||||
}
|
||||
ItemTreeNode::DynamicTree { index } => {
|
||||
match index {
|
||||
#(#repeated_input_branch)*
|
||||
_ => panic!("invalid index {}", index),
|
||||
}
|
||||
}
|
||||
};
|
||||
match res {
|
||||
InputEventResult::GrabMouse => (res, mouse_grabber),
|
||||
_ => (res, VisitChildrenResult::CONTINUE),
|
||||
}
|
||||
} else {
|
||||
process_ungrabbed_mouse_event(VRef::new_pin(self), mouse_event)
|
||||
};
|
||||
self.mouse_grabber.set(new_grab);
|
||||
status
|
||||
}
|
||||
|
||||
#layouts
|
||||
|
@ -467,6 +501,7 @@ fn generate_component(
|
|||
#(#repeated_dynmodel_names : ::core::default::Default::default(),)*
|
||||
self_weak : ::core::default::Default::default(),
|
||||
#(parent : parent as sixtyfps::re_exports::PinWeak::<#parent_component_type>,)*
|
||||
mouse_grabber: ::core::cell::Cell::new(sixtyfps::re_exports::VisitChildrenResult::CONTINUE),
|
||||
};
|
||||
let self_pinned = std::rc::Rc::pin(self_);
|
||||
self_pinned.self_weak.set(PinWeak::downgrade(self_pinned.clone())).map_err(|_|())
|
||||
|
@ -475,6 +510,14 @@ fn generate_component(
|
|||
self_pinned
|
||||
}
|
||||
#(#property_and_signal_accessors)*
|
||||
|
||||
fn item_tree() -> &'static [sixtyfps::re_exports::ItemTreeNode<Self>] {
|
||||
use sixtyfps::re_exports::*;
|
||||
// FIXME: ideally this should be a const
|
||||
static ITEM_TREE : Lazy<[sixtyfps::re_exports::ItemTreeNode<#component_id>; #item_tree_array_len]> =
|
||||
Lazy::new(|| [#(#item_tree_array),*]);
|
||||
&*ITEM_TREE
|
||||
}
|
||||
}
|
||||
|
||||
#(#extra_components)*
|
||||
|
@ -1236,27 +1279,3 @@ fn compile_path(path: &Path, component: &Rc<Component>) -> TokenStream {
|
|||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
quote! {
|
||||
|
||||
fn process_input_event(self: ::core::pin::Pin<&Self>, mouse_event) {
|
||||
if self.grab == -1 {
|
||||
sixtyfps::re_exports::process_ungrabbed_input_event(mouse_event)
|
||||
} else {
|
||||
let inx =self.grab & 0xffff;
|
||||
match child_array[inx] {
|
||||
DynamicItem(repeater_offset) => {
|
||||
let repeater_index = self.grab >> 16;
|
||||
match repeater_offset => {
|
||||
#(repeater_id => {
|
||||
self.#repeater_name.component[repeater_index].proccess_input_event()
|
||||
|
||||
} )*
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -4,7 +4,7 @@ TODO: Keyboard events
|
|||
*/
|
||||
|
||||
use crate::graphics::Point;
|
||||
use crate::item_tree::ItemVisitorResult;
|
||||
use crate::item_tree::{ItemVisitorResult, VisitChildrenResult};
|
||||
use crate::ComponentRefPin;
|
||||
use euclid::default::Vector2D;
|
||||
|
||||
|
@ -36,7 +36,7 @@ pub struct MouseEvent {
|
|||
/// to notify the run-time about how the event was handled and
|
||||
/// what the next steps are.
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum InputEventResult {
|
||||
/// The event was accepted. This may result in additional events, for example
|
||||
/// accepting a mouse move will result in a MouseExit event later.
|
||||
|
@ -60,7 +60,7 @@ pub enum InputEventResult {
|
|||
pub fn process_ungrabbed_mouse_event(
|
||||
component: ComponentRefPin,
|
||||
event: MouseEvent,
|
||||
) -> (InputEventResult, isize) {
|
||||
) -> (InputEventResult, VisitChildrenResult) {
|
||||
let offset = Vector2D::new(0., 0.);
|
||||
|
||||
let mut result = InputEventResult::EventIgnored;
|
||||
|
@ -90,8 +90,39 @@ pub fn process_ungrabbed_mouse_event(
|
|||
},
|
||||
offset,
|
||||
);
|
||||
(result, item_index)
|
||||
|
||||
(
|
||||
result,
|
||||
if result == InputEventResult::GrabMouse {
|
||||
item_index
|
||||
} else {
|
||||
VisitChildrenResult::CONTINUE
|
||||
},
|
||||
)
|
||||
}
|
||||
/*
|
||||
/// The event must be in the component coordinate
|
||||
/// Returns the new grabber.
|
||||
pub fn process_grabbed_mouse_event(
|
||||
component: ComponentRefPin,
|
||||
item: core::pin::Pin<ItemRef>,
|
||||
offset: Point,
|
||||
event: MouseEvent,
|
||||
old_grab: VisitChildrenResult,
|
||||
) -> (InputEventResult, VisitChildrenResult) {
|
||||
let mut event2 = event.clone();
|
||||
event2.pos -= offset.to_vector();
|
||||
|
||||
let res = item.as_ref().input_event(event2);
|
||||
match res {
|
||||
InputEventResult::EventIgnored => {
|
||||
// We need then to forward to another event
|
||||
process_ungrabbed_mouse_event(component, event)
|
||||
}
|
||||
InputEventResult::GrabMouse => (res, old_grab),
|
||||
InputEventResult::EventAccepted => (res, VisitChildrenResult::CONTINUE),
|
||||
}
|
||||
}*/
|
||||
|
||||
pub(crate) mod ffi {
|
||||
use super::*;
|
||||
|
@ -101,7 +132,18 @@ pub(crate) mod ffi {
|
|||
pub extern "C" fn sixtyfps_process_ungrabbed_mouse_event(
|
||||
component: ComponentRefPin,
|
||||
event: MouseEvent,
|
||||
) -> (InputEventResult, isize) {
|
||||
) -> (InputEventResult, crate::item_tree::VisitChildrenResult) {
|
||||
process_ungrabbed_mouse_event(component, event)
|
||||
}
|
||||
/*
|
||||
#[no_mangle]
|
||||
pub extern "C" fn sixtyfps_process_grabbed_mouse_event(
|
||||
component: ComponentRefPin,
|
||||
item: core::pin::Pin<ItemRef>,
|
||||
offset: Point,
|
||||
event: MouseEvent,
|
||||
old_grab: VisitChildrenResult,
|
||||
) -> (InputEventResult, crate::item_tree::VisitChildrenResult) {
|
||||
process_grabbed_mouse_event(component, item, offset, event, old_grab)
|
||||
}*/
|
||||
}
|
||||
|
|
|
@ -35,6 +35,13 @@ impl VisitChildrenResult {
|
|||
None
|
||||
}
|
||||
}
|
||||
pub fn aborted_indexes(&self) -> Option<(usize, usize)> {
|
||||
if self.0 != -1 {
|
||||
Some(((self.0 & 0xffff_ffff) as usize, (self.0 >> 32) as usize))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The item tree is an array of ItemTreeNode representing a static tree of items
|
||||
|
@ -70,14 +77,12 @@ pub struct ItemVisitorVTable {
|
|||
/// as the parent's component.
|
||||
/// `index` is to be used again in the visit_item_children function of the Component (the one passed as parameter)
|
||||
/// and `item` is a reference to the item itself
|
||||
///
|
||||
/// returns true to continue, or false to abort the visit
|
||||
visit_item: fn(
|
||||
VRefMut<ItemVisitorVTable>,
|
||||
component: Pin<VRef<ComponentVTable>>,
|
||||
index: isize,
|
||||
item: Pin<VRef<ItemVTable>>,
|
||||
) -> bool,
|
||||
) -> VisitChildrenResult,
|
||||
/// Destructor
|
||||
drop: fn(VRefMut<ItemVisitorVTable>),
|
||||
}
|
||||
|
@ -85,16 +90,129 @@ pub struct ItemVisitorVTable {
|
|||
/// Type alias to `vtable::VRefMut<ItemVisitorVTable>`
|
||||
pub type ItemVisitorRefMut<'a> = vtable::VRefMut<'a, ItemVisitorVTable>;
|
||||
|
||||
impl<T: FnMut(crate::ComponentRefPin, isize, Pin<ItemRef>) -> bool> ItemVisitor for T {
|
||||
impl<T: FnMut(crate::ComponentRefPin, isize, Pin<ItemRef>) -> VisitChildrenResult> ItemVisitor
|
||||
for T
|
||||
{
|
||||
fn visit_item(
|
||||
&mut self,
|
||||
component: crate::ComponentRefPin,
|
||||
index: isize,
|
||||
item: Pin<ItemRef>,
|
||||
) -> bool {
|
||||
) -> VisitChildrenResult {
|
||||
self(component, index, item)
|
||||
}
|
||||
}
|
||||
pub enum ItemVisitorResult<State> {
|
||||
Continue(State),
|
||||
Abort,
|
||||
}
|
||||
|
||||
/// Visit each items recursively
|
||||
///
|
||||
/// The state parametter returned by the visitor is passed to each children.
|
||||
///
|
||||
/// Returns the index of the item that cancelled, or -1 if nobody cancelled
|
||||
pub fn visit_items<State>(
|
||||
component: ComponentRefPin,
|
||||
mut visitor: impl FnMut(ComponentRefPin, Pin<ItemRef>, &State) -> ItemVisitorResult<State>,
|
||||
state: State,
|
||||
) -> VisitChildrenResult {
|
||||
visit_internal(component, &mut visitor, -1, &state)
|
||||
}
|
||||
|
||||
fn visit_internal<State>(
|
||||
component: ComponentRefPin,
|
||||
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 {
|
||||
match visitor(component, item, state) {
|
||||
ItemVisitorResult::Continue(state) => visit_internal(component, 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)
|
||||
}
|
||||
|
||||
/// Visit the children within an array of ItemTreeNode
|
||||
///
|
||||
/// The dynamic visitor is called for the dynamic nodes, its signature is
|
||||
/// `fn(base: &Base, visitor: vtable::VRefMut<ItemVisitorVTable>, dyn_index: usize)`
|
||||
///
|
||||
/// FIXME: the design of this use lots of indirection and stack frame in recursive functions
|
||||
/// Need to check if the compiler is able to optimize away some of it.
|
||||
/// Possibly we should generate code that directly call the visitor instead
|
||||
pub fn visit_item_tree<Base>(
|
||||
base: Pin<&Base>,
|
||||
component: ComponentRefPin,
|
||||
item_tree: &[ItemTreeNode<Base>],
|
||||
index: isize,
|
||||
mut visitor: vtable::VRefMut<ItemVisitorVTable>,
|
||||
visit_dynamic: impl Fn(Pin<&Base>, vtable::VRefMut<ItemVisitorVTable>, usize) -> VisitChildrenResult,
|
||||
) -> VisitChildrenResult {
|
||||
let mut visit_at_index = |idx: usize| -> VisitChildrenResult {
|
||||
match &item_tree[idx] {
|
||||
ItemTreeNode::Item { item, .. } => {
|
||||
visitor.visit_item(component, idx as isize, item.apply_pin(base))
|
||||
}
|
||||
ItemTreeNode::DynamicTree { index } => {
|
||||
if let Some(sub_idx) =
|
||||
visit_dynamic(base, visitor.borrow_mut(), *index).aborted_index()
|
||||
{
|
||||
VisitChildrenResult::abort(idx, sub_idx)
|
||||
} else {
|
||||
VisitChildrenResult::CONTINUE
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if index == -1 {
|
||||
visit_at_index(0)
|
||||
} 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);
|
||||
if maybe_abort_index.has_aborted() {
|
||||
return maybe_abort_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
ItemTreeNode::DynamicTree { .. } => panic!("should not be called with dynamic items"),
|
||||
};
|
||||
VisitChildrenResult::CONTINUE
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempt to find out the x, y position of the parent in the component's coordinate
|
||||
pub fn item_offset<Base>(
|
||||
base: Pin<&Base>,
|
||||
item_tree: &[ItemTreeNode<Base>],
|
||||
index: usize,
|
||||
) -> crate::graphics::Point {
|
||||
let index = index as u32;
|
||||
// FIXME: This algorithm is shit
|
||||
let parent = item_tree.iter().find_map(|n| match n {
|
||||
ItemTreeNode::Item { item, chilren_count, children_index } => {
|
||||
if *children_index > index && *children_index + *chilren_count < index {
|
||||
Some(item)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
ItemTreeNode::DynamicTree { .. } => None,
|
||||
});
|
||||
if let Some(parent) = parent {
|
||||
parent.apply_pin(base).as_ref().geometry().origin
|
||||
} else {
|
||||
crate::graphics::Point::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod ffi {
|
||||
#![allow(unsafe_code)]
|
||||
|
@ -126,101 +244,20 @@ pub(crate) mod ffi {
|
|||
|a, b, c| visit_dynamic(a.get_ref(), b, c),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ItemVisitorResult<State> {
|
||||
Continue(State),
|
||||
Abort,
|
||||
}
|
||||
|
||||
/// Visit each items recursively
|
||||
/// Expose `crate::item_tree::item_offset` to C++
|
||||
///
|
||||
/// The state parametter returned by the visitor is passed to each children.
|
||||
///
|
||||
/// Returns the index of the item that cancelled, or -1 if nobody cancelled
|
||||
pub fn visit_items<State>(
|
||||
component: ComponentRefPin,
|
||||
mut visitor: impl FnMut(ComponentRefPin, Pin<ItemRef>, &State) -> ItemVisitorResult<State>,
|
||||
state: State,
|
||||
) -> isize {
|
||||
visit_internal(component, &mut visitor, -1, &state)
|
||||
}
|
||||
|
||||
fn visit_internal<State>(
|
||||
component: ComponentRefPin,
|
||||
visitor: &mut impl FnMut(ComponentRefPin, Pin<ItemRef>, &State) -> ItemVisitorResult<State>,
|
||||
index: isize,
|
||||
state: &State,
|
||||
) -> isize {
|
||||
let mut result = -1;
|
||||
let mut actual_visitor =
|
||||
|component: ComponentRefPin, index: isize, item: Pin<ItemRef>| -> bool {
|
||||
match visitor(component, item, state) {
|
||||
ItemVisitorResult::Continue(state) => {
|
||||
result = visit_internal(component, visitor, index, &state);
|
||||
result == -1
|
||||
}
|
||||
ItemVisitorResult::Abort => {
|
||||
result = index;
|
||||
false
|
||||
}
|
||||
}
|
||||
};
|
||||
vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
|
||||
component.as_ref().visit_children_item(index, actual_visitor);
|
||||
result
|
||||
}
|
||||
|
||||
/// Visit the children within an array of ItemTreeNode
|
||||
///
|
||||
/// The dynamic visitor is called for the dynamic nodes, its signature is
|
||||
/// `fn(base: &Base, visitor: vtable::VRefMut<ItemVisitorVTable>, dyn_index: usize)`
|
||||
///
|
||||
/// FIXME: the design of this use lots of indirection and stack frame in recursive functions
|
||||
/// Need to check if the compiler is able to optimize away some of it.
|
||||
/// Possibly we should generate code that directly call the visitor instead
|
||||
pub fn visit_item_tree<Base>(
|
||||
base: Pin<&Base>,
|
||||
component: ComponentRefPin,
|
||||
item_tree: &[ItemTreeNode<Base>],
|
||||
index: isize,
|
||||
mut visitor: vtable::VRefMut<ItemVisitorVTable>,
|
||||
visit_dynamic: impl Fn(Pin<&Base>, vtable::VRefMut<ItemVisitorVTable>, usize) -> VisitChildrenResult,
|
||||
) -> VisitChildrenResult {
|
||||
let mut visit_at_index = |idx: usize| -> VisitChildrenResult {
|
||||
match &item_tree[idx] {
|
||||
ItemTreeNode::Item { item, .. } => {
|
||||
if visitor.visit_item(component, idx as isize, item.apply_pin(base)) {
|
||||
VisitChildrenResult::CONTINUE
|
||||
} else {
|
||||
VisitChildrenResult::abort(idx, 0)
|
||||
}
|
||||
}
|
||||
ItemTreeNode::DynamicTree { index } => {
|
||||
if let Some(sub_idx) =
|
||||
visit_dynamic(base, visitor.borrow_mut(), *index).aborted_index()
|
||||
{
|
||||
VisitChildrenResult::abort(idx, sub_idx)
|
||||
} else {
|
||||
VisitChildrenResult::CONTINUE
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if index == -1 {
|
||||
visit_at_index(0)
|
||||
} 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);
|
||||
if maybe_abort_index.has_aborted() {
|
||||
return maybe_abort_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
ItemTreeNode::DynamicTree { .. } => panic!("should not be called with dynamic items"),
|
||||
};
|
||||
VisitChildrenResult::CONTINUE
|
||||
/// Safety: Assume a correct implementation of the item_tree array
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sixtyfps_item_offset(
|
||||
component: Pin<VRef<ComponentVTable>>,
|
||||
item_tree: Slice<ItemTreeNode<u8>>,
|
||||
index: usize,
|
||||
) -> crate::graphics::Point {
|
||||
crate::item_tree::item_offset(
|
||||
Pin::new_unchecked(&*(component.as_ptr() as *const u8)),
|
||||
item_tree.as_slice(),
|
||||
index,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -371,14 +371,22 @@ impl Item for TouchArea {
|
|||
Self::FIELD_OFFSETS.pressed.apply_pin(self).set(match event.what {
|
||||
MouseEventType::MousePressed => true,
|
||||
MouseEventType::MouseExit | MouseEventType::MouseReleased => false,
|
||||
MouseEventType::MouseMoved => return InputEventResult::EventAccepted,
|
||||
MouseEventType::MouseMoved => {
|
||||
return if Self::FIELD_OFFSETS.pressed.apply_pin(self).get() {
|
||||
InputEventResult::GrabMouse
|
||||
} else {
|
||||
InputEventResult::EventIgnored
|
||||
}
|
||||
}
|
||||
});
|
||||
if matches!(event.what, MouseEventType::MouseReleased) {
|
||||
Self::FIELD_OFFSETS.clicked.apply_pin(self).emit(())
|
||||
}
|
||||
Self::FIELD_OFFSETS.clicked.apply_pin(self).emit(());
|
||||
InputEventResult::EventAccepted
|
||||
} else {
|
||||
InputEventResult::GrabMouse
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ItemConsts for TouchArea {
|
||||
const cached_rendering_data_offset: const_field_offset::FieldOffset<
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue