Skip to content

feat!: layout system and tree scene hierarchy - #83

Closed
abart27 wants to merge 102 commits into
mainfrom
scene-tree
Closed

feat!: layout system and tree scene hierarchy#83
abart27 wants to merge 102 commits into
mainfrom
scene-tree

Conversation

@abart27

@abart27 abart27 commented May 7, 2026

Copy link
Copy Markdown
Member

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 20.

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.

Layout

A rudimentary layout system has been introduced: controls can specify how their children are laid out, with the only layout modes being relative and stack.

background, border, and border_width

It's now possible to specify a background, border, and border_width for any control.

These are drawn before handing over to the control-specific drawing code and are particularly useful when used together with a panel.

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. Here are the docs:

---@alias SmartUnit
---| "0"
---| "auto"
---| string
---
---A size unit specification that can be:
---
---    `"auto"` - natural size
---    `"{}px"` - absolute pixels (e.g. `"100px"`)
---    `"{}%"` - percentage of parent size (e.g. `"50%"`)
---
---Zero literals are treated as `0px` (e.g. `0` => `0px`)
---
---Basic arithmetic operations are also supported: `+`, `-`, `*`, `/`.
---
---    `100px-3%`
---    `auto*10px`
---
---Constraints can also be applied:
---
---    `min(auto,5px)`
---    `max(auto,5px)`
---    `clamp(auto,5px,10px)`


---@alias SmartUnit2
---| "0"
---| "auto"
---| "0 0"
---| "auto auto"
---| string
---
---A two-dimensional unit that is composed of two SmartUnits.
---
---If one component is omitted, it's assumed to be equal to the other component.
---
---    `100px 100px`
---    `100px` (expands to `100px 100px`)
---    `auto 50%`

---@alias SmartAlignment
---| "0"
---| "0%"
---| "0.5"
---| "50%"
---| "1"
---| "100%"
---| "left"
---| "right"
---| "top"
---| "bottom"
---| "center"
---| string
---An alignment unit that specifies how a control is aligned within its parent.
---
---    `0`, `0%` - start of parent
---    `0.5`, `50%` - center of parent
---    `1`, `100%` - end of parent

---@alias SmartAlignment2
---| "0"
---| "0 0"
---| "0%"
---| "0% 0%"
---| "0.5"
---| "0.5 0.5"
---| "50%"
---| "50% 50%"
---| "1"
---| "1 1"
---| "100%"
---| "100% 100%"
---| "left"
---| "left left"
---| "right"
---| "right right"
---| "top"
---| "top top"
---| "bottom"
---| "bottom bottom"
---| "center"
---| "center center"
---| string
---
---A two-dimensional alignment unit that is composed of two SmartAlignments.
---
---If one component is omitted, it's assumed to be equal to the other component.
---
---    `0 0` - top-left corner
---    `0` - top-left corner
---    `50%`, `center`, `center center` - center
---    `left`, `left left` - left edge
---    `right`, `right right` - right edge
---    `top`, `top top` - top edge
---    `bottom`, `bottom bottom` - bottom edge

I understand that the type design for this isn't the most efficient or idiomatic in Lua. Cleaner design would be some lightweight factory that generates these in a more type-safe manner.

But I went for this because it was the simplest and nicest for now. I'm not particularly attached to this design, so fire away lol

@abart27 abart27 changed the title refactor!: store scene as tree feat!: tree scene hierarchy May 7, 2026
@abart27 abart27 changed the title feat!: tree scene hierarchy feat!: control layout model and tree scene hierarchy May 7, 2026
@abart27
abart27 marked this pull request as draft May 10, 2026 19:14
@abart27 abart27 mentioned this pull request May 11, 2026
@abart27 abart27 changed the title feat!: margin/sizing system and tree scene hierarchy feat!: layout system and tree scene hierarchy May 15, 2026
@abart27

abart27 commented Jun 22, 2026

Copy link
Copy Markdown
Member Author

The dynamic layout part (stacks, scrollviewers, etc...) is blowing up in complexity.

For that reason, we'll delay the implementation of that functionality indefinitely.

For now, this PR will only provide basic layout functionality with no dynamic layouts.

@abart27 abart27 closed this Jul 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants