-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Improve Sense
vs drag-and-drop
#3841
Comments
|
I have a list of custom widgets that I want to be able to reorder (for context, these widgets handle spacing themselves, so they are drawn with no margin/spacing between them). Here is the proto-code I need to use to have the ability to drag and drop. I think it's a good illustration of where the drag-and-drop API could be improved. fn some_ui(ui: &mut egui::Ui) {
let mut source_item_pos = None;
let mut target_item_pos = None;
for (i, widget) in list_items_to_display
{
let response = widget.show(ui);
// TODO(emilk/egui#3841): very tempting to use `response.dragged()` here, but it
// doesn't work. By the time `i.pointer.any_released()` is true, `response.dragged()`
// is false. So both condition never happen at the same time.
if ui.memory(|mem| mem.is_being_dragged(response.id)) {
source_item_pos = Some(i);
}
// TODO(emilk/egui#3841): very tempting to use `response.hovered()` here, but widgets
// that sense more than hover never get `response.hovered() == true` while another
// widget is being dragged.
if ui.memory(|mem| mem.is_anything_being_dragged())
&& ui.rect_contains_pointer(response.rect)
{
ui.painter().hline(
ui.cursor().x_range(),
ui.cursor().top(),
(2.0, egui::Color32::WHITE),
);
// TODO(emilk/egui#3841): it would be nice to have a drag specific API for that,
// for discoverability
if ui.input(|i| i.pointer.any_released()) {
target_item_pos = Some(i);
}
}
}
if let (Some(source), Some(target)) =
(source_item_pos, target_item_pos)
{
/* swap `source` and `target` in `list_items_to_display` */
}
} |
emilk
added a commit
that referenced
this issue
Jan 22, 2024
emilk
added a commit
that referenced
this issue
Jan 22, 2024
…3860) * Closes #3841⚠️ Breaking change! This defines `response.hovered()` to never be true if any other widget is being dragged. If you want to detect if a widget is being hovered while another widget is being dragged, use the new `response.contains_pointer` instead. This is necessaert for things like drag-and-drop targets. Overall, this removes special-casing of non-interactive widgets.
8 tasks
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
When dragging a widget (e.g. a slider), and letting the cursor move outside the slider, egui should not highlight that other widget:
egui implements this by never setting
response.hovered
for a widget if another widget is being dragged.There is a weird exception to this though: if the other widget is not interactive (doesn't sense any clicks or drags), then it will still have
response.hovered()
. This usually doesn't matter, because a widget that that is not interactive has no hover-effect anyway.This has implications for drag-and-drop: if the drop-target area has
Sense::hover()
then it will sense hovers while the user is dragging something else, so the user can doif drag_target_response.hovered() { …
to highlight the drop-area. But if the drop-area itself is sensitive to clicks and drags,.hovered()
will always be false while something is being dragged. This means it is really tricky to implement drag-and-drop reordering of a list, because usually you'd want to implement that by having each list item sense drags and be a drop-target, to sense how to reorder the items.A work-around it to use
ui.rect_contains_pointer
instead ofresponse.hovered()
, but this feels hacky.So: we should figure out:
response.hovered()
be true when something else is being dragged or not?drop-target
Sense
?The text was updated successfully, but these errors were encountered: