-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
Remove bevy_ui::Interaction
in favor of a bevy_picking
based solution
#15550
Comments
Bevy's enum Interaction {
Pressed,
Hovered,
None
} Ever since its inception, it has had a number of serious problems:
With the successful creation of Use casesThere are several things you might want to do with an Use case: clicking a button with the mouseThe user moves their mouse over a button and left-clicks it. The button is fired as soon as the button is pressed. Use case: clicking a focused button using a gamepad or keyboardSuppose we have some way of determining which element is focused. The user presses Enter or A on their gamepad, and the focused button is fired as soon as the button is pressed. Use case: context menusThe user moves their mouse over an element and right-clicks it. A context menu is opened with information and actions to perform relating to that object. Use case: drag and dropThe user moves their mouse over an object, presses left click, moves their mouse somewhere else and releases. The object is moved (in a literal or abstract sense) to the new destination. Use case: draggable tabsThe application has a collection of tabs, representing different workspaces. If a user presses and releases the left mouse button on the tab without dragging (a click), the tab is selected. But if the user instead clicks, drags and then releases, the tab is moved without focus swapping. Use case: tooltipsThe user moves their mouse over a button, waits for a second, but does not press any buttons. Some explanatory text appears about that object. Use case: Dynamic button stylingAll buttons in an app dynamically change their style (font, color, texture, drop shadow etc) based on their state.
Grayed-out state should take priority over pressed should take priority over hover should take priority over neutral. Additionally, we need to be able to distinguish where or not an element is focused. Proposed solutionsWe could solve this in several ways. Solution: boolean flagsKeep track of the following properties for each button-like UI element: For an initial implementation, only This can be done in a single component, or a set of related components, which can be gathered via a These values are updated by listening for picking events, except for hovering, which uses bevy_picking's hover map directly. This solution has the advantage of making dynamic button-styling super easy: the data needed is directly on the object, and we can match on the boolean flags to determine how to style our objects. Solution: yeet it completely
Rather than trying to reconstruct an event stream from stateful information (as is currently done in Bevy 0.14), The only use case where this stateful information is helpful is for dynamic button styling. In that case, a dedicated This design requires a bit more complexity for the users and has a more painful migration path, but is much more CPU and memory efficient. Path forwardI'm going to start implementing this tomorrow, aiming for a "just yeet it solution". If I can't get the ergonomics and clarity to where I want it to, I'll add a dedicated |
Another example of Hover/Pressed outside of UI is minecraft's feature where looking at a block gives it a black outline/border and clicking starts to break the block. This is a great place to use picking. Minecraft clones are a huge userbase! 😄 |
|
I have been doing these flags as separate components rather than as one component with multiple flags. There are a number of reasons for this:
I would divide the set of flags into the following groups: Universal States - that is, states that are used in the same way for almost all widgets:
Note that for hovering specifically, you could use the global picking hover map rather than a component or enter/leave events. However, the global hover map change bit changes every frame (the map is recomputed), which means that if you are doing change detection on the hover map you are updating every widget every frame. I don't like using enter/leave events for this because the event could be intercepted or re-routed because of a hierarchy change, leaving you with a "stuck key" syndrome. Using the hover map here is more robust. To make this efficient, we need a component which lets the widget author tell the system that they want to be notified when a given entity, or it's descendants, is hovered. The way I have implement this is to define Specialized States - states which are used by a particular type of widget
|
As a further example, let's dive deep into checkboxes for a second. There are two ways you can make a checkbox. The "simple" way is that checkboxes toggle their state on mouse down (if they aren't disabled). That is, unlike Button, they don't bother with pressed / dragging / roll-off / etc. So they don't need a The other way is that checkboxes work like Button, that is, the toggle happens on mouse up. I tend to like the first approach:
However, there's nothing wrong with doing the second approach. Toggle switches are exactly the same as checkboxes, except for two differences:
Other than that, the behavior is the same. Radio buttons are simply checkboxes that only toggle ON, not OFF. The mutual exclusion behavior is handled by the radio button group, which is a parent widget. In reactive apps, the mutual exclusion is done simply by setting a signal which stores the id of the current selected radio, and letting the radio buttons react to that signal. |
bevy_ui
'sInteraction
component is clunky and crude. Now that we have proper picking support, we should replace it completely in some form. See #8157, #10141, #9240, #7257, #420, #5769, #1239 and #2322 for prior related discussions.I'm aiming to tackle this over the next week as my primary task in the lead-up to the Bevy 0.15 release candidate :)
The text was updated successfully, but these errors were encountered: