-
-
Notifications
You must be signed in to change notification settings - Fork 173
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
Support pointer capture #241
Comments
It sounds like pointer capture is mostly useful for drag events, yet this crate already provides drag events. You mention:
Non standardization isn't something we need to worry about. With that in mind, what does pointer capturing enable that can't already be done with the drag events? |
The short answer to your question is "nothing" - that is, there's nothing that can be done with pointer capture that can't be done with drag events as you have defined them. The longer answer is "simplicity". With pointer capture, you have fewer events that need to be subscribed to. A slider widget, for example, only needs to subscribe to The way that you have implemented drag events is reminiscent of some older UI desktop frameworks in which dragging is a special state handled by the UI framework (this is not a criticism, just an observation). Most widgets on the web today simply use pointer events, and manage the dragging state themselves. Things get a bit confused because browsers also have something called "drag and drop" (DnD) which is mainly about dragging files from the desktop onto the browser window. This is a OS-level feature where the browser hooks into the DnD events from the native operating system. A "drag" event contains a payload and an icon. The payload consists of one or more data blocks, each of which has an associated MIME type. The icon is an image which is set by the drag source, which is often the icon for the file type being dragged. The recipient of the drag has no control over the data or icon, but can highlight itself (or not) based on whether the MIME type is acceptable. You can drag other things besides files - for example, in the past I've implemented a UI that lets you control the order of columns in a table by dragging. As you can imagine, this is a fairly heavyweight operation compared to dragging a slider thumb, which is why slider widgets don't use it. I only mention DnD because the terminology is confusing, what you call a "drag" event is not the same as what the browser calls a "drag" event, which is a DnD event. Other than DnD there are no drag events in the browser. Some widgets on the web have complex needs that don't fit into the standard model. Here are some use cases:
So the bottom line is, anything you can do with pointer capture can be done with your current design - the question is, which approach yields the best / simplest developer experience? |
So, now that I've had a chance to dive more deeply into bevy_mod_picking, I can better understand the difference in use cases between dragging and pointer capture. Either that, or cases where drag events could be improved. Take a widget such as a slider. When a slider is being dragged, all events go to the slider. If, while dragging the slider, you move the mouse over a button or other widget, you'll notice that they don't highlight. In the pointer capture world, this is easy to explain: when a ui element has capture, other elements on the page don't get in/out events. However, in a dragging world, you actually do want other elements to get in/out events because they might be a target. |
This was discussed on discord, but I'm writing down the details here.
Background: Many of the design choices of bevy_mod_picking are modeled after the web, and more specifically the documented behavior of the HTML DOM. The intent, I believe, is to make it easy for programmers who have web experience to transfer their skills to Rust and Bevy. One feature that is missing, and would be useful, is pointer capture. This API is used in many popular and creative widgets that support dragging: sliders, spinners, split panes, color wheels, hue/saturation pickers, trackballs, knobs; even complex components such as node graph editors.
The "capture" state would associate a given pointer (identified by a pointer id) with a given entity. While captured, all pointer events for that pointer are routed to the target entity, regardless of where the pointer is on the screen.
Pointer capture lasts until one of three conditions occurs:
A typical slider widget on the web uses pointer capture in the following way:
Note that because capture is automatically released by pointer up, there's no need for an "up" event handler, unless the widget wants to send a final event to indicate that the user has finished dragging. The 'hasPointerCapture()' method is used to determine whether the slider is in a dragging state, avoiding the need for a boolean state variable.
Also note that this scheme does not use "drag" events (which are kind of a pain in JS because they aren't entirely standard across browsers), but just ordinary pointer events. In general, "drag" events are only needed when dragging between two separate components that have no knowledge of each other.
A slightly more advanced version of this is an widget which supports both double-click and drag gestures, such as a node editor. On the web, the capture state prevents double-click events from firing, so supporting both requires delaying capturing until the drag has moved a few pixels.
The text was updated successfully, but these errors were encountered: