M layout/example_test.go => layout/example_test.go +12 -15
@@ 53,21 53,18 @@ func ExampleFlex() {
gtx := new(layout.Context)
gtx.Reset(nil, image.Point{X: 100, Y: 100})
- flex := layout.Flex{}
-
- // Rigid 10x10 widget.
- child1 := flex.Rigid(gtx, func() {
- fmt.Printf("Rigid: %v\n", gtx.Constraints.Width)
- layoutWidget(gtx, 10, 10)
- })
-
- // Child with 50% space allowance.
- child2 := flex.Flex(gtx, 0.5, func() {
- fmt.Printf("50%%: %v\n", gtx.Constraints.Width)
- layoutWidget(gtx, 10, 10)
- })
-
- flex.Layout(gtx, child1, child2)
+ layout.Flex{}.Layout(gtx,
+ // Rigid 10x10 widget.
+ layout.Rigid(func() {
+ fmt.Printf("Rigid: %v\n", gtx.Constraints.Width)
+ layoutWidget(gtx, 10, 10)
+ }),
+ // Child with 50% space allowance.
+ layout.Flexed(0.5, func() {
+ fmt.Printf("50%%: %v\n", gtx.Constraints.Width)
+ layoutWidget(gtx, 10, 10)
+ }),
+ )
// Output:
// Rigid: {0 100}
M layout/flex.go => layout/flex.go +77 -76
@@ 19,20 19,16 @@ type Flex struct {
Spacing Spacing
// Alignment is the alignment in the cross axis.
Alignment Alignment
-
- size int
- rigidSize int
- // fraction is the rounding error from a Flex weighting.
- fraction float32
-
- // Use an empty StackOp for tracking whether Rigid, Flex
- // is called in the same layout scope as Layout.
- begun bool
- stack op.StackOp
}
-// FlexChild is the layout result of a call End.
+// FlexChild is the descriptor for a Flex child.
type FlexChild struct {
+ flex bool
+ weight float32
+
+ widget Widget
+
+ // Scratch space.
macro op.MacroOp
dims Dimensions
}
@@ 60,74 56,82 @@ const (
SpaceEvenly
)
-// Rigid lays out a widget with the main axis constrained to the range
-// from 0 to the remaining space.
-func (f *Flex) Rigid(gtx *Context, w Widget) FlexChild {
- f.begin(gtx.Ops)
- cs := gtx.Constraints
- mainc := axisMainConstraint(f.Axis, cs)
- mainMax := mainc.Max - f.size
- if mainMax < 0 {
- mainMax = 0
+// Rigid returns a Flex child with a maximal constraint of the
+// remaining space.
+func Rigid(widget Widget) FlexChild {
+ return FlexChild{
+ widget: widget,
}
- cs = axisConstraints(f.Axis, Constraint{Max: mainMax}, axisCrossConstraint(f.Axis, cs))
- var m op.MacroOp
- m.Record(gtx.Ops)
- dims := ctxLayout(gtx, cs, w)
- m.Stop()
- f.rigidSize += axisMain(f.Axis, dims.Size)
- f.expand(dims)
- return FlexChild{m, dims}
}
-func (f *Flex) begin(ops *op.Ops) {
- if f.begun {
- return
+// Flexed returns a Flex child forced to take up a fraction of
+// the remaining space.
+func Flexed(weight float32, widget Widget) FlexChild {
+ return FlexChild{
+ flex: true,
+ weight: weight,
+ widget: widget,
}
- f.stack.Push(ops)
- f.begun = true
}
-// Flex is like Rigid, where the main axis size is also constrained to a
-// fraction of the space not taken up by Rigid children.
-func (f *Flex) Flex(gtx *Context, weight float32, w Widget) FlexChild {
- f.begin(gtx.Ops)
- cs := gtx.Constraints
- mainc := axisMainConstraint(f.Axis, cs)
- var flexSize int
- if mainc.Max > f.size {
- flexSize = mainc.Max - f.rigidSize
- // Apply weight and add any leftover fraction from a
- // previous Flex.
- size := float32(flexSize)*weight + f.fraction
- flexSize = int(size + .5)
- f.fraction = size - float32(flexSize)
- if max := mainc.Max - f.size; flexSize > max {
- flexSize = max
+// Layout a list of children. The position of the children are
+// determined by the specified order, but Rigid children are laid out
+// before Flexed children.
+func (f Flex) Layout(gtx *Context, children ...FlexChild) {
+ size := 0
+ // Lay out Rigid children.
+ for i, child := range children {
+ if child.flex {
+ continue
}
+ cs := gtx.Constraints
+ mainc := axisMainConstraint(f.Axis, cs)
+ mainMax := mainc.Max - size
+ if mainMax < 0 {
+ mainMax = 0
+ }
+ cs = axisConstraints(f.Axis, Constraint{Max: mainMax}, axisCrossConstraint(f.Axis, cs))
+ var m op.MacroOp
+ m.Record(gtx.Ops)
+ dims := ctxLayout(gtx, cs, child.widget)
+ m.Stop()
+ sz := axisMain(f.Axis, dims.Size)
+ size += sz
+ children[i].macro = m
+ children[i].dims = dims
}
- submainc := Constraint{Min: flexSize, Max: flexSize}
- cs = axisConstraints(f.Axis, submainc, axisCrossConstraint(f.Axis, cs))
- var m op.MacroOp
- m.Record(gtx.Ops)
- dims := ctxLayout(gtx, cs, w)
- m.Stop()
- f.expand(dims)
- return FlexChild{m, dims}
-}
-
-// End a child by specifying its dimensions. Pass the returned layout result
-// to Layout.
-func (f *Flex) expand(dims Dimensions) {
- sz := axisMain(f.Axis, dims.Size)
- f.size += sz
-}
-
-// Layout a list of children. The order of the children determines their laid
-// out order.
-func (f *Flex) Layout(gtx *Context, children ...FlexChild) {
- if len(children) > 0 {
- f.stack.Pop()
+ rigidSize := size
+ // fraction is the rounding error from a Flex weighting.
+ var fraction float32
+ // Lay out Flexed children.
+ for i, child := range children {
+ if !child.flex {
+ continue
+ }
+ cs := gtx.Constraints
+ mainc := axisMainConstraint(f.Axis, cs)
+ var flexSize int
+ if mainc.Max > size {
+ flexSize = mainc.Max - rigidSize
+ // Apply weight and add any leftover fraction from a
+ // previous Flexed.
+ childSize := float32(flexSize)*child.weight + fraction
+ flexSize = int(childSize + .5)
+ fraction = childSize - float32(flexSize)
+ if max := mainc.Max - size; flexSize > max {
+ flexSize = max
+ }
+ }
+ submainc := Constraint{Min: flexSize, Max: flexSize}
+ cs = axisConstraints(f.Axis, submainc, axisCrossConstraint(f.Axis, cs))
+ var m op.MacroOp
+ m.Record(gtx.Ops)
+ dims := ctxLayout(gtx, cs, child.widget)
+ m.Stop()
+ sz := axisMain(f.Axis, dims.Size)
+ size += sz
+ children[i].macro = m
+ children[i].dims = dims
}
var maxCross int
var maxBaseline int
@@ 142,8 146,8 @@ func (f *Flex) Layout(gtx *Context, children ...FlexChild) {
cs := gtx.Constraints
mainc := axisMainConstraint(f.Axis, cs)
var space int
- if mainc.Min > f.size {
- space = mainc.Min - f.size
+ if mainc.Min > size {
+ space = mainc.Min - size
}
var mainSize int
switch f.Spacing {
@@ 199,9 203,6 @@ func (f *Flex) Layout(gtx *Context, children ...FlexChild) {
}
sz := axisPoint(f.Axis, mainSize, maxCross)
gtx.Dimensions = Dimensions{Size: sz, Baseline: sz.Y - maxBaseline}
- f.begun = false
- f.size = 0
- f.rigidSize = 0
}
func axisPoint(a Axis, main, cross int) image.Point {
M widget/material/checkable.go => widget/material/checkable.go +22 -24
@@ 36,32 36,30 @@ func (c *checkable) layout(gtx *layout.Context, checked bool) {
hmin := gtx.Constraints.Width.Min
vmin := gtx.Constraints.Height.Min
- flex := layout.Flex{Alignment: layout.Middle}
-
- ico := flex.Rigid(gtx, func() {
- layout.Align(layout.Center).Layout(gtx, func() {
- layout.UniformInset(unit.Dp(2)).Layout(gtx, func() {
- size := gtx.Px(c.Size)
- icon.Color = c.IconColor
- icon.Layout(gtx, unit.Px(float32(size)))
- gtx.Dimensions = layout.Dimensions{
- Size: image.Point{X: size, Y: size},
- }
+ layout.Flex{Alignment: layout.Middle}.Layout(gtx,
+ layout.Rigid(func() {
+ layout.Align(layout.Center).Layout(gtx, func() {
+ layout.UniformInset(unit.Dp(2)).Layout(gtx, func() {
+ size := gtx.Px(c.Size)
+ icon.Color = c.IconColor
+ icon.Layout(gtx, unit.Px(float32(size)))
+ gtx.Dimensions = layout.Dimensions{
+ Size: image.Point{X: size, Y: size},
+ }
+ })
})
- })
- })
+ }),
- lbl := flex.Rigid(gtx, func() {
- gtx.Constraints.Width.Min = hmin
- gtx.Constraints.Height.Min = vmin
- layout.Align(layout.Start).Layout(gtx, func() {
- layout.UniformInset(unit.Dp(2)).Layout(gtx, func() {
- paint.ColorOp{Color: c.Color}.Add(gtx.Ops)
- widget.Label{}.Layout(gtx, c.shaper, c.Font, c.Label)
+ layout.Rigid(func() {
+ gtx.Constraints.Width.Min = hmin
+ gtx.Constraints.Height.Min = vmin
+ layout.Align(layout.Start).Layout(gtx, func() {
+ layout.UniformInset(unit.Dp(2)).Layout(gtx, func() {
+ paint.ColorOp{Color: c.Color}.Add(gtx.Ops)
+ widget.Label{}.Layout(gtx, c.shaper, c.Font, c.Label)
+ })
})
- })
- })
-
- flex.Layout(gtx, ico, lbl)
+ }),
+ )
pointer.Rect(image.Rectangle{Max: gtx.Dimensions.Size}).Add(gtx.Ops)
}