forked from joejulian/gio
ae8a377cda
The funcs replace stack.Push and macro.Record, which become private. This makes stack and macro faster to write, in particular for stacks where you can just write the following line to save and restore the state : defer op.Push(ops).Pop() This usage requires Push to return a pointer (since Pop has a pointer receiver), or else the code doesn't compile. For consistancy, I tried to do the same for op.Record, but this implied to turn all the MacroOp fields into pointers, and this caused some panics. As a result, op.Record doesn't return a pointer. An other side effect pointed by Larry Clapp: StackOp and MacroOp are not re-usable any more, you have to allocate a new one for each usage, using the described funcs above. Signed-off-by: Thomas Bruyelle <thomas.bruyelle@gmail.com>
125 lines
2.6 KiB
Go
125 lines
2.6 KiB
Go
// SPDX-License-Identifier: Unlicense OR MIT
|
|
|
|
package layout
|
|
|
|
import (
|
|
"image"
|
|
|
|
"gioui.org/op"
|
|
)
|
|
|
|
// Stack lays out child elements on top of each other,
|
|
// according to an alignment direction.
|
|
type Stack struct {
|
|
// Alignment is the direction to align children
|
|
// smaller than the available space.
|
|
Alignment Direction
|
|
}
|
|
|
|
// StackChild represents a child for a Stack layout.
|
|
type StackChild struct {
|
|
expanded bool
|
|
widget Widget
|
|
|
|
// Scratch space.
|
|
macro op.MacroOp
|
|
dims Dimensions
|
|
}
|
|
|
|
// Stacked returns a Stack child that is laid out with no minimum
|
|
// constraints and the maximum constraints passed to Stack.Layout.
|
|
func Stacked(w Widget) StackChild {
|
|
return StackChild{
|
|
widget: w,
|
|
}
|
|
}
|
|
|
|
// Expanded returns a Stack child with the minimum constraints set
|
|
// to the largest Stacked child. The maximum constraints are set to
|
|
// the same as passed to Stack.Layout.
|
|
func Expanded(w Widget) StackChild {
|
|
return StackChild{
|
|
expanded: true,
|
|
widget: w,
|
|
}
|
|
}
|
|
|
|
// Layout a stack of children. The position of the children are
|
|
// determined by the specified order, but Stacked children are laid out
|
|
// before Expanded children.
|
|
func (s Stack) Layout(gtx Context, children ...StackChild) Dimensions {
|
|
var maxSZ image.Point
|
|
// First lay out Stacked children.
|
|
for i, w := range children {
|
|
if w.expanded {
|
|
continue
|
|
}
|
|
macro := op.Record(gtx.Ops)
|
|
gtx := gtx
|
|
gtx.Constraints.Min = image.Pt(0, 0)
|
|
dims := w.widget(gtx)
|
|
macro.Stop()
|
|
if w := dims.Size.X; w > maxSZ.X {
|
|
maxSZ.X = w
|
|
}
|
|
if h := dims.Size.Y; h > maxSZ.Y {
|
|
maxSZ.Y = h
|
|
}
|
|
children[i].macro = macro
|
|
children[i].dims = dims
|
|
}
|
|
// Then lay out Expanded children.
|
|
for i, w := range children {
|
|
if !w.expanded {
|
|
continue
|
|
}
|
|
macro := op.Record(gtx.Ops)
|
|
gtx := gtx
|
|
gtx.Constraints = Constraints{
|
|
Min: maxSZ, Max: gtx.Constraints.Max,
|
|
}
|
|
dims := w.widget(gtx)
|
|
macro.Stop()
|
|
if w := dims.Size.X; w > maxSZ.X {
|
|
maxSZ.X = w
|
|
}
|
|
if h := dims.Size.Y; h > maxSZ.Y {
|
|
maxSZ.Y = h
|
|
}
|
|
children[i].macro = macro
|
|
children[i].dims = dims
|
|
}
|
|
|
|
maxSZ = gtx.Constraints.Constrain(maxSZ)
|
|
var baseline int
|
|
for _, ch := range children {
|
|
sz := ch.dims.Size
|
|
var p image.Point
|
|
switch s.Alignment {
|
|
case N, S, Center:
|
|
p.X = (maxSZ.X - sz.X) / 2
|
|
case NE, SE, E:
|
|
p.X = maxSZ.X - sz.X
|
|
}
|
|
switch s.Alignment {
|
|
case W, Center, E:
|
|
p.Y = (maxSZ.Y - sz.Y) / 2
|
|
case SW, S, SE:
|
|
p.Y = maxSZ.Y - sz.Y
|
|
}
|
|
stack := op.Push(gtx.Ops)
|
|
op.TransformOp{}.Offset(FPt(p)).Add(gtx.Ops)
|
|
ch.macro.Add()
|
|
stack.Pop()
|
|
if baseline == 0 {
|
|
if b := ch.dims.Baseline; b != 0 {
|
|
baseline = b + maxSZ.Y - sz.Y - p.Y
|
|
}
|
|
}
|
|
}
|
|
return Dimensions{
|
|
Size: maxSZ,
|
|
Baseline: baseline,
|
|
}
|
|
}
|