bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
36.14k stars 3.56k forks source link

Add PositionType::Fixed #9564

Open viridia opened 1 year ago

viridia commented 1 year ago

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.

alice-i-cecile commented 1 year ago

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

viridia commented 1 year ago

@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 commented 1 year ago

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 commented 1 year ago

PositionType::Origin?

viridia commented 1 year ago

Other possible names:

PositionType::Root
PositionType::Window
alice-i-cecile commented 1 year ago

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

ickshonpe commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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

danik292 commented 1 year ago

Hello where to fix

viridia commented 1 month ago

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

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

viridia commented 1 month ago

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

This raises some questions:

UkoeHB commented 1 month ago

Both options seem fine to me.

alice-i-cecile commented 1 month ago

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.