Skip to content

Commit

Permalink
add functions to check which button triggered a drag start & end (#2507)
Browse files Browse the repository at this point in the history
* add button release events for drags

* add utility functions

* fix CHANGELOG.md

* fix CHANGELOG.md

Co-authored-by: Emil Ernerfeldt <[email protected]>
  • Loading branch information
lictex and emilk authored Jan 24, 2023
1 parent 4bd4eca commit eee4cf6
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 29 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG

## Unreleased
### 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)).
* 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)).
Expand All @@ -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)).

### 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)).
* 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)).
Expand Down
8 changes: 4 additions & 4 deletions crates/egui/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -564,17 +564,17 @@ impl Context {
}
}
}
PointerEvent::Released(click) => {
PointerEvent::Released { click, button } => {
response.drag_released = response.dragged;
response.dragged = false;

if hovered && response.is_pointer_button_down_on {
if let Some(click) = click {
let clicked = hovered && response.is_pointer_button_down_on;
response.clicked[click.button as usize] = clicked;
response.double_clicked[click.button as usize] =
response.clicked[*button as usize] = clicked;
response.double_clicked[*button as usize] =
clicked && click.is_double();
response.triple_clicked[click.button as usize] =
response.triple_clicked[*button as usize] =
clicked && click.is_triple();
}
}
Expand Down
69 changes: 44 additions & 25 deletions crates/egui/src/input_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,6 @@ impl InputState {
#[derive(Clone, Debug, PartialEq)]
pub(crate) struct Click {
pub pos: Pos2,
pub button: PointerButton,
/// 1 or 2 (double-click) or 3 (triple-click)
pub count: u32,
/// Allows you to check for e.g. shift-click
Expand All @@ -471,7 +470,10 @@ pub(crate) enum PointerEvent {
position: Pos2,
button: PointerButton,
},
Released(Option<Click>),
Released {
click: Option<Click>,
button: PointerButton,
},
}

impl PointerEvent {
Expand All @@ -480,11 +482,11 @@ impl PointerEvent {
}

pub fn is_release(&self) -> bool {
matches!(self, PointerEvent::Released(_))
matches!(self, PointerEvent::Released { .. })
}

pub fn is_click(&self) -> bool {
matches!(self, PointerEvent::Released(Some(_click)))
matches!(self, PointerEvent::Released { click: Some(_), .. })
}
}

Expand Down Expand Up @@ -639,15 +641,15 @@ impl PointerState {

Some(Click {
pos,
button,
count,
modifiers,
})
} else {
None
};

self.pointer_events.push(PointerEvent::Released(click));
self.pointer_events
.push(PointerEvent::Released { click, button });

self.press_origin = None;
self.press_start_time = None;
Expand Down Expand Up @@ -775,11 +777,28 @@ impl PointerState {
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?
pub fn button_released(&self, button: PointerButton) -> bool {
self.pointer_events
.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?
Expand Down Expand Up @@ -811,16 +830,28 @@ impl PointerState {

/// Was the button given double clicked this frame?
pub fn button_double_clicked(&self, button: PointerButton) -> bool {
self.pointer_events
.iter()
.any(|event| matches!(&event, PointerEvent::Released(Some(click)) if click.button == button && click.is_double()))
self.pointer_events.iter().any(|event| {
matches!(
&event,
PointerEvent::Released {
click: Some(click),
button: b,
} if *b == button && click.is_double()
)
})
}

/// Was the button given triple clicked this frame?
pub fn button_triple_clicked(&self, button: PointerButton) -> bool {
self.pointer_events
.iter()
.any(|event| matches!(&event, PointerEvent::Released(Some(click)) if click.button == button && click.is_triple()))
self.pointer_events.iter().any(|event| {
matches!(
&event,
PointerEvent::Released {
click: Some(click),
button: b,
} if *b == button && click.is_triple()
)
})
}

/// Was the primary button clicked this frame?
Expand All @@ -833,18 +864,6 @@ impl PointerState {
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?
#[inline(always)]
pub fn button_down(&self, button: PointerButton) -> bool {
Expand Down
10 changes: 10 additions & 0 deletions crates/egui/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,11 +278,21 @@ impl Response {
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.
pub fn drag_released(&self) -> bool {
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?
pub fn drag_delta(&self) -> Vec2 {
if self.dragged() {
Expand Down

0 comments on commit eee4cf6

Please sign in to comment.