ui: replace PushOp, PopOp with a StackOp

Before this change, there was no guarantee that a PopOp matched
the intended PushOp. With a single stack operation, the client is
forced to match pop with the right push.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2019-07-16 13:41:10 +02:00
parent f9fda47d25
commit 586d33c26e
7 changed files with 50 additions and 25 deletions
+3 -2
View File
@@ -157,12 +157,13 @@ func (f *Flex) Layout(children ...FlexChild) Dimens {
cross = f.maxBaseline - b cross = f.maxBaseline - b
} }
} }
ui.PushOp{}.Add(f.ops) var stack ui.StackOp
stack.Push(f.ops)
ui.TransformOp{ ui.TransformOp{
Transform: ui.Offset(toPointF(axisPoint(f.Axis, mainSize, cross))), Transform: ui.Offset(toPointF(axisPoint(f.Axis, mainSize, cross))),
}.Add(f.ops) }.Add(f.ops)
child.macro.Add(f.ops) child.macro.Add(f.ops)
ui.PopOp{}.Add(f.ops) stack.Pop()
mainSize += axisMain(f.Axis, dims.Size) mainSize += axisMain(f.Axis, dims.Size)
if i < len(children)-1 { if i < len(children)-1 {
switch f.MainAxisAlignment { switch f.MainAxisAlignment {
+6 -7
View File
@@ -54,8 +54,8 @@ func RigidConstraints(size image.Point) Constraints {
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 top, right, bottom, left int
ops *ui.Ops
begun bool begun bool
cs Constraints cs Constraints
} }
@@ -69,7 +69,6 @@ func (in *Inset) Begin(c ui.Config, ops *ui.Ops, cs Constraints) Constraints {
in.bottom = c.Px(in.Bottom) in.bottom = c.Px(in.Bottom)
in.left = c.Px(in.Left) in.left = c.Px(in.Left)
in.begun = true in.begun = true
in.ops = ops
in.cs = cs in.cs = cs
mcs := cs mcs := cs
if mcs.Width.Max != ui.Inf { if mcs.Width.Max != ui.Inf {
@@ -92,7 +91,7 @@ func (in *Inset) Begin(c ui.Config, ops *ui.Ops, cs Constraints) Constraints {
mcs.Height.Max = mcs.Height.Min mcs.Height.Max = mcs.Height.Min
} }
} }
ui.PushOp{}.Add(ops) in.stack.Push(ops)
ui.TransformOp{Transform: ui.Offset(toPointF(image.Point{X: in.left, Y: in.top}))}.Add(ops) ui.TransformOp{Transform: ui.Offset(toPointF(image.Point{X: in.left, Y: in.top}))}.Add(ops)
return mcs return mcs
} }
@@ -102,8 +101,7 @@ func (in *Inset) End(dims Dimens) Dimens {
panic("must Begin before End") panic("must Begin before End")
} }
in.begun = false in.begun = false
ops := in.ops in.stack.Pop()
ui.PopOp{}.Add(ops)
return Dimens{ return Dimens{
Size: in.cs.Constrain(dims.Size.Add(image.Point{X: in.right + in.left, Y: in.top + in.bottom})), Size: in.cs.Constrain(dims.Size.Add(image.Point{X: in.right + in.left, Y: in.top + in.bottom})),
Baseline: dims.Baseline + in.top, Baseline: dims.Baseline + in.top,
@@ -165,10 +163,11 @@ func (a *Align) End(dims Dimens) Dimens {
case SW, S, SE: case SW, S, SE:
p.Y = sz.Y - dims.Size.Y p.Y = sz.Y - dims.Size.Y
} }
ui.PushOp{}.Add(ops) var stack ui.StackOp
stack.Push(ops)
ui.TransformOp{Transform: ui.Offset(toPointF(p))}.Add(ops) ui.TransformOp{Transform: ui.Offset(toPointF(p))}.Add(ops)
a.macro.Add(ops) a.macro.Add(ops)
ui.PopOp{}.Add(ops) stack.Pop()
return Dimens{ return Dimens{
Size: sz, Size: sz,
Baseline: dims.Baseline, Baseline: dims.Baseline,
+3 -2
View File
@@ -224,13 +224,14 @@ func (l *List) Layout() Dimens {
Min: axisPoint(l.Axis, min, -ui.Inf), Min: axisPoint(l.Axis, min, -ui.Inf),
Max: axisPoint(l.Axis, max, ui.Inf), Max: axisPoint(l.Axis, max, ui.Inf),
} }
ui.PushOp{}.Add(ops) var stack ui.StackOp
stack.Push(ops)
draw.RectClip(r).Add(ops) draw.RectClip(r).Add(ops)
ui.TransformOp{ ui.TransformOp{
Transform: ui.Offset(toPointF(axisPoint(l.Axis, transPos, cross))), Transform: ui.Offset(toPointF(axisPoint(l.Axis, transPos, cross))),
}.Add(ops) }.Add(ops)
child.macro.Add(ops) child.macro.Add(ops)
ui.PopOp{}.Add(ops) stack.Pop()
pos += childSize pos += childSize
} }
atStart := l.first == 0 && l.offset <= 0 atStart := l.first == 0 && l.offset <= 0
+3 -2
View File
@@ -104,10 +104,11 @@ func (s *Stack) Layout(children ...StackChild) Dimens {
case SW, S, SE: case SW, S, SE:
p.Y = s.maxSZ.Y - sz.Y p.Y = s.maxSZ.Y - sz.Y
} }
ui.PushOp{}.Add(s.ops) var stack ui.StackOp
stack.Push(s.ops)
ui.TransformOp{Transform: ui.Offset(toPointF(p))}.Add(s.ops) ui.TransformOp{Transform: ui.Offset(toPointF(p))}.Add(s.ops)
ch.macro.Add(s.ops) ch.macro.Add(s.ops)
ui.PopOp{}.Add(s.ops) stack.Pop()
} }
b := s.baseline b := s.baseline
if b == 0 { if b == 0 {
+26 -6
View File
@@ -14,6 +14,8 @@ type Ops struct {
// Op references. // Op references.
refs []interface{} refs []interface{}
stackDepth int
inAux bool inAux bool
auxOff int auxOff int
auxLen int auxLen int
@@ -52,9 +54,11 @@ type pc struct {
refs int refs int
} }
type PushOp struct{} type StackOp struct {
depth int
type PopOp struct{} active bool
ops *Ops
}
type MacroOp struct { type MacroOp struct {
recording bool recording bool
@@ -71,12 +75,27 @@ type opAux struct {
len int len int
} }
func (p PushOp) Add(o *Ops) { func (s *StackOp) Push(o *Ops) {
if s.active {
panic("unbalanced push")
}
s.active = true
s.ops = o
o.stackDepth++
s.depth = o.stackDepth
o.Write([]byte{byte(ops.TypePush)}) o.Write([]byte{byte(ops.TypePush)})
} }
func (p PopOp) Add(o *Ops) { func (s *StackOp) Pop() {
o.Write([]byte{byte(ops.TypePop)}) if !s.active {
panic("unbalanced pop")
}
d := s.ops.stackDepth
if d != s.depth {
panic("unbalanced pop")
}
s.ops.stackDepth--
s.ops.Write([]byte{byte(ops.TypePop)})
} }
func (op *opAux) decode(data []byte) { func (op *opAux) decode(data []byte) {
@@ -107,6 +126,7 @@ func (op *opMacroDef) decode(data []byte) {
// Reset the Ops, preparing it for re-use. // Reset the Ops, preparing it for re-use.
func (o *Ops) Reset() { func (o *Ops) Reset() {
o.inAux = false o.inAux = false
o.stackDepth = 0
// Leave references to the GC. // Leave references to the GC.
for i := range o.refs { for i := range o.refs {
o.refs[i] = nil o.refs[i] = nil
+6 -4
View File
@@ -194,7 +194,8 @@ func (e *Editor) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens {
Width: e.viewWidth(), Width: e.viewWidth(),
Offset: off, Offset: off,
} }
ui.PushOp{}.Add(ops) var stack ui.StackOp
stack.Push(ops)
// Apply material. Set a default color in case the material is empty. // Apply material. Set a default color in case the material is empty.
if e.rr.len() > 0 { if e.rr.len() > 0 {
draw.ColorOp{Color: color.RGBA{A: 0xff}}.Add(ops) draw.ColorOp{Color: color.RGBA{A: 0xff}}.Add(ops)
@@ -208,11 +209,12 @@ func (e *Editor) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens {
if !ok { if !ok {
break break
} }
ui.PushOp{}.Add(ops) var stack ui.StackOp
stack.Push(ops)
ui.TransformOp{Transform: ui.Offset(lineOff)}.Add(ops) ui.TransformOp{Transform: ui.Offset(lineOff)}.Add(ops)
e.Face.Path(str).Add(ops) e.Face.Path(str).Add(ops)
draw.DrawOp{Rect: toRectF(clip).Sub(lineOff)}.Add(ops) draw.DrawOp{Rect: toRectF(clip).Sub(lineOff)}.Add(ops)
ui.PopOp{}.Add(ops) stack.Pop()
} }
if e.focused { if e.focused {
now := e.Config.Now() now := e.Config.Now()
@@ -245,7 +247,7 @@ func (e *Editor) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens {
redraw.Add(ops) redraw.Add(ops)
} }
} }
ui.PopOp{}.Add(ops) stack.Pop()
baseline := e.padTop + e.dims.Baseline baseline := e.padTop + e.dims.Baseline
pointer.RectAreaOp{Size: e.viewSize}.Add(ops) pointer.RectAreaOp{Size: e.viewSize}.Add(ops)
+3 -2
View File
@@ -107,14 +107,15 @@ func (l Label) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens {
break break
} }
lclip := toRectF(clip).Sub(off) lclip := toRectF(clip).Sub(off)
ui.PushOp{}.Add(ops) var stack ui.StackOp
stack.Push(ops)
ui.TransformOp{Transform: ui.Offset(off)}.Add(ops) ui.TransformOp{Transform: ui.Offset(off)}.Add(ops)
l.Face.Path(str).Add(ops) l.Face.Path(str).Add(ops)
// Set a default color in case the material is empty. // Set a default color in case the material is empty.
draw.ColorOp{Color: color.RGBA{A: 0xff}}.Add(ops) draw.ColorOp{Color: color.RGBA{A: 0xff}}.Add(ops)
l.Material.Add(ops) l.Material.Add(ops)
draw.DrawOp{Rect: lclip}.Add(ops) draw.DrawOp{Rect: lclip}.Add(ops)
ui.PopOp{}.Add(ops) stack.Pop()
} }
return dims return dims
} }