Skip to content

Commit

Permalink
Fix drag-and-drop termination condition bug (#5452)
Browse files Browse the repository at this point in the history
I introduced this in #5433.

TL;DR: there are two termination conditions for drag-and-drop
operations:
- ESC
- release mouse

The former _must_ happen at frame start (to properly capture the
keystroke). The latter _must_ happen at end-of-frame (to _not_ shadow
the mouse release event from user code).

This is now properly documented.
  • Loading branch information
abey79 authored Dec 9, 2024
1 parent 5384600 commit 13352d6
Showing 1 changed file with 19 additions and 12 deletions.
31 changes: 19 additions & 12 deletions crates/egui/src/drag_and_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,38 @@ impl DragAndDrop {
ctx.on_end_pass("drag_and_drop_end_pass", Arc::new(Self::end_pass));
}

/// Interrupt drag-and-drop if the user presses the escape key.
///
/// This needs to happen at frame start so we can properly capture the escape key.
fn begin_pass(ctx: &Context) {
let has_any_payload = Self::has_any_payload(ctx);

if has_any_payload {
let abort_dnd = ctx.input_mut(|i| {
i.pointer.any_released()
|| i.consume_key(crate::Modifiers::NONE, crate::Key::Escape)
});
let abort_dnd_due_to_escape_key =
ctx.input_mut(|i| i.consume_key(crate::Modifiers::NONE, crate::Key::Escape));

if abort_dnd {
if abort_dnd_due_to_escape_key {
Self::clear_payload(ctx);
}
}
}

/// Interrupt drag-and-drop if the user releases the mouse button.
///
/// This is a catch-all safety net in case user code doesn't capture the drag payload itself.
/// This must happen at end-of-frame such that we don't shadow the mouse release event from user
/// code.
fn end_pass(ctx: &Context) {
let mut is_dragging = false;
let has_any_payload = Self::has_any_payload(ctx);

ctx.data_mut(|data| {
let state = data.get_temp_mut_or_default::<Self>(Id::NULL);
is_dragging = state.payload.is_some();
});
if has_any_payload {
let abort_dnd_due_to_mouse_release = ctx.input_mut(|i| i.pointer.any_released());

if is_dragging {
ctx.set_cursor_icon(CursorIcon::Grabbing);
if abort_dnd_due_to_mouse_release {
Self::clear_payload(ctx);
} else {
ctx.set_cursor_icon(CursorIcon::Grabbing);
}
}
}

Expand Down

0 comments on commit 13352d6

Please sign in to comment.