~eliasnaur/gio

586d33c26e58b076f5f11bd842ca50a82be21f9c — Elias Naur 1 year, 4 months ago f9fda47
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>
M ui/layout/flex.go => ui/layout/flex.go +3 -2
@@ 157,12 157,13 @@ func (f *Flex) Layout(children ...FlexChild) Dimens {
				cross = f.maxBaseline - b
			}
		}
		ui.PushOp{}.Add(f.ops)
		var stack ui.StackOp
		stack.Push(f.ops)
		ui.TransformOp{
			Transform: ui.Offset(toPointF(axisPoint(f.Axis, mainSize, cross))),
		}.Add(f.ops)
		child.macro.Add(f.ops)
		ui.PopOp{}.Add(f.ops)
		stack.Pop()
		mainSize += axisMain(f.Axis, dims.Size)
		if i < len(children)-1 {
			switch f.MainAxisAlignment {

M ui/layout/layout.go => ui/layout/layout.go +6 -7
@@ 54,8 54,8 @@ func RigidConstraints(size image.Point) Constraints {
type Inset struct {
	Top, Right, Bottom, Left ui.Value

	stack                    ui.StackOp
	top, right, bottom, left int
	ops                      *ui.Ops
	begun                    bool
	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.left = c.Px(in.Left)
	in.begun = true
	in.ops = ops
	in.cs = cs
	mcs := cs
	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
		}
	}
	ui.PushOp{}.Add(ops)
	in.stack.Push(ops)
	ui.TransformOp{Transform: ui.Offset(toPointF(image.Point{X: in.left, Y: in.top}))}.Add(ops)
	return mcs
}


@@ 102,8 101,7 @@ func (in *Inset) End(dims Dimens) Dimens {
		panic("must Begin before End")
	}
	in.begun = false
	ops := in.ops
	ui.PopOp{}.Add(ops)
	in.stack.Pop()
	return Dimens{
		Size:     in.cs.Constrain(dims.Size.Add(image.Point{X: in.right + in.left, Y: in.top + in.bottom})),
		Baseline: dims.Baseline + in.top,


@@ 165,10 163,11 @@ func (a *Align) End(dims Dimens) Dimens {
	case SW, S, SE:
		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)
	a.macro.Add(ops)
	ui.PopOp{}.Add(ops)
	stack.Pop()
	return Dimens{
		Size:     sz,
		Baseline: dims.Baseline,

M ui/layout/list.go => ui/layout/list.go +3 -2
@@ 224,13 224,14 @@ func (l *List) Layout() Dimens {
			Min: axisPoint(l.Axis, min, -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)
		ui.TransformOp{
			Transform: ui.Offset(toPointF(axisPoint(l.Axis, transPos, cross))),
		}.Add(ops)
		child.macro.Add(ops)
		ui.PopOp{}.Add(ops)
		stack.Pop()
		pos += childSize
	}
	atStart := l.first == 0 && l.offset <= 0

M ui/layout/stack.go => ui/layout/stack.go +3 -2
@@ 104,10 104,11 @@ func (s *Stack) Layout(children ...StackChild) Dimens {
		case SW, S, SE:
			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)
		ch.macro.Add(s.ops)
		ui.PopOp{}.Add(s.ops)
		stack.Pop()
	}
	b := s.baseline
	if b == 0 {

M ui/ops.go => ui/ops.go +26 -6
@@ 14,6 14,8 @@ type Ops struct {
	// Op references.
	refs []interface{}

	stackDepth int

	inAux  bool
	auxOff int
	auxLen int


@@ 52,9 54,11 @@ type pc struct {
	refs int
}

type PushOp struct{}

type PopOp struct{}
type StackOp struct {
	depth  int
	active bool
	ops    *Ops
}

type MacroOp struct {
	recording bool


@@ 71,12 75,27 @@ type opAux struct {
	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)})
}

func (p PopOp) Add(o *Ops) {
	o.Write([]byte{byte(ops.TypePop)})
func (s *StackOp) Pop() {
	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) {


@@ 107,6 126,7 @@ func (op *opMacroDef) decode(data []byte) {
// Reset the Ops, preparing it for re-use.
func (o *Ops) Reset() {
	o.inAux = false
	o.stackDepth = 0
	// Leave references to the GC.
	for i := range o.refs {
		o.refs[i] = nil

M ui/text/editor.go => ui/text/editor.go +6 -4
@@ 194,7 194,8 @@ func (e *Editor) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens {
		Width:     e.viewWidth(),
		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.
	if e.rr.len() > 0 {
		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 {
			break
		}
		ui.PushOp{}.Add(ops)
		var stack ui.StackOp
		stack.Push(ops)
		ui.TransformOp{Transform: ui.Offset(lineOff)}.Add(ops)
		e.Face.Path(str).Add(ops)
		draw.DrawOp{Rect: toRectF(clip).Sub(lineOff)}.Add(ops)
		ui.PopOp{}.Add(ops)
		stack.Pop()
	}
	if e.focused {
		now := e.Config.Now()


@@ 245,7 247,7 @@ func (e *Editor) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens {
			redraw.Add(ops)
		}
	}
	ui.PopOp{}.Add(ops)
	stack.Pop()

	baseline := e.padTop + e.dims.Baseline
	pointer.RectAreaOp{Size: e.viewSize}.Add(ops)

M ui/text/label.go => ui/text/label.go +3 -2
@@ 107,14 107,15 @@ func (l Label) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens {
			break
		}
		lclip := toRectF(clip).Sub(off)
		ui.PushOp{}.Add(ops)
		var stack ui.StackOp
		stack.Push(ops)
		ui.TransformOp{Transform: ui.Offset(off)}.Add(ops)
		l.Face.Path(str).Add(ops)
		// Set a default color in case the material is empty.
		draw.ColorOp{Color: color.RGBA{A: 0xff}}.Add(ops)
		l.Material.Add(ops)
		draw.DrawOp{Rect: lclip}.Add(ops)
		ui.PopOp{}.Add(ops)
		stack.Pop()
	}
	return dims
}