layout/flex.go

Functions Structs

Functions

func Compute

Compute performs flexbox layout on the tree starting at root.

func (f *FlexLayout) Compute(tree LayoutTree, root NodeID, available geometry.Size) Result {
	style := tree.Style(root)
	childCount := tree.ChildCount(root)

	if childCount == 0 {
		return Result{Size: geometry.Size{}}
	}

	isHorizontal := style.FlexDirection.IsHorizontal()
	isReversed := style.FlexDirection.IsReversed()

	// Get main/cross axis constraints
	mainMax, crossMax := f.getAxisSizes(available, isHorizontal)

	// Collect children and measure them
	items := make([]flexItem, childCount)
	for i := 0; i < childCount; i++ {
		childID := tree.ChildAt(root, i)
		childStyle := tree.Style(childID)

		// Measure child with loose constraints
		constraints := f.createMeasureConstraints(crossMax, isHorizontal)
		childSize := tree.Measure(childID, constraints)

		items[i] = flexItem{
			id:		childID,
			grow:		childStyle.FlexGrow,
			shrink:		childStyle.FlexShrink,
			basis:		childStyle.FlexBasis.Resolve(mainMax, 0),
			mainSize:	f.mainSize(childSize, isHorizontal),
			crossSize:	f.crossSize(childSize, isHorizontal),
		}

		// Use basis if specified, otherwise use measured size
		if !childStyle.FlexBasis.IsAuto() {
			items[i].mainSize = items[i].basis
		}
	}

	// Calculate totals
	totalMain := f.calculateTotalMain(items, style.Gap)
	totalGrow := f.calculateTotalGrow(items)
	totalShrink := f.calculateTotalShrink(items)
	maxCross := f.calculateMaxCross(items)

	// Distribute space
	freeSpace := mainMax - totalMain
	if freeSpace > 0 && totalGrow > 0 {
		f.growItems(items, freeSpace, totalGrow)
	} else if freeSpace < 0 && totalShrink > 0 {
		f.shrinkItems(items, -freeSpace, totalShrink)
	}

	// Calculate positioning
	numGaps := childCount - 1
	if numGaps < 0 {
		numGaps = 0
	}
	contentMain := f.sumMainSizes(items) + style.Gap*float32(numGaps)
	mainStart, mainSpacing := f.calculateJustification(style, mainMax-contentMain, childCount)

	// Position children
	currentMain := mainStart
	if isReversed {
		currentMain = mainMax - mainStart
	}

	for i := range items {
		item := &items[i]

		// Calculate main position
		var mainPos float32
		if isReversed {
			mainPos = currentMain - item.mainSize
			currentMain -= item.mainSize + mainSpacing
		} else {
			mainPos = currentMain
			currentMain += item.mainSize + mainSpacing
		}

		// Calculate cross position
		crossPos := f.calculateCrossPosition(item, maxCross, style.AlignItems)

		// Set layout
		var pos geometry.Point
		var size geometry.Size
		if isHorizontal {
			pos = geometry.Point{X: mainPos, Y: crossPos}
			size = geometry.Size{Width: item.mainSize, Height: item.crossSize}
		} else {
			pos = geometry.Point{X: crossPos, Y: mainPos}
			size = geometry.Size{Width: item.crossSize, Height: item.mainSize}
		}
		tree.SetLayout(item.id, NodeLayout{Position: pos, Size: size})
	}

	// Calculate final size
	var resultSize geometry.Size
	if isHorizontal {
		resultSize = geometry.Size{Width: contentMain, Height: maxCross}
	} else {
		resultSize = geometry.Size{Width: maxCross, Height: contentMain}
	}

	return Result{
		Size:		resultSize,
		Overflow:	contentMain > mainMax,
	}
}

func Name

Name returns "flex".

func (f *FlexLayout) Name() string {
	return flexLayoutName
}

Structs

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

type FlexLayout struct{}