~eliasnaur/gio

ref: 5c3dcc6f9a07dc22a26319616adc2c63e33da966 gio/ui/layout/stack.go -rw-r--r-- 2.4 KiB
5c3dcc6fElias Naur ui/gesture: typo 1 year, 1 month ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// SPDX-License-Identifier: Unlicense OR MIT

package layout

import (
	"image"

	"gioui.org/ui"
)

// 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

	macro       ui.MacroOp
	ops         *ui.Ops
	constrained bool
	cs          Constraints
	begun       bool
	maxSZ       image.Point
	baseline    int
}

// StackChild is the layout result of a call to End.
type StackChild struct {
	macro ui.MacroOp
	dims  Dimens
}

// Init a stack before calling Rigid or Expand.
func (s *Stack) Init(ops *ui.Ops, cs Constraints) *Stack {
	s.ops = ops
	s.cs = cs
	s.constrained = true
	s.maxSZ = image.Point{}
	s.baseline = 0
	return s
}

func (s *Stack) begin() {
	if !s.constrained {
		panic("must Init before adding a child")
	}
	if s.begun {
		panic("must End before adding a child")
	}
	s.begun = true
	s.macro.Record(s.ops)
}

// Rigid begins a child with the same constraints that were
// passed to Init.
func (s *Stack) Rigid() Constraints {
	s.begin()
	return s.cs
}

// Expand begins a child with constraints that exactly match
// the biggest child previously added.
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},
	}
}

// End a child by specifying its dimensions.
func (s *Stack) End(dims Dimens) StackChild {
	s.macro.Stop()
	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{s.macro, dims}
}

// Layout a list of children. The order of the children determines their laid
// out order.
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
		}
		var stack ui.StackOp
		stack.Push(s.ops)
		ui.TransformOp{}.Offset(toPointF(p)).Add(s.ops)
		ch.macro.Add(s.ops)
		stack.Pop()
	}
	b := s.baseline
	if b == 0 {
		b = s.maxSZ.Y
	}
	return Dimens{
		Size:     s.maxSZ,
		Baseline: b,
	}
}