mirror of
https://github.com/slint-ui/slint.git
synced 2025-09-30 13:51:13 +00:00
Add an mouse handler for the TouchArea
This commit is contained in:
parent
5acb8e7bdd
commit
94c58dc1c4
6 changed files with 141 additions and 24 deletions
|
@ -69,14 +69,17 @@ fn main() {
|
||||||
|
|
||||||
renderer.finish_primitives(rendering_primitives_builder);
|
renderer.finish_primitives(rendering_primitives_builder);
|
||||||
|
|
||||||
main_window.run_event_loop(move |frame, rendering_cache| {
|
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(root), &Matrix4::identity());
|
||||||
frame.render_primitive(
|
frame.render_primitive(
|
||||||
rendering_cache.entry_at(child_rect),
|
rendering_cache.entry_at(child_rect),
|
||||||
&Matrix4::from_translation(Vector3::new(100., 100., 0.)),
|
&Matrix4::from_translation(Vector3::new(100., 100., 0.)),
|
||||||
);
|
);
|
||||||
frame.render_primitive(rendering_cache.entry_at(image_node), &Matrix4::identity());
|
frame.render_primitive(rendering_cache.entry_at(image_node), &Matrix4::identity());
|
||||||
});
|
},
|
||||||
|
|_, _| (),
|
||||||
|
);
|
||||||
|
|
||||||
//render_cache.free_entry(root);
|
//render_cache.free_entry(root);
|
||||||
//render_cache.free_entry(child_rect);
|
//render_cache.free_entry(child_rect);
|
||||||
|
|
|
@ -16,6 +16,7 @@ const-field-offset = { path = "../../helper_crates/const-field-offset" }
|
||||||
vtable = { path = "../../helper_crates/vtable" }
|
vtable = { path = "../../helper_crates/vtable" }
|
||||||
winit = "0.22.1"
|
winit = "0.22.1"
|
||||||
lyon = { version = "0.15.8" }
|
lyon = { version = "0.15.8" }
|
||||||
|
euclid = "0.20.11"
|
||||||
servo_arc = "0.1.1" #we need the Arc::from_header_and_iter
|
servo_arc = "0.1.1" #we need the Arc::from_header_and_iter
|
||||||
once_cell = "1.4"
|
once_cell = "1.4"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,27 @@
|
||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
use vtable::*;
|
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]
|
#[vtable]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct ComponentVTable {
|
pub struct ComponentVTable {
|
||||||
|
@ -68,8 +89,8 @@ unsafe impl Sync for ItemTreeNode {}
|
||||||
#[vtable]
|
#[vtable]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct ItemVTable {
|
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.
|
/// offset in bytes fromthe *const ItemImpl.
|
||||||
/// isize::MAX means None
|
/// isize::MAX means None
|
||||||
|
@ -109,7 +130,20 @@ pub enum RenderingInfo {
|
||||||
Image(OpaqueImageHandle, AspectRatio)*/
|
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*/
|
/* -- Safe wrappers*/
|
||||||
|
|
||||||
|
|
|
@ -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)]
|
#![allow(non_upper_case_globals)]
|
||||||
|
|
||||||
use super::datastructures::{
|
use super::datastructures::{
|
||||||
CachedRenderingData, Item, ItemConsts, ItemVTable, LayoutInfo, RenderingInfo,
|
CachedRenderingData, Item, ItemConsts, ItemVTable, LayoutInfo, Rect, RenderingInfo,
|
||||||
};
|
};
|
||||||
use crate::{Property, SharedString};
|
use crate::{Property, SharedString};
|
||||||
use vtable::HasStaticVTable;
|
use vtable::HasStaticVTable;
|
||||||
|
@ -33,7 +33,9 @@ pub struct Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item for 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 {
|
fn rendering_info(&self) -> RenderingInfo {
|
||||||
RenderingInfo::Rectangle(
|
RenderingInfo::Rectangle(
|
||||||
self.x.get(),
|
self.x.get(),
|
||||||
|
@ -74,7 +76,9 @@ pub struct Image {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item for 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 {
|
fn rendering_info(&self) -> RenderingInfo {
|
||||||
RenderingInfo::Image(self.x.get(), self.y.get(), self.source.get())
|
RenderingInfo::Image(self.x.get(), self.y.get(), self.source.get())
|
||||||
}
|
}
|
||||||
|
@ -107,7 +111,10 @@ pub struct Text {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item for 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 {
|
fn rendering_info(&self) -> RenderingInfo {
|
||||||
RenderingInfo::Text(self.x.get(), self.y.get(), self.text.get(), self.color.get())
|
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 {
|
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 {
|
fn rendering_info(&self) -> RenderingInfo {
|
||||||
RenderingInfo::NoContents
|
RenderingInfo::NoContents
|
||||||
}
|
}
|
||||||
|
@ -148,7 +157,9 @@ impl Item for TouchArea {
|
||||||
todo!()
|
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 {
|
impl ItemConsts for TouchArea {
|
||||||
|
|
28
sixtyfps_runtime/corelib/input.rs
Normal file
28
sixtyfps_runtime/corelib/input.rs
Normal 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,
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
pub mod graphics;
|
pub mod graphics;
|
||||||
|
pub mod input;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
|
|
||||||
pub mod abi {
|
pub mod abi {
|
||||||
|
@ -45,14 +46,18 @@ where
|
||||||
Self { graphics_backend, event_loop, rendering_cache: graphics::RenderingCache::default() }
|
Self { graphics_backend, event_loop, rendering_cache: graphics::RenderingCache::default() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_event_loop<RenderFunction>(self, mut render_function: RenderFunction)
|
pub fn run_event_loop(
|
||||||
where
|
self,
|
||||||
GraphicsBackend: 'static,
|
mut render_function: impl FnMut(&mut GraphicsBackend::Frame, &mut graphics::RenderingCache<GraphicsBackend>)
|
||||||
RenderFunction: FnMut(&mut GraphicsBackend::Frame, &mut graphics::RenderingCache<GraphicsBackend>)
|
|
||||||
+ 'static,
|
+ '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 graphics_backend = self.graphics_backend;
|
||||||
let mut rendering_cache = self.rendering_cache;
|
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| {
|
self.event_loop.run(move |event, _, control_flow| {
|
||||||
*control_flow = winit::event_loop::ControlFlow::Wait;
|
*control_flow = winit::event_loop::ControlFlow::Wait;
|
||||||
|
|
||||||
|
@ -73,6 +78,23 @@ where
|
||||||
render_function(&mut frame, &mut rendering_cache);
|
render_function(&mut frame, &mut rendering_cache);
|
||||||
graphics_backend.present_frame(frame);
|
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);
|
renderer.finish_primitives(rendering_primitives_builder);
|
||||||
let component = component.into_ref();
|
let component = component.into_ref();
|
||||||
main_window.run_event_loop(move |frame, rendering_cache| {
|
main_window.run_event_loop(
|
||||||
|
move |frame, rendering_cache| {
|
||||||
item_rendering::render_component_items(component, 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
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue