PistonDevelopers / conrod

An easy-to-use, 2D GUI library written entirely in Rust.
Other
3.35k stars 296 forks source link

Canvas example: dragging with quick movements #788

Open killkrt opened 8 years ago

killkrt commented 8 years ago

Hi,

I'm making some tests under Windows 10 and I've found an issue using the canvas example. It seems that if I drag fast (actually a little faster than slow) around the windows the two boxes labeled with "Blue" and "Orange" they loose the drag, so they stop moving, while if I move quite slow the mouse the issue never happens. I've noticed that this problem happens especially when I dag in a diagonal direction, it seems that the mouse pointer goes faster than the redraw process and so the dragging stops.

System details: OS: Windows 10 64bit (4K screen resolution at 60Hz) Rust: 1.10 MSVC ABI 64bit GFX card: nVidia GeForce 970Ti (driver 368.81) Conrod: 82f0a1b

mitchmindtree commented 8 years ago

Ah yes I've noticed this too, I'm pretty sure it's an issue with the dragging logic here. It's overly complicated and could probably be simplified.

I think the best bet for a fix might be to remove the Widget::drag_area method entirely in favour of two methods:

  1. Widget::drag_by(&[MouseButton]) that allows the user to specify that the widget can be dragged by the given mouse buttons and
  2. Widget::drag_by_child(widget::Index, &[MouseButton]) that allows the widget to be dragged when the given child widget is dragged.

Then we could:

killkrt commented 8 years ago

Just as info, I can confirm the issue also on OS X 10.11 and Linux (Arch Linux with Budgie as desktop environment).

emdash commented 5 years ago

What's happening here is that you are not taking what's called a "pointer grab", or else you are not reacting to the system native drag-and-drop API.

The drag state machine is dependent receiving pointer events while the mouse button is depressed. On most platforms, you will only receive such events while the pointer is within your window. What happens when the mouse leaves the window will be either:

The latter case corresponds to what the OP described. The former case happens for me under X11. Why this manifests with rapid movements is that the pointer acceleration provided by the OS causes the pointer to leave the window much more easily with rapid movements.

You cannot naively implement your own drag-and-drop state machine for windowed applications by responding to the usual pointer events, you must use some system API that allows you to keep receiving mouse events even when the cursor leaves the window. X11 provides the notion of a "pointer grab", which allows you to receive mouse events until the button is released. Other systems allow you to subscribe to "global" pointer events, but then it's up to you to translate the coordinates into your application's coordinate system.

Most graphical systems also offer some dedicated "drag-and-drop" api, which often seems fiendishly complicated and over-engineered, but one of the the many benefits they offer is correctly routing events when the pointer moves between windows.

emdash commented 5 years ago
* Sum the drag events' `delta_xy` field onto the current position to determine the widget's new position.

Don't do that. Integrating over the deltas will cause the object's position to drift away from the pointer over time. This will also create the perception of "lagginess". Windowing systems don't send you every mouse event: the XY delta is completely useless for direct manipulation. The XY delta is for gaming; it represents the instantaneous pointer velocity, but there is absolutely no guarantee that successive deltas will sum to the current pointer position. On the contrary, it is because windowing systems, in general, make no such guarantee that the XY delta is even necessary.

For direct manipulation, always compute the drag offset vector as the difference of drag_vector = cursor_pos - cursor_pos_at_mousedown. In this way, you can always compute the current value of the quantity being manipulated by the cursor as value_at_mousedown + drag_vector. If you miss events, or any other weird circumstances arise, the only price is a little stuttering in the UI (versus total meltdown). Plus it's easier to reason about.

mitchmindtree commented 5 years ago

Sorry for the late reply @emdash!

I just want to add that I agree and would be more than happy to accept a PR if someone was up for making this change.

emdash commented 5 years ago

If I can find some time to, I will but I've got a lot on my plate.

On Tue, Dec 25, 2018, 21:23 mitchmindtree <notifications@github.com wrote:

Sorry for the late reply @emdash https://github.com/emdash!

I just want to add that I agree and would be more than happy to accept a PR if someone was up for making this change.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/PistonDevelopers/conrod/issues/788#issuecomment-449906155, or mute the thread https://github.com/notifications/unsubscribe-auth/AAAt2znvTUg__NjradO2xloVEFvEHaLIks5u8wfsgaJpZM4Jjt13 .

csirkeee commented 5 years ago

I just noticed this issue, but I think it was fixed by my pull request, right? https://github.com/PistonDevelopers/conrod/pull/1260

emdash commented 5 years ago

I think to fix this bug, you still need to handle losing the pointer grab, but definitely #1260 is the correct way to handle mouse motion...

On Sun, Jun 23, 2019, 07:52 András Eisenberger notifications@github.com wrote:

I just noticed this issue, but I think it was fixed by my pull request, right?

1260 https://github.com/PistonDevelopers/conrod/pull/1260

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/PistonDevelopers/conrod/issues/788?email_source=notifications&email_token=AAAC3WZCGQN7V2G45VKZSXDP36EZTA5CNFSM4CMO3V32YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODYLAHLQ#issuecomment-504759214, or mute the thread https://github.com/notifications/unsubscribe-auth/AAAC3WYEQ4W6GHBB5A23LJTP36EZTANCNFSM4CMO3V3Q .

csirkeee commented 5 years ago

I think it fixes the original issue. For me, on Windows 10, there it no problem with losing the pointer grab even if I move the cursor outside the application window. Since the original issue was for Windows 10 too, I'm guessing it's fixed for them too. And we should probably open a new issue like "MacOS dragging behaviour fails if cursor moves outside of window." That seems related to issue https://github.com/PistonDevelopers/conrod/issues/1245 as well, but I can't test and fix that since I don't have access to a Mac machine.

I think to fix this bug, you still need to handle losing the pointer grab, but definitely #1260 is the correct way to handle mouse motion...

emdash commented 5 years ago

OK. FYI, X11 has similar behavior to OSX w/r/t pointer grabs.

On Sun, Jun 23, 2019, 08:39 András Eisenberger notifications@github.com wrote:

I think it fixes the original issue. For me, on Windows 10, there it no problem with losing the pointer grab even if I move the cursor outside the application window. Since the original issue was for Windows 10 too, I'm guessing it's fixed for them too. And we should probably open a new issue like "MacOS dragging behaviour fails if cursor moves outside of window." That seems related to issue #1245 https://github.com/PistonDevelopers/conrod/issues/1245 as well, but I can't test and fix that since I don't have access to a Mac machine.

I think to fix this bug, you still need to handle losing the pointer grab, but definitely #1260 https://github.com/PistonDevelopers/conrod/pull/1260 is the correct way to handle mouse motion...

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/PistonDevelopers/conrod/issues/788?email_source=notifications&email_token=AAAC3W2NLDI4UMI6FOQFPHTP36KLPA5CNFSM4CMO3V32YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODYLBELA#issuecomment-504762924, or mute the thread https://github.com/notifications/unsubscribe-auth/AAAC3W4POGK6JZCQEKE26CTP36KLPANCNFSM4CMO3V3Q .