Skip to content
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

Add PositionType::Fixed #9564

Open
viridia opened this issue Aug 24, 2023 · 14 comments · May be fixed by #11926
Open

Add PositionType::Fixed #9564

viridia opened this issue Aug 24, 2023 · 14 comments · May be fixed by #11926
Labels
A-UI Graphical user interfaces, styles, layouts, and widgets C-Feature A new feature, making something new possible D-Trivial Nice and easy! A great choice to get started with Bevy

Comments

@viridia
Copy link
Contributor

viridia commented Aug 24, 2023

What problem does this solve or what need does it fill?

For modal dialogs and popup menus, it is helpful to be able to position an element relative to the window rather than its parent element.

What solution would you like?

Currently the UI PositionType enum supports two types of positioning: PositionType::Absolute and PositionType::Relative which correspond to the CSS properties position: absolute and position: relative. This proposal adds a third choice, PositionType::Fixed which positions elements relative to the window, and which also corresponds to the CSS attribute of that name. In other words, the element's parent position is ignored, and instead its layout is considered as if its parent was the same coordinates and dimensions as the window.

Note: the semantics of "fixed" as proposed here are slightly different than the meaning of the CSS property - a "fixed" element in CSS is one that never scrolls, and is always relative to the viewport. Since Bevy doesn't have scrolling, the difference is moot.

What alternative(s) have you considered?

For something like a modal dialog or popup menu, it's possible to work around this by creating a completely separate view hierarchy for the overlay element, and then using state variables to control the opening and closing of it.

However, this approach has a drawback, which means that you can no longer use event bubbling to communicate between the dialogue and the code that invoked it. (I know Bevy doesn't have bubbling yet, but bevy_eventlistener does, and I believe bubbling is a planned feature).

Particularly for popup menus, the logic for positioning a menu requires placing the menu in absolute window coordinates (often limiting the menu size or switching sides depending on the available space), but still communicating with the anchor element (such as the menu button) as if it were a child element. (This also requires knowing the coordinates of the anchor in absolute window coordinates, but that's a different problem).

Dialogues which represent major "game modes" are often root-level components and thus don't require this; however contextual dialogues which are triggered by some other UI element (such as a combo box) are often implemented as children of that element; requiring the dialogue to be a root involves additional boilerplate.

Additional context

Frameworks such as React and Solid also provide a feature known as "portals" which allow sub-components to render elements that are located at the root of the DOM but still communicate with their parents as though they were children. This feature covers some of the same use cases.

@viridia viridia added C-Feature A new feature, making something new possible S-Needs-Triage This issue needs to be labelled labels Aug 24, 2023
@viridia viridia changed the title Add Position::Fixed Add PositionType::Fixed Aug 24, 2023
@alice-i-cecile alice-i-cecile added A-UI Graphical user interfaces, styles, layouts, and widgets and removed S-Needs-Triage This issue needs to be labelled labels Aug 24, 2023
@alice-i-cecile
Copy link
Member

@nicoburns this feels like a feature we should implement in Taffy, and then expose in Bevy. Do you agree?

@viridia
Copy link
Contributor Author

viridia commented Aug 24, 2023

@nicoburns this feels like a feature we should implement in Taffy, and then expose in Bevy. Do you agree?

You might not need to. The root element (that is, any UI element that doesn't have a parent) already has this behavior; perhaps all you need to do is layout the element as if it had no parent.

@ickshonpe
Copy link
Contributor

I think this can be implemented quite easily in Bevy itself. The proposal makes a reasonable argument as to why it would be useful I guess. I'm not sure about the name, scrolling is something we are planning to implement and there is a PR #8104 though it hasn't seen much progress lately. Regardless, feels like we should be able to come up with something more descriptive than Fixed.

@ickshonpe
Copy link
Contributor

PositionType::Origin?

@viridia
Copy link
Contributor Author

viridia commented Aug 24, 2023

Other possible names:

PositionType::Root
PositionType::Window

@alice-i-cecile
Copy link
Member

I like PositionType::Window quite a lot: it's very explicit about what it's positioned relative to.

@alice-i-cecile alice-i-cecile added the D-Trivial Nice and easy! A great choice to get started with Bevy label Aug 25, 2023
@ickshonpe
Copy link
Contributor

ickshonpe commented Aug 25, 2023

Root seems like it might be confusing but Window seems alright. Maybe it doesn't quite fit when rendering to texture but that's probably not a problem.

@ewrogers
Copy link

ewrogers commented Aug 26, 2023

I like PositionType::Window quite a lot: it's very explicit about what it's positioned relative to.

Coming from CSS / Tailwind, Fixed seems more logical to me as it's often used in modals and other web-based "popups. It also seems to fit in with the rest of the variant names.

Looking at the variants, Absolute and Relative make sense but Window in the context of those is a bit unclear. Whereas Fixed has the implication of "this does not move" and would be familiar to people coming from CSS backgrounds.

I'm somewhat new to Rust and just getting into Bevy, so I am considering this as a good first issue to take and contribute!

@alice-i-cecile
Copy link
Member

That sounds great! Link this issue in that PR and we'll give you some reviews :)

@danik292
Copy link

danik292 commented Sep 4, 2023

Hello where to fix

@viridia
Copy link
Contributor Author

viridia commented Sep 16, 2024

BTW, just to be clear - the reason I chose the word "fixed" is because:

  • Bevy's PositionType enum is clearly inspired by the CSS position attribute.
  • Of the available options for CSS position, the fixed value is the one that most closely matches the behavior we want. (Some options, like sticky and static, are meaningless in the context of Bevy.)

In other words, web developers will know exactly what it means. Non-web developers will have to learn what it means :)

@viridia
Copy link
Contributor Author

viridia commented Oct 6, 2024

@UkoeHB @nicoburns Some additional thoughts on implementation. There are two obvious approaches:

  • Add support for fixed positions in Taffy.
  • Implement purely this in Bevy, without changing Taffy. That is, we'd still use the same positioning logic in Taffy as for absolute positioning, except that instead of passing in a layout context that includes the coordinates of the parent rect, we would instead pass in the coordinates of the window rect. In other words, we'd just lie to Taffy about the parent's rect.

This raises some questions:

  • Which window? The obvious choice is the same window as the parent. Position::Fixed as proposed doesn't affect the inheritance of TargetCamera or any other inherited rendering attributes, so we'd be rendering on the same surface as the ui ancestors, with the same surface dimensions.
  • Note that the user always has an option to insert a TargetCamera component, which would impact this calculation, but this also would logically impact vh and vw length calculations as well - see next bullet point. However, for MVP we really don't need to consider the case of overriding TargetCamera, but it can be something considered for the future.
  • How do we get the window rect? Do we need to walk up the ancestor chain until we find a root ancestor? I strongly suspect not:
    • For the (top, left) coordinates, these should always be (0, 0).
    • For the (width, height) values, we should already have these available in scope, since they are needed for the vwin and hwin length calculations.

@UkoeHB
Copy link
Contributor

UkoeHB commented Oct 7, 2024

Both options seem fine to me.

@alice-i-cecile
Copy link
Member

Wearing my taffy maintainer hat, I'd prefer the former solution if everything else is equal. I think it's cleaner, and this is functionality that all of our consumers could benefit from.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-UI Graphical user interfaces, styles, layouts, and widgets C-Feature A new feature, making something new possible D-Trivial Nice and easy! A great choice to get started with Bevy
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants