-
Notifications
You must be signed in to change notification settings - Fork 1
Layouts
The layout system is go-gui's flex model. Every container is a Row or Column at
its core; the specialised containers (Splitter, DockLayout, etc.) layer behaviour on top.
Understanding sizing modes is the key to productive layout work.
All containers accept a Sizing field that controls how width and height are determined.
The pattern is Width×Height:
| Mode | Width | Height |
|---|---|---|
FillFill |
Grow to fill parent | Grow to fill parent |
FillFit |
Grow to fill parent | Shrink to fit children |
FitFill |
Shrink to fit children | Grow to fill parent |
FitFit |
Shrink to fit children | Shrink to fit children |
FixedFixed |
Use explicit Width/Height
|
Use explicit Width/Height
|
FixedFit |
Use explicit Width
|
Shrink to fit children |
FillFixed |
Grow to fill parent | Use explicit Height
|
FillFill makes a container take all available space. FitFit makes it hug its
content. FixedFixed pins both dimensions explicitly — useful for the root container
at window size:
gui.Column(gui.ContainerCfg{
Width: float32(ww),
Height: float32(wh),
Sizing: gui.FixedFixed,
})gui.Row and gui.Column are the fundamental containers. They arrange children
horizontally or vertically with configurable alignment and spacing.
gui.Row(gui.ContainerCfg{
Sizing: gui.FillFit,
Spacing: gui.SomeF(8),
VAlign: gui.VAlignMiddle,
Padding: gui.SomeP(4, 8, 4, 8), // top, right, bottom, left
Content: []gui.View{
icon,
label,
},
})gui.Column uses the same ContainerCfg; only the axis changes.
Alignment constants:
- HAlign:
HAlignLeft,HAlignCenter,HAlignRight - VAlign:
VAlignTop,VAlignMiddle,VAlignBottom
gui.Wrap flows children left-to-right and wraps to a new row when the available width
is exhausted — the same model as CSS flex-wrap: wrap.
gui.Wrap(gui.ContainerCfg{
Sizing: gui.FillFit,
Spacing: gui.SomeF(8),
Content: tagViews, // []gui.View — wraps automatically
})Useful for tag clouds, icon grids, and responsive button groups.
gui.Canvas places children at absolute coordinates. Each child positions itself via
X/Y on its Shape. Use this when precise pixel placement is required.
gui.Canvas(gui.ContainerCfg{
Width: 400,
Height: 300,
Sizing: gui.FixedFixed,
Content: []gui.View{
labelAt(50, 40, "Origin marker"),
iconAt(200, 150, gui.IconStar),
},
})For procedural drawing within a fixed area, see DrawCanvas in
Display Widgets.
gui.ExpandPanel(gui.ExpandPanelCfg{...}) is a collapsible accordion section. The Head
view is always visible; Content reveals when Open is true.
gui.ExpandPanel(gui.ExpandPanelCfg{
ID: "details",
Open: app.DetailsOpen,
Head: gui.Text(gui.TextCfg{Text: "Advanced options", TextStyle: t.B3}),
Content: gui.Column(gui.ContainerCfg{
Sizing: gui.FillFit,
Padding: gui.SomeP(8, 0, 8, 0),
Content: []gui.View{
optionRows...,
},
}),
OnToggle: func(w *gui.Window) {
gui.State[App](w).DetailsOpen = !gui.State[App](w).DetailsOpen
},
})Stack multiple ExpandPanel widgets in a Column to build a full accordion.
gui.Splitter(gui.SplitterCfg{...}) divides space between two panes with a draggable
handle. The split can be horizontal (top/bottom) or vertical (left/right).
gui.Splitter(gui.SplitterCfg{
ID: "editor-preview",
IDFocus: 20,
Orientation: gui.SplitterVertical,
Sizing: gui.FillFill,
Ratio: gui.SomeF(app.SplitRatio), // 0.0–1.0
ShowCollapseButtons: true,
Collapsed: app.SplitCollapsed,
OnChange: func(ratio float64, collapsed int, w *gui.Window) {
a := gui.State[App](w)
a.SplitRatio = ratio
a.SplitCollapsed = collapsed
},
First: gui.SplitterPaneCfg{
MinSize: 110,
Content: []gui.View{editorView},
},
Second: gui.SplitterPaneCfg{
MinSize: 90,
Content: []gui.View{previewView},
},
})The ratio and collapsed state live in your own state struct — go-gui does not own them.
Home/End collapse the focused pane when ShowCollapseButtons is true.
w.Sidebar(gui.SidebarCfg{...}) is an animated slide-out side panel. It is typically
placed as the first child of a Row, beside the main content area.
gui.Row(gui.ContainerCfg{
Sizing: gui.FillFixed,
Height: 500,
Padding: gui.NoPadding,
Content: []gui.View{
w.Sidebar(gui.SidebarCfg{
ID: "nav",
Open: app.NavOpen,
Width: 220,
Content: []gui.View{navItems},
}),
mainContent,
},
})Flip app.NavOpen in any OnClick to animate open/close.
gui.OverflowPanel(gui.OverflowPanelCfg{...}) clips its children to a fixed area and
provides scroll controls for the overflow. Use it when the content list is long but the
available space is fixed.
gui.OverflowPanel(gui.OverflowPanelCfg{
ID: "log-panel",
IDScroll: 300,
Sizing: gui.FillFixed,
Height: 240,
Content: logLineViews,
})IDScroll registers the container with the scroll system so the framework tracks its
offset. See Focus and Scrolling for programmatic scroll control.
gui.DockLayout(gui.DockLayoutCfg{...}) provides IDE-style dockable panels: areas that
can be split, merged, and rearranged by dragging tabs between them at runtime.
The layout tree is a *gui.DockNode stored in your state. The framework calls
OnLayoutChange whenever the user rearranges panels so you can persist the new
arrangement.
// initial layout: left sidebar + main split (editor on top, terminal below)
func initialLayout() *gui.DockNode {
return gui.DockSplit("root", gui.DockSplitHorizontal, 0.2,
gui.DockPanelGroup("left", []string{"explorer"}, "explorer"),
gui.DockSplit("right", gui.DockSplitVertical, 0.75,
gui.DockPanelGroup("editor-area", []string{"editor"}, "editor"),
gui.DockPanelGroup("bottom", []string{"terminal"}, "terminal"),
),
)
}
// in the view function
gui.DockLayout(gui.DockLayoutCfg{
ID: "main-dock",
Root: app.DockRoot,
Panels: dockPanels(),
OnLayoutChange: func(root *gui.DockNode, w *gui.Window) {
gui.State[App](w).DockRoot = root
},
OnPanelSelect: func(groupID, panelID string, w *gui.Window) {
a := gui.State[App](w)
a.DockRoot = gui.DockTreeSelectPanel(a.DockRoot, groupID, panelID)
},
})dockPanels() returns []gui.DockPanelCfg, each with an ID and a View factory.
The view factory is called each frame only for visible panels.
gui.RotatedBox(gui.RotatedBoxCfg{...}) rotates its single child by a multiple of 90°.
QuarterTurns: 1 is 90° clockwise, 2 is 180°, 3 is 270°.
gui.RotatedBox(gui.RotatedBoxCfg{
QuarterTurns: 1,
Content: gui.Text(gui.TextCfg{
Text: "Rotated label",
TextStyle: gui.CurrentTheme().N3,
}),
})Useful for vertical axis labels in charts or sideways tab strips.
Getting Started
Widgets
Layout & Interaction
Visuals
Reference