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

New UI Layout System #2641

Open
MechWarrior99 opened this issue Feb 15, 2025 · 8 comments
Open

New UI Layout System #2641

MechWarrior99 opened this issue Feb 15, 2025 · 8 comments
Labels
enhancement New feature or request

Comments

@MechWarrior99
Copy link
Contributor

Overview

The current UI layout system is has limited layout abilities, inconsistent behaviors, and un-needed properties. These make it clunky and slow to create complex UIs with. This proposes a new layout system using a single type that can be a fixed size, flex or percent of parent.

Current Issues

  1. Alignment
    • Context: UIElement has vertical and horizontal alignment properties that influence size and position.
    • These only take affect with certain parent configurations, making them feel unpredictable and useless much of the time.
    • Mixes size and position responsibility between parents and children.
  2. Default size
    • Context: UIElement has a default size property for each axis.
    • These are only used when an axis size and MeasureOverirde() both are NaN.
    • They add add bloat when creating UI and are rarely used.
  3. Margins
    • Context: UIElement has margins property for each side of the element.
    • They generally make elements difficult to re-use.
    • Margins don't really belong to any given element since it is the space between them.
    • If margins are used to separate elements in a collection, special handling is needed for the last/first one.

Proposed System

Introduce a new Length value type with three modes:

  • Fixed – Absolute pixel value.
  • Flex – Fills available space.
  • Percent – Relative to the parent’s size.

Use Length for all spacing and sizing properties (Width, Height, Padding, etc.).

Refactored/Replace StackPanel

  • Orientation – Defines the layout axis.
  • SpaceBefore / SpaceAfter – Controls space before/after the first/last element along the main axis.
  • SpaceBetween – Defines space between elements along the main axis.
  • DefaultCrossAxisSpaceBefore / After – Default space between children between a child and the edges of the panel along the cross axis.
  • CrossAxisSpaceBefore / After (attached property) – The cross axis spacing defined per-child.

Other elements (Canvas, ContentControl, Grid, etc.) would see similar changes.

New System Rules

  • Parents control child positioning and external spacing.
  • An element can never be smaller than the size of its content or defined size (whichever is larger).
  • The fallback size of an element is always to its smallest size.
  • Flex values in infinite space default to the smallest fixed value (e.g. content size for flex elements, or 0 for padding, etc.).
  • Conflicting positioning defaults to centering, unless the parent specifies otherwise.

Removals

  • Margins – Parent elements control spacing.
  • Vertical/Horizontal Alignment – Positioning is managed by parents; stretching is handled by Flex.
  • Default Width/Height – Replaced with sensible default behavior when encountering a NaN size.

Conclusion

This system would allow much more versatile layouts than are currently possible, and keeps to a set of simple, predictable rules that are reused through the system.

Here is a prototype of the changes to the StackPanel showing the Length based properties.

Stride.GameStudio_2025-02-15_10-55-21.mp4

This would either have to be a very breaking change, or introduce a lot of redundant properties and elements. For example, changing public float Width {get; set;} to public Length Width {get; set; } would be desired, but breaking. Could introduce a new property, but then you have 2 sets of widths (and lots of others) which would add to the bloat.

Please let me know if you have any thoughts, like or dislike it, questions etc!

@MechWarrior99 MechWarrior99 added the enhancement New feature or request label Feb 15, 2025
@Eideren
Copy link
Collaborator

Eideren commented Feb 16, 2025

Looks like every parent would effectively be a stack panel, how do you think Grids would work under this new system ?

In the video you've attached, we can see that the elements have both a Width and Flex Width - I'm guessing the width here is just temporary, and would be entirely replaced by the latter ?

I'm not sure I understood what the cross axis is for, I'm afraid the name/description is a bit too obtuse

We could build an upgrader to take care of the breaking changes on the assets themselves, while other properties could temporarily remap to similar concepts in this new layout design with an added obsolete flag.

@MechWarrior99
Copy link
Contributor Author

MechWarrior99 commented Feb 16, 2025

Looks like every parent would effectively be a stack panel, how do you think Grids would work under this new system ?

I imagine that they would work much the same as they do now, with each row and column defined using a Length. And adding a 'space between' option as well. With each cell being sort of like its own little content container.

[..] elements have both a Width and Flex Width -I'm guessing the width here is just temporary, and would be entirely replaced by the latter ?

I started it as a prototype to test the layout system, so to avoid ldealing with compile errors by changing the types of Width, and Height, and since I didn't know what the upgrade path may look like, I just added Flex Width/Height for now. My intent/ideal would be to change the type of Width and Height and remove Flex Width/Height as that makes the most naming sense and would feel cleanest in the end.
(You can also see that the alignment, margin, and default properties are all still present as well.)

I'm not sure I understood what the cross axis is for, I'm afraid the name/description is a bit too obtuse

The cross axis is the non-main layout axis of the stack panel. So if a stack panel arranges children vertically, the cross axis would be the horizontal axis.
At first I was not sure on the term either, but other libraries use it and I haven't thought of a more intuative term yet.

@MechWarrior99
Copy link
Contributor Author

@Eideren This proposed new system, along with the Depth Removal PR and the Styling Changes proposal all being fairly breaking changes to the UI, with many having limited ability to migrate. And the UI system being used as little as it is. I wonder if it is really worth trying to prevent breaking changes at the cost of the API (like having to introduce new Flex Width/Height properties).

Opting instead for just a written guide for updating (blog post or page on the docs?). And only including the changes in the next major release.

Asking because I would like to clean up my prototype and open a draft PR so others can actually try it out if they so desire, and to avoid just dropping a very large PR out of nowhere. But not sure what is okay to remove/change if we are going to try to support upgrading. Let me know what you think (or others too!), thanks! :D

@Kryptos-FR
Copy link
Member

There is a mechanism to write asset updaters. It can be used to upgrade an old system to a new one. It doesn't cover breaking change in code though.

In any case, breaking change should be kept to a major version of Stride. Maybe we should create a new branch for all UI related stuff (and have all those PRs target that branch), which will let us more time to test out regressions and breaks.

@MechWarrior99
Copy link
Contributor Author

There is a mechanism to write asset updaters

Oh nice! Is there a class I could look at for an example (a quick search of the code base didn't reveal anything really)? And does it require the old properties to be present?

breaking change should be kept to a major version of Stride

Yeah my intentation has been that these changes would be for a major version because they are breaking.

Maybe we should create a new branch for all UI related stuff

That seems like a good idea to me

@Eideren
Copy link
Collaborator

Eideren commented Feb 22, 2025

Is there a class I could look at for an example

Have a look at the AssetUpgraderAttribute and references to it.


Do you happen to have ideas on how we could improve the layout system to make supporting different screen sizes easier ?
Something drastic like support between phone and desktop is too large a change, but between 16:9, 16:10, 32:9 or 4:3 with the same UI would be nice.

Building the UI around a static ratio doesn't work too well with the different screen ratios we have, especially when the game's window is resized.

I know Unity has a weird anchor system were UI elements can be attached to screen edges, this makes it easier for certain ui types like the player's own health bars, spell bars and such. It's a bit obtuse though, and really works best with a fixed resolution.

For example, it would be nice to fix the following case: a container with a specific size which should scale up to fit snugly inside the viewport, with some margin if at all possible. It would take the smallest size between the viewport's X/Y size and scales itself to match it in that axis while the other axis scales as well but should keep the same ratio.

@MechWarrior99
Copy link
Contributor Author

Have a look at the AssetUpgraderAttribute and references to it.

Ahh, not sure why I didn't see it when I searched eariler, thanks!


Do you happen to have ideas on how we could improve the layout system to make supporting different screen sizes easier?

Yeah, I think the Percentage, and Flex can help a lot with that. You could combine a flex width with a maximum size to let things scale to take up as much space as they can up to a point. While being able to be 'squashed' when they have less room.

I know Unity has a weird anchor system were UI elements can be attached to screen edges,

Stride has the Canvas which can do the same sort of thing currently using attached properties.

For the ratio, I was thinking either a content container that specifically does ratio scaling from the parent's size, or a property on UIElement that would 'lock' the size to a certain ratio. Need to think about the actual requirements and conditions for what would make sense. But does one of those sound like it would help?

@Eideren
Copy link
Collaborator

Eideren commented Feb 22, 2025

Yeah, that was one of the reason why I liked your idea of the flex and percentage stuff.
The idea of the lock makes me think that it could very well be another property that takes part in the flex stuff, not sure how it would fit in though, but yes, that sounds pretty good !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants