WIP input events

Compile and passes tests. But the mouse event are currently not working
This commit is contained in:
Olivier Goffart 2020-08-06 12:33:07 +02:00
parent 829990f9b1
commit 55ec533c40
11 changed files with 96 additions and 53 deletions

View file

@ -142,12 +142,16 @@ struct Repeater
} }
} }
void visit(ItemVisitorRefMut visitor) const intptr_t visit(ItemVisitorRefMut visitor) const
{ {
for (const auto &x : data) { for (auto i = 0; i < data.size(); ++i) {
const auto &x = data.at(i);
VRef<ComponentVTable> ref { &C::component_type, x.get() }; VRef<ComponentVTable> ref { &C::component_type, x.get() };
ref.vtable->visit_children_item(ref, -1, visitor); if (ref.vtable->visit_children_item(ref, -1, visitor) == -1) {
return i;
}
} }
return -1;
} }
}; };

View file

@ -81,6 +81,7 @@ pub mod re_exports {
pub use sixtyfps_corelib::graphics::{ pub use sixtyfps_corelib::graphics::{
PathArcTo, PathData, PathElement, PathEvent, PathLineTo, Point, Rect, Size, PathArcTo, PathData, PathElement, PathEvent, PathLineTo, Point, Rect, Size,
}; };
pub use sixtyfps_corelib::input::{InputEventResult, MouseEvent};
pub use sixtyfps_corelib::item_tree::{ pub use sixtyfps_corelib::item_tree::{
visit_item_tree, ItemTreeNode, ItemVisitorRefMut, ItemVisitorVTable, visit_item_tree, ItemTreeNode, ItemVisitorRefMut, ItemVisitorVTable,
}; };

View file

@ -41,10 +41,13 @@ where
} }
/// Call the visitor for each component /// Call the visitor for each component
pub fn visit(&self, mut visitor: sixtyfps_corelib::item_tree::ItemVisitorRefMut) { pub fn visit(&self, mut visitor: sixtyfps_corelib::item_tree::ItemVisitorRefMut) -> isize {
for c in self.components.borrow().iter() { for (i, c) in self.components.borrow().iter().enumerate() {
c.as_ref().visit_children_item(-1, visitor.borrow_mut()); if c.as_ref().visit_children_item(-1, visitor.borrow_mut()) != -1 {
return i as isize;
}
} }
-1
} }
/// Return the amount of item currently in the component /// Return the amount of item currently in the component

View file

@ -353,7 +353,7 @@ fn handle_repeater(
if repeated.model.is_constant() { if repeated.model.is_constant() {
children_repeater_cases.push(format!( children_repeater_cases.push(format!(
"\n case {i}: self->{id}.visit(visitor); break;", "\n case {i}: return self->{id}.visit(visitor);",
id = repeater_id, id = repeater_id,
i = repeater_count i = repeater_count
)); ));
@ -703,7 +703,7 @@ fn generate_component(
Access::Private, Access::Private,
Declaration::Function(Function { Declaration::Function(Function {
name: "visit_children".into(), name: "visit_children".into(),
signature: "(sixtyfps::ComponentRef, intptr_t, sixtyfps::ItemVisitorRefMut) -> void" signature: "(sixtyfps::ComponentRef, intptr_t, sixtyfps::ItemVisitorRefMut) -> intptr_t"
.into(), .into(),
is_static: true, is_static: true,
..Default::default() ..Default::default()
@ -742,14 +742,15 @@ fn generate_component(
declarations.push(Declaration::Function(Function { declarations.push(Declaration::Function(Function {
name: format!("{}::visit_children", component_id), name: format!("{}::visit_children", component_id),
signature: "(sixtyfps::ComponentRef component, intptr_t index, sixtyfps::ItemVisitorRefMut visitor) -> void".into(), signature: "(sixtyfps::ComponentRef component, intptr_t index, sixtyfps::ItemVisitorRefMut visitor) -> intptr_t".into(),
statements: Some(vec![ statements: Some(vec![
"static const sixtyfps::ItemTreeNode<uint8_t> children[] {".to_owned(), "static const sixtyfps::ItemTreeNode<uint8_t> children[] {".to_owned(),
format!(" {} }};", tree_array.join(", ")), format!(" {} }};", tree_array.join(", ")),
"static const auto dyn_visit = [] (const uint8_t *base, [[maybe_unused]] sixtyfps::ItemVisitorRefMut visitor, uintptr_t dyn_index) {".to_owned(), "static const auto dyn_visit = [] (const uint8_t *base, [[maybe_unused]] sixtyfps::ItemVisitorRefMut visitor, uintptr_t dyn_index) -> intptr_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 // Fixme: this is not the root component
format!(" switch(dyn_index) {{ {} }}\n }};", children_visitor_case.join("")), format!(" switch(dyn_index) {{ {} }};", children_visitor_case.join("")),
" return -1; //should not happen\n};".to_owned(),
"return sixtyfps::sixtyfps_visit_item_tree(component, { const_cast<sixtyfps::ItemTreeNode<uint8_t>*>(children), std::size(children)}, index, visitor, dyn_visit);".to_owned(), "return sixtyfps::sixtyfps_visit_item_tree(component, { const_cast<sixtyfps::ItemTreeNode<uint8_t>*>(children), std::size(children)}, index, visitor, dyn_visit);".to_owned(),
]), ]),
..Default::default() ..Default::default()

View file

@ -430,12 +430,12 @@ 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, visitor: sixtyfps::re_exports::ItemVisitorRefMut) -> isize {
use sixtyfps::re_exports::*; use sixtyfps::re_exports::*;
let tree = &[#(#item_tree_array),*]; let tree = &[#(#item_tree_array),*];
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), tree, index, visitor, visit_dynamic);
#[allow(unused)] #[allow(unused)]
fn visit_dynamic(self_pinned: ::core::pin::Pin<&#component_id>, visitor: ItemVisitorRefMut, dyn_index: usize) { fn visit_dynamic(self_pinned: ::core::pin::Pin<&#component_id>, visitor: ItemVisitorRefMut, dyn_index: usize) -> isize {
match dyn_index { match dyn_index {
#(#repeated_visit_branch)* #(#repeated_visit_branch)*
_ => panic!("invalid dyn_index {}", dyn_index), _ => panic!("invalid dyn_index {}", dyn_index),
@ -443,6 +443,10 @@ fn generate_component(
} }
} }
fn input_event(self: ::core::pin::Pin<&Self>, _ : sixtyfps::re_exports::MouseEvent) -> sixtyfps::re_exports::InputEventResult {
todo!()
}
#layouts #layouts
} }
@ -1230,7 +1234,7 @@ fn compile_path(path: &Path, component: &Rc<Component>) -> TokenStream {
} }
} }
} }
/*
quote! { quote! {
fn process_input_event(self: ::core::pin::Pin<&Self>, mouse_event) { fn process_input_event(self: ::core::pin::Pin<&Self>, mouse_event) {
@ -1253,3 +1257,4 @@ match repeater_offset => {
} }
} }
} }
*/

View file

@ -37,7 +37,7 @@ impl FlickableData {
.get(), .get(),
) )
} }
MouseEventType::MouseReleased => { MouseEventType::MouseExit | MouseEventType::MouseReleased => {
if let Some(pressed_time) = inner.pressed_time { if let Some(pressed_time) = inner.pressed_time {
let dist = event.pos - inner.pressed_pos; let dist = event.pos - inner.pressed_pos;
let speed = dist let speed = dist

View file

@ -447,10 +447,9 @@ impl<Backend: GraphicsBackend> crate::eventloop::GenericWindow for GraphicsWindo
what: MouseEventType, what: MouseEventType,
component: crate::ComponentRefPin, component: crate::ComponentRefPin,
) { ) {
crate::input::process_mouse_event( component
component, .as_ref()
MouseEvent { pos: euclid::point2(pos.x as _, pos.y as _), what }, .input_event(MouseEvent { pos: euclid::point2(pos.x as _, pos.y as _), what });
);
} }
fn window_handle(&self) -> std::cell::Ref<winit::window::Window> { fn window_handle(&self) -> std::cell::Ref<winit::window::Window> {
std::cell::Ref::map(self.map_state.borrow(), |window| window.as_mapped().backend.window()) std::cell::Ref::map(self.map_state.borrow(), |window| window.as_mapped().backend.window())

View file

@ -81,7 +81,7 @@ pub(crate) mod ffi {
base: &u8, base: &u8,
visitor: vtable::VRefMut<ItemVisitorVTable>, visitor: vtable::VRefMut<ItemVisitorVTable>,
dyn_index: usize, dyn_index: usize,
) -> bool, ) -> isize,
) -> isize { ) -> isize {
crate::item_tree::visit_item_tree( crate::item_tree::visit_item_tree(
Pin::new_unchecked(&*(component.as_ptr() as *const u8)), Pin::new_unchecked(&*(component.as_ptr() as *const u8)),
@ -151,21 +151,25 @@ pub fn visit_item_tree<Base>(
item_tree: &[ItemTreeNode<Base>], item_tree: &[ItemTreeNode<Base>],
index: isize, index: isize,
mut visitor: vtable::VRefMut<ItemVisitorVTable>, mut visitor: vtable::VRefMut<ItemVisitorVTable>,
visit_dynamic: impl Fn(Pin<&Base>, vtable::VRefMut<ItemVisitorVTable>, usize) -> bool, visit_dynamic: impl Fn(Pin<&Base>, vtable::VRefMut<ItemVisitorVTable>, usize) -> isize,
) -> isize { ) -> isize {
let mut visit_at_index = |idx: usize| -> isize { let mut visit_at_index = |idx: usize| -> isize {
let continue_ = match &item_tree[idx] { match &item_tree[idx] {
ItemTreeNode::Item { item, .. } => { ItemTreeNode::Item { item, .. } => {
visitor.visit_item(component, idx as isize, item.apply_pin(base)) if visitor.visit_item(component, idx as isize, item.apply_pin(base)) {
-1
} else {
idx as isize
}
} }
ItemTreeNode::DynamicTree { index } => { ItemTreeNode::DynamicTree { index } => {
visit_dynamic(base, visitor.borrow_mut(), *index) let sub_idx = visit_dynamic(base, visitor.borrow_mut(), *index);
if sub_idx == -1 {
-1
} else {
idx as isize | sub_idx << 16
}
} }
};
if continue_ {
idx as isize | continue_ << 16
} else {
-1
} }
}; };
if index == -1 { if index == -1 {

View file

@ -18,7 +18,7 @@ When adding an item or a property, it needs to be kept in sync with different pl
use super::abi::datastructures::{Item, ItemConsts}; use super::abi::datastructures::{Item, ItemConsts};
use super::graphics::{Color, HighLevelRenderingPrimitive, PathData, Rect, Resource}; use super::graphics::{Color, HighLevelRenderingPrimitive, PathData, Rect, Resource};
use super::input::{MouseEvent, MouseEventType}; use super::input::{InputEventResult, MouseEvent, MouseEventType};
use super::item_rendering::CachedRenderingData; use super::item_rendering::CachedRenderingData;
use super::layout::LayoutInfo; use super::layout::LayoutInfo;
#[cfg(feature = "rtti")] #[cfg(feature = "rtti")]
@ -70,7 +70,9 @@ impl Item for Rectangle {
Default::default() Default::default()
} }
fn input_event(self: Pin<&Self>, _: MouseEvent) {} fn input_event(self: Pin<&Self>, _: MouseEvent) -> InputEventResult {
InputEventResult::EventIgnored
}
} }
impl ItemConsts for Rectangle { impl ItemConsts for Rectangle {
@ -133,7 +135,9 @@ impl Item for BorderRectangle {
Default::default() Default::default()
} }
fn input_event(self: Pin<&Self>, _: MouseEvent) {} fn input_event(self: Pin<&Self>, _: MouseEvent) -> InputEventResult {
InputEventResult::EventIgnored
}
} }
impl ItemConsts for BorderRectangle { impl ItemConsts for BorderRectangle {
@ -194,7 +198,9 @@ impl Item for Image {
Default::default() Default::default()
} }
fn input_event(self: Pin<&Self>, _: MouseEvent) {} fn input_event(self: Pin<&Self>, _: MouseEvent) -> InputEventResult {
InputEventResult::EventIgnored
}
} }
impl ItemConsts for Image { impl ItemConsts for Image {
@ -312,7 +318,9 @@ impl Item for Text {
}) })
} }
fn input_event(self: Pin<&Self>, _: MouseEvent) {} fn input_event(self: Pin<&Self>, _: MouseEvent) -> InputEventResult {
InputEventResult::EventIgnored
}
} }
impl ItemConsts for Text { impl ItemConsts for Text {
@ -359,15 +367,16 @@ impl Item for TouchArea {
LayoutInfo::default() LayoutInfo::default()
} }
fn input_event(self: Pin<&Self>, event: MouseEvent) { fn input_event(self: Pin<&Self>, event: MouseEvent) -> InputEventResult {
Self::FIELD_OFFSETS.pressed.apply_pin(self).set(match event.what { Self::FIELD_OFFSETS.pressed.apply_pin(self).set(match event.what {
MouseEventType::MousePressed => true, MouseEventType::MousePressed => true,
MouseEventType::MouseReleased => false, MouseEventType::MouseExit | MouseEventType::MouseReleased => false,
MouseEventType::MouseMoved => return, MouseEventType::MouseMoved => return InputEventResult::EventAccepted,
}); });
if matches!(event.what, MouseEventType::MouseReleased) { if matches!(event.what, MouseEventType::MouseReleased) {
Self::FIELD_OFFSETS.clicked.apply_pin(self).emit(()) Self::FIELD_OFFSETS.clicked.apply_pin(self).emit(())
} }
InputEventResult::GrabMouse
} }
} }
@ -424,7 +433,9 @@ impl Item for Path {
LayoutInfo::default() LayoutInfo::default()
} }
fn input_event(self: Pin<&Self>, _: MouseEvent) {} fn input_event(self: Pin<&Self>, _: MouseEvent) -> InputEventResult {
InputEventResult::EventIgnored
}
} }
impl ItemConsts for Path { impl ItemConsts for Path {
@ -471,8 +482,10 @@ impl Item for Flickable {
LayoutInfo::default() LayoutInfo::default()
} }
fn input_event(self: Pin<&Self>, event: MouseEvent) { fn input_event(self: Pin<&Self>, event: MouseEvent) -> InputEventResult {
self.data.handle_mouse(self, event); self.data.handle_mouse(self, event);
// FIXME
InputEventResult::EventAccepted
} }
} }

View file

@ -142,7 +142,7 @@ unsafe extern "C" fn visit_children_item(
component: ComponentRefPin, component: ComponentRefPin,
index: isize, index: isize,
v: ItemVisitorRefMut, v: ItemVisitorRefMut,
) { ) -> isize {
let component_type = let component_type =
&*(component.get_vtable() as *const ComponentVTable as *const ComponentDescription); &*(component.get_vtable() as *const ComponentVTable as *const ComponentDescription);
let item_tree = &component_type.it; let item_tree = &component_type.it;
@ -189,11 +189,14 @@ unsafe extern "C" fn visit_children_item(
}); });
} }
} }
for x in vec { for (i, x) in vec.iter().enumerate() {
x.borrow().as_ref().visit_children_item(-1, visitor.borrow_mut()); if x.borrow().as_ref().visit_children_item(-1, visitor.borrow_mut()) != -1 {
return i as isize;
}
} }
-1
}, },
); )
} }
/// Information attached to a builtin item /// Information attached to a builtin item
@ -412,7 +415,7 @@ fn generate_component(root_component: &Rc<object_tree::Component>) -> Rc<Compone
todo!() todo!()
} }
let t = ComponentVTable { visit_children_item, layout_info, compute_layout }; let t = ComponentVTable { visit_children_item, layout_info, compute_layout, input_event };
let t = ComponentDescription { let t = ComponentDescription {
ct: t, ct: t,
dynamic_type: builder.build(), dynamic_type: builder.build(),
@ -914,6 +917,13 @@ impl<'a> LayoutTreeItem<'a> {
} }
} }
extern "C" fn input_event(
_component: ComponentRefPin,
_mouse: sixtyfps_corelib::input::MouseEvent,
) -> sixtyfps_corelib::input::InputEventResult {
todo!()
}
unsafe extern "C" fn compute_layout(component: ComponentRefPin) { unsafe extern "C" fn compute_layout(component: ComponentRefPin) {
// This is fine since we can only be called with a component that with our vtable which is a ComponentDescription // This is fine since we can only be called with a component that with our vtable which is a ComponentDescription
let component_type = let component_type =

View file

@ -7,7 +7,7 @@ use core::pin::Pin;
use cpp::cpp; use cpp::cpp;
use sixtyfps_corelib::abi::datastructures::{Item, ItemConsts, ItemVTable}; use sixtyfps_corelib::abi::datastructures::{Item, ItemConsts, ItemVTable};
use sixtyfps_corelib::graphics::{HighLevelRenderingPrimitive, Rect, RenderingVariable, Resource}; use sixtyfps_corelib::graphics::{HighLevelRenderingPrimitive, Rect, RenderingVariable, Resource};
use sixtyfps_corelib::input::{MouseEvent, MouseEventType}; use sixtyfps_corelib::input::{InputEventResult, MouseEvent, MouseEventType};
use sixtyfps_corelib::item_rendering::CachedRenderingData; use sixtyfps_corelib::item_rendering::CachedRenderingData;
use sixtyfps_corelib::layout::LayoutInfo; use sixtyfps_corelib::layout::LayoutInfo;
#[cfg(feature = "rtti")] #[cfg(feature = "rtti")]
@ -130,15 +130,16 @@ impl Item for QtStyleButton {
LayoutInfo::default() LayoutInfo::default()
} }
fn input_event(self: Pin<&Self>, event: MouseEvent) { fn input_event(self: Pin<&Self>, event: MouseEvent) -> InputEventResult {
Self::FIELD_OFFSETS.pressed.apply_pin(self).set(match event.what { Self::FIELD_OFFSETS.pressed.apply_pin(self).set(match event.what {
MouseEventType::MousePressed => true, MouseEventType::MousePressed => true,
MouseEventType::MouseReleased => false, MouseEventType::MouseExit | MouseEventType::MouseReleased => false,
MouseEventType::MouseMoved => return, MouseEventType::MouseMoved => return InputEventResult::EventAccepted,
}); });
if matches!(event.what, MouseEventType::MouseReleased) { if matches!(event.what, MouseEventType::MouseReleased) {
Self::FIELD_OFFSETS.clicked.apply_pin(self).emit(()) Self::FIELD_OFFSETS.clicked.apply_pin(self).emit(())
} }
InputEventResult::GrabMouse
} }
} }
@ -234,7 +235,7 @@ impl Item for QtStyleCheckBox {
LayoutInfo::default() LayoutInfo::default()
} }
fn input_event(self: Pin<&Self>, event: MouseEvent) { fn input_event(self: Pin<&Self>, event: MouseEvent) -> InputEventResult {
if matches!(event.what, MouseEventType::MouseReleased) { if matches!(event.what, MouseEventType::MouseReleased) {
Self::FIELD_OFFSETS Self::FIELD_OFFSETS
.checked .checked
@ -242,6 +243,7 @@ impl Item for QtStyleCheckBox {
.set(!Self::FIELD_OFFSETS.checked.apply_pin(self).get()); .set(!Self::FIELD_OFFSETS.checked.apply_pin(self).get());
Self::FIELD_OFFSETS.toggled.apply_pin(self).emit(()) Self::FIELD_OFFSETS.toggled.apply_pin(self).emit(())
} }
InputEventResult::GrabMouse
} }
} }
@ -379,7 +381,7 @@ impl Item for QtStyleSpinBox {
LayoutInfo::default() LayoutInfo::default()
} }
fn input_event(self: Pin<&Self>, event: MouseEvent) { fn input_event(self: Pin<&Self>, event: MouseEvent) -> InputEventResult {
#[cfg(have_qt)] #[cfg(have_qt)]
{ {
let size: qttypes::QSize = qttypes::QSize { let size: qttypes::QSize = qttypes::QSize {
@ -413,7 +415,7 @@ impl Item for QtStyleSpinBox {
data.pressed = true; data.pressed = true;
true true
} }
MouseEventType::MouseReleased => { MouseEventType::MouseExit | MouseEventType::MouseReleased => {
data.pressed = false; data.pressed = false;
if new_control if new_control
== cpp!(unsafe []->u32 as "int" { return QStyle::SC_SpinBoxUp;}) == cpp!(unsafe []->u32 as "int" { return QStyle::SC_SpinBoxUp;})
@ -434,6 +436,7 @@ impl Item for QtStyleSpinBox {
self.data.set(data); self.data.set(data);
} }
} }
InputEventResult::GrabMouse
} }
} }