add functions to check which button triggered a drag start & end (#2507)

* add button release events for drags

* add utility functions

* fix CHANGELOG.md

* fix CHANGELOG.md

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
lictex_ 2023-01-24 17:11:32 +08:00 committed by GitHub
parent 4bd4eca2e4
commit eee4cf6a82
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 61 additions and 29 deletions

View file

@ -6,6 +6,8 @@ NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG
## Unreleased ## Unreleased
### Added ⭐ ### Added ⭐
* Add `Response::drag_started_by` and `Response::drag_released_by` for convenience, similar to `dragged` and `dragged_by` ([#2507](https://github.com/emilk/egui/pull/2507)).
* Add `PointerState::*_pressed` to check if the given button was pressed in this frame ([#2507](https://github.com/emilk/egui/pull/2507)).
* `Event::Key` now has a `repeat` field that is set to `true` if the event was the result of a key-repeat ([#2435](https://github.com/emilk/egui/pull/2435)). * `Event::Key` now has a `repeat` field that is set to `true` if the event was the result of a key-repeat ([#2435](https://github.com/emilk/egui/pull/2435)).
* Add `Slider::drag_value_speed`, which lets you ask for finer precision when dragging the slider value rather than the actual slider. * Add `Slider::drag_value_speed`, which lets you ask for finer precision when dragging the slider value rather than the actual slider.
* Add `Memory::any_popup_open`, which returns true if any popup is currently open ([#2464](https://github.com/emilk/egui/pull/2464)). * Add `Memory::any_popup_open`, which returns true if any popup is currently open ([#2464](https://github.com/emilk/egui/pull/2464)).
@ -23,6 +25,7 @@ NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG
* Default `ComboBox` is now controlled with `Spacing::combo_width` ([#2621](https://github.com/emilk/egui/pull/2621)). * Default `ComboBox` is now controlled with `Spacing::combo_width` ([#2621](https://github.com/emilk/egui/pull/2621)).
### Fixed 🐛 ### Fixed 🐛
* Trigger `PointerEvent::Released` for drags ([#2507](https://github.com/emilk/egui/pull/2507)).
* Expose `TextEdit`'s multiline flag to AccessKit ([#2448](https://github.com/emilk/egui/pull/2448)). * Expose `TextEdit`'s multiline flag to AccessKit ([#2448](https://github.com/emilk/egui/pull/2448)).
* Don't render `\r` (Carriage Return) ([#2452](https://github.com/emilk/egui/pull/2452)). * Don't render `\r` (Carriage Return) ([#2452](https://github.com/emilk/egui/pull/2452)).
* The `button_padding` style option works closer as expected with image+text buttons now ([#2510](https://github.com/emilk/egui/pull/2510)). * The `button_padding` style option works closer as expected with image+text buttons now ([#2510](https://github.com/emilk/egui/pull/2510)).

View file

@ -564,17 +564,17 @@ impl Context {
} }
} }
} }
PointerEvent::Released(click) => { PointerEvent::Released { click, button } => {
response.drag_released = response.dragged; response.drag_released = response.dragged;
response.dragged = false; response.dragged = false;
if hovered && response.is_pointer_button_down_on { if hovered && response.is_pointer_button_down_on {
if let Some(click) = click { if let Some(click) = click {
let clicked = hovered && response.is_pointer_button_down_on; let clicked = hovered && response.is_pointer_button_down_on;
response.clicked[click.button as usize] = clicked; response.clicked[*button as usize] = clicked;
response.double_clicked[click.button as usize] = response.double_clicked[*button as usize] =
clicked && click.is_double(); clicked && click.is_double();
response.triple_clicked[click.button as usize] = response.triple_clicked[*button as usize] =
clicked && click.is_triple(); clicked && click.is_triple();
} }
} }

View file

@ -447,7 +447,6 @@ impl InputState {
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub(crate) struct Click { pub(crate) struct Click {
pub pos: Pos2, pub pos: Pos2,
pub button: PointerButton,
/// 1 or 2 (double-click) or 3 (triple-click) /// 1 or 2 (double-click) or 3 (triple-click)
pub count: u32, pub count: u32,
/// Allows you to check for e.g. shift-click /// Allows you to check for e.g. shift-click
@ -471,7 +470,10 @@ pub(crate) enum PointerEvent {
position: Pos2, position: Pos2,
button: PointerButton, button: PointerButton,
}, },
Released(Option<Click>), Released {
click: Option<Click>,
button: PointerButton,
},
} }
impl PointerEvent { impl PointerEvent {
@ -480,11 +482,11 @@ impl PointerEvent {
} }
pub fn is_release(&self) -> bool { pub fn is_release(&self) -> bool {
matches!(self, PointerEvent::Released(_)) matches!(self, PointerEvent::Released { .. })
} }
pub fn is_click(&self) -> bool { pub fn is_click(&self) -> bool {
matches!(self, PointerEvent::Released(Some(_click))) matches!(self, PointerEvent::Released { click: Some(_), .. })
} }
} }
@ -639,7 +641,6 @@ impl PointerState {
Some(Click { Some(Click {
pos, pos,
button,
count, count,
modifiers, modifiers,
}) })
@ -647,7 +648,8 @@ impl PointerState {
None None
}; };
self.pointer_events.push(PointerEvent::Released(click)); self.pointer_events
.push(PointerEvent::Released { click, button });
self.press_origin = None; self.press_origin = None;
self.press_start_time = None; self.press_start_time = None;
@ -775,11 +777,28 @@ impl PointerState {
self.pointer_events.iter().any(|event| event.is_release()) self.pointer_events.iter().any(|event| event.is_release())
} }
/// Was the button given pressed this frame?
pub fn button_pressed(&self, button: PointerButton) -> bool {
self.pointer_events
.iter()
.any(|event| matches!(event, &PointerEvent::Pressed{button: b, ..} if button == b))
}
/// Was the button given released this frame? /// Was the button given released this frame?
pub fn button_released(&self, button: PointerButton) -> bool { pub fn button_released(&self, button: PointerButton) -> bool {
self.pointer_events self.pointer_events
.iter() .iter()
.any(|event| matches!(event, &PointerEvent::Released(Some(Click{button: b, ..})) if button == b)) .any(|event| matches!(event, &PointerEvent::Released{button: b, ..} if button == b))
}
/// Was the primary button pressed this frame?
pub fn primary_pressed(&self) -> bool {
self.button_pressed(PointerButton::Primary)
}
/// Was the secondary button pressed this frame?
pub fn secondary_pressed(&self) -> bool {
self.button_pressed(PointerButton::Secondary)
} }
/// Was the primary button released this frame? /// Was the primary button released this frame?
@ -811,16 +830,28 @@ impl PointerState {
/// Was the button given double clicked this frame? /// Was the button given double clicked this frame?
pub fn button_double_clicked(&self, button: PointerButton) -> bool { pub fn button_double_clicked(&self, button: PointerButton) -> bool {
self.pointer_events self.pointer_events.iter().any(|event| {
.iter() matches!(
.any(|event| matches!(&event, PointerEvent::Released(Some(click)) if click.button == button && click.is_double())) &event,
PointerEvent::Released {
click: Some(click),
button: b,
} if *b == button && click.is_double()
)
})
} }
/// Was the button given triple clicked this frame? /// Was the button given triple clicked this frame?
pub fn button_triple_clicked(&self, button: PointerButton) -> bool { pub fn button_triple_clicked(&self, button: PointerButton) -> bool {
self.pointer_events self.pointer_events.iter().any(|event| {
.iter() matches!(
.any(|event| matches!(&event, PointerEvent::Released(Some(click)) if click.button == button && click.is_triple())) &event,
PointerEvent::Released {
click: Some(click),
button: b,
} if *b == button && click.is_triple()
)
})
} }
/// Was the primary button clicked this frame? /// Was the primary button clicked this frame?
@ -833,18 +864,6 @@ impl PointerState {
self.button_clicked(PointerButton::Secondary) self.button_clicked(PointerButton::Secondary)
} }
// /// Was this button pressed (`!down -> down`) this frame?
// /// This can sometimes return `true` even if `any_down() == false`
// /// because a press can be shorted than one frame.
// pub fn button_pressed(&self, button: PointerButton) -> bool {
// self.pointer_events.iter().any(|event| event.is_press())
// }
// /// Was this button released (`down -> !down`) this frame?
// pub fn button_released(&self, button: PointerButton) -> bool {
// self.pointer_events.iter().any(|event| event.is_release())
// }
/// Is this button currently down? /// Is this button currently down?
#[inline(always)] #[inline(always)]
pub fn button_down(&self, button: PointerButton) -> bool { pub fn button_down(&self, button: PointerButton) -> bool {

View file

@ -278,11 +278,21 @@ impl Response {
self.dragged && self.ctx.input().pointer.any_pressed() self.dragged && self.ctx.input().pointer.any_pressed()
} }
/// Did a drag on this widgets by the button begin this frame?
pub fn drag_started_by(&self, button: PointerButton) -> bool {
self.drag_started() && self.ctx.input().pointer.button_pressed(button)
}
/// The widget was being dragged, but now it has been released. /// The widget was being dragged, but now it has been released.
pub fn drag_released(&self) -> bool { pub fn drag_released(&self) -> bool {
self.drag_released self.drag_released
} }
/// The widget was being dragged by the button, but now it has been released.
pub fn drag_released_by(&self, button: PointerButton) -> bool {
self.drag_released() && self.ctx.input().pointer.button_released(button)
}
/// If dragged, how many points were we dragged and in what direction? /// If dragged, how many points were we dragged and in what direction?
pub fn drag_delta(&self) -> Vec2 { pub fn drag_delta(&self) -> Vec2 {
if self.dragged() { if self.dragged() {