-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Add IgnoreParentClip component to ignore parent element clipping #21836
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
base: main
Are you sure you want to change the base?
Conversation
|
Can be used to implement scrollarea that utilizes taffy scrollbar_size: scroll-area-auto-attached.mov |
|
Is |
|
In case of Another option would be to set |
ickshonpe
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is the right approach. Instead the scrollbars should just be rendered for the parent element of the scrolling area, which precludes the need for this opt out.
I see. I think the correct answer here is better ergonomics around adding children to the right place or something like react portals, or simply living with the boilerplate of wrappers. I don't disagree with any of the code or the implementation itself, but that i think this kind of corner-case feature is very easy to have regressions on or make future changes to clipping more difficult |
|
Thanks for your comments. I understand your point of view. I will tell you my experience with current bevy ui scrollarea approach. I would argue against requiring unnecessary ui node hierarchy where it is not needed. Taffy layout already handles scroll overflow and even provides space for scrollbars. No need for any portals, boilerplate, parent elements. I am currently creating complex ui interfaces in bevy ui: https://github.com/PPakalns/bevy_immediate/ I have already worked with a ton of scrollareas in my ui and I see problems with the current "grid with content and scrollbars" approach or with any "wrapper node approach".
I think that these changes or similar functionality would be very, very useful to simplify ui creation in bevy. ❤️ |
There is no easy way to correctly position scrollbars at correct place when rendering them in parent element without requiring additional wrapper element. Of course this could be done by manually positioning |
I can migrate existing Scrollbars example or add a new example with this approach. |
387c13b to
e6ae9e8
Compare
|
Added an example for
Check out how much simpler the possible api is for defining scroll areas: Example: bevy/examples/ui/scrollbars.rs Lines 202 to 236 in e6ae9e8
P.S. Grid example of course could be simplified too with wrapper function. But remember that grid element and scroll element requires separate styling and it is a lot less ergonomic. Sadly |
My reply was a bit misphrased. With "parent element of the scrolling area", the parent would be the UI node with In this model there wouldn't be any need for nodes representing the scrollbars at all, which avoids the synchronisation and clipping problems. |
|
And I think even with a scrolling area widget, it's simpler to have a parent node that contains the scrolling area, with child nodes representing the scrolling view, horizontal scrollbar, and vertical scrollbar. So a construction something like (very loosely): (
scrolling_widget(),
children![
(
// Suspect it might be simplest to always spawn scrollbar nodes, and disable them with `Display::None` when the content isn't overflowing.
horizontal_scrollbar(),
vertical_scrollbar(),
(
scrolling_view(),
children![
text_row("Alpha Wolf"),
text_row("Beta Blocker"),
text_row("Delta Sleep"),
text_row("Gamma Ray"),
text_row("Epsilon Eridani"),
text_row("Zeta Function"),
text_row("Lambda Calculus"),
text_row("Nu Metal"),
text_row("Pi Day"),
text_row("Chi Pants"),
text_row("Psi Powers"),
],
)
),
],
)I don't like the |
| fn scroll_area_with_overlay_demo() -> impl Bundle { | ||
| ( | ||
| // The scroll area with scrollable content | ||
| Node { | ||
| display: Display::Flex, | ||
| overflow: Overflow::scroll(), | ||
| scrollbar_width: 8., | ||
| width: px(200), | ||
| height: px(150), | ||
| flex_direction: FlexDirection::Column, | ||
| padding: UiRect::all(px(4)), | ||
| ..default() | ||
| }, | ||
| BackgroundColor(colors::GRAY1.into()), | ||
| ScrollPosition(Vec2::new(0.0, 10.0)), | ||
| Children::spawn(( | ||
| // Add scroll area overlay to this element | ||
| scroll_area_overlay_for_overlay_demo(), | ||
| // | ||
| // The actual content of the scrolling area | ||
| Spawn(text_row("Alpha Wolf")), | ||
| Spawn(text_row("Beta Blocker")), | ||
| Spawn(text_row("Delta Sleep")), | ||
| Spawn(text_row("Gamma Ray")), | ||
| Spawn(text_row("Epsilon Eridani")), | ||
| Spawn(text_row("Zeta Function")), | ||
| Spawn(text_row("Lambda Calculus")), | ||
| Spawn(text_row("Nu Metal")), | ||
| Spawn(text_row("Pi Day")), | ||
| Spawn(text_row("Chi Pants")), | ||
| Spawn(text_row("Psi Powers")), | ||
| // Spawn(text_row("Omega Fatty Acid")), | ||
| )), | ||
| ) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dislike this design with the overlay stored as a sibling of the content, as it requires the user to be mindful of the overlay node. Ideally the construction of the scrolling view widget should be completely opaque to the user.
So here instead I'd prefer a composition something like:
| fn scroll_area_with_overlay_demo() -> impl Bundle { | |
| ( | |
| // The scroll area with scrollable content | |
| Node { | |
| display: Display::Flex, | |
| overflow: Overflow::scroll(), | |
| scrollbar_width: 8., | |
| width: px(200), | |
| height: px(150), | |
| flex_direction: FlexDirection::Column, | |
| padding: UiRect::all(px(4)), | |
| ..default() | |
| }, | |
| BackgroundColor(colors::GRAY1.into()), | |
| ScrollPosition(Vec2::new(0.0, 10.0)), | |
| Children::spawn(( | |
| // Add scroll area overlay to this element | |
| scroll_area_overlay_for_overlay_demo(), | |
| // | |
| // The actual content of the scrolling area | |
| Spawn(text_row("Alpha Wolf")), | |
| Spawn(text_row("Beta Blocker")), | |
| Spawn(text_row("Delta Sleep")), | |
| Spawn(text_row("Gamma Ray")), | |
| Spawn(text_row("Epsilon Eridani")), | |
| Spawn(text_row("Zeta Function")), | |
| Spawn(text_row("Lambda Calculus")), | |
| Spawn(text_row("Nu Metal")), | |
| Spawn(text_row("Pi Day")), | |
| Spawn(text_row("Chi Pants")), | |
| Spawn(text_row("Psi Powers")), | |
| // Spawn(text_row("Omega Fatty Acid")), | |
| )), | |
| ) | |
| } | |
| fn scroll_area_with_overlay_demo() -> impl Bundle { | |
| ( | |
| // The scroll area with scrollable content | |
| Node { | |
| display: Display::Flex, | |
| overflow: Overflow::scroll(), | |
| scrollbar_width: 8., | |
| width: px(200), | |
| height: px(150), | |
| padding: UiRect::all(px(4)), | |
| ..default() | |
| }, | |
| BackgroundColor(colors::GRAY1.into()), | |
| ScrollPosition(Vec2::new(0.0, 10.0)), | |
| Children::spawn(( | |
| // Add scroll area overlay to this element | |
| scroll_area_overlay_for_overlay_demo(), | |
| Spawn(( | |
| Node { | |
| flex_direction: FlexDirection::Column, | |
| ..default() | |
| }, | |
| Children::spawn(( | |
| // The actual content of the scrolling area | |
| Spawn(text_row("Alpha Wolf")), | |
| Spawn(text_row("Beta Blocker")), | |
| Spawn(text_row("Delta Sleep")), | |
| Spawn(text_row("Gamma Ray")), | |
| Spawn(text_row("Epsilon Eridani")), | |
| Spawn(text_row("Zeta Function")), | |
| Spawn(text_row("Lambda Calculus")), | |
| Spawn(text_row("Nu Metal")), | |
| Spawn(text_row("Pi Day")), | |
| Spawn(text_row("Chi Pants")), | |
| Spawn(text_row("Psi Powers")), | |
| // Spawn(text_row("Omega Fatty Acid")), | |
| )), | |
| )), | |
| )), | |
| ) | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This again introduces multi layer layout that makes getting the right layout behavior working correctly more difficult. (at least in my experience) And requires ui styling to be split for outer and inner node.
If you play around with scrollareas that can shrink or expand only to the required size, it is easy to see that introducing additional hierarchy makes it a lot harder to predict how layout will behave.
This was the reason why I want to get rid of requiring additional hierarchy for scroll areas.
Instead users can simply add overflow: clip and scrollbar_width where necessary.
And users of scroll area can write a system that automatically inserts scroll area overlay where it's needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can even add that logic to the example, it is a very simple system and additional marker component to track if overlay has been inserted.
|
I think we have two different problems that we are trying to resolve. 😄 In my case: I just want to simplify scroll area use as much as possible, but with keeping full customization of how they are styled and work.
This was the simplest approach to get this simple mechanism working. I do not need to modify layout, introduce additional ui element hierarchy to turn something into a scroll area. It works great with hot reloading solutions like bevy subsecond or bevy flair. It make creating ui interfaces a lot easier. |
I don't see any other approach where we can fully reuse bevy ui functionality to get maximal customization out of the box. There is no easy alternative way that I know without additional hierarchy to automatically place scroll bars at correct place that work with so many use cases that i have mentioned. If you do not like introducing additional Maybe we can merge together Like this is such a simple feature that enables so many use cases with such a small change to clipping logic. |
Additional use case for this featureAdding decorations to elements in front and background (even dynamically) without requiring changes in ui element hierarchy. Basically IgnoreParentClip can be used for all use cases of OverrideClip , but in situations where clipping still must happen, because it is inserted inside some other clipped ui element. Maybe |

Objective
Implement UI nodes that can ignore parent node clipping restrictions, but still are restricted by grandparent node clipping restrictions.
Useful for creating scroll-areas that utilize scrollbar-width provided by taffy. Using IgnoreParentClip it is possible to avoid two element hierarchy requirement for scroll-areas. Instead scrollbar overlay can be inserted as child element with
position: absolute; width: 100%; height: 100%; z-index: 1; ignore-scroll: true. Then scrollbars can be inserted inside this overlay element. If we want to place scrollbars on space provided byscrollbar-width, negative offset is needed, e.g.right: -8px. This goes outside clipping rect of scrollarea. Therefore functionality to ignore parent element clipping rect is needed.Solution
Introduce
IgnoreParentClipcomponent that instructs clipping rect calculations to use grand parent clipping rect in calculations for ui entities with this component.Testing