Skip to content

Commit

Permalink
Add support for more mouse buttons and tracking holding. (#843)
Browse files Browse the repository at this point in the history
  • Loading branch information
xStrom authored Apr 30, 2020
1 parent 9768b92 commit 3445361
Show file tree
Hide file tree
Showing 12 changed files with 518 additions and 213 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ While some features like the clipboard, menus or file dialogs are not yet availa
- Window title can be any `LabelText` (such as a simple `String`). ([#869] by [@cmyr])
- `Label::with_font` and `set_font`. ([#785] by [@thecodewarrior])
- `InternalEvent::RouteTimer` to route timer events. ([#831] by [@sjoshid])
- `MouseButtons` to `MouseEvent` to track which buttons are being held down during an event. ([#843] by [@xStrom])

### Changed

Expand Down Expand Up @@ -65,6 +66,7 @@ While some features like the clipboard, menus or file dialogs are not yet availa
- Supply correct `LifeCycleCtx` to `Event::FocusChanged`. ([#878] by [@cmyr])
- Windows: Termiate app when all windows have closed. ([#763] by [@xStrom])
- macOS: `Application::quit` now quits the run loop instead of killing the process. ([#763] by [@xStrom])
- macOS/GTK/web: `MouseButton::X1` and `MouseButton::X2` clicks are now recognized. ([#843] by [@xStrom])

### Visual

Expand Down Expand Up @@ -123,6 +125,7 @@ While some features like the clipboard, menus or file dialogs are not yet availa
[#839]: https://github.com/xi-editor/druid/pull/839
[#840]: https://github.com/xi-editor/druid/pull/840
[#841]: https://github.com/xi-editor/druid/pull/841
[#843]: https://github.com/xi-editor/druid/pull/843
[#845]: https://github.com/xi-editor/druid/pull/845
[#847]: https://github.com/xi-editor/druid/pull/847
[#850]: https://github.com/xi-editor/druid/pull/850
Expand Down
2 changes: 1 addition & 1 deletion druid-shell/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub use hotkey::{HotKey, KeyCompare, RawMods, SysMods};
pub use keyboard::{KeyEvent, KeyModifiers};
pub use keycodes::KeyCode;
pub use menu::Menu;
pub use mouse::{Cursor, MouseButton, MouseEvent};
pub use mouse::{Cursor, MouseButton, MouseButtons, MouseEvent};
pub use window::{
IdleHandle, IdleToken, Text, TimerToken, WinHandler, WindowBuilder, WindowHandle,
};
185 changes: 172 additions & 13 deletions druid-shell/src/mouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,50 +18,209 @@ use crate::kurbo::Point;

use crate::keyboard::KeyModifiers;

/// The state of the mouse for a click, mouse-up, or move event.
/// Information about the mouse event.
#[derive(Debug, Clone, PartialEq)]
pub struct MouseEvent {
/// The location of the mouse in the current window.
///
/// This is in px units, that is, adjusted for hi-dpi.
/// This is in px units not device pixels, that is, adjusted for hi-dpi.
pub pos: Point,
/// Keyboard modifiers at the time of the mouse event.
/// Mouse buttons being held down during a move or after a click event.
/// Thus it will contain the `button` that triggered a mouse-down event,
/// and it will not contain the `button` that triggered a mouse-up event.
pub buttons: MouseButtons,
/// Keyboard modifiers at the time of the event.
pub mods: KeyModifiers,
/// The number of mouse clicks associated with this event. This will always
/// be `0` for a mouse-up event.
pub count: u32,
/// The currently pressed button in the case of a move or click event,
/// or the released button in the case of a mouse-up event.
/// be `0` for a mouse-up and mouse-move events.
pub count: u8,
/// The button that was pressed down in the case of mouse-down,
/// 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,
}

/// An indicator of which mouse button was pressed.
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[repr(u8)]
pub enum MouseButton {
/// No mouse button.
// MUST BE FIRST (== 0)
None,
/// Left mouse button.
Left,
/// Middle mouse button.
Middle,
/// Right mouse button.
Right,
/// Middle mouse button.
Middle,
/// First X button.
X1,
/// Second X button.
X2,
}

impl MouseButton {
/// Returns `true` if this is the left mouse button.
#[inline(always)]
/// Returns `true` if this is [`MouseButton::Left`].
///
/// [`MouseButton::Left`]: #variant.Left
#[inline]
pub fn is_left(self) -> bool {
self == MouseButton::Left
}

/// Returns `true` if this is the right mouse button.
#[inline(always)]
/// Returns `true` if this is [`MouseButton::Right`].
///
/// [`MouseButton::Right`]: #variant.Right
#[inline]
pub fn is_right(self) -> bool {
self == MouseButton::Right
}

/// Returns `true` if this is [`MouseButton::Middle`].
///
/// [`MouseButton::Middle`]: #variant.Middle
#[inline]
pub fn is_middle(self) -> bool {
self == MouseButton::Middle
}

/// Returns `true` if this is [`MouseButton::X1`].
///
/// [`MouseButton::X1`]: #variant.X1
#[inline]
pub fn is_x1(self) -> bool {
self == MouseButton::X1
}

/// Returns `true` if this is [`MouseButton::X2`].
///
/// [`MouseButton::X2`]: #variant.X2
#[inline]
pub fn is_x2(self) -> bool {
self == MouseButton::X2
}
}

/// A set of [`MouseButton`]s.
///
/// [`MouseButton`]: enum.MouseButton.html
#[derive(PartialEq, Eq, Clone, Copy, Default)]
pub struct MouseButtons(u8);

impl MouseButtons {
/// Create a new empty set.
#[inline]
pub fn new() -> MouseButtons {
MouseButtons(0)
}

/// Add the `button` to the set.
#[inline]
pub fn insert(&mut self, button: MouseButton) {
self.0 |= 1.min(button as u8) << button as u8;
}

/// Remove the `button` from the set.
#[inline]
pub fn remove(&mut self, button: MouseButton) {
self.0 &= !(1.min(button as u8) << button as u8);
}

/// Builder-style method for adding the `button` to the set.
#[inline]
pub fn with(mut self, button: MouseButton) -> MouseButtons {
self.0 |= 1.min(button as u8) << button as u8;
self
}

/// Builder-style method for removing the `button` from the set.
#[inline]
pub fn without(mut self, button: MouseButton) -> MouseButtons {
self.0 &= !(1.min(button as u8) << button as u8);
self
}

/// Returns `true` if the `button` is in the set.
#[inline]
pub fn contains(self, button: MouseButton) -> bool {
(self.0 & (1.min(button as u8) << button as u8)) != 0
}

/// Returns `true` if the set is empty.
#[inline]
pub fn is_empty(self) -> bool {
self.0 == 0
}

/// Returns `true` if all the `buttons` are in the set.
#[inline]
pub fn is_superset(self, buttons: MouseButtons) -> bool {
self.0 & buttons.0 == buttons.0
}

/// Returns `true` if [`MouseButton::Left`] is in the set.
///
/// [`MouseButton::Left`]: enum.MouseButton.html#variant.Left
#[inline]
pub fn has_left(self) -> bool {
self.contains(MouseButton::Left)
}

/// Returns `true` if [`MouseButton::Right`] is in the set.
///
/// [`MouseButton::Right`]: enum.MouseButton.html#variant.Right
#[inline]
pub fn has_right(self) -> bool {
self.contains(MouseButton::Right)
}

/// Returns `true` if [`MouseButton::Middle`] is in the set.
///
/// [`MouseButton::Middle`]: enum.MouseButton.html#variant.Middle
#[inline]
pub fn has_middle(self) -> bool {
self.contains(MouseButton::Middle)
}

/// Returns `true` if [`MouseButton::X1`] is in the set.
///
/// [`MouseButton::X1`]: enum.MouseButton.html#variant.X1
#[inline]
pub fn has_x1(self) -> bool {
self.contains(MouseButton::X1)
}

/// Returns `true` if [`MouseButton::X2`] is in the set.
///
/// [`MouseButton::X2`]: enum.MouseButton.html#variant.X2
#[inline]
pub fn has_x2(self) -> bool {
self.contains(MouseButton::X2)
}

/// Adds all the `buttons` to the set.
pub fn extend(&mut self, buttons: MouseButtons) {
self.0 |= buttons.0;
}

/// Returns a union of the values in `self` and `other`.
#[inline]
pub fn union(mut self, other: MouseButtons) -> MouseButtons {
self.0 |= other.0;
self
}

/// Clear the set.
#[inline]
pub fn clear(&mut self) {
self.0 = 0;
}
}

impl std::fmt::Debug for MouseButtons {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "MouseButtons({:05b})", self.0 >> 1)
}
}

//NOTE: this currently only contains cursors that are included by default on
Expand Down
Loading

0 comments on commit 3445361

Please sign in to comment.