Skip to content

Commit

Permalink
TouchArea: add the pointer-event callback
Browse files Browse the repository at this point in the history
... instead of `pressed-changed`

This allows to see what mouse button was pressed.

Closes slint-ui#535
  • Loading branch information
ogoffart committed Oct 4, 2021
1 parent 137ad32 commit 2716e4b
Show file tree
Hide file tree
Showing 21 changed files with 200 additions and 59 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ All notable changes to this project will be documented in this file.
- New `Dialog` element
- `sixtyfps::Image` has now a `path()` accessor function in Rust and C++ to access the optional path
of the file on disk that's backing the image.
- New `moved` and `pressed-changed` callback in `TouchArea`
- New `moved` and `pointer-event` callback in `TouchArea`

### Fixed

Expand Down
7 changes: 6 additions & 1 deletion api/sixtyfps-cpp/cbindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ fn default_config() -> cbindgen::Config {
("Callback".into(), "private_api::CallbackHelper".into()),
("VoidArg".into(), "void".into()),
("KeyEventArg".into(), "KeyEvent".into()),
("PointerEventArg".into(), "PointerEvent".into()),
("PointArg".into(), "Point".into()),
]
.iter()
Expand Down Expand Up @@ -115,6 +116,9 @@ fn gen_corelib(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> {
"ImageFit",
"FillRule",
"StandardButtonKind",
"PointerEventKind",
"PointerEventButton",
"PointerEvent",
]
.iter()
.chain(items.iter())
Expand Down Expand Up @@ -143,6 +147,7 @@ fn gen_corelib(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> {
"WindowRc",
"VoidArg",
"KeyEventArg",
"PointerEventArg",
"PointArg",
"Point",
"sixtyfps_color_brighter",
Expand Down Expand Up @@ -340,7 +345,7 @@ namespace sixtyfps {{
namespace cbindgen_private {{
using sixtyfps::private_api::WindowRc;
using namespace vtable;
struct KeyEvent;
struct KeyEvent; struct PointerEvent;
using private_api::Property;
using private_api::PathData;
using private_api::Point;
Expand Down
1 change: 1 addition & 0 deletions api/sixtyfps-cpp/include/sixtyfps.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ namespace private_api {
using ItemTreeNode = cbindgen_private::ItemTreeNode<uint8_t>;
using cbindgen_private::KeyboardModifiers;
using cbindgen_private::KeyEvent;
using cbindgen_private::PointerEvent;

/// Internal function that checks that the API that must be called from the main
/// thread is indeed called from the main thread, or abort the program otherwise
Expand Down
14 changes: 13 additions & 1 deletion docs/builtin_elements.md
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ When not part of a layout, its width or height default to 100% of the parent ele

* **`clicked`**: Emitted when clicked (the mouse is pressed, then released on this element)
* **`moved`**: The mouse has been moved. This will only be called if the mouse is also pressed.
* **`pressed-changed`**: The value of the `pressed` property changed.
* **`pointer-event(PointerEvent)`**: Received when a button was pressed or released.

### Example

Expand Down Expand Up @@ -718,6 +718,18 @@ are pressed during the generation of a key event.
* **`shift`** (*bool*): `true` if the shift key is pressed.
* **`meta`** (*bool*): `true` if the windows key is pressed on Windows, or the control key on macOS.

## `PointerEvent`

This structure is generated and passed to the `pointer-event` callback of the `TouchArea` element.

### Fields

* **`kind`** (*enum PointerEventKind*): The kind of the event: one of the following
- `down`: The button was pressed.
- `up`: The button was released.
- `cancel`: Another element or window took hold of the grab. This applies to all pressed button and the `button` is not relevent.
* **`button`** (*enum PointerEventButton*): The button that was pressed or released. `left`, `right`, `middle`, or `none`.

# Builtin Enums

The default value of each enum type is always the first value
Expand Down
9 changes: 8 additions & 1 deletion sixtyfps_compiler/builtins.60
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@ export Text := _ {
//-default_size_binding:implicit_size
}


export struct PointerEvent := {
//-name:sixtyfps::private_api::PointerEvent
button: PointerEventButton,
kind: PointerEventKind,
}

export TouchArea := _ {
property <length> x;
property <length> y;
Expand All @@ -110,7 +117,7 @@ export TouchArea := _ {
property <length> pressed_y: native_output;
callback clicked;
callback moved;
callback pressed-changed;
callback pointer-event(PointerEvent);
//-default_size_binding:expands_to_parent_geometry
}

Expand Down
2 changes: 2 additions & 0 deletions sixtyfps_compiler/typeregister.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ impl TypeRegister {
"ignore",
],
);
declare_enum("PointerEventKind", &["cancel", "down", "up"]);
declare_enum("PointerEventButton", &["none", "left", "right", "middle"]);

register.supported_property_animation_types.insert(Type::Float32.to_string());
register.supported_property_animation_types.insert(Type::Int32.to_string());
Expand Down
6 changes: 4 additions & 2 deletions sixtyfps_compiler/widgets/fluent/sixtyfps_widgets.60
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,10 @@ export Slider := Rectangle {
width: parent.width;
height: parent.height;
property <float> pressed-value;
pressed-changed => {
if (pressed) { pressed-value = root.value; }
pointer-event(event) => {
if (event.button == PointerEventButton.left && event.kind == PointerEventKind.down) {
pressed-value = root.value;
}
}
moved => {
if (enabled && pressed) {
Expand Down
6 changes: 4 additions & 2 deletions sixtyfps_compiler/widgets/fluent/sixtyfps_widgets_impl.60
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,10 @@ ScrollBar := Rectangle {
width: parent.width;
height: parent.height;
property <length> pressed-value;
pressed-changed => {
if (pressed) { pressed-value = -root.value; }
pointer-event(event) => {
if (event.button == PointerEventButton.left && event.kind == PointerEventKind.down) {
pressed-value = -root.value;
}
}
moved => {
if (enabled && pressed) {
Expand Down
10 changes: 8 additions & 2 deletions sixtyfps_runtime/corelib/flickable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::animations::EasingCurve;
use crate::animations::Instant;
use crate::graphics::Point;
use crate::input::{InputEventFilterResult, InputEventResult, MouseEvent};
use crate::items::PointerEventButton;
use crate::items::{Flickable, PropertyAnimation, Rectangle};
use core::cell::RefCell;
use core::pin::Pin;
Expand Down Expand Up @@ -48,7 +49,7 @@ impl FlickableData {
) -> InputEventFilterResult {
let mut inner = self.inner.borrow_mut();
match event {
MouseEvent::MousePressed { pos } => {
MouseEvent::MousePressed { pos, button: PointerEventButton::left } => {
inner.pressed_pos = pos;
inner.pressed_time = Some(crate::animations::current_tick());
inner.pressed_viewport_pos = Point::new(
Expand All @@ -65,7 +66,8 @@ impl FlickableData {
InputEventFilterResult::ForwardAndInterceptGrab
}
}
MouseEvent::MouseExit | MouseEvent::MouseReleased { .. } => {
MouseEvent::MouseExit
| MouseEvent::MouseReleased { button: PointerEventButton::left, .. } => {
let was_capturing = inner.capture_events;
Self::mouse_released(&mut inner, flick, event);
if was_capturing {
Expand All @@ -90,6 +92,10 @@ impl FlickableData {
}
}
MouseEvent::MouseWheel { .. } => InputEventFilterResult::Intercept,
// Not the left button
MouseEvent::MousePressed { .. } | MouseEvent::MouseReleased { .. } => {
InputEventFilterResult::ForwardAndIgnore
}
}
}

Expand Down
14 changes: 7 additions & 7 deletions sixtyfps_runtime/corelib/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ LICENSE END */

use crate::graphics::Point;
use crate::item_tree::{ItemVisitorResult, VisitChildrenResult};
use crate::items::{ItemRc, ItemRef, ItemWeak};
use crate::items::{ItemRc, ItemRef, ItemWeak, PointerEventButton};
use crate::window::WindowRc;
use crate::Property;
use crate::{component::ComponentRc, SharedString};
Expand All @@ -28,9 +28,9 @@ use std::rc::Rc;
#[allow(missing_docs)]
pub enum MouseEvent {
/// The mouse was pressed
MousePressed { pos: Point },
MousePressed { pos: Point, button: PointerEventButton },
/// The mouse was released
MouseReleased { pos: Point },
MouseReleased { pos: Point, button: PointerEventButton },
/// The mouse position has changed
MouseMoved { pos: Point },
/// Wheel was operated.
Expand All @@ -45,8 +45,8 @@ impl MouseEvent {
/// The position of the cursor
pub fn pos(&self) -> Option<Point> {
match self {
MouseEvent::MousePressed { pos } => Some(*pos),
MouseEvent::MouseReleased { pos } => Some(*pos),
MouseEvent::MousePressed { pos, .. } => Some(*pos),
MouseEvent::MouseReleased { pos, .. } => Some(*pos),
MouseEvent::MouseMoved { pos } => Some(*pos),
MouseEvent::MouseWheel { pos, .. } => Some(*pos),
MouseEvent::MouseExit => None,
Expand All @@ -56,8 +56,8 @@ impl MouseEvent {
/// Translate the position by the given value
pub fn translate(&mut self, vec: Vector2D<f32>) {
let pos = match self {
MouseEvent::MousePressed { pos } => Some(pos),
MouseEvent::MouseReleased { pos } => Some(pos),
MouseEvent::MousePressed { pos, .. } => Some(pos),
MouseEvent::MouseReleased { pos, .. } => Some(pos),
MouseEvent::MouseMoved { pos } => Some(pos),
MouseEvent::MouseWheel { pos, .. } => Some(pos),
MouseEvent::MouseExit => None,
Expand Down
90 changes: 74 additions & 16 deletions sixtyfps_runtime/corelib/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type ItemRendererRef<'a> = &'a mut dyn crate::item_rendering::ItemRenderer;
/// Workarounds for cbindgen
pub type VoidArg = ();
type KeyEventArg = (KeyEvent,);
type PointerEventArg = (PointerEvent,);
type PointArg = (Point,);

#[macro_export]
Expand Down Expand Up @@ -351,7 +352,7 @@ pub struct TouchArea {
pub mouse_y: Property<f32>,
pub clicked: Callback<VoidArg>,
pub moved: Callback<VoidArg>,
pub pressed_changed: Callback<VoidArg>,
pub pointer_event: Callback<PointerEventArg>,
/// FIXME: remove this
pub cached_rendering_data: CachedRenderingData,
}
Expand Down Expand Up @@ -400,25 +401,43 @@ impl Item for TouchArea {
if !self.enabled() {
return InputEventResult::EventIgnored;
}
let result = if let MouseEvent::MouseReleased { pos, .. } = event {
if euclid::rect(0., 0., self.width(), self.height()).contains(pos) {
Self::FIELD_OFFSETS.clicked.apply_pin(self).call(&());
}
InputEventResult::EventAccepted
} else {
InputEventResult::GrabMouse
};
let result =
if let MouseEvent::MouseReleased { pos, button: PointerEventButton::left } = event {
if euclid::rect(0., 0., self.width(), self.height()).contains(pos) {
Self::FIELD_OFFSETS.clicked.apply_pin(self).call(&());
}
InputEventResult::EventAccepted
} else {
InputEventResult::GrabMouse
};

match event {
MouseEvent::MousePressed { pos } => {
Self::FIELD_OFFSETS.pressed_x.apply_pin(self).set(pos.x);
Self::FIELD_OFFSETS.pressed_y.apply_pin(self).set(pos.y);
Self::FIELD_OFFSETS.pressed.apply_pin(self).set(true);
Self::FIELD_OFFSETS.pressed_changed.apply_pin(self).call(&());
MouseEvent::MousePressed { pos, button } => {
if button == PointerEventButton::left {
Self::FIELD_OFFSETS.pressed_x.apply_pin(self).set(pos.x);
Self::FIELD_OFFSETS.pressed_y.apply_pin(self).set(pos.y);
Self::FIELD_OFFSETS.pressed.apply_pin(self).set(true);
}
Self::FIELD_OFFSETS
.pointer_event
.apply_pin(self)
.call(&(PointerEvent { button, kind: PointerEventKind::down },));
}
MouseEvent::MouseExit | MouseEvent::MouseReleased { .. } => {
MouseEvent::MouseExit => {
Self::FIELD_OFFSETS.pressed.apply_pin(self).set(false);
Self::FIELD_OFFSETS.pressed_changed.apply_pin(self).call(&());
Self::FIELD_OFFSETS.pointer_event.apply_pin(self).call(&(PointerEvent {
button: PointerEventButton::none,
kind: PointerEventKind::down,
},));
}
MouseEvent::MouseReleased { button, .. } => {
if button == PointerEventButton::left {
Self::FIELD_OFFSETS.pressed.apply_pin(self).set(false);
}
Self::FIELD_OFFSETS
.pointer_event
.apply_pin(self)
.call(&(PointerEvent { button, kind: PointerEventKind::down },));
}
MouseEvent::MouseMoved { .. } => {
return if self.pressed() {
Expand Down Expand Up @@ -1277,3 +1296,42 @@ impl Default for StandardButtonKind {
Self::ok
}
}

#[derive(Copy, Clone, Debug, PartialEq, strum_macros::EnumString, strum_macros::Display)]
#[repr(C)]
#[allow(non_camel_case_types)]
pub enum PointerEventKind {
cancel,
down,
up,
}

impl Default for PointerEventKind {
fn default() -> Self {
Self::cancel
}
}

#[derive(Copy, Clone, Debug, PartialEq, strum_macros::EnumString, strum_macros::Display)]
#[repr(C)]
#[allow(non_camel_case_types)]
pub enum PointerEventButton {
none,
left,
right,
middle,
}

impl Default for PointerEventButton {
fn default() -> Self {
Self::none
}
}

/// Represents a key event sent by the windowing system.
#[derive(Debug, Clone, PartialEq, Default)]
#[repr(C)]
pub struct PointerEvent {
pub button: PointerEventButton,
pub kind: PointerEventKind,
}
11 changes: 5 additions & 6 deletions sixtyfps_runtime/corelib/items/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ When adding an item or a property, it needs to be kept in sync with different pl
Lookup the [`crate::items`] module documentation.
*/

use super::{Item, ItemConsts, ItemRc, PointArg, VoidArg};
use super::{Item, ItemConsts, ItemRc, PointArg, PointerEventButton, VoidArg};
use crate::graphics::{Brush, Color, FontRequest, Rect};
use crate::input::{
FocusEvent, InputEventResult, KeyEvent, KeyEventResult, KeyEventType, KeyboardModifiers,
Expand Down Expand Up @@ -325,7 +325,7 @@ impl Item for TextInput {
return InputEventResult::EventIgnored;
}
match event {
MouseEvent::MousePressed { pos } => {
MouseEvent::MousePressed { pos, button: PointerEventButton::left } => {
let clicked_offset = window.text_input_byte_offset_for_position(self, pos) as i32;
self.as_ref().pressed.set(true);
self.as_ref().anchor_position.set(clicked_offset);
Expand All @@ -334,17 +334,16 @@ impl Item for TextInput {
window.clone().set_focus_item(self_rc);
}
}
MouseEvent::MouseReleased { .. } | MouseEvent::MouseExit => {
self.as_ref().pressed.set(false)
}
MouseEvent::MouseReleased { button: PointerEventButton::left, .. }
| MouseEvent::MouseExit => self.as_ref().pressed.set(false),
MouseEvent::MouseMoved { pos } => {
if self.as_ref().pressed.get() {
let clicked_offset =
window.text_input_byte_offset_for_position(self, pos) as i32;
self.set_cursor_position(clicked_offset, window);
}
}
MouseEvent::MouseWheel { .. } => return InputEventResult::EventIgnored,
_ => return InputEventResult::EventIgnored,
}
InputEventResult::EventAccepted
}
Expand Down
3 changes: 3 additions & 0 deletions sixtyfps_runtime/corelib/rtti.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ declare_ValueType![
crate::items::FillRule,
crate::items::StandardButtonKind,
crate::graphics::Point,
crate::items::PointerEvent,
crate::items::PointerEventButton,
crate::items::PointerEventKind,
];

/// What kind of animation is on a binding
Expand Down
Loading

0 comments on commit 2716e4b

Please sign in to comment.