mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-04 18:58:36 +00:00
parent
2f4e110111
commit
4c0a435196
12 changed files with 116 additions and 19 deletions
|
@ -17,6 +17,7 @@ All notable changes to this project are documented in this file.
|
|||
- Added `Number`, `Decimal` variant to enum `InputType`
|
||||
- Added `spacing-horizontal` and `spacing-vertical` in `GridLayout`
|
||||
- Fixed conversion in array of array of structs (#3574)
|
||||
- Added `scroll-event` callback to `TouchArea`
|
||||
|
||||
### Rust API
|
||||
|
||||
|
|
|
@ -186,6 +186,7 @@ fn default_config() -> cbindgen::Config {
|
|||
("VoidArg".into(), "void".into()),
|
||||
("KeyEventArg".into(), "KeyEvent".into()),
|
||||
("PointerEventArg".into(), "PointerEvent".into()),
|
||||
("PointerScrollEventArg".into(), "PointerScrollEvent".into()),
|
||||
("PointArg".into(), "slint::LogicalPosition".into()),
|
||||
("FloatArg".into(), "float".into()),
|
||||
("Coord".into(), "float".into()),
|
||||
|
@ -277,6 +278,7 @@ fn gen_corelib(
|
|||
"PointerEventKind",
|
||||
"PointerEventButton",
|
||||
"PointerEvent",
|
||||
"PointerScrollEvent",
|
||||
"Rect",
|
||||
"SortOrder",
|
||||
"BitmapFont",
|
||||
|
@ -325,6 +327,7 @@ fn gen_corelib(
|
|||
"VoidArg",
|
||||
"KeyEventArg",
|
||||
"PointerEventArg",
|
||||
"PointerScrollEventArg",
|
||||
"PointArg",
|
||||
"Point",
|
||||
"slint_color_brighter",
|
||||
|
|
|
@ -59,6 +59,7 @@ using ItemArray = slint::cbindgen_private::Slice<ItemArrayEntry>;
|
|||
using cbindgen_private::KeyboardModifiers;
|
||||
using cbindgen_private::KeyEvent;
|
||||
using cbindgen_private::PointerEvent;
|
||||
using cbindgen_private::PointerScrollEvent;
|
||||
using cbindgen_private::TableColumn;
|
||||
|
||||
constexpr inline ItemTreeNode make_item_node(uint32_t child_count, uint32_t child_index,
|
||||
|
|
|
@ -145,8 +145,7 @@ widgets, then the following algorithm is used to distinguish between the user's
|
|||
interacting with `TouchArea` elements:
|
||||
|
||||
1. If the `Flickable`'s `interactive` property is `false`, all events are forwarded to elements underneath.
|
||||
2. Any wheel events are interpreted as attempt of the user to scroll.
|
||||
3. If a press event is received where the event's coordinates interact with a `TouchArea`, the event is stored
|
||||
2. If a press event is received where the event's coordinates interact with a `TouchArea`, the event is stored
|
||||
and any subsequent move and release events are handled as follows:
|
||||
1. If 100ms elapse without any events, the stored press event is delivered to the `TouchArea`.
|
||||
2. If a release event is received before 100ms have elapsed, the stored press event as well as the
|
||||
|
@ -157,7 +156,7 @@ interacting with `TouchArea` elements:
|
|||
2. The distance to the press event exceeds 8 logical pixels in an orientation in which we are allowed to move.
|
||||
If `Flickable` decides to flick, any press event sent previously to a `TouchArea`, is followed up
|
||||
by an exit event. During the phase of receiving move events, the flickable follows the coordinates.
|
||||
4. If the interaction of press, move, and release events begins at coordinates that do not intersect with
|
||||
3. If the interaction of press, move, and release events begins at coordinates that do not intersect with
|
||||
a `TouchArea`, then `Flickable` will flick immediately on pointer move events when the euclidean distance
|
||||
to the coordinates of the press event exceeds 8 logical pixels.
|
||||
|
||||
|
@ -246,7 +245,7 @@ Alternatively, the item can be put in a `Row` element.
|
|||
### Properties
|
||||
|
||||
- **`spacing`** (_in_ _length_): The distance between the elements in the layout.
|
||||
- **`spacing-horizontal`**, **`spacing-vertical`** (_in_ _length_):
|
||||
- **`spacing-horizontal`**, **`spacing-vertical`** (_in_ _length_):
|
||||
Set these properties to override the spacing on specific directions.
|
||||
- **`padding`** (_in_ _length_): The padding within the layout.
|
||||
- **`padding-left`**, **`padding-right`**, **`padding-top`** and **`padding-bottom`** (_in_ _length_):
|
||||
|
@ -753,8 +752,12 @@ When not part of a layout, its width or height default to 100% of the parent ele
|
|||
|
||||
- **`clicked()`**: Invoked 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.
|
||||
- **`pointer-event(PointerEvent)`**: Invoked when a button was pressed or released The [_`PointerEvent`_](structs.md#pointerevent)
|
||||
- **`pointer-event(PointerEvent)`**: Invoked when a button was pressed or released. The [_`PointerEvent`_](structs.md#pointerevent)
|
||||
argument contains information such which button was pressed and any active keyboard modifiers.
|
||||
- **`scroll-event(PointerScrollEvent) -> EventResult`**: Invoked when the mouse wheel was rotated or another scroll gesture was made.
|
||||
The [_`PointerEvent`_](structs.md#pointerscrollevent) argument contains information about how much to scroll in what direction.
|
||||
The returned [`EventResult`](enums.md#eventresult) indicates whether to accept or ignore the event. Ignored events are
|
||||
forwarded to the parent element.
|
||||
|
||||
### Example
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ macro_rules! for_each_builtin_structs {
|
|||
}
|
||||
|
||||
/// Represents a Pointer event sent by the windowing system.
|
||||
/// This structure is generated and passed to the `pointer-event` callback of the `TouchArea` element.
|
||||
/// This structure is passed to the `pointer-event` callback of the `TouchArea` element.
|
||||
struct PointerEvent {
|
||||
@name = "slint::private_api::PointerEvent"
|
||||
export {
|
||||
|
@ -66,6 +66,22 @@ macro_rules! for_each_builtin_structs {
|
|||
}
|
||||
}
|
||||
|
||||
/// Represents a Pointer scroll (or wheel) event sent by the windowing system.
|
||||
/// This structure is passed to the `scroll-event` callback of the `TouchArea` element.
|
||||
struct PointerScrollEvent {
|
||||
@name = "slint::private_api::PointerScrollEvent"
|
||||
export {
|
||||
/// The amount of pixel in the horizontal direction
|
||||
delta_x: Coord,
|
||||
/// The amount of pixel in the vertical direction
|
||||
delta_y: Coord,
|
||||
/// The keyboard modifiers pressed during the event
|
||||
modifiers: KeyboardModifiers,
|
||||
}
|
||||
private {
|
||||
}
|
||||
}
|
||||
|
||||
/// This structure is generated and passed to the key press and release callbacks of the `FocusScope` element.
|
||||
struct KeyEvent {
|
||||
@name = "slint::private_api::KeyEvent"
|
||||
|
|
|
@ -100,6 +100,7 @@ export component TouchArea {
|
|||
callback clicked;
|
||||
callback moved;
|
||||
callback pointer-event(PointerEvent);
|
||||
callback scroll-event(PointerScrollEvent) -> EventResult;
|
||||
//-default_size_binding:expands_to_parent_geometry
|
||||
}
|
||||
|
||||
|
|
|
@ -473,8 +473,8 @@ impl Window {
|
|||
crate::platform::WindowEvent::PointerScrolled { position, delta_x, delta_y } => {
|
||||
self.0.process_mouse_input(MouseEvent::Wheel {
|
||||
position: position.to_euclid().cast(),
|
||||
delta_x,
|
||||
delta_y,
|
||||
delta_x: delta_x as _,
|
||||
delta_y: delta_y as _,
|
||||
});
|
||||
}
|
||||
crate::platform::WindowEvent::PointerExited => {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
#![warn(missing_docs)]
|
||||
|
||||
use crate::component::ComponentRc;
|
||||
use crate::item_tree::{ItemRc, ItemWeak, VisitChildrenResult};
|
||||
pub use crate::items::PointerEventButton;
|
||||
use crate::items::{ItemRef, TextCursorDirection};
|
||||
|
@ -12,8 +13,7 @@ pub use crate::items::{KeyEvent, KeyboardModifiers};
|
|||
use crate::lengths::{LogicalPoint, LogicalVector};
|
||||
use crate::timers::Timer;
|
||||
use crate::window::{WindowAdapter, WindowInner};
|
||||
use crate::Property;
|
||||
use crate::{component::ComponentRc, SharedString};
|
||||
use crate::{Coord, Property, SharedString};
|
||||
use alloc::rc::Rc;
|
||||
use alloc::vec::Vec;
|
||||
use const_field_offset::FieldOffsets;
|
||||
|
@ -44,7 +44,7 @@ pub enum MouseEvent {
|
|||
/// `pos` is the position of the mouse when the event happens.
|
||||
/// `delta_x` is the amount of pixels to scroll in horizontal direction,
|
||||
/// `delta_y` is the amount of pixels to scroll in vertical direction.
|
||||
Wheel { position: LogicalPoint, delta_x: f32, delta_y: f32 },
|
||||
Wheel { position: LogicalPoint, delta_x: Coord, delta_y: Coord },
|
||||
/// The mouse exited the item or component
|
||||
Exit,
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ type ItemRendererRef<'a> = &'a mut dyn crate::item_rendering::ItemRenderer;
|
|||
pub type VoidArg = ();
|
||||
pub type KeyEventArg = (KeyEvent,);
|
||||
type PointerEventArg = (PointerEvent,);
|
||||
type PointerScrollEventArg = (PointerScrollEvent,);
|
||||
type PointArg = (Point,);
|
||||
|
||||
#[cfg(all(feature = "ffi", windows))]
|
||||
|
@ -425,6 +426,7 @@ pub struct TouchArea {
|
|||
pub clicked: Callback<VoidArg>,
|
||||
pub moved: Callback<VoidArg>,
|
||||
pub pointer_event: Callback<PointerEventArg>,
|
||||
pub scroll_event: Callback<PointerScrollEventArg, EventResult>,
|
||||
/// FIXME: remove this
|
||||
pub cached_rendering_data: CachedRenderingData,
|
||||
/// true when we are currently grabbing the mouse
|
||||
|
@ -536,12 +538,20 @@ impl Item for TouchArea {
|
|||
InputEventResult::EventAccepted
|
||||
}
|
||||
}
|
||||
MouseEvent::Wheel { .. } => {
|
||||
MouseEvent::Wheel { delta_x, delta_y, .. } => {
|
||||
let modifiers = window_adapter.window().0.modifiers.get().into();
|
||||
let r = Self::FIELD_OFFSETS
|
||||
.scroll_event
|
||||
.apply_pin(self)
|
||||
.call(&(PointerScrollEvent { delta_x, delta_y, modifiers },));
|
||||
return if self.grabbed.get() {
|
||||
InputEventResult::GrabMouse
|
||||
} else {
|
||||
InputEventResult::EventAccepted
|
||||
}
|
||||
match r {
|
||||
EventResult::Reject => InputEventResult::EventIgnored,
|
||||
EventResult::Accept => InputEventResult::EventAccepted,
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
result
|
||||
|
|
|
@ -251,9 +251,7 @@ impl FlickableData {
|
|||
InputEventFilterResult::ForwardEvent
|
||||
}
|
||||
}
|
||||
MouseEvent::Wheel { position, .. } => {
|
||||
InputEventFilterResult::InterceptAndDispatch(MouseEvent::Moved { position })
|
||||
}
|
||||
MouseEvent::Wheel { .. } => InputEventFilterResult::ForwardEvent,
|
||||
// Not the left button
|
||||
MouseEvent::Pressed { .. } | MouseEvent::Released { .. } => {
|
||||
InputEventFilterResult::ForwardAndIgnore
|
||||
|
@ -324,9 +322,9 @@ impl FlickableData {
|
|||
&& !cfg!(target_os = "macos")
|
||||
{
|
||||
// Shift invert coordinate for the purpose of scrolling. But not on macOs because there the OS already take care of the change
|
||||
LogicalVector::new(delta_y as _, delta_x as _)
|
||||
LogicalVector::new(delta_y, delta_x)
|
||||
} else {
|
||||
LogicalVector::new(delta_x as _, delta_y as _)
|
||||
LogicalVector::new(delta_x, delta_y)
|
||||
};
|
||||
let new_pos = ensure_in_bound(flick, old_pos + delta, flick_rc);
|
||||
(Flickable::FIELD_OFFSETS.viewport_x).apply_pin(flick).set(new_pos.x_length());
|
||||
|
|
|
@ -42,6 +42,7 @@ macro_rules! declare_ValueType_2 {
|
|||
crate::Brush,
|
||||
crate::graphics::Point,
|
||||
crate::items::PointerEvent,
|
||||
crate::items::PointerScrollEvent,
|
||||
crate::lengths::LogicalLength,
|
||||
crate::component_factory::ComponentFactory,
|
||||
$(crate::items::$Name,)*
|
||||
|
|
63
tests/cases/input/scroll-event.slint
Normal file
63
tests/cases/input/scroll-event.slint
Normal file
|
@ -0,0 +1,63 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
|
||||
|
||||
|
||||
export component TestCase inherits Window {
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
in-out property<string> result;
|
||||
f := Flickable {
|
||||
viewport_width: 2100px;
|
||||
viewport_height: 2100px;
|
||||
ta1 := TouchArea {
|
||||
x: 20px;
|
||||
y: 20px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
Rectangle { background: red; }
|
||||
scroll-event(e) => {
|
||||
result += "ta1{" + e.delta-x/1px + "," + e.delta-y/1px + " at " + self.mouse-x/1px + "," + self.mouse-y/1px + "}";
|
||||
accept
|
||||
}
|
||||
}
|
||||
|
||||
ta2 := TouchArea {
|
||||
x: 120px;
|
||||
y: 20px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
Rectangle { background: green; }
|
||||
scroll-event(e) => {
|
||||
result += "ta2{" + e.delta-x/1px + "," + e.delta-y/1px + " at " + self.mouse-x/1px + "," + self.mouse-y/1px + "}";
|
||||
EventResult.reject
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
out property<length> offset_x: -f.viewport_x;
|
||||
out property<length> offset_y: -f.viewport_y;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
|
||||
```rust
|
||||
// Test wheel events
|
||||
use slint::{LogicalPosition, platform::WindowEvent };
|
||||
let instance = TestCase::new().unwrap();
|
||||
|
||||
instance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(25.0, 30.0), delta_x: -3.0, delta_y: -50.0 });
|
||||
assert_eq!(instance.get_result(), "ta1{-3,-50 at 5,10}");
|
||||
assert_eq!(instance.get_offset_y(), 0.0);
|
||||
assert_eq!(instance.get_offset_x(), 0.0);
|
||||
|
||||
instance.set_result("".into());
|
||||
|
||||
instance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(155.0, 50.0), delta_x: -30.0, delta_y: -50.0 });
|
||||
assert_eq!(instance.get_result(), "ta2{-30,-50 at 35,30}");
|
||||
assert_eq!(instance.get_offset_x(), 30.0);
|
||||
assert_eq!(instance.get_offset_y(), 50.0);
|
||||
```
|
||||
|
||||
*/
|
Loading…
Add table
Add a link
Reference in a new issue