$npx -y skills add ZhangHanDong/makepad-skills --skill makepad-2.0-layoutCRITICAL: Use for Makepad 2.0 layout system. Triggers on: makepad layout, makepad width, makepad height, makepad flex, makepad flow, makepad padding, makepad margin, makepad spacing, makepad align, makepad sizing, Fill, Fit, Inset, Flow.Down, Flow.Right, ScrollXView, ScrollYView,
| 1 | # Makepad 2.0 Layout System |
| 2 | |
| 3 | Makepad uses a **layout turtle** system -- not CSS flexbox, not CSS grid. The turtle walks |
| 4 | through children one by one, placing each widget according to two core concepts: |
| 5 | |
| 6 | - **Walk** -- how a widget sizes itself (width, height, margin) |
| 7 | - **Layout** -- how a container arranges its children (flow, spacing, padding, align) |
| 8 | |
| 9 | Every container widget (View, SolidView, RoundedView, ScrollYView, etc.) has both Walk |
| 10 | properties (its own size) and Layout properties (how it lays out children). |
| 11 | |
| 12 | --- |
| 13 | |
| 14 | ## Walk System (Widget Sizing) |
| 15 | |
| 16 | Walk controls how an individual widget claims space inside its parent. |
| 17 | |
| 18 | ### width / height |
| 19 | |
| 20 | | Syntax | Meaning | |
| 21 | |--------|---------| |
| 22 | | `width: Fill` | Fill all remaining horizontal space (default) | |
| 23 | | `width: Fit` | Shrink to fit content | |
| 24 | | `width: 200` | Fixed 200 pixels | |
| 25 | | `width: Fill{min: 100 max: 500}` | Fill with constraints | |
| 26 | | `width: Fit{max: Abs(300)}` | Fit content, capped at 300px | |
| 27 | | `height: Fill` | Fill all remaining vertical space (default) | |
| 28 | | `height: Fit` | Shrink to fit content | |
| 29 | | `height: 100` | Fixed 100 pixels | |
| 30 | |
| 31 | ``` |
| 32 | use mod.prelude.widgets.* |
| 33 | |
| 34 | // Fill: takes all available width |
| 35 | View{ |
| 36 | width: Fill height: Fit |
| 37 | flow: Down |
| 38 | Label{text: "I stretch to fill the width"} |
| 39 | } |
| 40 | |
| 41 | // Fit: shrinks to content |
| 42 | View{ |
| 43 | width: Fit height: Fit |
| 44 | padding: 10 |
| 45 | Label{text: "I am only as wide as this text"} |
| 46 | } |
| 47 | |
| 48 | // Fixed: exact pixel size |
| 49 | View{ |
| 50 | width: 300 height: 200 |
| 51 | Label{text: "I am exactly 300x200 pixels"} |
| 52 | } |
| 53 | |
| 54 | // Constrained Fill: fills but within bounds |
| 55 | View{ |
| 56 | width: Fill{min: 200 max: 600} height: Fit |
| 57 | flow: Down padding: 16 |
| 58 | Label{text: "I fill available space but stay between 200-600px"} |
| 59 | } |
| 60 | ``` |
| 61 | |
| 62 | ### CRITICAL: height: Fit on Containers |
| 63 | |
| 64 | **This is the number one layout bug in Makepad.** |
| 65 | |
| 66 | The default height is `Fill`. When your output renders inside a `Fit` container, |
| 67 | `Fill` inside `Fit` creates a circular dependency and resolves to **0 pixels**. |
| 68 | Your entire UI becomes invisible. |
| 69 | |
| 70 | **Rule: ALWAYS set `height: Fit` on every View, SolidView, RoundedView, and similar |
| 71 | container unless the parent has a fixed or Fill height.** |
| 72 | |
| 73 | ``` |
| 74 | // CORRECT -- height: Fit makes the container visible |
| 75 | View{ |
| 76 | width: Fill height: Fit |
| 77 | flow: Down padding: 10 |
| 78 | Label{text: "I am visible"} |
| 79 | } |
| 80 | |
| 81 | // WRONG -- defaults to height: Fill, resolves to 0px, invisible |
| 82 | View{ |
| 83 | width: Fill |
| 84 | flow: Down padding: 10 |
| 85 | Label{text: "I am invisible (0px tall)"} |
| 86 | } |
| 87 | ``` |
| 88 | |
| 89 | **Exceptions where height: Fill is acceptable:** |
| 90 | 1. Inside a fixed-height parent: |
| 91 | ``` |
| 92 | View{ |
| 93 | height: 400 |
| 94 | View{ |
| 95 | height: Fill |
| 96 | Label{text: "I fill the 400px parent"} |
| 97 | } |
| 98 | } |
| 99 | ``` |
| 100 | 2. Inside a `height: Fill` chain that ultimately reaches a known size (e.g., Window body). |
| 101 | 3. ScrollYView always uses `height: Fill` because it must fill its parent to scroll. |
| 102 | |
| 103 | ### margin |
| 104 | |
| 105 | Margin adds space around the outside of a widget. |
| 106 | |
| 107 | ``` |
| 108 | // Uniform margin on all sides |
| 109 | Label{text: "Hello" margin: 10} |
| 110 | |
| 111 | // Selective margin with Inset |
| 112 | Label{ |
| 113 | text: "Indented" |
| 114 | margin: Inset{top: 5 bottom: 5 left: 20 right: 20} |
| 115 | } |
| 116 | |
| 117 | // Zero margin (note the trailing dot for float literal) |
| 118 | Label{text: "Flush" margin: 0.} |
| 119 | ``` |
| 120 | |
| 121 | --- |
| 122 | |
| 123 | ## Layout System (Child Arrangement) |
| 124 | |
| 125 | Layout controls how a container positions its children. |
| 126 | |
| 127 | ### flow (Direction) |
| 128 | |
| 129 | | Syntax | Meaning | CSS Equivalent | |
| 130 | |--------|---------|----------------| |
| 131 | | `flow: Right` | Left-to-right, single line (default) | `flex-direction: row` | |
| 132 | | `flow: Down` | Top-to-bottom, single column | `flex-direction: column` | |
| 133 | | `flow: Overlay` | Stack children on top of each other | `position: absolute` stacking | |
| 134 | | `flow: Flow.Right{wrap: true}` | Left-to-right with wrapping | `flex-wrap: wrap` | |
| 135 | | `flow: Flow.Down{wrap: true}` | Top-to-bottom with wrapping | column wrap | |
| 136 | |
| 137 | ``` |
| 138 | use mod.prelude.widgets.* |
| 139 | |
| 140 | // Vertical stack (most common) |
| 141 | View{ |
| 142 | width: Fill height: Fit |
| 143 | flow: Down spacing: 10 |
| 144 | Label{text: "First"} |
| 145 | Label{text: "Second"} |
| 146 | Label{text: "Third"} |
| 147 | } |
| 148 | |
| 149 | // Horizontal row |
| 150 | View{ |
| 151 | width: Fill height: Fit |
| 152 | flow: Right spacing: 10 |
| 153 | Label{text: "Left"} |
| 154 | Label{text: "Center"} |
| 155 | Label{text: "Right"} |
| 156 | } |
| 157 | |
| 158 | // Overlay -- children stacked on top of each other |
| 159 | View{ |
| 160 | width: Fill height: 200 |
| 161 | flow: Overlay |
| 162 | Image{width: Fill height: Fill fit: ImageFit.Biggest} |
| 163 | View{ |
| 164 | width: Fill height: Fit |
| 165 | align: Align{x: 0.5 y: 1.0} |
| 166 | padding: 10 |
| 167 | Label{text: "Caption overlay" draw_text.color: #fff} |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | // Wrapping flow -- like a tag cloud or grid of cards |
| 172 | View{ |
| 173 | width: Fill height: Fit |
| 174 | flow: Flow.Right{wrap: true} |
| 175 | spacing: 8 |
| 176 | padding: 10 |