Add an mouse handler for the TouchArea

This commit is contained in:
Olivier Goffart 2020-05-20 12:03:06 +02:00
parent 5acb8e7bdd
commit 94c58dc1c4
6 changed files with 141 additions and 24 deletions

View file

@ -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);

View file

@ -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"

View file

@ -1,6 +1,27 @@
use core::ptr::NonNull;
use vtable::*;
pub type Rect = euclid::default::Rect<f32>;
pub type Point = euclid::default::Point2D<f32>;
/// Expand Rect so that cbindgen can see it. ( is in fact euclid::default::Rect<f32>)
#[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<f32>)
#[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*/

View file

@ -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 {

View file

@ -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,
);
}

View file

@ -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<RenderFunction>(self, mut render_function: RenderFunction)
where
GraphicsBackend: 'static,
RenderFunction: FnMut(&mut GraphicsBackend::Frame, &mut graphics::RenderingCache<GraphicsBackend>)
pub fn run_event_loop(
self,
mut render_function: impl FnMut(&mut GraphicsBackend::Frame, &mut graphics::RenderingCache<GraphicsBackend>)
+ 'static,
mut input_function: impl FnMut(winit::dpi::PhysicalPosition<f64>, 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<GraphicsBackend, GraphicsFactoryFunc>(
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
}
},
},
)
},
);
}