WIP: feat!: tree scene hierarchy and single-pass layout system #88

Draft
abart27 wants to merge 50 commits from simple-layout into main
abart27 commented 2026-07-10 12:14:53 +00:00 (Migrated from github.com)

TODO

  • Layout tests (just some basic render_rect comparisons)
  • Test compat in Redux

Breaking Changes

UID slot changes

Various controls now use more UID slots due to internal changes.

button - 2 slots
toggle_button - 2 slots
carrousel_button - 4 slots
combobox - 9 slots
spinner - 9 slots
tabcontrol - n(children) * 2 + 1

Tip: if you find yourself having to fix UID-related breakage often, space out the UIDs in your scene by 100 - it's easy to keep an eye on and reasonably safe against future breakage.

Reserved UID

UID math.mininteger is now reserved by ugui and can't be used by library consumers. If you're using that UID, change it to something else.

Control references

While not explicitly documented anywhere, previous versions of ugui somewhat tolerated holding on to a Control instance after it's consumed by ugui.control (or one of the control placing functions like ugui.button).

This behavior is now out the window: reading back from control tables after they're consumed is undefined behavior.

Barely any library consumers rely on this behavior, but if you do, you can re-architect your script to store data in a safe local context instead of smuggling it through ugui.


Templated controls

ugui.control as well as all control spawning functions (e.g. ugui.button) now have an additional parameter, fn.

fn is a callback that's called immediately after the control was placed. Any controls placed within the callback will be parented to the newly placed control.

It's important to note that the controls themselves decide when fn is called. Therefore, it behaves more like a slot, similar to WPF's ContentPresenter.

Many controls now place children by default, but this isn't something public API consumers should care about.

Control.rectangle

The Control.rectangle field has been deprecated.

Any usages of it will be internally translated to margins and sizes (see below).

Control positioning and sizing

The positioning and sizing of controls is now controlled via the Control.margin, Control.align, Control.size, and Control.padding properties. See the docs.

Note the Smart[...] units.

Units

A unit system has been introduced. If you're familiar with CSS units, these are basically a barebones version of that.

See the docs for more.

# TODO - [ ] Layout tests (just some basic render_rect comparisons) - [ ] Test compat in Redux ## Breaking Changes ### UID slot changes Various controls now use more UID slots due to internal changes. `button` - 2 slots `toggle_button` - 2 slots `carrousel_button` - 4 slots `combobox` - 9 slots `spinner` - 9 slots `tabcontrol` - `n(children) * 2 + 1` Tip: if you find yourself having to fix UID-related breakage often, space out the UIDs in your scene by `100` - it's easy to keep an eye on and reasonably safe against future breakage. ### Reserved UID UID `math.mininteger` is now reserved by ugui and can't be used by library consumers. If you're using that UID, change it to something else. ### Control references While not explicitly documented anywhere, previous versions of ugui somewhat tolerated holding on to a `Control` instance after it's consumed by `ugui.control` (or one of the control placing functions like `ugui.button`). This behavior is now out the window: reading back from control tables after they're consumed is undefined behavior. Barely any library consumers rely on this behavior, but if you do, you can re-architect your script to store data in a safe local context instead of smuggling it through ugui. --------------- ## Templated controls `ugui.control` as well as all control spawning functions (e.g. `ugui.button`) now have an additional parameter, `fn`. `fn` is a callback that's called immediately after the control was placed. Any controls placed within the callback will be parented to the newly placed control. It's important to note that **the controls themselves decide when `fn` is called**. Therefore, it behaves more like a slot, similar to WPF's `ContentPresenter`. Many controls now place children by default, but this isn't something public API consumers should care about. ## `Control.rectangle` The `Control.rectangle` field has been deprecated. Any usages of it will be internally translated to margins and sizes (see below). ## Control positioning and sizing The positioning and sizing of controls is now controlled via the `Control.margin`, `Control.align`, `Control.size`, and `Control.padding` properties. See [the docs](https://github.com/mupen64/ugui/blob/scene-tree/src/ugui/controls/control.lua). Note the `Smart[...]` units. ## Units A unit system has been introduced. If you're familiar with CSS units, these are basically a barebones version of that. See the docs for more.
This pull request is marked as a work in progress.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin simple-layout:simple-layout
git switch simple-layout

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch main
git merge --no-ff simple-layout
git switch simple-layout
git rebase main
git switch main
git merge --ff-only simple-layout
git switch simple-layout
git rebase main
git switch main
git merge --no-ff simple-layout
git switch main
git merge --squash simple-layout
git switch main
git merge --ff-only simple-layout
git switch main
git merge simple-layout
git push origin main
Sign in to join this conversation.
No description provided.