Documentation
¶
Overview ¶
Package layout provides a public, extensible layout system for gogpu/ui.
This package exposes layout algorithms that third-party developers can use and extend to create custom layouts. It provides the LayoutAlgorithm interface for pluggable layout computation and a Registry for registering custom layouts.
Architecture ¶
The layout system is built around several key concepts:
- LayoutAlgorithm: Interface for pluggable layout computation
- LayoutTree: Interface providing access to the node tree for algorithms
- Registry: Global registry for layout algorithms by name
- Style: CSS-like layout properties for nodes
Built-in Layouts ¶
The package provides built-in layout algorithms:
- "flex": CSS Flexbox-style layout (FlexLayout)
- "vstack": Vertical stack layout
- "hstack": Horizontal stack layout
- "zstack": Overlay stack layout
- "grid": CSS Grid-style layout (GridLayout)
These are automatically registered via init() functions.
Custom Layouts ¶
Third-party developers can create custom layouts by implementing LayoutAlgorithm:
package masonry
import "github.com/gogpu/ui/layout"
func init() {
layout.Register("masonry", &MasonryLayout{})
}
type MasonryLayout struct {
Columns int
}
func (m *MasonryLayout) Name() string { return "masonry" }
func (m *MasonryLayout) Compute(tree layout.LayoutTree, root layout.NodeID, available geometry.Size) layout.Result {
// Custom masonry algorithm implementation
// ...
}
Thread Safety ¶
The Registry is thread-safe for concurrent registration and lookup. Individual layout algorithms may have their own thread-safety requirements.
Relationship to internal/layout ¶
This package provides the public API for layout extensibility. The internal/layout package contains the actual layout implementations (FlexContainer, VStack, HStack, ZStack, GridContainer, Engine) that are used by the UI framework internally.
The algorithms in this package wrap the internal implementations and expose them through the LayoutAlgorithm interface.
Index ¶
- func Count() int
- func Has(name string) bool
- func List() []string
- func Register(algorithm LayoutAlgorithm)
- func RegisterWithName(name string, algorithm LayoutAlgorithm)
- func Unregister(name string) bool
- type AlignContent
- type AlignItems
- type Dimension
- type DimensionUnit
- type Display
- type FlexDirection
- type FlexLayout
- type FlexWrap
- type GridLayout
- type GridTrack
- type GridTrackSizing
- type JustifyContent
- type LayoutAlgorithm
- type LayoutFunc
- type LayoutTree
- type LayoutTreeAdapter
- type NodeID
- type NodeLayout
- type Registry
- func (r *Registry) Clear()
- func (r *Registry) Clone() *Registry
- func (r *Registry) Count() int
- func (r *Registry) Get(name string) (LayoutAlgorithm, bool)
- func (r *Registry) Has(name string) bool
- func (r *Registry) List() []string
- func (r *Registry) MustGet(name string) LayoutAlgorithm
- func (r *Registry) Register(algorithm LayoutAlgorithm)
- func (r *Registry) RegisterWithName(name string, algorithm LayoutAlgorithm)
- func (r *Registry) Unregister(name string) bool
- type Result
- type StackAlignment
- type StackDirection
- type StackLayout
- type Style
- func (s Style) WithAlignItems(align AlignItems) Style
- func (s Style) WithDisplay(display Display) Style
- func (s Style) WithFlex(grow, shrink float32, basis Dimension) Style
- func (s Style) WithFlexDirection(direction FlexDirection) Style
- func (s Style) WithGap(gap float32) Style
- func (s Style) WithJustifyContent(justify JustifyContent) Style
- func (s Style) WithMargin(margin geometry.Insets) Style
- func (s Style) WithPadding(padding geometry.Insets) Style
- func (s Style) WithSize(width, height Dimension) Style
- type ZStackAlignment
- type ZStackLayout
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Register ¶
func Register(algorithm LayoutAlgorithm)
Register adds a layout algorithm to the global registry.
This is typically called from init() functions:
func init() {
layout.Register(&MyCustomLayout{})
}
func RegisterWithName ¶
func RegisterWithName(name string, algorithm LayoutAlgorithm)
RegisterWithName adds a layout algorithm with an explicit name to the global registry.
func Unregister ¶
Unregister removes a layout algorithm from the global registry.
Types ¶
type AlignContent ¶
type AlignContent int
AlignContent specifies how to distribute space between wrapped lines.
const ( // AlignContentStart packs lines at the start. AlignContentStart AlignContent = iota // AlignContentEnd packs lines at the end. AlignContentEnd // AlignContentCenter centers lines. AlignContentCenter // AlignContentStretch stretches lines to fill. AlignContentStretch // AlignContentSpaceBetween distributes space between lines. AlignContentSpaceBetween // AlignContentSpaceAround distributes space around lines. AlignContentSpaceAround )
func (AlignContent) String ¶
func (a AlignContent) String() string
String returns a string representation of align content.
type AlignItems ¶
type AlignItems int
AlignItems specifies how to align children along the cross axis.
const ( // AlignItemsStart aligns children to the start of the cross axis. AlignItemsStart AlignItems = iota // AlignItemsEnd aligns children to the end of the cross axis. AlignItemsEnd // AlignItemsCenter centers children along the cross axis. AlignItemsCenter // AlignItemsStretch stretches children to fill the cross axis. AlignItemsStretch // AlignItemsBaseline aligns children by their baselines. AlignItemsBaseline )
func (AlignItems) String ¶
func (a AlignItems) String() string
String returns a string representation of align items.
type Dimension ¶
type Dimension struct {
Value float32
Unit DimensionUnit
}
Dimension represents a size value that can be auto, pixels, or percent.
type DimensionUnit ¶
type DimensionUnit int
DimensionUnit specifies how a dimension value is interpreted.
const ( // DimensionAuto uses automatic sizing based on content. DimensionAuto DimensionUnit = iota // DimensionPixels uses an absolute pixel value. DimensionPixels // DimensionPercent uses a percentage of the parent's size. DimensionPercent )
type FlexDirection ¶
type FlexDirection int
FlexDirection specifies the main axis direction for flex layout.
const ( // FlexRow arranges children horizontally from left to right. FlexRow FlexDirection = iota // FlexRowReverse arranges children horizontally from right to left. FlexRowReverse // FlexColumn arranges children vertically from top to bottom. FlexColumn // FlexColumnReverse arranges children vertically from bottom to top. FlexColumnReverse )
func (FlexDirection) IsHorizontal ¶
func (d FlexDirection) IsHorizontal() bool
IsHorizontal returns true if the direction is horizontal.
func (FlexDirection) IsReversed ¶
func (d FlexDirection) IsReversed() bool
IsReversed returns true if the direction is reversed.
func (FlexDirection) String ¶
func (d FlexDirection) String() string
String returns a string representation of the flex direction.
type FlexLayout ¶
type FlexLayout struct{}
FlexLayout implements CSS Flexbox-style layout.
FlexLayout arranges children along a main axis (row or column), distributing space according to flex properties from the node styles.
Properties Used ¶
From parent style:
- FlexDirection: main axis direction
- FlexWrap: whether items wrap
- JustifyContent: main axis space distribution
- AlignItems: cross axis alignment
- Gap: space between items
From child styles:
- FlexGrow: how much item grows to fill space
- FlexShrink: how much item shrinks when space is tight
- FlexBasis: initial size before grow/shrink
func (*FlexLayout) Compute ¶
func (f *FlexLayout) Compute(tree LayoutTree, root NodeID, available geometry.Size) Result
Compute performs flexbox layout on the tree starting at root.
type GridLayout ¶
type GridLayout struct {
// Columns defines the column tracks.
Columns []GridTrack
// Rows defines the row tracks.
Rows []GridTrack
// ColumnGap is the space between columns.
ColumnGap float32
// RowGap is the space between rows.
RowGap float32
}
GridLayout implements CSS Grid-style layout.
GridLayout arranges children in a grid of rows and columns, with support for fixed, auto, and fractional track sizes.
func SimpleGrid ¶
func SimpleGrid(numColumns int, gap float32) *GridLayout
SimpleGrid creates a grid layout with equal fractional columns.
func (*GridLayout) Compute ¶
func (g *GridLayout) Compute(tree LayoutTree, root NodeID, available geometry.Size) Result
Compute performs grid layout on the tree starting at root.
type GridTrack ¶
type GridTrack struct {
// Sizing specifies how the track is sized.
Sizing GridTrackSizing
// Value is the size value. Meaning depends on Sizing:
// - GridTrackAuto: ignored
// - GridTrackFixed: pixel size
// - GridTrackFraction: fraction value (like 1fr, 2fr)
Value float32
}
GridTrack defines a grid row or column.
func FractionTrack ¶
FractionTrack creates a fractional track.
type GridTrackSizing ¶
type GridTrackSizing int
GridTrackSizing specifies how a grid track (row or column) is sized.
const ( // GridTrackAuto sizes the track to fit its content. GridTrackAuto GridTrackSizing = iota // GridTrackFixed uses a fixed pixel size. GridTrackFixed // GridTrackFraction uses a fraction of available space (like CSS fr unit). GridTrackFraction )
type JustifyContent ¶
type JustifyContent int
JustifyContent specifies how to distribute space along the main axis.
const ( // JustifyStart packs children at the start of the main axis. JustifyStart JustifyContent = iota // JustifyEnd packs children at the end of the main axis. JustifyEnd // JustifyCenter centers children along the main axis. JustifyCenter // JustifySpaceBetween distributes space between children (no space at edges). JustifySpaceBetween // JustifySpaceAround distributes space around children (half space at edges). JustifySpaceAround // JustifySpaceEvenly distributes space evenly (equal space everywhere). JustifySpaceEvenly )
func (JustifyContent) String ¶
func (j JustifyContent) String() string
String returns a string representation of justify content.
type LayoutAlgorithm ¶
type LayoutAlgorithm interface {
// Name returns the algorithm identifier.
// This name is used to register and look up the algorithm in the registry.
// Names should be lowercase and may use hyphens (e.g., "flex", "simple-row").
Name() string
// Compute calculates layout for the given tree starting at root.
//
// Parameters:
// - tree: Interface for accessing and modifying the node tree
// - root: The root node to start layout from
// - available: The available space for the root node
//
// Returns:
// - Result containing the computed size and overflow status
//
// The algorithm must call tree.SetLayout() for each node it processes.
Compute(tree LayoutTree, root NodeID, available geometry.Size) Result
}
LayoutAlgorithm computes layout for a tree of nodes.
Implementations of this interface define how child nodes are positioned and sized within their parent. The algorithm receives access to the node tree through the LayoutTree interface and must set layouts for all nodes it processes.
Implementation Guidelines ¶
A layout algorithm should:
- Traverse children via [LayoutTree.ChildCount] and [LayoutTree.ChildAt]
- Get style properties via [LayoutTree.Style]
- Measure leaf nodes via [LayoutTree.Measure]
- Compute positions and sizes for each child
- Set computed layouts via [LayoutTree.SetLayout]
- Return the total size in Result
Example Implementation ¶
type SimpleRowLayout struct{}
func (s *SimpleRowLayout) Name() string { return "simple-row" }
func (s *SimpleRowLayout) Compute(tree LayoutTree, root NodeID, available geometry.Size) Result {
var x float32
var maxHeight float32
for i := 0; i < tree.ChildCount(root); i++ {
child := tree.ChildAt(root, i)
constraints := geometry.Constraints{MaxWidth: available.Width - x, MaxHeight: available.Height}
childSize := tree.Measure(child, constraints)
tree.SetLayout(child, NodeLayout{
Position: geometry.Point{X: x, Y: 0},
Size: childSize,
})
x += childSize.Width
if childSize.Height > maxHeight {
maxHeight = childSize.Height
}
}
return Result{Size: geometry.Size{Width: x, Height: maxHeight}}
}
func Get ¶
func Get(name string) (LayoutAlgorithm, bool)
Get retrieves a layout algorithm from the global registry.
func MustGet ¶
func MustGet(name string) LayoutAlgorithm
MustGet retrieves a layout algorithm from the global registry, panicking if not found.
type LayoutFunc ¶
type LayoutFunc struct {
// NameValue is the algorithm name.
NameValue string
// ComputeFunc is the layout computation function.
ComputeFunc func(tree LayoutTree, root NodeID, available geometry.Size) Result
}
LayoutFunc is a convenience type for creating algorithms from functions.
This allows creating simple layout algorithms without defining a new type:
layout.Register("custom", layout.LayoutFunc{
NameValue: "custom",
ComputeFunc: func(tree layout.LayoutTree, root layout.NodeID, available geometry.Size) layout.Result {
// Layout logic here
},
})
func (LayoutFunc) Compute ¶
func (f LayoutFunc) Compute(tree LayoutTree, root NodeID, available geometry.Size) Result
Compute delegates to ComputeFunc.
type LayoutTree ¶
type LayoutTree interface {
// Style returns the layout style for a node.
// Returns a default Style if the node has no explicit style.
// Never returns nil.
Style(node NodeID) *Style
// SetLayout sets the computed layout for a node.
// This should be called by layout algorithms after computing positions.
SetLayout(node NodeID, layout NodeLayout)
// GetLayout returns the previously set layout for a node.
// Returns a zero NodeLayout if no layout has been set.
GetLayout(node NodeID) NodeLayout
// ChildCount returns the number of children for a node.
// Returns 0 for leaf nodes.
ChildCount(parent NodeID) int
// ChildAt returns the child at the given index.
// Returns InvalidNodeID if index is out of bounds.
// Index is 0-based.
ChildAt(parent NodeID, index int) NodeID
// Measure measures a node's content size given constraints.
// For leaf nodes, this returns the intrinsic content size.
// For container nodes, this may trigger a recursive layout.
Measure(node NodeID, constraints geometry.Constraints) geometry.Size
}
LayoutTree provides access to the node tree for layout algorithms.
This interface abstracts the node tree structure, allowing layout algorithms to traverse nodes, access style properties, measure content, and set computed layouts without knowing the underlying node implementation.
Usage by Layout Algorithms ¶
Layout algorithms use LayoutTree to:
- Traverse the tree via ChildCount() and ChildAt()
- Get layout styles via Style()
- Measure leaf content via Measure()
- Store computed layouts via SetLayout()
Implementation Requirements ¶
Implementations must:
- Return consistent child counts and indices
- Support Measure() for leaf nodes (nodes with no children)
- Accept SetLayout() calls for any valid NodeID
- Return non-nil Style for all nodes (use default Style if none set)
type LayoutTreeAdapter ¶
type LayoutTreeAdapter struct {
// Styles maps node IDs to their styles.
Styles map[NodeID]*Style
// Layouts maps node IDs to their computed layouts.
Layouts map[NodeID]NodeLayout
// contains filtered or unexported fields
}
LayoutTreeAdapter helps implement LayoutTree for existing data structures.
This is a convenience helper that provides default implementations for some LayoutTree methods. Embed this in your implementation and override methods as needed.
func NewLayoutTreeAdapter ¶
func NewLayoutTreeAdapter() *LayoutTreeAdapter
NewLayoutTreeAdapter creates a new adapter with initialized maps.
func (*LayoutTreeAdapter) Clear ¶
func (a *LayoutTreeAdapter) Clear()
Clear removes all stored styles and layouts.
func (*LayoutTreeAdapter) GetLayout ¶
func (a *LayoutTreeAdapter) GetLayout(node NodeID) NodeLayout
GetLayout returns the previously set layout for a node.
func (*LayoutTreeAdapter) SetLayout ¶
func (a *LayoutTreeAdapter) SetLayout(node NodeID, layout NodeLayout)
SetLayout stores the computed layout for a node.
func (*LayoutTreeAdapter) SetStyle ¶
func (a *LayoutTreeAdapter) SetStyle(node NodeID, style *Style)
SetStyle sets the style for a node.
func (*LayoutTreeAdapter) Style ¶
func (a *LayoutTreeAdapter) Style(node NodeID) *Style
Style returns the style for a node, or a default style if not set.
type NodeID ¶
type NodeID uint64
NodeID identifies a node in the layout tree.
NodeID is an opaque identifier used by layout algorithms to reference nodes in the tree. The actual node storage and management is handled by the LayoutTree implementation.
const InvalidNodeID NodeID = 0
InvalidNodeID represents an invalid or unset node identifier.
type NodeLayout ¶
type NodeLayout struct {
// Position is the offset from the parent node's origin.
Position geometry.Point
// Size is the computed size of the node.
Size geometry.Size
}
NodeLayout is the computed layout for a single node.
After a layout algorithm runs, each node will have a NodeLayout describing its position relative to its parent and its computed size.
func (NodeLayout) Bounds ¶
func (n NodeLayout) Bounds() geometry.Rect
Bounds returns the layout as a rectangle.
func (NodeLayout) IsZero ¶
func (n NodeLayout) IsZero() bool
IsZero returns true if the layout has zero position and size.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry is a thread-safe registry for layout algorithms.
The registry allows layout algorithms to be registered by name and looked up at runtime. This enables third-party developers to create custom layouts that can be used alongside built-in layouts.
A global registry is provided via the package-level functions Register, Get, MustGet, and List.
func GlobalRegistry ¶
func GlobalRegistry() *Registry
GlobalRegistry returns the global registry instance.
This can be used when you need direct access to the registry, for example, to clone it or clear it for testing.
func (*Registry) Get ¶
func (r *Registry) Get(name string) (LayoutAlgorithm, bool)
Get retrieves a layout algorithm by name.
Returns the algorithm and true if found, or nil and false if not found.
func (*Registry) MustGet ¶
func (r *Registry) MustGet(name string) LayoutAlgorithm
MustGet retrieves a layout algorithm by name, panicking if not found.
Use this only when you're certain the algorithm exists (e.g., built-in layouts).
func (*Registry) Register ¶
func (r *Registry) Register(algorithm LayoutAlgorithm)
Register adds a layout algorithm to the registry.
If an algorithm with the same name already exists, it will be replaced. The algorithm's Name() method is used as the key.
func (*Registry) RegisterWithName ¶
func (r *Registry) RegisterWithName(name string, algorithm LayoutAlgorithm)
RegisterWithName adds a layout algorithm with an explicit name.
This allows registering the same algorithm under different names or using a name different from the algorithm's Name() method.
func (*Registry) Unregister ¶
Unregister removes a layout algorithm from the registry.
Returns true if the algorithm was removed, false if it wasn't registered.
type Result ¶
type Result struct {
// Size is the computed size of the root node.
Size geometry.Size
// Overflow indicates if content exceeds the available space.
Overflow bool
}
Result is the output of a layout algorithm computation.
Result contains the computed size of the root node and indicates whether the layout was successful.
type StackAlignment ¶
type StackAlignment int
StackAlignment specifies how children are aligned within a stack.
const ( // StackAlignStart aligns children to the start (top/left). StackAlignStart StackAlignment = iota // StackAlignCenter centers children. StackAlignCenter // StackAlignEnd aligns children to the end (bottom/right). StackAlignEnd // StackAlignStretch stretches children to fill available space. StackAlignStretch )
func (StackAlignment) String ¶
func (a StackAlignment) String() string
String returns a string representation of stack alignment.
type StackDirection ¶
type StackDirection int
StackDirection specifies the direction for stack layouts.
const ( // StackVertical stacks children vertically (VStack). StackVertical StackDirection = iota // StackHorizontal stacks children horizontally (HStack). StackHorizontal // StackZ overlays children on top of each other (ZStack). StackZ )
type StackLayout ¶
type StackLayout struct {
// Direction specifies the stack direction.
Direction StackDirection
// Alignment specifies cross-axis alignment (or position for ZStack).
Alignment StackAlignment
// Spacing is the gap between children (not used for ZStack).
Spacing float32
}
StackLayout implements VStack, HStack, and ZStack layouts.
StackLayout arranges children in a single direction with spacing, or overlays them on top of each other for ZStack.
func (*StackLayout) Compute ¶
func (s *StackLayout) Compute(tree LayoutTree, root NodeID, available geometry.Size) Result
Compute performs stack layout on the tree starting at root.
func (*StackLayout) Name ¶
func (s *StackLayout) Name() string
Name returns the algorithm name based on direction.
type Style ¶
type Style struct {
// Display mode
Display Display
// Flexbox properties
FlexDirection FlexDirection
FlexWrap FlexWrap
JustifyContent JustifyContent
AlignItems AlignItems
AlignContent AlignContent
// Flex item properties
FlexGrow float32
FlexShrink float32
FlexBasis Dimension
// Sizing
Width Dimension
Height Dimension
MinWidth Dimension
MinHeight Dimension
MaxWidth Dimension
MaxHeight Dimension
// Spacing
Margin geometry.Insets
Padding geometry.Insets
Gap float32
// Grid properties
GridGap float32
GridRowGap float32
GridColumnGap float32
}
Style defines layout properties for a node (CSS-like).
Style contains all the properties that layout algorithms use to determine how a node should be sized and positioned.
func DefaultStyle ¶
func DefaultStyle() Style
DefaultStyle returns a Style with sensible defaults.
Default values:
- Display: DisplayFlex
- FlexDirection: FlexRow
- FlexShrink: 1 (items can shrink)
- All dimensions: Auto
func (Style) WithAlignItems ¶
func (s Style) WithAlignItems(align AlignItems) Style
WithAlignItems returns a copy of the style with the given align items.
func (Style) WithDisplay ¶
WithDisplay returns a copy of the style with the given display mode.
func (Style) WithFlexDirection ¶
func (s Style) WithFlexDirection(direction FlexDirection) Style
WithFlexDirection returns a copy of the style with the given flex direction.
func (Style) WithJustifyContent ¶
func (s Style) WithJustifyContent(justify JustifyContent) Style
WithJustifyContent returns a copy of the style with the given justify content.
func (Style) WithMargin ¶
WithMargin returns a copy of the style with the given margin.
func (Style) WithPadding ¶
WithPadding returns a copy of the style with the given padding.
type ZStackAlignment ¶
type ZStackAlignment int
ZStackAlignment specifies position alignment for ZStack.
const ( // ZAlignTopLeft positions children at the top-left. ZAlignTopLeft ZStackAlignment = iota // ZAlignTop positions children at the top-center. ZAlignTop // ZAlignTopRight positions children at the top-right. ZAlignTopRight // ZAlignLeft positions children at the middle-left. ZAlignLeft // ZAlignCenter positions children at the center. ZAlignCenter // ZAlignRight positions children at the middle-right. ZAlignRight // ZAlignBottomLeft positions children at the bottom-left. ZAlignBottomLeft // ZAlignBottom positions children at the bottom-center. ZAlignBottom // ZAlignBottomRight positions children at the bottom-right. ZAlignBottomRight )
type ZStackLayout ¶
type ZStackLayout struct {
Alignment ZStackAlignment
}
ZStackLayout implements overlay stack with 9-position alignment.
func (*ZStackLayout) Compute ¶
func (z *ZStackLayout) Compute(tree LayoutTree, root NodeID, available geometry.Size) Result
Compute performs ZStack layout.