Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ While some features like the clipboard, menus or file dialogs are not yet availa
- `request_timer` uses `Duration` instead of `Instant`. ([#847] by [@finnerale])
- Global `Application` associated functions are instance methods instead, e.g. `Application::global().quit()` instead of the old `Application::quit()`. ([#763] by [@xStrom])
- Timer events will only be delivered to the widgets that requested them. ([#831] by [@sjoshid])
- `Event::Wheel` now contains a `MouseEvent` structure. ([#895] by [@teddemunnik])

### Deprecated

Expand Down Expand Up @@ -148,6 +149,7 @@ While some features like the clipboard, menus or file dialogs are not yet availa
[#889]: https://github.com/xi-editor/druid/pull/889
[#892]: https://github.com/xi-editor/druid/pull/892
[#894]: https://github.com/xi-editor/druid/pull/894
[#895]: https://github.com/xi-editor/druid/pull/895
[#897]: https://github.com/xi-editor/druid/pull/897
[#898]: https://github.com/xi-editor/druid/pull/898
[#900]: https://github.com/xi-editor/druid/pull/900
Expand Down
10 changes: 5 additions & 5 deletions druid-shell/examples/shello.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@

use std::any::Any;

use druid_shell::kurbo::{Line, Rect, Vec2};
use druid_shell::kurbo::{Line, Rect};
use druid_shell::piet::{Color, RenderContext};

use druid_shell::{
Application, Cursor, FileDialogOptions, FileSpec, HotKey, KeyEvent, KeyModifiers, Menu,
MouseEvent, SysMods, TimerToken, WinHandler, WindowBuilder, WindowHandle,
Application, Cursor, FileDialogOptions, FileSpec, HotKey, KeyEvent, Menu, MouseEvent, SysMods,
TimerToken, WinHandler, WindowBuilder, WindowHandle,
};

const BG_COLOR: Color = Color::rgb8(0x27, 0x28, 0x22);
Expand Down Expand Up @@ -71,8 +71,8 @@ impl WinHandler for HelloState {
false
}

fn wheel(&mut self, delta: Vec2, mods: KeyModifiers) {
println!("mouse_wheel {:?} {:?}", delta, mods);
fn wheel(&mut self, event: &MouseEvent) {
println!("mouse_wheel {:?}", event);
}

fn mouse_move(&mut self, event: &MouseEvent) {
Expand Down
11 changes: 10 additions & 1 deletion druid-shell/src/mouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

//! Common types for representing mouse events and state

use crate::kurbo::Point;
use crate::kurbo::{Point, Vec2};

use crate::keyboard::KeyModifiers;

Expand All @@ -38,6 +38,15 @@ pub struct MouseEvent {
/// or the button that was released in the case of mouse-up.
/// This will always be `MouseButton::None` in the case of mouse-move.
pub button: MouseButton,
/// The wheel movement.
///
/// The polarity is the amount to be added to the scroll position,
/// in other words the opposite of the direction the content should
/// move on scrolling. This polarity is consistent with the
/// deltaX and deltaY values in a web [WheelEvent].
///
/// [WheelEvent]: https://w3c.github.io/uievents/#event-type-wheel
pub wheel_delta: Vec2,
}

/// An indicator of which mouse button was pressed.
Expand Down
52 changes: 28 additions & 24 deletions druid-shell/src/platform/gtk/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ impl WindowBuilder {
mods: get_modifiers(button_state),
count: get_mouse_click_count(event.get_event_type()),
button,
wheel_delta: Vec2::ZERO
},
);
}
Expand All @@ -320,6 +321,7 @@ impl WindowBuilder {
mods: get_modifiers(button_state),
count: 0,
button,
wheel_delta: Vec2::ZERO
},
);
}
Expand All @@ -340,6 +342,7 @@ impl WindowBuilder {
mods: get_modifiers(motion_state),
count: 0,
button: MouseButton::None,
wheel_delta: Vec2::ZERO
};

if let Ok(mut handler) = state.handler.try_borrow_mut() {
Expand All @@ -361,6 +364,7 @@ impl WindowBuilder {
mods: get_modifiers(crossing_state),
count: 0,
button: MouseButton::None,
wheel_delta: Vec2::ZERO
};

if let Ok(mut handler) = state.handler.try_borrow_mut() {
Expand All @@ -377,48 +381,48 @@ impl WindowBuilder {
if let Some(state) = handle.state.upgrade() {
if let Ok(mut handler) = state.handler.try_borrow_mut() {

let modifiers = get_modifiers(scroll.get_state());
let mods = get_modifiers(scroll.get_state());

// The magic "120"s are from Microsoft's documentation for WM_MOUSEWHEEL.
// They claim that one "tick" on a scroll wheel should be 120 units.
match scroll.get_direction() {
ScrollDirection::Up => {
if modifiers.shift {
handler.wheel(Vec2::from((-120.0, 0.0)), modifiers);
} else {
handler.wheel(Vec2::from((0.0, -120.0)), modifiers);
}
}
ScrollDirection::Down => {
if modifiers.shift {
handler.wheel(Vec2::from((120.0, 0.0)), modifiers);
} else {
handler.wheel(Vec2::from((0.0, 120.0)), modifiers);
}
}
ScrollDirection::Left => {
handler.wheel(Vec2::from((-120.0, 0.0)), modifiers);
}
ScrollDirection::Right => {
handler.wheel(Vec2::from((120.0, 0.0)), modifiers);
}
let wheel_delta = match scroll.get_direction() {
ScrollDirection::Up if mods.shift => Some(Vec2::new(-120.0, 0.0)),
ScrollDirection::Up => Some(Vec2::new(0.0, -120.0)),
ScrollDirection::Down if mods.shift => Some(Vec2::new(120.0, 0.0)),
ScrollDirection::Down => Some(Vec2::new(0.0, 120.0)),
ScrollDirection::Left => Some(Vec2::new(-120.0, 0.0)),
ScrollDirection::Right => Some(Vec2::new(120.0, 0.0)),
ScrollDirection::Smooth => {
//TODO: Look at how gtk's scroll containers implements it
let (mut delta_x, mut delta_y) = scroll.get_delta();
delta_x *= 120.;
delta_y *= 120.;
if modifiers.shift {
if mods.shift {
delta_x += delta_y;
delta_y = 0.;
}
handler.wheel(Vec2::from((delta_x, delta_y)), modifiers)
Some(Vec2::new(delta_x, delta_y))
}
e => {
eprintln!(
"Warning: the Druid widget got some whacky scroll direction {:?}",
e
);
None
}
};

if let Some(wheel_delta) = wheel_delta{
let mouse_event = MouseEvent{
pos: Point::from(scroll.get_position()),
buttons: get_mouse_buttons_from_modifiers(scroll.get_state()),
mods,
count: 0,
button: MouseButton::None,
wheel_delta
};

handler.wheel(&mouse_event);
}
} else {
log::info!("GTK event was dropped because the handler was already borrowed");
Expand Down
21 changes: 13 additions & 8 deletions druid-shell/src/platform/mac/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,13 @@ extern "C" fn set_frame_size(this: &mut Object, _: Sel, size: NSSize) {
}
}

fn mouse_event(nsevent: id, view: id, count: u8, button: MouseButton) -> MouseEvent {
fn mouse_event(
nsevent: id,
view: id,
count: u8,
button: MouseButton,
wheel_delta: Vec2,
) -> MouseEvent {
unsafe {
let point = nsevent.locationInWindow();
let view_point = view.convertPoint_fromView_(point, nil);
Expand All @@ -373,6 +379,7 @@ fn mouse_event(nsevent: id, view: id, count: u8, button: MouseButton) -> MouseEv
mods: modifiers,
count,
button,
wheel_delta,
}
}
}
Expand Down Expand Up @@ -429,7 +436,7 @@ fn mouse_down(this: &mut Object, nsevent: id, button: MouseButton) {
let view_state: *mut c_void = *this.get_ivar("viewState");
let view_state = &mut *(view_state as *mut ViewState);
let count = nsevent.clickCount() as u8;
let event = mouse_event(nsevent, this as id, count, button);
let event = mouse_event(nsevent, this as id, count, button, Vec2::ZERO);
(*view_state).handler.mouse_down(&event);
}
}
Expand All @@ -454,7 +461,7 @@ fn mouse_up(this: &mut Object, nsevent: id, button: MouseButton) {
unsafe {
let view_state: *mut c_void = *this.get_ivar("viewState");
let view_state = &mut *(view_state as *mut ViewState);
let event = mouse_event(nsevent, this as id, 0, button);
let event = mouse_event(nsevent, this as id, 0, button, Vec2::ZERO);
(*view_state).handler.mouse_up(&event);
}
}
Expand All @@ -463,7 +470,7 @@ extern "C" fn mouse_move(this: &mut Object, _: Sel, nsevent: id) {
unsafe {
let view_state: *mut c_void = *this.get_ivar("viewState");
let view_state = &mut *(view_state as *mut ViewState);
let event = mouse_event(nsevent, this as id, 0, MouseButton::None);
let event = mouse_event(nsevent, this as id, 0, MouseButton::None, Vec2::ZERO);
(*view_state).handler.mouse_move(&event);
}
}
Expand All @@ -481,11 +488,9 @@ extern "C" fn scroll_wheel(this: &mut Object, _: Sel, nsevent: id) {
(dx * 32.0, dy * 32.0)
}
};
let mods = nsevent.modifierFlags();
let mods = make_modifiers(mods);

let delta = Vec2::new(dx, dy);
(*view_state).handler.wheel(delta, mods);
let event = mouse_event(nsevent, this as id, 0, MouseButton::None, Vec2::new(dx, dy));
(*view_state).handler.wheel(&event);
}
}

Expand Down
33 changes: 21 additions & 12 deletions druid-shell/src/platform/web/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ fn setup_mouse_down_callback(ws: &Rc<WindowState>) {
mods: get_modifiers!(event),
count: 1,
button,
wheel_delta: Vec2::ZERO,
};
state.handler.borrow_mut().mouse_down(&event);
}
Expand All @@ -165,6 +166,7 @@ fn setup_mouse_up_callback(ws: &Rc<WindowState>) {
mods: get_modifiers!(event),
count: 0,
button,
wheel_delta: Vec2::ZERO,
};
state.handler.borrow_mut().mouse_up(&event);
}
Expand All @@ -181,6 +183,7 @@ fn setup_mouse_move_callback(ws: &Rc<WindowState>) {
mods: get_modifiers!(event),
count: 0,
button: MouseButton::None,
wheel_delta: Vec2::ZERO,
};
state.handler.borrow_mut().mouse_move(&event);
});
Expand All @@ -196,20 +199,26 @@ fn setup_scroll_callback(ws: &Rc<WindowState>) {
let height = state.canvas.height() as f64;
let width = state.canvas.width() as f64;

let modifiers = get_modifiers!(event);
let mut handler = state.handler.borrow_mut();

// The value 35.0 was manually picked to produce similar behavior to mac/linux.
match delta_mode {
web_sys::WheelEvent::DOM_DELTA_PIXEL => handler.wheel(Vec2::from((dx, dy)), modifiers),
web_sys::WheelEvent::DOM_DELTA_LINE => {
handler.wheel(Vec2::from((35.0 * dx, 35.0 * dy)), modifiers)
}
web_sys::WheelEvent::DOM_DELTA_PAGE => {
handler.wheel(Vec2::from((width * dx, height * dy)), modifiers)
let wheel_delta = match delta_mode {
web_sys::WheelEvent::DOM_DELTA_PIXEL => Vec2::new(dx, dy),
web_sys::WheelEvent::DOM_DELTA_LINE => Vec2::new(35.0 * dx, 35.0 * dy),
web_sys::WheelEvent::DOM_DELTA_PAGE => Vec2::new(width * dx, height * dy),
_ => {
log::warn!("Invalid deltaMode in WheelEvent: {}", delta_mode);
return;
}
_ => log::warn!("Invalid deltaMode in WheelEvent: {}", delta_mode),
}
};

let event = MouseEvent {
pos: Point::new(event.offset_x() as f64, event.offset_y() as f64),
buttons: mouse_buttons(event.buttons()),
mods: get_modifiers!(event),
count: 0,
button: MouseButton::None,
wheel_delta,
};
state.handler.borrow_mut().wheel(&event);
});
}

Expand Down
63 changes: 43 additions & 20 deletions druid-shell/src/platform/windows/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -655,31 +655,52 @@ impl WndProc for MyWndProc {
Some(0)
}
//TODO: WM_SYSCOMMAND
WM_MOUSEWHEEL => {
WM_MOUSEWHEEL | WM_MOUSEHWHEEL => {
// TODO: apply mouse sensitivity based on
// SPI_GETWHEELSCROLLLINES setting.
if let Ok(mut s) = self.state.try_borrow_mut() {
let s = s.as_mut().unwrap();
let delta_y = HIWORD(wparam as u32) as i16 as f64;
let mods = get_mod_state();
let delta = if mods.shift {
Vec2::new(-delta_y, 0.)
} else {
Vec2::new(0., -delta_y)
let system_delta = HIWORD(wparam as u32) as i16 as f64;
let down_state = LOWORD(wparam as u32) as usize;
let mods = KeyModifiers {
shift: down_state & MK_SHIFT != 0,
alt: get_mod_state_alt(),
ctrl: down_state & MK_CONTROL != 0,
meta: get_mod_state_win(),
};
s.handler.wheel(delta, mods);
} else {
self.log_dropped_msg(hwnd, msg, wparam, lparam);
}
Some(0)
}
WM_MOUSEHWHEEL => {
if let Ok(mut s) = self.state.try_borrow_mut() {
let s = s.as_mut().unwrap();
let delta_x = HIWORD(wparam as u32) as i16 as f64;
let delta = Vec2::new(delta_x, 0.0);
let mods = get_mod_state();
s.handler.wheel(delta, mods);
let wheel_delta = match msg {
WM_MOUSEWHEEL if mods.shift => Vec2::new(-system_delta, 0.),
WM_MOUSEWHEEL => Vec2::new(0., -system_delta),
WM_MOUSEHWHEEL => Vec2::new(system_delta, 0.),
_ => unreachable!(),
};

let mut p = POINT {
x: LOWORD(lparam as u32) as i16 as i32,
y: HIWORD(lparam as u32) as i16 as i32,
};
unsafe {
if ScreenToClient(hwnd, &mut p) == FALSE {
log::warn!(
"ScreenToClient failed: {}",
Error::Hr(HRESULT_FROM_WIN32(GetLastError()))
);
return None;
}
}

let (px, py) = self.handle.borrow().pixels_to_px_xy(p.x, p.y);
let pos = Point::new(px as f64, py as f64);
let buttons = get_buttons(down_state);
let event = MouseEvent {
pos,
mods,
button: MouseButton::None,
count: 0,
wheel_delta,
buttons,
};
s.handler.wheel(&event);
} else {
self.log_dropped_msg(hwnd, msg, wparam, lparam);
}
Expand Down Expand Up @@ -729,6 +750,7 @@ impl WndProc for MyWndProc {
mods,
count: 0,
button: MouseButton::None,
wheel_delta: Vec2::ZERO,
};
s.handler.mouse_move(&event);
} else {
Expand Down Expand Up @@ -795,6 +817,7 @@ impl WndProc for MyWndProc {
mods,
count,
button,
wheel_delta: Vec2::ZERO,
};
if count > 0 {
s.enter_mouse_capture(hwnd, button);
Expand Down
Loading