mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 23:55:39 +00:00
df791f2e9b
Layouts and path builders are transient and need an ops list for operation. However, instead of passing the ops list to every method, pass the list in an init method and store it for subsequent methods. Signed-off-by: Elias Naur <mail@eliasnaur.com>
120 lines
1.9 KiB
Go
120 lines
1.9 KiB
Go
// SPDX-License-Identifier: Unlicense OR MIT
|
|
|
|
package layout
|
|
|
|
import (
|
|
"image"
|
|
|
|
"gioui.org/ui"
|
|
)
|
|
|
|
type Stack struct {
|
|
Alignment Direction
|
|
|
|
ops *ui.Ops
|
|
constrained bool
|
|
cs Constraints
|
|
begun bool
|
|
maxSZ image.Point
|
|
baseline int
|
|
}
|
|
|
|
type StackChild struct {
|
|
block ui.OpBlock
|
|
dims Dimens
|
|
}
|
|
|
|
type Direction uint8
|
|
|
|
const (
|
|
NW Direction = iota
|
|
N
|
|
NE
|
|
E
|
|
SE
|
|
S
|
|
SW
|
|
W
|
|
)
|
|
|
|
func (s *Stack) Init(ops *ui.Ops, cs Constraints) {
|
|
s.ops = ops
|
|
s.cs = cs
|
|
s.constrained = true
|
|
s.maxSZ = image.Point{}
|
|
s.baseline = 0
|
|
}
|
|
|
|
func (s *Stack) begin() {
|
|
if !s.constrained {
|
|
panic("must Constrain before adding a child")
|
|
}
|
|
if s.begun {
|
|
panic("must End before adding a child")
|
|
}
|
|
s.begun = true
|
|
s.ops.Begin()
|
|
ui.OpLayer{}.Add(s.ops)
|
|
}
|
|
|
|
func (s *Stack) Rigid() Constraints {
|
|
s.begin()
|
|
return s.cs
|
|
}
|
|
|
|
func (s *Stack) Expand() Constraints {
|
|
s.begin()
|
|
return Constraints{
|
|
Width: Constraint{Min: s.maxSZ.X, Max: s.maxSZ.X},
|
|
Height: Constraint{Min: s.maxSZ.Y, Max: s.maxSZ.Y},
|
|
}
|
|
}
|
|
|
|
func (s *Stack) End(dims Dimens) StackChild {
|
|
b := s.ops.End()
|
|
s.begun = false
|
|
if w := dims.Size.X; w > s.maxSZ.X {
|
|
s.maxSZ.X = w
|
|
}
|
|
if h := dims.Size.Y; h > s.maxSZ.Y {
|
|
s.maxSZ.Y = h
|
|
}
|
|
if s.baseline == 0 {
|
|
if b := dims.Baseline; b != dims.Size.Y {
|
|
s.baseline = b
|
|
}
|
|
}
|
|
return StackChild{b, dims}
|
|
}
|
|
|
|
func (s *Stack) Layout(children ...StackChild) Dimens {
|
|
for _, ch := range children {
|
|
sz := ch.dims.Size
|
|
var p image.Point
|
|
switch s.Alignment {
|
|
case N, S, Center:
|
|
p.X = (s.maxSZ.X - sz.X) / 2
|
|
case NE, SE, E:
|
|
p.X = s.maxSZ.X - sz.X
|
|
}
|
|
switch s.Alignment {
|
|
case W, Center, E:
|
|
p.Y = (s.maxSZ.Y - sz.Y) / 2
|
|
case SW, S, SE:
|
|
p.Y = s.maxSZ.Y - sz.Y
|
|
}
|
|
ui.OpPush{}.Add(s.ops)
|
|
ui.OpTransform{Transform: ui.Offset(toPointF(p))}.Add(s.ops)
|
|
ch.block.Add(s.ops)
|
|
ui.OpPop{}.Add(s.ops)
|
|
}
|
|
b := s.baseline
|
|
if b == 0 {
|
|
b = s.maxSZ.Y
|
|
}
|
|
return Dimens{
|
|
Size: s.maxSZ,
|
|
Baseline: b,
|
|
}
|
|
}
|