From 94c58dc1c401ea123d356fd5b759aeff1de612a0 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 20 May 2020 12:03:06 +0200 Subject: [PATCH] Add an mouse handler for the TouchArea --- examples/graphicstest/src/main.rs | 19 ++++--- sixtyfps_runtime/corelib/Cargo.toml | 1 + .../corelib/abi/datastructures.rs | 40 ++++++++++++-- sixtyfps_runtime/corelib/abi/primitives.rs | 23 +++++--- sixtyfps_runtime/corelib/input.rs | 28 ++++++++++ sixtyfps_runtime/corelib/lib.rs | 54 ++++++++++++++++--- 6 files changed, 141 insertions(+), 24 deletions(-) create mode 100644 sixtyfps_runtime/corelib/input.rs diff --git a/examples/graphicstest/src/main.rs b/examples/graphicstest/src/main.rs index 2d3f2b57a..eec29f627 100644 --- a/examples/graphicstest/src/main.rs +++ b/examples/graphicstest/src/main.rs @@ -69,14 +69,17 @@ fn main() { renderer.finish_primitives(rendering_primitives_builder); - main_window.run_event_loop(move |frame, rendering_cache| { - frame.render_primitive(rendering_cache.entry_at(root), &Matrix4::identity()); - frame.render_primitive( - rendering_cache.entry_at(child_rect), - &Matrix4::from_translation(Vector3::new(100., 100., 0.)), - ); - frame.render_primitive(rendering_cache.entry_at(image_node), &Matrix4::identity()); - }); + main_window.run_event_loop( + move |frame, rendering_cache| { + frame.render_primitive(rendering_cache.entry_at(root), &Matrix4::identity()); + frame.render_primitive( + rendering_cache.entry_at(child_rect), + &Matrix4::from_translation(Vector3::new(100., 100., 0.)), + ); + frame.render_primitive(rendering_cache.entry_at(image_node), &Matrix4::identity()); + }, + |_, _| (), + ); //render_cache.free_entry(root); //render_cache.free_entry(child_rect); diff --git a/sixtyfps_runtime/corelib/Cargo.toml b/sixtyfps_runtime/corelib/Cargo.toml index 3463e5322..f67cc942e 100644 --- a/sixtyfps_runtime/corelib/Cargo.toml +++ b/sixtyfps_runtime/corelib/Cargo.toml @@ -16,6 +16,7 @@ const-field-offset = { path = "../../helper_crates/const-field-offset" } vtable = { path = "../../helper_crates/vtable" } winit = "0.22.1" lyon = { version = "0.15.8" } +euclid = "0.20.11" servo_arc = "0.1.1" #we need the Arc::from_header_and_iter once_cell = "1.4" diff --git a/sixtyfps_runtime/corelib/abi/datastructures.rs b/sixtyfps_runtime/corelib/abi/datastructures.rs index e0c59dc79..315b1ef3a 100644 --- a/sixtyfps_runtime/corelib/abi/datastructures.rs +++ b/sixtyfps_runtime/corelib/abi/datastructures.rs @@ -1,6 +1,27 @@ use core::ptr::NonNull; use vtable::*; +pub type Rect = euclid::default::Rect; +pub type Point = euclid::default::Point2D; + +/// Expand Rect so that cbindgen can see it. ( is in fact euclid::default::Rect) +#[cfg(cbindgen)] +#[repr(C)] +struct Rect { + x: f32, + y: f32, + width: f32, + height: f32, +} + +/// Expand Point so that cbindgen can see it. ( is in fact euclid::default::PointD2) +#[cfg(cbindgen)] +#[repr(C)] +struct Point { + x: f32, + y: f32, +} + #[vtable] #[repr(C)] pub struct ComponentVTable { @@ -68,8 +89,8 @@ unsafe impl Sync for ItemTreeNode {} #[vtable] #[repr(C)] pub struct ItemVTable { - /// Rectangle: x/y/width/height ==> (path -> vertices/indicies(triangle)) - pub geometry: extern "C" fn(VRef<'_, ItemVTable>) -> (), // like kurbo::Rect + /// + pub geometry: extern "C" fn(VRef<'_, ItemVTable>) -> Rect, /// offset in bytes fromthe *const ItemImpl. /// isize::MAX means None @@ -109,7 +130,20 @@ pub enum RenderingInfo { Image(OpaqueImageHandle, AspectRatio)*/ } -pub type MouseEvent = (); +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub enum MouseEventType { + MousePressed, + MouseReleased, + MouseMoved, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct MouseEvent { + pub pos: Point, + pub what: MouseEventType, +} /* -- Safe wrappers*/ diff --git a/sixtyfps_runtime/corelib/abi/primitives.rs b/sixtyfps_runtime/corelib/abi/primitives.rs index fe03db1f6..88bccf8ac 100644 --- a/sixtyfps_runtime/corelib/abi/primitives.rs +++ b/sixtyfps_runtime/corelib/abi/primitives.rs @@ -15,7 +15,7 @@ When adding an item or a property, it needs to be kept in sync with different pl #![allow(non_upper_case_globals)] use super::datastructures::{ - CachedRenderingData, Item, ItemConsts, ItemVTable, LayoutInfo, RenderingInfo, + CachedRenderingData, Item, ItemConsts, ItemVTable, LayoutInfo, Rect, RenderingInfo, }; use crate::{Property, SharedString}; use vtable::HasStaticVTable; @@ -33,7 +33,9 @@ pub struct Rectangle { } impl Item for Rectangle { - fn geometry(&self) {} + fn geometry(&self) -> Rect { + euclid::rect(self.x.get(), self.y.get(), self.width.get(), self.height.get()) + } fn rendering_info(&self) -> RenderingInfo { RenderingInfo::Rectangle( self.x.get(), @@ -74,7 +76,9 @@ pub struct Image { } impl Item for Image { - fn geometry(&self) {} + fn geometry(&self) -> Rect { + euclid::rect(self.x.get(), self.y.get(), self.width.get(), self.height.get()) + } fn rendering_info(&self) -> RenderingInfo { RenderingInfo::Image(self.x.get(), self.y.get(), self.source.get()) } @@ -107,7 +111,10 @@ pub struct Text { } impl Item for Text { - fn geometry(&self) {} + // FIXME: width / height. or maybe it doesn't matter? ( + fn geometry(&self) -> Rect { + euclid::rect(self.x.get(), self.y.get(), 0., 0.) + } fn rendering_info(&self) -> RenderingInfo { RenderingInfo::Text(self.x.get(), self.y.get(), self.text.get(), self.color.get()) } @@ -139,7 +146,9 @@ pub struct TouchArea { } impl Item for TouchArea { - fn geometry(&self) {} + fn geometry(&self) -> Rect { + euclid::rect(self.x.get(), self.y.get(), self.width.get(), self.height.get()) + } fn rendering_info(&self) -> RenderingInfo { RenderingInfo::NoContents } @@ -148,7 +157,9 @@ impl Item for TouchArea { todo!() } - fn input_event(&self, _: super::datastructures::MouseEvent) {} + fn input_event(&self, event: super::datastructures::MouseEvent) { + println!("Touch Area Event {:?}", event) + } } impl ItemConsts for TouchArea { diff --git a/sixtyfps_runtime/corelib/input.rs b/sixtyfps_runtime/corelib/input.rs new file mode 100644 index 000000000..d6e9ffaf7 --- /dev/null +++ b/sixtyfps_runtime/corelib/input.rs @@ -0,0 +1,28 @@ +/*! Module handling mouse events + +TODO: Keyboard events +*/ + +use crate::abi::datastructures::{ComponentRef, MouseEvent}; +use euclid::default::Vector2D; + +pub fn process_mouse_event(component: ComponentRef<'_>, event: MouseEvent) { + let offset = Vector2D::new(0., 0.); + + crate::abi::datastructures::visit_items( + component, + |item, offset| { + let geom = item.geometry(); + let geom = geom.translate(*offset); + + if geom.contains(event.pos) { + let mut event2 = event.clone(); + event2.pos -= geom.origin.to_vector(); + item.input_event(event2); + } + + geom.origin.to_vector() + }, + offset, + ); +} diff --git a/sixtyfps_runtime/corelib/lib.rs b/sixtyfps_runtime/corelib/lib.rs index 2d0229d64..866221f56 100644 --- a/sixtyfps_runtime/corelib/lib.rs +++ b/sixtyfps_runtime/corelib/lib.rs @@ -1,4 +1,5 @@ pub mod graphics; +pub mod input; pub mod layout; pub mod abi { @@ -45,14 +46,18 @@ where Self { graphics_backend, event_loop, rendering_cache: graphics::RenderingCache::default() } } - pub fn run_event_loop(self, mut render_function: RenderFunction) - where - GraphicsBackend: 'static, - RenderFunction: FnMut(&mut GraphicsBackend::Frame, &mut graphics::RenderingCache) + pub fn run_event_loop( + self, + mut render_function: impl FnMut(&mut GraphicsBackend::Frame, &mut graphics::RenderingCache) + 'static, + mut input_function: impl FnMut(winit::dpi::PhysicalPosition, winit::event::ElementState) + + 'static, + ) where + GraphicsBackend: 'static, { let mut graphics_backend = self.graphics_backend; let mut rendering_cache = self.rendering_cache; + let mut cursor_pos = winit::dpi::PhysicalPosition::new(0., 0.); self.event_loop.run(move |event, _, control_flow| { *control_flow = winit::event_loop::ControlFlow::Wait; @@ -73,6 +78,23 @@ where render_function(&mut frame, &mut rendering_cache); graphics_backend.present_frame(frame); } + winit::event::Event::WindowEvent { + event: winit::event::WindowEvent::CursorMoved { position, .. }, + .. + } => { + cursor_pos = position; + // TODO: propagate mouse move? + } + + winit::event::Event::WindowEvent { + event: winit::event::WindowEvent::MouseInput { state, .. }, + .. + } => { + input_function(cursor_pos, state); + // FIXME: remove this, it should be based on actual changes rather than this + window.request_redraw(); + } + _ => (), } }); @@ -109,7 +131,25 @@ pub fn run_component( renderer.finish_primitives(rendering_primitives_builder); let component = component.into_ref(); - main_window.run_event_loop(move |frame, rendering_cache| { - item_rendering::render_component_items(component, frame, &rendering_cache); - }); + main_window.run_event_loop( + move |frame, rendering_cache| { + item_rendering::render_component_items(component, frame, &rendering_cache); + }, + move |pos, state| { + input::process_mouse_event( + component, + crate::abi::datastructures::MouseEvent { + pos: euclid::point2(pos.x as _, pos.y as _), + what: match state { + winit::event::ElementState::Pressed => { + crate::abi::datastructures::MouseEventType::MousePressed + } + winit::event::ElementState::Released => { + crate::abi::datastructures::MouseEventType::MouseReleased + } + }, + }, + ) + }, + ); }