Skip to content

Commit

Permalink
Add API for checking if there is anything being dragged onto a Response
Browse files Browse the repository at this point in the history
  • Loading branch information
emilk committed Jan 25, 2024
1 parent 4531b81 commit e778cd5
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 10 deletions.
13 changes: 12 additions & 1 deletion crates/egui/src/drag_and_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,21 @@ impl DragAndDrop {
///
/// Returns `true` both during a drag and on the frame the pointer is released
/// (if there is a payload).
pub fn has_payload<T>(ctx: &Context) -> bool
pub fn has_payload_of_type<T>(ctx: &Context) -> bool
where
T: Any + Send + Sync,
{
Self::payload::<T>(ctx).is_some()
}

/// Are we carrying a payload?
///
/// Returns `true` both during a drag and on the frame the pointer is released
/// (if there is a payload).
pub fn has_any_payload(ctx: &Context) -> bool {
ctx.data(|data| {
let state = data.get_temp::<Self>(Id::NULL);
state.map_or(false, |state| state.payload.is_some())
})
}
}
30 changes: 30 additions & 0 deletions crates/egui/src/response.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::{any::Any, sync::Arc};

use crate::{
emath::{Align, Pos2, Rect, Vec2},
menu, Context, CursorIcon, Id, LayerId, PointerButton, Sense, Ui, WidgetText,
Expand Down Expand Up @@ -325,6 +327,34 @@ impl Response {
}
}

/// Drag-and-Drop: Return what the is being held over this widget, if any.
///
/// Only returns something if [`Self::contains_pointer`] is true,
/// and the user is drag-dropping something of this type.
pub fn drag_drop_hover_payload<T: Any + Send + Sync>(&self) -> Option<Arc<T>> {
// NOTE: we use `response.contains_pointer` here instead of `hovered`, because
// `hovered` is always false when another widget is being dragged.
if self.contains_pointer() {
crate::DragAndDrop::payload::<T>(&self.ctx)
} else {
None
}
}
/// Drag-and-Drop: Return what the is being dropped onto this widget, if any.
///
/// Only returns something if [`Self::contains_pointer`] is true,
/// the user is drag-dropping something of this type,
/// and they released it this frame
pub fn dnd_release_payload<T: Any + Send + Sync>(&self) -> Option<Arc<T>> {
// NOTE: we use `response.contains_pointer` here instead of `hovered`, because
// `hovered` is always false when another widget is being dragged.
if self.contains_pointer() && self.ctx.input(|i| i.pointer.any_released()) {
crate::DragAndDrop::payload::<T>(&self.ctx)
} else {
None
}
}

/// Where the pointer (mouse/touch) were when when this widget was clicked or dragged.
///
/// `None` if the widget is not being interacted with.
Expand Down
14 changes: 5 additions & 9 deletions crates/egui_demo_lib/src/demo/drag_and_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub fn drop_target<R>(
can_accept_what_is_being_dragged: bool,
body: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> {
let is_being_dragged = ui.memory(|mem| mem.is_anything_being_dragged());
let is_being_dragged = DragAndDrop::has_any_payload(ui.ctx());

let margin = Vec2::splat(4.0);

Expand Down Expand Up @@ -128,7 +128,7 @@ impl super::View for DragAndDropDemo {
for (col_idx, column) in self.columns.clone().into_iter().enumerate() {
let ui = &mut uis[col_idx];
let can_accept_what_is_being_dragged =
DragAndDrop::has_payload::<DragInfo>(ui.ctx());
DragAndDrop::has_payload_of_type::<DragInfo>(ui.ctx());

let response = drop_target(ui, can_accept_what_is_being_dragged, |ui| {
ui.set_min_size(vec2(64.0, 100.0));
Expand All @@ -145,13 +145,9 @@ impl super::View for DragAndDropDemo {
})
.response;

// NOTE: we use `response.contains_pointer` here instead of `hovered`, because
// `hovered` is always false when another widget is being dragged.
if response.contains_pointer() && ui.input(|i| i.pointer.any_released()) {
if let Some(source) = DragAndDrop::payload::<DragInfo>(ui.ctx()) {
let item = self.columns[source.col_idx].remove(source.row_idx);
self.columns[col_idx].push(item);
}
if let Some(source) = response.dnd_release_payload::<DragInfo>() {
let item = self.columns[source.col_idx].remove(source.row_idx);
self.columns[col_idx].push(item);
}
}
});
Expand Down

0 comments on commit e778cd5

Please sign in to comment.