Skip to content

Commit

Permalink
feat(core): 🎸Added grab_pointer to grabs all the pointer input
Browse files Browse the repository at this point in the history
  • Loading branch information
wjian23 committed Dec 13, 2024
1 parent 75df512 commit 7c2bb7b
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 30 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he

## [@Unreleased] - @ReleaseDate

### Features

- **core**: Added `grab_pointer` to grabs all the pointer input. (#pr @wjian23)

### Fixed
- **core**: fix mismatch of providers (#pr @wjian23)

Expand Down
4 changes: 2 additions & 2 deletions core/src/builtin_widgets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -959,13 +959,13 @@ impl<'a> FatObj<Widget<'a>> {
text_style,
scrollable,
layout_box,
mix_builtin,
request_focus,
class,
cursor,
constrained_box,
tooltips,
margin,
mix_builtin,
request_focus,
transform,
opacity,
visibility,
Expand Down
8 changes: 7 additions & 1 deletion core/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
};

pub(crate) mod dispatcher;
pub use dispatcher::{GrabPointerHandle, GrabPointerHandleGuard};
mod pointers;
pub use pointers::*;
use ribir_geom::Point;
Expand Down Expand Up @@ -166,6 +167,8 @@ pub enum Event {
/// The main difference between this event and focusout is that focusout emit
/// in bubbles phase but this event emit in capture phase.
FocusOutCapture(FocusEvent),
/// The dragstart event is fired when a drag operation is started.
Drag(DragEvent, DragEventType),
}

impl std::ops::Deref for Event {
Expand Down Expand Up @@ -197,6 +200,7 @@ impl std::ops::Deref for Event {
Event::Wheel(e) | Event::WheelCapture(e) => e,
Event::Chars(e) | Event::CharsCapture(e) => e,
Event::KeyDown(e) | Event::KeyDownCapture(e) | Event::KeyUp(e) | Event::KeyUpCapture(e) => e,
Event::Drag(e, _) => e,
}
}
}
Expand Down Expand Up @@ -228,6 +232,7 @@ impl std::ops::DerefMut for Event {
Event::Wheel(e) | Event::WheelCapture(e) => e,
Event::Chars(e) | Event::CharsCapture(e) => e,
Event::KeyDown(e) | Event::KeyDownCapture(e) | Event::KeyUp(e) | Event::KeyUpCapture(e) => e,
Event::Drag(e, _) => e,
}
}
}
Expand All @@ -246,7 +251,8 @@ impl Event {
| Event::PointerEnter(_)
| Event::PointerLeave(_)
| Event::Tap(_)
| Event::TapCapture(_) => MixFlags::Pointer,
| Event::TapCapture(_)
| Event::Drag(_, _) => MixFlags::Pointer,
Event::Wheel(_) | Event::WheelCapture(_) => MixFlags::Wheel,
Event::ImePreEdit(_)
| Event::ImePreEditCapture(_)
Expand Down
120 changes: 93 additions & 27 deletions core/src/events/dispatcher.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,55 @@
use std::{cell::RefCell, rc::Rc};

use winit::event::{DeviceId, ElementState, MouseButton, MouseScrollDelta, WindowEvent};

use crate::{
prelude::*,
window::{DelayEvent, WindowId},
};

pub struct GrabPointerHandle(Rc<RefCell<Option<WidgetId>>>);
impl GrabPointerHandle {
pub fn release(self) { self.0.borrow_mut().take(); }

pub fn guard(self) -> GrabPointerHandleGuard { GrabPointerHandleGuard(Some(self)) }
}

pub struct GrabPointerHandleGuard(Option<GrabPointerHandle>);

impl Drop for GrabPointerHandleGuard {
fn drop(&mut self) {
if let Some(h) = self.0.take() {
h.release();
}
}
}

pub(crate) struct Dispatcher {
wnd_id: WindowId,
pub(crate) info: DispatchInfo,
pub(crate) entered_widgets: Vec<WidgetId>,
pub(crate) pointer_down_uid: Option<WidgetId>,
grab_mouse_wid: Rc<RefCell<Option<WidgetId>>>,
pointer_down_wid: Option<WidgetId>,
}

impl Dispatcher {
pub fn new(wnd_id: WindowId) -> Self {
Self { wnd_id, info: <_>::default(), entered_widgets: vec![], pointer_down_uid: None }
Self {
wnd_id,
info: <_>::default(),
entered_widgets: vec![],
grab_mouse_wid: Rc::new(RefCell::new(None)),
pointer_down_wid: None,
}
}

pub(crate) fn grab_pointer(&self, wid: WidgetId) -> Option<GrabPointerHandle> {
if self.grab_mouse_wid.borrow().is_none() {
*self.grab_mouse_wid.borrow_mut() = Some(wid);
Some(GrabPointerHandle(self.grab_mouse_wid.clone()))
} else {
None
}
}

fn window(&self) -> Sc<Window> {
Expand Down Expand Up @@ -77,19 +112,63 @@ impl Dispatcher {
}
}

fn cursor_press_down(&mut self, hit: Option<WidgetId>) {
let grab_pointer = *self.grab_mouse_wid.borrow();
if let Some(grab_pointer) = grab_pointer {
self
.window()
.add_delay_event(DelayEvent::GrabPointerDown(grab_pointer));
} else {
self.pointer_down_wid = None;
if let Some(hit) = hit {
self.pointer_down_wid = Some(hit);
self
.window()
.add_delay_event(DelayEvent::PointerDown(hit));
}
}
}

fn cursor_press_up(&mut self, hit: Option<WidgetId>) {
let wnd = self.window();
let grab_pointer = *self.grab_mouse_wid.borrow();
if let Some(grab_pointer) = grab_pointer {
wnd.add_delay_event(DelayEvent::GrabPointerUp(grab_pointer));
} else {
if let Some(hit) = hit {
wnd.add_delay_event(DelayEvent::PointerUp(hit));
if let Some(wid) = self.pointer_down_wid {
if let Some(p) = wid.lowest_common_ancestor(hit, wnd.tree()) {
wnd.add_delay_event(DelayEvent::Tap(p));
}
}
}
self.pointer_down_wid = None;
}
}

pub fn cursor_move_to(&mut self, position: Point) {
self.info.cursor_pos = position;
self.pointer_enter_leave_dispatch();
if let Some(hit) = self.hit_widget() {
let grab_pointer = *self.grab_mouse_wid.borrow();
if let Some(grab_pointer) = grab_pointer {
self
.window()
.add_delay_event(DelayEvent::PointerMove(hit));
.add_delay_event(DelayEvent::GrabPointerMove(grab_pointer));
} else {
self.pointer_enter_leave_dispatch();
if let Some(hit) = self.hit_widget() {
self
.window()
.add_delay_event(DelayEvent::PointerMove(hit));
}
}
}

pub fn on_cursor_left(&mut self) {
self.info.cursor_pos = Point::new(-1., -1.);
self.pointer_enter_leave_dispatch();
if self.grab_mouse_wid.borrow().is_none() {
self.info.cursor_pos = Point::new(-1., -1.);
self.pointer_enter_leave_dispatch();
}
}

pub fn dispatch_mouse_input(
Expand All @@ -110,20 +189,9 @@ impl Dispatcher {
// only the last button release emit event.
if self.info.mouse_button.1.is_empty() {
self.info.mouse_button.0 = None;
let wnd = self.window();
let mut dispatch = |tree: &WidgetTree| {
let hit = self.hit_widget()?;
wnd.add_delay_event(DelayEvent::PointerUp(hit));

let tap_on = self
.pointer_down_uid
.take()?
.lowest_common_ancestor(hit, tree)?;
wnd.add_delay_event(DelayEvent::Tap(tap_on));
Some(())
};

dispatch(wnd.tree());
let hit = self.hit_widget();

self.cursor_press_up(hit);
}
}
};
Expand All @@ -148,11 +216,10 @@ impl Dispatcher {

fn bubble_pointer_down(&mut self) {
let hit = self.hit_widget();
self.pointer_down_uid = hit;
let wnd = self.window();
let tree = wnd.tree();

let nearest_focus = self.pointer_down_uid.and_then(|wid| {
let nearest_focus = hit.and_then(|wid| {
wid.ancestors(tree).find(|id| {
id.query_all_iter::<MixBuiltin>(tree)
.any(|m| m.contain_flag(MixFlags::Focus))
Expand All @@ -163,9 +230,8 @@ impl Dispatcher {
} else {
wnd.focus_mgr.borrow_mut().blur(tree);
}
if let Some(hit) = hit {
wnd.add_delay_event(DelayEvent::PointerDown(hit));
}

self.cursor_press_down(hit);
}

fn pointer_enter_leave_dispatch(&mut self) {
Expand Down Expand Up @@ -438,10 +504,10 @@ mod tests {
let w = fn_widget! {
@MockBox {
size: INFINITY_SIZE,
padding: EdgeInsets::all(4.),
on_pointer_enter: move |_| { $e_writer.write().push(2); },
on_pointer_leave: move |_| { $l_writer.write().push(2); },
@MockBox {
margin: EdgeInsets::all(4.),
size: INFINITY_SIZE,
on_pointer_enter: move |_| { $e_writer.write().push(1); },
on_pointer_leave: move |_| { $l_writer.write().push(1); }
Expand Down
15 changes: 15 additions & 0 deletions core/src/events/pointers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,21 @@ pub struct PointerEvent {
pub common: CommonEvent,
}

/// The drag event type
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DragEventType {
/// Indicates the start of drag
Start,

/// Indicates the drag is moving
Move,

/// Indicates the end of drag
End,
}

pub type DragEvent = PointerEvent;

bitflags! {
#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
pub struct MouseButtons: u8 {
Expand Down
26 changes: 26 additions & 0 deletions core/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::{
ptr::NonNull,
};

use dispatcher::GrabPointerHandle;
use futures::{Future, task::LocalSpawnExt};
use ribir_algo::Sc;
use widget_id::TrackId;
Expand Down Expand Up @@ -194,6 +195,15 @@ impl Window {
.set(self.running_animates.get() - 1);
}

/// Grabs the pointer input.
///
/// The widget corresponding to the wid will receives all pointer events
/// (on_pointer_down, on_pointer_move, and on_pointer_up) until the handle's
/// release() is called; other widgets get no pointer events at all.
pub fn grab_pointer(&self, wid: WidgetId) -> Option<GrabPointerHandle> {
self.dispatcher.borrow().grab_pointer(wid)
}

/// Draw an image what current render tree represent.
#[track_caller]
pub fn draw_frame(&self) -> bool {
Expand Down Expand Up @@ -550,6 +560,19 @@ impl Window {
let Event::ImePreEditCapture(e) = e else { unreachable!() };
self.bottom_up_emit(&mut Event::ImePreEdit(e), wid, None);
}

DelayEvent::GrabPointerDown(wid) => {
let mut e = Event::PointerDown(PointerEvent::from_mouse(wid, self));
self.emit(wid, &mut e);
}
DelayEvent::GrabPointerMove(wid) => {
let mut e = Event::PointerMove(PointerEvent::from_mouse(wid, self));
self.emit(wid, &mut e);
}
DelayEvent::GrabPointerUp(wid) => {
let mut e = Event::PointerUp(PointerEvent::from_mouse(wid, self));
self.emit(wid, &mut e);
}
}
}
}
Expand Down Expand Up @@ -774,6 +797,9 @@ pub(crate) enum DelayEvent {
PointerLeave { bottom: WidgetId, up: Option<WidgetId> },
Tap(WidgetId),
ImePreEdit { wid: WidgetId, pre_edit: ImePreEdit },
GrabPointerDown(WidgetId),
GrabPointerMove(WidgetId),
GrabPointerUp(WidgetId),
}

impl From<u64> for WindowId {
Expand Down
2 changes: 2 additions & 0 deletions macros/src/declare_derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,8 @@ pub(crate) fn declare_derive(input: &mut syn::DeriveInput) -> syn::Result<TokenS
self.fat_obj = self.fat_obj.tooltips(v);
self
}


}
}
};
Expand Down

0 comments on commit 7c2bb7b

Please sign in to comment.