mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-06 18:05:35 +00:00
ui/layout: replace implicit begin/end scopes with explicit function scopes
Before this change, layout objects followed a pattern where a
begin method would set up the layout and return a tweaked set
of constraints, and a end method would take the widget dimensions
and return the tweaked dimensions.
As has been pointed out, this process is error prone, because the
scope of the layout objects are not clear and because it is easy
to swap two begins or two ends.
It turns out that it is possible to implement layout with function
scopes in garbage free way. A typical layout changes from
al := layout.Align{Alignment: layout.NE}
cs = al.Begin(ops, cs)
in := layout.Inset{Top: ui.Dp(16)}
cs = in.Begin(c, ops, cs)
txt := fmt.Sprintf("m: %d %s", mallocs, u.profile.Timings)
dims := text.Label{Material: theme.text, Face: u.face(fonts.mono, 10), Text: txt}.Layout(ops, cs)
dims = in.End(dims)
return al.End(dims)
to
al := layout.Align{Alignment: layout.NE}
return al.Layout(ops, cs, func(cs layout.Constraints) layout.Dimensions {
in := layout.Inset{Top: ui.Dp(16)}
return in.Layout(c, ops, cs, func(cs layout.Constraints) layout.Dimensions {
txt := fmt.Sprintf("m: %d %s", mallocs, u.profile.Timings)
return text.Label{Material: theme.text, Face: u.face(fonts.mono, 10), Text: txt}.Layout(ops, cs)
})
})
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+11
-9
@@ -94,21 +94,22 @@ func (f *Flex) begin(mode flexMode) {
|
|||||||
f.macro.Record(f.ops)
|
f.macro.Record(f.ops)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rigid begins a child and return its constraints. The main axis is constrained
|
// Rigid lays out a widget with the main axis constrained to the range
|
||||||
// to the range from 0 to the remaining space.
|
// from 0 to the remaining space.
|
||||||
func (f *Flex) Rigid() Constraints {
|
func (f *Flex) Rigid(w Widget) FlexChild {
|
||||||
f.begin(modeRigid)
|
f.begin(modeRigid)
|
||||||
mainc := axisMainConstraint(f.Axis, f.cs)
|
mainc := axisMainConstraint(f.Axis, f.cs)
|
||||||
mainMax := mainc.Max - f.size
|
mainMax := mainc.Max - f.size
|
||||||
if mainMax < 0 {
|
if mainMax < 0 {
|
||||||
mainMax = 0
|
mainMax = 0
|
||||||
}
|
}
|
||||||
return axisConstraints(f.Axis, Constraint{Max: mainMax}, axisCrossConstraint(f.Axis, f.cs))
|
cs := axisConstraints(f.Axis, Constraint{Max: mainMax}, axisCrossConstraint(f.Axis, f.cs))
|
||||||
|
return f.end(w(cs))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flexible is like Rigid, where the main axis size is also constrained to a
|
// Flexible is like Rigid, where the main axis size is also constrained to a
|
||||||
// fraction of the space not taken up by Rigid children.
|
// fraction of the space not taken up by Rigid children.
|
||||||
func (f *Flex) Flexible(weight float32) Constraints {
|
func (f *Flex) Flexible(weight float32, w Widget) FlexChild {
|
||||||
f.begin(modeFlex)
|
f.begin(modeFlex)
|
||||||
mainc := axisMainConstraint(f.Axis, f.cs)
|
mainc := axisMainConstraint(f.Axis, f.cs)
|
||||||
var flexSize int
|
var flexSize int
|
||||||
@@ -124,12 +125,13 @@ func (f *Flex) Flexible(weight float32) Constraints {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
submainc := Constraint{Max: flexSize}
|
submainc := Constraint{Max: flexSize}
|
||||||
return axisConstraints(f.Axis, submainc, axisCrossConstraint(f.Axis, f.cs))
|
cs := axisConstraints(f.Axis, submainc, axisCrossConstraint(f.Axis, f.cs))
|
||||||
|
return f.end(w(cs))
|
||||||
}
|
}
|
||||||
|
|
||||||
// End a child by specifying its dimensions. Pass the returned layout result
|
// End a child by specifying its dimensions. Pass the returned layout result
|
||||||
// to Layout.
|
// to Layout.
|
||||||
func (f *Flex) End(dims Dimensions) FlexChild {
|
func (f *Flex) end(dims Dimensions) FlexChild {
|
||||||
if f.mode <= modeBegun {
|
if f.mode <= modeBegun {
|
||||||
panic("End called without an active child")
|
panic("End called without an active child")
|
||||||
}
|
}
|
||||||
@@ -263,9 +265,9 @@ func axisCrossConstraint(a Axis, cs Constraints) Constraint {
|
|||||||
|
|
||||||
func axisConstraints(a Axis, mainc, crossc Constraint) Constraints {
|
func axisConstraints(a Axis, mainc, crossc Constraint) Constraints {
|
||||||
if a == Horizontal {
|
if a == Horizontal {
|
||||||
return Constraints{mainc, crossc}
|
return Constraints{Width: mainc, Height: crossc}
|
||||||
} else {
|
} else {
|
||||||
return Constraints{crossc, mainc}
|
return Constraints{Width: crossc, Height: mainc}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+35
-69
@@ -39,6 +39,10 @@ type Alignment uint8
|
|||||||
// relative to a containing space.
|
// relative to a containing space.
|
||||||
type Direction uint8
|
type Direction uint8
|
||||||
|
|
||||||
|
// Widget is a function that computes a set of dimensions that
|
||||||
|
// satisfies the given cosntraints.
|
||||||
|
type Widget func(cs Constraints) Dimensions
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Start Alignment = iota
|
Start Alignment = iota
|
||||||
End
|
End
|
||||||
@@ -90,68 +94,44 @@ func RigidConstraints(size image.Point) Constraints {
|
|||||||
// Inset adds space around an interface element.
|
// Inset adds space around an interface element.
|
||||||
type Inset struct {
|
type Inset struct {
|
||||||
Top, Right, Bottom, Left ui.Value
|
Top, Right, Bottom, Left ui.Value
|
||||||
|
|
||||||
stack ui.StackOp
|
|
||||||
top, right, bottom, left int
|
|
||||||
begun bool
|
|
||||||
cs Constraints
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Align aligns an interface element in the available space.
|
// Align aligns an interface element in the available space.
|
||||||
type Align struct {
|
type Align struct {
|
||||||
Alignment Direction
|
Alignment Direction
|
||||||
|
|
||||||
macro ui.MacroOp
|
|
||||||
ops *ui.Ops
|
|
||||||
begun bool
|
|
||||||
cs Constraints
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Begin the inset operation and modify the input constraints to
|
// Layout a widget.
|
||||||
// account for the insets.
|
func (in *Inset) Layout(c ui.Config, ops *ui.Ops, cs Constraints, w Widget) Dimensions {
|
||||||
func (in *Inset) Begin(c ui.Config, ops *ui.Ops, cs Constraints) Constraints {
|
top := c.Px(in.Top)
|
||||||
if in.begun {
|
right := c.Px(in.Right)
|
||||||
panic("must End before Begin")
|
bottom := c.Px(in.Bottom)
|
||||||
}
|
left := c.Px(in.Left)
|
||||||
in.top = c.Px(in.Top)
|
|
||||||
in.right = c.Px(in.Right)
|
|
||||||
in.bottom = c.Px(in.Bottom)
|
|
||||||
in.left = c.Px(in.Left)
|
|
||||||
in.begun = true
|
|
||||||
in.cs = cs
|
|
||||||
mcs := cs
|
mcs := cs
|
||||||
mcs.Width.Min -= in.left + in.right
|
mcs.Width.Min -= left + right
|
||||||
mcs.Width.Max -= in.left + in.right
|
mcs.Width.Max -= left + right
|
||||||
if mcs.Width.Min < 0 {
|
if mcs.Width.Min < 0 {
|
||||||
mcs.Width.Min = 0
|
mcs.Width.Min = 0
|
||||||
}
|
}
|
||||||
if mcs.Width.Max < mcs.Width.Min {
|
if mcs.Width.Max < mcs.Width.Min {
|
||||||
mcs.Width.Max = mcs.Width.Min
|
mcs.Width.Max = mcs.Width.Min
|
||||||
}
|
}
|
||||||
mcs.Height.Min -= in.top + in.bottom
|
mcs.Height.Min -= top + bottom
|
||||||
mcs.Height.Max -= in.top + in.bottom
|
mcs.Height.Max -= top + bottom
|
||||||
if mcs.Height.Min < 0 {
|
if mcs.Height.Min < 0 {
|
||||||
mcs.Height.Min = 0
|
mcs.Height.Min = 0
|
||||||
}
|
}
|
||||||
if mcs.Height.Max < mcs.Height.Min {
|
if mcs.Height.Max < mcs.Height.Min {
|
||||||
mcs.Height.Max = mcs.Height.Min
|
mcs.Height.Max = mcs.Height.Min
|
||||||
}
|
}
|
||||||
in.stack.Push(ops)
|
var stack ui.StackOp
|
||||||
ui.TransformOp{}.Offset(toPointF(image.Point{X: in.left, Y: in.top})).Add(ops)
|
stack.Push(ops)
|
||||||
return mcs
|
ui.TransformOp{}.Offset(toPointF(image.Point{X: left, Y: top})).Add(ops)
|
||||||
}
|
dims := w(mcs)
|
||||||
|
stack.Pop()
|
||||||
// End the inset operation and return the dimensions for the
|
|
||||||
// inset child.
|
|
||||||
func (in *Inset) End(dims Dimensions) Dimensions {
|
|
||||||
if !in.begun {
|
|
||||||
panic("must Begin before End")
|
|
||||||
}
|
|
||||||
in.begun = false
|
|
||||||
in.stack.Pop()
|
|
||||||
return Dimensions{
|
return Dimensions{
|
||||||
Size: in.cs.Constrain(dims.Size.Add(image.Point{X: in.right + in.left, Y: in.top + in.bottom})),
|
Size: cs.Constrain(dims.Size.Add(image.Point{X: right + left, Y: top + bottom})),
|
||||||
Baseline: dims.Baseline + in.top,
|
Baseline: dims.Baseline + top,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,35 +141,21 @@ func UniformInset(v ui.Value) Inset {
|
|||||||
return Inset{Top: v, Right: v, Bottom: v, Left: v}
|
return Inset{Top: v, Right: v, Bottom: v, Left: v}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Begin aligning and return the constraints with no minimum size.
|
// Layout a widget.
|
||||||
func (a *Align) Begin(ops *ui.Ops, cs Constraints) Constraints {
|
func (a *Align) Layout(ops *ui.Ops, cs Constraints, w Widget) Dimensions {
|
||||||
if a.begun {
|
var macro ui.MacroOp
|
||||||
panic("must End before Begin")
|
mcs := cs
|
||||||
}
|
mcs.Width.Min = 0
|
||||||
a.begun = true
|
mcs.Height.Min = 0
|
||||||
a.ops = ops
|
macro.Record(ops)
|
||||||
a.cs = cs
|
dims := w(mcs)
|
||||||
a.macro.Record(ops)
|
macro.Stop()
|
||||||
cs.Width.Min = 0
|
|
||||||
cs.Height.Min = 0
|
|
||||||
return cs
|
|
||||||
}
|
|
||||||
|
|
||||||
// End the align operation and return the dimensions for the
|
|
||||||
// aligned child.
|
|
||||||
func (a *Align) End(dims Dimensions) Dimensions {
|
|
||||||
if !a.begun {
|
|
||||||
panic("must Begin before End")
|
|
||||||
}
|
|
||||||
a.begun = false
|
|
||||||
ops := a.ops
|
|
||||||
a.macro.Stop()
|
|
||||||
sz := dims.Size
|
sz := dims.Size
|
||||||
if sz.X < a.cs.Width.Min {
|
if sz.X < cs.Width.Min {
|
||||||
sz.X = a.cs.Width.Min
|
sz.X = cs.Width.Min
|
||||||
}
|
}
|
||||||
if sz.Y < a.cs.Height.Min {
|
if sz.Y < cs.Height.Min {
|
||||||
sz.Y = a.cs.Height.Min
|
sz.Y = cs.Height.Min
|
||||||
}
|
}
|
||||||
var p image.Point
|
var p image.Point
|
||||||
switch a.Alignment {
|
switch a.Alignment {
|
||||||
@@ -207,7 +173,7 @@ func (a *Align) End(dims Dimensions) Dimensions {
|
|||||||
var stack ui.StackOp
|
var stack ui.StackOp
|
||||||
stack.Push(ops)
|
stack.Push(ops)
|
||||||
ui.TransformOp{}.Offset(toPointF(p)).Add(ops)
|
ui.TransformOp{}.Offset(toPointF(p)).Add(ops)
|
||||||
a.macro.Add(ops)
|
macro.Add(ops)
|
||||||
stack.Pop()
|
stack.Pop()
|
||||||
return Dimensions{
|
return Dimensions{
|
||||||
Size: sz,
|
Size: sz,
|
||||||
|
|||||||
+32
-37
@@ -27,11 +27,12 @@ func ExampleInset() {
|
|||||||
|
|
||||||
// Inset all edges by 10.
|
// Inset all edges by 10.
|
||||||
inset := layout.UniformInset(ui.Dp(10))
|
inset := layout.UniformInset(ui.Dp(10))
|
||||||
cs = inset.Begin(cfg, ops, cs)
|
dims := inset.Layout(cfg, ops, cs, func(cs layout.Constraints) layout.Dimensions {
|
||||||
// Lay out a 50x50 sized widget.
|
// Lay out a 50x50 sized widget.
|
||||||
dims := layoutWidget(50, 50, cs)
|
dims := layoutWidget(50, 50, cs)
|
||||||
fmt.Println(dims.Size)
|
fmt.Println(dims.Size)
|
||||||
dims = inset.End(dims)
|
return dims
|
||||||
|
})
|
||||||
|
|
||||||
fmt.Println(dims.Size)
|
fmt.Println(dims.Size)
|
||||||
|
|
||||||
@@ -47,13 +48,12 @@ func ExampleAlign() {
|
|||||||
cs := layout.RigidConstraints(image.Point{X: 100, Y: 100})
|
cs := layout.RigidConstraints(image.Point{X: 100, Y: 100})
|
||||||
|
|
||||||
align := layout.Align{Alignment: layout.Center}
|
align := layout.Align{Alignment: layout.Center}
|
||||||
cs = align.Begin(ops, cs)
|
dims := align.Layout(ops, cs, func(cs layout.Constraints) layout.Dimensions {
|
||||||
|
// Lay out a 50x50 sized widget.
|
||||||
// Lay out a 50x50 sized widget.
|
dims := layoutWidget(50, 50, cs)
|
||||||
dims := layoutWidget(50, 50, cs)
|
fmt.Println(dims.Size)
|
||||||
fmt.Println(dims.Size)
|
return dims
|
||||||
|
})
|
||||||
dims = align.End(dims)
|
|
||||||
|
|
||||||
fmt.Println(dims.Size)
|
fmt.Println(dims.Size)
|
||||||
|
|
||||||
@@ -71,18 +71,18 @@ func ExampleFlex() {
|
|||||||
flex.Init(ops, cs)
|
flex.Init(ops, cs)
|
||||||
|
|
||||||
// Rigid 10x10 widget.
|
// Rigid 10x10 widget.
|
||||||
cs = flex.Rigid()
|
child1 := flex.Rigid(func(cs layout.Constraints) layout.Dimensions {
|
||||||
fmt.Printf("Rigid: %v\n", cs.Width)
|
fmt.Printf("Rigid: %v\n", cs.Width)
|
||||||
dims := layoutWidget(10, 10, cs)
|
return layoutWidget(10, 10, cs)
|
||||||
child1 := flex.End(dims)
|
})
|
||||||
|
|
||||||
// Child with 50% space allowance.
|
// Child with 50% space allowance.
|
||||||
cs = flex.Flexible(0.5)
|
child2 := flex.Flexible(0.5, func(cs layout.Constraints) layout.Dimensions {
|
||||||
fmt.Printf("50%%: %v\n", cs.Width)
|
fmt.Printf("50%%: %v\n", cs.Width)
|
||||||
dims = layoutWidget(10, 10, cs)
|
return layoutWidget(10, 10, cs)
|
||||||
child2 := flex.End(dims)
|
})
|
||||||
|
|
||||||
dims = flex.Layout(child1, child2)
|
flex.Layout(child1, child2)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// Rigid: {0 100}
|
// Rigid: {0 100}
|
||||||
@@ -98,17 +98,17 @@ func ExampleStack() {
|
|||||||
stack.Init(ops, cs)
|
stack.Init(ops, cs)
|
||||||
|
|
||||||
// Rigid 50x50 widget.
|
// Rigid 50x50 widget.
|
||||||
cs = stack.Rigid()
|
child1 := stack.Rigid(func(cs layout.Constraints) layout.Dimensions {
|
||||||
dims := layoutWidget(50, 50, cs)
|
return layoutWidget(50, 50, cs)
|
||||||
child1 := stack.End(dims)
|
})
|
||||||
|
|
||||||
// Force widget to the same size as the first.
|
// Force widget to the same size as the first.
|
||||||
cs = stack.Expand()
|
child2 := stack.Expand(func(cs layout.Constraints) layout.Dimensions {
|
||||||
fmt.Printf("Expand: %v\n", cs)
|
fmt.Printf("Expand: %v\n", cs)
|
||||||
dims = layoutWidget(10, 10, cs)
|
return layoutWidget(10, 10, cs)
|
||||||
child2 := stack.End(dims)
|
})
|
||||||
|
|
||||||
dims = stack.Layout(child1, child2)
|
stack.Layout(child1, child2)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// Expand: {{50 50} {50 50}}
|
// Expand: {{50 50} {50 50}}
|
||||||
@@ -123,19 +123,14 @@ func ExampleList() {
|
|||||||
const listLen = 1e6
|
const listLen = 1e6
|
||||||
|
|
||||||
var list layout.List
|
var list layout.List
|
||||||
list.Init(cfg, q, ops, cs, listLen)
|
|
||||||
count := 0
|
count := 0
|
||||||
for ; list.More(); list.Next() {
|
list.Layout(cfg, q, ops, cs, listLen, func(cs layout.Constraints, i int) layout.Dimensions {
|
||||||
dims := layoutWidget(20, 20, list.Constraints())
|
|
||||||
list.End(dims)
|
|
||||||
count++
|
count++
|
||||||
}
|
return layoutWidget(20, 20, cs)
|
||||||
|
})
|
||||||
|
|
||||||
fmt.Println(count)
|
fmt.Println(count)
|
||||||
|
|
||||||
dims := list.Layout()
|
|
||||||
_ = dims
|
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 5
|
// 5
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-19
@@ -56,6 +56,10 @@ type List struct {
|
|||||||
dir iterationDir
|
dir iterationDir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListElement is a function that computes the dimensions of
|
||||||
|
// a list element.
|
||||||
|
type ListElement func(cs Constraints, index int) Dimensions
|
||||||
|
|
||||||
type iterationDir uint8
|
type iterationDir uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -67,8 +71,8 @@ const (
|
|||||||
const inf = 1e6
|
const inf = 1e6
|
||||||
|
|
||||||
// Init prepares the list for iterating through its children with Next.
|
// Init prepares the list for iterating through its children with Next.
|
||||||
func (l *List) Init(cfg ui.Config, q input.Queue, ops *ui.Ops, cs Constraints, len int) {
|
func (l *List) init(cfg ui.Config, q input.Queue, ops *ui.Ops, cs Constraints, len int) {
|
||||||
if l.More() {
|
if l.more() {
|
||||||
panic("unfinished child")
|
panic("unfinished child")
|
||||||
}
|
}
|
||||||
l.config = cfg
|
l.config = cfg
|
||||||
@@ -88,7 +92,15 @@ func (l *List) Init(cfg ui.Config, q input.Queue, ops *ui.Ops, cs Constraints, l
|
|||||||
l.first = len
|
l.first = len
|
||||||
}
|
}
|
||||||
l.macro.Record(ops)
|
l.macro.Record(ops)
|
||||||
l.Next()
|
l.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layout the List and return its dimensions.
|
||||||
|
func (l *List) Layout(c ui.Config, q input.Queue, ops *ui.Ops, cs Constraints, len int, w ListElement) Dimensions {
|
||||||
|
for l.init(c, q, ops, cs, len); l.more(); l.next() {
|
||||||
|
l.end(w(l.constraints(), l.index()))
|
||||||
|
}
|
||||||
|
return l.layout()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *List) scrollToEnd() bool {
|
func (l *List) scrollToEnd() bool {
|
||||||
@@ -106,23 +118,23 @@ func (l *List) update() {
|
|||||||
l.offset += d
|
l.offset += d
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next advances to the next child.
|
// next advances to the next child.
|
||||||
func (l *List) Next() {
|
func (l *List) next() {
|
||||||
l.dir = l.next()
|
l.dir = l.nextDir()
|
||||||
// The user scroll offset is applied after scrolling to
|
// The user scroll offset is applied after scrolling to
|
||||||
// list end.
|
// list end.
|
||||||
if l.scrollToEnd() && !l.More() && l.scrollDelta < 0 {
|
if l.scrollToEnd() && !l.more() && l.scrollDelta < 0 {
|
||||||
l.beforeEnd = true
|
l.beforeEnd = true
|
||||||
l.offset += l.scrollDelta
|
l.offset += l.scrollDelta
|
||||||
l.dir = l.next()
|
l.dir = l.nextDir()
|
||||||
}
|
}
|
||||||
if l.More() {
|
if l.more() {
|
||||||
l.child.Record(l.ops)
|
l.child.Record(l.ops)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Index is current child's position in the underlying list.
|
// index is current child's position in the underlying list.
|
||||||
func (l *List) Index() int {
|
func (l *List) index() int {
|
||||||
switch l.dir {
|
switch l.dir {
|
||||||
case iterateBackward:
|
case iterateBackward:
|
||||||
return l.first - 1
|
return l.first - 1
|
||||||
@@ -133,17 +145,17 @@ func (l *List) Index() int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constraints is the constraints for the current child.
|
// constraints is the constraints for the current child.
|
||||||
func (l *List) Constraints() Constraints {
|
func (l *List) constraints() Constraints {
|
||||||
return axisConstraints(l.Axis, Constraint{Max: inf}, axisCrossConstraint(l.Axis, l.cs))
|
return axisConstraints(l.Axis, Constraint{Max: inf}, axisCrossConstraint(l.Axis, l.cs))
|
||||||
}
|
}
|
||||||
|
|
||||||
// More reports whether more children are needed.
|
// more reports whether more children are needed.
|
||||||
func (l *List) More() bool {
|
func (l *List) more() bool {
|
||||||
return l.dir != iterateNone
|
return l.dir != iterateNone
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *List) next() iterationDir {
|
func (l *List) nextDir() iterationDir {
|
||||||
vsize := axisMainConstraint(l.Axis, l.cs).Max
|
vsize := axisMainConstraint(l.Axis, l.cs).Max
|
||||||
last := l.first + len(l.children)
|
last := l.first + len(l.children)
|
||||||
// Clamp offset.
|
// Clamp offset.
|
||||||
@@ -165,7 +177,7 @@ func (l *List) next() iterationDir {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// End the current child by specifying its dimensions.
|
// End the current child by specifying its dimensions.
|
||||||
func (l *List) End(dims Dimensions) {
|
func (l *List) end(dims Dimensions) {
|
||||||
l.child.Stop()
|
l.child.Stop()
|
||||||
child := scrollChild{dims.Size, l.child}
|
child := scrollChild{dims.Size, l.child}
|
||||||
mainSize := axisMain(l.Axis, child.size)
|
mainSize := axisMain(l.Axis, child.size)
|
||||||
@@ -184,8 +196,8 @@ func (l *List) End(dims Dimensions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Layout the List and return its dimensions.
|
// Layout the List and return its dimensions.
|
||||||
func (l *List) Layout() Dimensions {
|
func (l *List) layout() Dimensions {
|
||||||
if l.More() {
|
if l.more() {
|
||||||
panic("unfinished child")
|
panic("unfinished child")
|
||||||
}
|
}
|
||||||
mainc := axisMainConstraint(l.Axis, l.cs)
|
mainc := axisMainConstraint(l.Axis, l.cs)
|
||||||
|
|||||||
+8
-7
@@ -51,25 +51,26 @@ func (s *Stack) begin() {
|
|||||||
s.macro.Record(s.ops)
|
s.macro.Record(s.ops)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rigid begins a child with the same constraints that were
|
// Rigid lays out a widget with the same constraints that were
|
||||||
// passed to Init.
|
// passed to Init.
|
||||||
func (s *Stack) Rigid() Constraints {
|
func (s *Stack) Rigid(w Widget) StackChild {
|
||||||
s.begin()
|
s.begin()
|
||||||
return s.cs
|
return s.end(w(s.cs))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expand begins a child with constraints that exactly match
|
// Expand lays out a widget with constraints that exactly match
|
||||||
// the biggest child previously added.
|
// the biggest child previously added.
|
||||||
func (s *Stack) Expand() Constraints {
|
func (s *Stack) Expand(w Widget) StackChild {
|
||||||
s.begin()
|
s.begin()
|
||||||
return Constraints{
|
cs := Constraints{
|
||||||
Width: Constraint{Min: s.maxSZ.X, Max: s.maxSZ.X},
|
Width: Constraint{Min: s.maxSZ.X, Max: s.maxSZ.X},
|
||||||
Height: Constraint{Min: s.maxSZ.Y, Max: s.maxSZ.Y},
|
Height: Constraint{Min: s.maxSZ.Y, Max: s.maxSZ.Y},
|
||||||
}
|
}
|
||||||
|
return s.end(w(cs))
|
||||||
}
|
}
|
||||||
|
|
||||||
// End a child by specifying its dimensions.
|
// End a child by specifying its dimensions.
|
||||||
func (s *Stack) End(dims Dimensions) StackChild {
|
func (s *Stack) end(dims Dimensions) StackChild {
|
||||||
s.macro.Stop()
|
s.macro.Stop()
|
||||||
s.begun = false
|
s.begun = false
|
||||||
if w := dims.Size.X; w > s.maxSZ.X {
|
if w := dims.Size.X; w > s.maxSZ.X {
|
||||||
|
|||||||
Reference in New Issue
Block a user