-
-
Notifications
You must be signed in to change notification settings - Fork 3.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
WIP: Support scrolling (Overflow::Scroll
) in bevy_ui
#8104
Conversation
29aa3a0
to
4379fd5
Compare
It looks like your PR is a breaking change, but you didn't provide a migration guide. Could you add some context on what users should update when this change get released in a new version of Bevy? |
Hmm... This adds new variants to an enum and a new component to a bundle. Would bevy consider that a breaking change? |
dddd297
to
8a33a96
Compare
63d9c8f
to
cf4bfb6
Compare
@nicoburns Question I have is, how will games control the appearance of the scrollbars? On the web, the ability to customize the look of scrollbars is quite limited (more so in some browsers than others), and the web community has generally punted on this issue by converging on a fairly common (and boring) visual design for scrollbars which nearly every UI toolkit adheres to. However, games want novel and fancy UI designs, and I think scrollbars are no exception. Granted, not many game HUDs have scrollbars, but there are exceptions:
Editors and other tools built on Bevy UI are of course going to have lots of scrollbars, but their need for visual novelty is not quite as acute. A related question is the API for controlling scroll position. "Scroll selected item into view" is probably the most common of these. If scrolling is just mucking around with the node transform, then user code which explicitly sets the translation is probably going to mess things up. We really ought to define an API to let user code do the standard things (scroll to top, scroll to bottom, show selected, etc.) without having to directly touch the node transforms. As someone in the process of writing a UI framework, I'm perfectly prepared to do my own "scrollview" widget implementation if that's what it takes. I know that on the web, scrolling is a style property that is inherent in every element, but that is not the case in desktop toolkits such as Java Swing or Qt, where scrolling is a specific widget type. I actually think that model may be more appropriate, given the general rarity of scrolling views in games, but the question then becomes where do we draw the line between the responsibilities of bevy_ui and the responsibilities of the toolkit? |
# Objective - Enables support for `Display::Block` - Enables support for `Overflow::Hidden` - Allows for cleaner integration with text, image and other content layout. - Unblocks #8104 - Unlocks the possibility of Bevy creating a custom layout tree over which Taffy operates. - Enables #8808 / #10193 to remove a Mutex around the font system. ## Todo - [x] ~Fix rendering of text/images to account for padding/border on nodes (should size/position to content box rather than border box)~ In order get this into a mergeable state this PR instead zeroes out padding/border when syncing leaf node styles into Taffy to preserve the existing behaviour. #6879 can be fixed in a followup PR. ## Solution - Update the version of Taffy - Update code to work with the new version Note: Taffy 0.4 has not yet been released. This PR is being created in advance of the release to ensure that there are no blockers to upgrading once the release occurs. --- ## Changelog - Bevy now supports the `Display::Block` and `Overflow::Hidden` styles.
Is there anything new to announce? |
Closing as adopted <3 |
# Objective - Fixes #8074 - Adopts / Supersedes #8104 ## Solution Adapted from #8104 and affords the same benefits. **Additions** - [x] Update scrolling on relayout (height of node or contents may have changed) - [x] Make ScrollPosition component optional for ui nodes to avoid checking every node on scroll - [x] Nested scrollviews **Omissions** - Removed input handling for scrolling from `bevy_ui`. Users should update `ScrollPosition` directly. ### Implementation Adds a new `ScrollPosition` component. Updating this component on a `Node` with an overflow axis set to `OverflowAxis::Scroll` will reposition its children by that amount when calculating node transforms. As before, no impact on the underlying Taffy layout. Calculating this correctly is trickier than it was in #8104 due to `"Update scrolling on relayout"`. **Background** When `ScrollPosition` is updated directly by the user, it can be trivially handled in-engine by adding the parent's scroll position to the final location of each child node. However, _other layout actions_ may result in a situation where `ScrollPosition` needs to be updated. Consider a 1000 pixel tall vertically scrolling list of 100 elements, each 100 pixels tall. Scrolled to the bottom, the `ScrollPosition.offset_y` is 9000, just enough to display the last element in the list. When removing an element from that list, the new desired `ScrollPosition.offset_y` is 8900, but, critically, that is not known until after the sizes and positions of the children of the scrollable node are resolved. All user scrolling code today handles this by delaying the resolution by one frame. One notable disadvantage of this is the inability to support `WinitSettings::desktop_app()`, since there would need to be an input AFTER the layout change that caused the scroll position to update for the results of the scroll position update to render visually. I propose the alternative in this PR, which allows for same-frame resolution of scrolling layout. **Resolution** _Edit: Below resolution is outdated, and replaced with the simpler usage of taffy's `Layout::content_size`._ When recursively iterating the children of a node, each child now returns a `Vec2` representing the location of their own bottom right corner. Then, `[[0,0, [x,y]]` represents a bounding box containing the scrollable area filled by that child. Scrollable parents aggregate those areas into the bounding box of _all_ children, then consider that result against `ScrollPosition` to ensure its validity. In the event that resolution of the layout of the children invalidates the `ScrollPosition` (e.g. scrolled further than there were children to scroll to), _all_ children of that node must be recursively repositioned. The position of each child must change as a result of the change in scroll position. Therefore, this implementation takes care to only spend the cost of the "second layout pass" when a specific node actually had a `ScrollPosition` forcibly updated by the layout of its children. ## Testing Examples in `ui/scroll.rs`. There may be more complex node/style interactions that were unconsidered. --- ## Showcase ![scroll](https://github.com/user-attachments/assets/1331138f-93aa-4a8f-959c-6be18a04ff03) ## Alternatives - `bevy_ui` doesn't support scrolling. - `bevy_ui` implements scrolling with a one-frame delay on reactions to layout changes.
Objective
Allow users to create scrollable regions using
bevy_ui
.Fixes #8074
Prior Art
https://github.com/Piefayth/bevy_ui_scroll
Solution
This is adapted from the scrolling implementation in the
examples/ui/ui.rs
example, but is improved in that it does not use the style system in order to apply offsets (which requires a relayout each time the scroll position changes, and interferes with users wanting to use that same style):Overflow::Scroll
variant has been added to theOverflow
enum to mark nodes that should be scrollableRequirements from Taffy:
Overflow::Hidden
DioxusLabs/taffy#424 (Correctly lay outOverflow::Scroll
/Overflow::Hidden
nodes)Overflow::Scroll
DioxusLabs/taffy#446 (Support reserving space for scrollbars forOverflow::Scroll
nodes)Tasks
Overflow::Scroll
variant toOverflow
enumScrollPosition
componentupdate_scroll_position
systemOverflow
in each axis (Split UIOverflow
by axis #8095)ScrollPosition
component optional for ui nodes to avoid checking every node on scrollChangelog
Overflow::Scroll