-
Notifications
You must be signed in to change notification settings - Fork 567
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for more mouse buttons and tracking holding. #843
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. okay, thinking about the API: I think that separating out
My gut tells me that mouse-up should include count, though? (but this is unrelated to current PR). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
As for |
||
} | ||
|
||
/// 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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we probably have more than 8 bits of possible buttons; I would just make this a u32 now, that should be enough for anybody. |
||
|
||
impl MouseButtons { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just sort of riffing on this type; if the idea is to construct it from let buttons: MouseButtons = [MouseButton::Left, MouseButton::X1].iter().copied().collect(); That doesn't feel great really; probably simpler to have a constructor that just takes a In any case I'm just daydreaming, this isn't necessary or anything. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The following one liner isn't too bad either: let buttons = MouseButtons::new().with(MouseButton::Left).with(MouseButton::Right); There can be value in adding more methods, however I think I would leave these slice/iterator constructors out of this PR. |
||
/// 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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm getting some YAGNI vibes here; it isn't clear when or where these would be used? Are they just by us, or do we expect external users to need to synthesize mouse buttons? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well this specific More generally these functions can be used by external users. Yes they might synthesize |
||
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 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just discussion, but I wonder if it makes more sense for, in the case of mouse-up, for
count
to be the same as the count of the corresponding mouse-down.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes but it's not a trivial change and so will come with #859.