Skip to content
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

Better distinction of dragged vs clicked #547

Open
WeiPhil opened this issue Jul 6, 2021 · 4 comments
Open

Better distinction of dragged vs clicked #547

WeiPhil opened this issue Jul 6, 2021 · 4 comments
Labels
feature New feature or request

Comments

@WeiPhil
Copy link

WeiPhil commented Jul 6, 2021

Hello,
First of all, I'd like to point out how amazing the library is. It does most of what one would expect from an immediate-mode GUI and can easily handle new cases/features. Thanks for all the time passed on working on this!
Now on my issue, which might actually not be an issue but intended. When using dragged() on a Response of a widget to detect a change, I noticed that clicking on a widget also seems to count as dragged. At least on an egui::DragValue. Is this intended? In my case, I want to allow the user to change the field (by clicking and entering a custom value) without triggering a change, if not explicitly dragged. A workaround that works well for me uses an epsilon value to differentiate between a simple click or a "real" drag action, something like: if response.drag_delta().max_elem() > 1e-5 { do_something(); }. Also note that (response.dragged() && !response.clicked()) does not result in not detecting a change when clicked (which definitely looks like a bug).
Should this approach be the default behaviour when checking for dragged(), or are there specific use cases where a simple click should count as a drag event? My choice of epsilon is, of course, completely arbitrary, and I suppose there are better choices.
Best,
Philippe

@emilk
Copy link
Owner

emilk commented Jul 6, 2021

I think it would make sense if egui would not report dragged() until the mouse have moved at least a few pixels, but this hasn't been implemented. It requires some finessing to make sure the initial drag is not forgotten, but reported.

In egui/src/input_state.rs there is this:

/// If the pointer moves more than this, it is no longer a click (but maybe a drag)
const MAX_CLICK_DIST: f32 = 6.0;
/// The new pointer press must come within this many seconds from previous pointer release
const MAX_CLICK_DELAY: f64 = 0.3;

We should probably not consider it a drag until the mouse has moved that many pixels or have been down for that many seconds.

@emilk emilk added the feature New feature or request label Jul 6, 2021
@WeiPhil
Copy link
Author

WeiPhil commented Jul 7, 2021

I see, and actually, my simple workaround is not great after some more testing. If you need very fine dragging you almost never find the sweet spot.

I think the most intuitive would be the time the mouse has been down. A very small delay until you can start dragging is less problematic, but I would still expose it through a builder parameter as one might still want the super responsive drag response and not care about actual clicks.

@emilk
Copy link
Owner

emilk commented Sep 8, 2021

Related change: a76b816 (don't register as click if the pointer has been pressed for too long)

@emilk emilk changed the title Manual implementation of dragged but not clicked Better distinction of dragged vs clicked Apr 16, 2022
@aclysma
Copy link

aclysma commented Nov 29, 2023

Just a note for anyone else who needs a solution to this, I started from the example code here https://github.com/emilk/egui/blob/master/crates/egui_demo_lib/src/demo/drag_and_drop.rs

Most of this is duplicating the functionality in egui of setting has_moved_too_much_for_a_click, but it isn't publicly exposed. The other issue is that the logic in egui can only start on a drag on the same frame as when the mouse goes down, so we have to set that manually too.

Modified:

// Check for drags:
let mut allow_check_for_drag = false;
ui.input(|input| {
    if let Some(press_origin) = input.pointer.press_origin() {
        if let Some(latest_pos) = input.pointer.latest_pos() {
            if press_origin.distance(latest_pos) > 6.0 {
                allow_check_for_drag = true;
            }
        }
    }
});
if allow_check_for_drag && response.hovered() {
    ui.memory_mut(|mem| mem.set_dragged_id(id));
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants