[← Home](../../../README.md) · [Intuition](../../README.md) · [Frameworks](../README.md) # Layout System ## Overview MUI handles widget positioning automatically through its Group classes. Rather than specifying absolute coordinates, you declare the structure of your UI and MUI computes sizes and positions based on: - Each widget's minimum, default, and maximum size requirements - Group direction (horizontal or vertical) - Spacing, framing, and balancing hints - User preferences from the MUI settings program ## Group Classes Groups are containers that arrange their children. There are three primary group macros: | Macro | Direction | Description | |-------|-----------|-------------| | `VGroup` | Vertical | Stacks children top-to-bottom | | `HGroup` | Horizontal | Stacks children left-to-right | | `GroupObject` | Configurable | Defaults to vertical; can be changed with `MUIA_Group_Horiz` | ### Basic Vertical Layout ```c WindowContents, VGroup, Child, TextObject, MUIA_Text_Contents, "First line", End, Child, TextObject, MUIA_Text_Contents, "Second line", End, Child, StringObject, StringFrame, MUIA_String_Contents, "Input here", End, End, ``` **Visual result:** ```mermaid graph TB T1["Text: First line"] --> T2["Text: Second line"] --> S1["String: Input here"] style T1 fill:#e8f4fd,stroke:#2196f3,color:#333 style T2 fill:#e8f4fd,stroke:#2196f3,color:#333 style S1 fill:#fff3e0,stroke:#ff9800,color:#333 linkStyle default stroke:#ccc,stroke-width:1px ``` > VGroup stacks children **top-to-bottom**. Each child gets the full window width. ### Basic Horizontal Layout ```c WindowContents, HGroup, Child, SimpleButton("OK"), Child, SimpleButton("Cancel"), End, ``` **Visual result:** ```mermaid graph LR OK["OK"] --- CANCEL["Cancel"] style OK fill:#e8f5e9,stroke:#4caf50,color:#333 style CANCEL fill:#ffebee,stroke:#f44336,color:#333 ``` > HGroup arranges children **left-to-right**. Both buttons share available width equally. ### Nested Groups Complex layouts are built by nesting groups: ```c WindowContents, VGroup, Child, TextObject, TextFrame, MUIA_Background, MUII_TextBack, MUIA_Text_Contents, "\33cTitle", End, Child, HGroup, Child, VGroup, Child, SimpleButton("A"), Child, SimpleButton("B"), End, Child, VGroup, Child, SimpleButton("C"), Child, SimpleButton("D"), End, End, Child, HGroup, Child, HSpace(0), Child, SimpleButton("Close"), Child, HSpace(0), End, End, ``` **Visual result:** ```mermaid graph TB TITLE["Title"] --> HGROUP["HGroup"] HGROUP --> A["A"] & C["C"] A --> B["B"] C --> D["D"] TITLE --> BOTTOM["HGroup"] BOTTOM --> CLOSE["Close"] style TITLE fill:#e8f4fd,stroke:#2196f3,color:#333 style A fill:#e8f5e9,stroke:#4caf50,color:#333 style B fill:#e8f5e9,stroke:#4caf50,color:#333 style C fill:#e8f5e9,stroke:#4caf50,color:#333 style D fill:#e8f5e9,stroke:#4caf50,color:#333 style CLOSE fill:#fff3e0,stroke:#ff9800,color:#333 style HGROUP fill:#f5f5f5,stroke:#bdbdbd,color:#333 style BOTTOM fill:#f5f5f5,stroke:#bdbdbd,color:#333 linkStyle default stroke:#ccc,stroke-width:1px ``` > The outer VGroup stacks Title → HGroup → Close vertically. The HGroup lays out VGroup1 and VGroup2 side-by-side. A and B stack within VGroup1; C and D within VGroup2. ## Spacing Objects ### Rectangle A Rectangle is an invisible spacing object. Use it to create fixed or flexible gaps. ```c Child, RectangleObject, MUIA_Rectangle_HMin, 20, MUIA_Rectangle_VMin, 10, End, ``` ### Balance A Balance object is a draggable separator that divides space between adjacent children. Users can drag it to resize the areas. ```c Child, ListviewObject, MUIA_Listview_List, myList, End, Child, BalanceObject, End, Child, TextObject, MUIA_Text_Contents, "Details pane", End, ``` ### HSpace and VSpace Quick macros for adding flexible spacing: ```c Child, HSpace(0), /* expands to fill available horizontal space */ Child, VSpace(0), /* expands to fill available vertical space */ ``` Use these to push widgets to the edges or center them. ## Frames and Backgrounds Frames are visual borders around objects. MUI provides frame macros that set both the frame style and background: | Macro | Appearance | |-------|------------| | `TextFrame` | Standard text field frame | | `StringFrame` | Input field frame | | `GroupFrame` | Group border with optional title | | `ReadListFrame` | Listview frame | | `ButtonFrame` | Button frame | Usage: ```c Child, TextObject, TextFrame, MUIA_Background, MUII_TextBack, MUIA_Text_Contents, "Framed text", End, ``` Backgrounds can be specified with standard MUI images: | Constant | Meaning | |----------|---------| | `MUII_BACKGROUND` | Standard background | | `MUII_SHADOW` | Shadow color | | `MUII_SHINE` | Highlight color | | `MUII_FILL` | Fill pattern | | `MUII_TEXTBACK` | Text background | | `MUII_BUTTONBACK` | Button background | ## Group Attributes ### Same Size Force all children to have the same size: ```c HGroup, MUIA_Group_SameSize, TRUE, Child, SimpleButton("Short"), Child, SimpleButton("A much longer label"), End, ``` Both buttons will expand to fit the widest label. ### Columns Arrange children in a grid with a fixed number of columns: ```c GroupObject, MUIA_Group_Columns, 3, Child, SimpleButton("1"), Child, SimpleButton("2"), Child, SimpleButton("3"), Child, SimpleButton("4"), Child, SimpleButton("5"), End, ``` **Visual result (3-column grid, 5 children):** ```mermaid graph TB subgraph "ColGroup 3" direction TB subgraph "Row 1" direction LR B1["1"] B2["2"] B3["3"] end subgraph "Row 2" direction LR B4["4"] B5["5"] EMPTY[" "] end end style B1 fill:#e8f5e9,stroke:#4caf50,color:#333 style B2 fill:#e8f5e9,stroke:#4caf50,color:#333 style B3 fill:#e8f5e9,stroke:#4caf50,color:#333 style B4 fill:#e8f5e9,stroke:#4caf50,color:#333 style B5 fill:#e8f5e9,stroke:#4caf50,color:#333 style EMPTY fill:none,stroke:none ``` ### Horiz Make a Group horizontal instead of vertical: ```c GroupObject, MUIA_Group_Horiz, TRUE, ... End, ``` ## Custom Layout Hooks For complex layouts that MUI's built-in groups cannot express, you can provide a custom layout hook. The hook receives layout messages and positions children manually. ### Hook Structure ```c SAVEDS ULONG __asm LayoutFunc(REG(a0) struct Hook *h, REG(a2) Object *obj, REG(a1) struct MUI_LayoutMsg *lm) { switch (lm->lm_Type) { case MUILM_MINMAX: /* Calculate and return min/max/default sizes */ lm->lm_MinMax.MinWidth = ...; lm->lm_MinMax.MinHeight = ...; lm->lm_MinMax.DefWidth = ...; lm->lm_MinMax.DefHeight = ...; lm->lm_MinMax.MaxWidth = MUI_MAXMAX; lm->lm_MinMax.MaxHeight = MUI_MAXMAX; return 0; case MUILM_LAYOUT: /* Position each child with MUI_Layout() */ Object *cstate = (Object *)lm->lm_Children->mlh_Head; Object *child; while (child = NextObject(&cstate)) { if (!MUI_Layout(child, left, top, width, height, 0)) return FALSE; } return TRUE; } return MUILM_UNKNOWN; } ``` ### Attaching the Hook ```c static struct Hook LayoutHook = { {0,0}, LayoutFunc, NULL, NULL }; ... GroupObject, MUIA_Group_LayoutHook, &LayoutHook, Child, ..., Child, ..., End, ``` ### Important Notes - In `MUILM_MINMAX`, the children's min/max values are already calculated. You can use them to derive your group's size. - In `MUILM_LAYOUT`, you must call `MUI_Layout()` for every child. The rectangle you are given is `(0, 0, width-1, height-1)`. - Return `MUILM_UNKNOWN` for any message type you do not handle. - Avoid errors during layout; MUI does not handle them gracefully. ## Virtual Groups and Scroll Groups When content exceeds available space, use a virtual group with scrollbars: ```c Child, ScrollgroupObject, MUIA_Scrollgroup_Contents, VirtgroupObject, Child, /* lots of widgets */, Child, /* lots of widgets */, End, End, ``` The `Virtgroup` creates a virtual canvas. The `Scrollgroup` adds scrollbars as needed. **Scrollgroup structure:** ```mermaid graph TB subgraph "ScrollgroupObject" direction TB subgraph "Visible viewport" V1["Widget 1"] V2["Widget 2"] V3["Widget 3"] end VSCROLL["▲ Scrollbar ▼"] subgraph "Hidden (below viewport)" V4["Widget 4"] V5["Widget 5"] V6["..."] end end style V1 fill:#e8f5e9,stroke:#4caf50,color:#333 style V2 fill:#e8f5e9,stroke:#4caf50,color:#333 style V3 fill:#e8f5e9,stroke:#4caf50,color:#333 style V4 fill:#f5f5f5,stroke:#bdbdbd,color:#999 style V5 fill:#f5f5f5,stroke:#bdbdbd,color:#999 style V6 fill:#f5f5f5,stroke:#bdbdbd,color:#999 style VSCROLL fill:#fff3e0,stroke:#ff9800,color:#333 ``` ## Layout Algorithm ```mermaid sequenceDiagram participant App as Application participant Win as Window participant Root as Root Group participant C1 as Child 1 participant C2 as Child 2 Note over App,C2: Pass 1 — AskMinMax (bottom-up) Root->>C1: MUIM_AskMinMax C1-->>Root: min=40, def=80, max=200 Root->>C2: MUIM_AskMinMax C2-->>Root: min=60, def=100, max=300 Root-->>Win: group min=100, def=180, max=500 Note over App,C2: Window opens at calculated size Win->>Win: OpenWindow(def_width=180) Note over App,C2: Pass 2 — Layout (top-down) Win->>Root: Layout(0, 0, 180, h) Root->>Root: Distribute 180px by weight Root->>C1: MUI_Layout(x=0, w=80) Root->>C2: MUI_Layout(x=82, w=98) Note over App,C2: Pass 3 — Draw Root->>C1: MUIM_Draw Root->>C2: MUIM_Draw ``` ### On Window Resize ```mermaid sequenceDiagram participant User participant Win as Window participant Root as Root Group participant C1 as Child 1 participant C2 as Child 2 User->>Win: Drags size gadget Win->>C1: MUIM_Hide Win->>C2: MUIM_Hide Win->>Root: Layout(0, 0, new_w, new_h) Root->>Root: Redistribute space Root->>C1: MUI_Layout(new rect) Root->>C2: MUI_Layout(new rect) Win->>C1: MUIM_Show + MUIM_Draw Win->>C2: MUIM_Show + MUIM_Draw ``` ### File Requester — Real-World Layout Example From the official MUI SDK, a file requester demonstrates nested group layout: ```mermaid graph TB subgraph "Window (VGroup)" direction TB subgraph "HGroup — Lists" direction LR FILELIST["File List
(Listview)
C/
Classes/
Devs/
..."] DEVLIST["Device List
(Listview)
dh0:
dh1:
df0:
ram:"] end PATH["Path: ___________________"] FILE["File: ___________________"] subgraph "HGroup — Buttons" direction LR OK["OK"] SPACE1[" "] CANCEL["Cancel"] end end style FILELIST fill:#e8f4fd,stroke:#2196f3,color:#333 style DEVLIST fill:#e8f4fd,stroke:#2196f3,color:#333 style PATH fill:#fff3e0,stroke:#ff9800,color:#333 style FILE fill:#fff3e0,stroke:#ff9800,color:#333 style OK fill:#e8f5e9,stroke:#4caf50,color:#333 style CANCEL fill:#ffebee,stroke:#f44336,color:#333 style SPACE1 fill:none,stroke:none ``` **Corresponding MUI code:** ```c VGroup, Child, HGroup, Child, FileListview(), Child, DeviceListview(), End, Child, PathGadget(), Child, FileGadget(), Child, HGroup, Child, OkayButton(), Child, HSpace(0), Child, CancelButton(), End, End; ``` --- Previous: [Core Concepts](04-core-concepts.md) Next: [Widgets Overview](06-widgets-overview.md)