~eliasnaur/gio

9142345fd41636140f6e1e24f838f50fff5b837f — Elias Naur 2 years ago bf5d083
ui: make OpPush and OpPop explicit

We're about to allow OpBlock for invoking ops from multiple (cached)
Ops containers. To allow for drawing state changes to stick after
invoking such a cached block, we can't let OpBlock perform an implicit
save and restore of drawing state.

Instead, introduce OpPush and OpPop for explicit drawing state stack
management.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
M ui/layout/flex.go => ui/layout/flex.go +2 -2
@@ 157,12 157,12 @@ func (f *Flex) Layout(ops *ui.Ops, children ...FlexChild) Dimens {
				cross = f.maxBaseline - b
			}
		}
		ops.Begin()
		ui.OpPush{}.Add(ops)
		ui.OpTransform{
			Transform: ui.Offset(toPointF(axisPoint(f.Axis, mainSize, cross))),
		}.Add(ops)
		child.block.Add(ops)
		ops.End().Add(ops)
		ui.OpPop{}.Add(ops)
		mainSize += axisMain(f.Axis, dims.Size)
		switch f.MainAxisAlignment {
		case SpaceEvenly:

M ui/layout/layout.go => ui/layout/layout.go +4 -4
@@ 97,13 97,13 @@ func (in *Insets) Begin(ops *ui.Ops, cs Constraints) Constraints {
			mcs.Height.Max = mcs.Height.Min
		}
	}
	ops.Begin()
	ui.OpPush{}.Add(ops)
	ui.OpTransform{Transform: ui.Offset(toPointF(image.Point{X: l, Y: t}))}.Add(ops)
	return mcs
}

func (in *Insets) End(ops *ui.Ops, dims Dimens) Dimens {
	ops.End().Add(ops)
	ui.OpPop{}.Add(ops)
	t, r, b, l := int(math.Round(float64(in.Top))), int(math.Round(float64(in.Right))), int(math.Round(float64(in.Bottom))), int(math.Round(float64(in.Left)))
	return Dimens{
		Size:     in.cs.Constrain(dims.Size.Add(image.Point{X: r + l, Y: t + b})),


@@ 176,10 176,10 @@ func (a *Align) End(ops *ui.Ops, dims Dimens) Dimens {
	case SW, S, SE:
		p.Y = sz.Y - dims.Size.Y
	}
	ops.Begin()
	ui.OpPush{}.Add(ops)
	ui.OpTransform{Transform: ui.Offset(toPointF(p))}.Add(ops)
	block.Add(ops)
	ops.End().Add(ops)
	ui.OpPop{}.Add(ops)
	return Dimens{
		Size:     sz,
		Baseline: dims.Baseline,

M ui/layout/list.go => ui/layout/list.go +2 -2
@@ 178,13 178,13 @@ func (l *List) Layout(ops *ui.Ops) Dimens {
			Min: axisPoint(l.Axis, min, -ui.Inf),
			Max: axisPoint(l.Axis, max, ui.Inf),
		}
		ops.Begin()
		ui.OpPush{}.Add(ops)
		draw.OpClip{Path: draw.RectPath(r)}.Add(ops)
		ui.OpTransform{
			Transform: ui.Offset(toPointF(axisPoint(l.Axis, pos, cross))),
		}.Add(ops)
		child.block.Add(ops)
		ops.End().Add(ops)
		ui.OpPop{}.Add(ops)
		pos += axisMain(l.Axis, sz)
	}
	atStart := l.first == 0 && l.offset <= 0

M ui/layout/stack.go => ui/layout/stack.go +2 -2
@@ 101,10 101,10 @@ func (s *Stack) Layout(ops *ui.Ops, children ...StackChild) Dimens {
		case SW, S, SE:
			p.Y = s.maxSZ.Y - sz.Y
		}
		ops.Begin()
		ui.OpPush{}.Add(ops)
		ui.OpTransform{Transform: ui.Offset(toPointF(p))}.Add(ops)
		ch.block.Add(ops)
		ops.End().Add(ops)
		ui.OpPop{}.Add(ops)
	}
	b := s.baseline
	if b == 0 {

M ui/ops.go => ui/ops.go +14 -6
@@ 24,8 24,6 @@ type OpsReader struct {
	pc    pc
	stack []block
	ops   opsData

	pseudoOp [1]byte
}

type block struct {


@@ 73,6 71,10 @@ var refLengths = [...]int{
	ops.TypePopRefs,
}

type OpPush struct{}

type OpPop struct{}

type OpBlock struct {
	ops *Ops
	pc  pc


@@ 82,6 84,14 @@ type opBlockDef struct {
	endpc pc
}

func (p OpPush) Add(o *Ops) {
	o.Write([]byte{byte(ops.TypePush)}, nil)
}

func (p OpPop) Add(o *Ops) {
	o.Write([]byte{byte(ops.TypePop)}, nil)
}

// Begin a block of ops.
func (o *Ops) Begin() {
	o.stack = append(o.stack, o.ops.pc())


@@ 183,8 193,7 @@ func (r *OpsReader) Decode() ([]byte, []interface{}, bool) {
				r.ops = b.ops
				r.pc = b.retPC
				r.stack = r.stack[:len(r.stack)-1]
				r.pseudoOp[0] = byte(ops.TypePop)
				return r.pseudoOp[:], nil, true
				continue
			}
		}
		if r.pc.data == len(r.ops.data) {


@@ 217,8 226,7 @@ func (r *OpsReader) Decode() ([]byte, []interface{}, bool) {
			r.pc = op.pc
			r.pc.data += ops.TypeBlockDefLen
			r.pc.refs += ops.TypeBlockDefRefs
			r.pseudoOp[0] = byte(ops.TypePush)
			return r.pseudoOp[:], nil, true
			continue
		case ops.TypeBlockDef:
			var op opBlockDef
			op.decode(data)

M ui/text/editor.go => ui/text/editor.go +2 -2
@@ 171,11 171,11 @@ func (e *Editor) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens {
			break
		}
		path := e.Face.Path(str)
		ops.Begin()
		ui.OpPush{}.Add(ops)
		ui.OpTransform{Transform: ui.Offset(lineOff)}.Add(ops)
		draw.OpClip{Path: path}.Add(ops)
		draw.OpDraw{Rect: toRectF(clip).Sub(lineOff)}.Add(ops)
		ops.End().Add(ops)
		ui.OpPop{}.Add(ops)
	}
	if e.focused {
		now := e.cfg.Now

M ui/text/label.go => ui/text/label.go +2 -2
@@ 102,11 102,11 @@ func (l Label) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens {
		}
		path := l.Face.Path(str)
		lclip := toRectF(clip).Sub(off)
		ops.Begin()
		ui.OpPush{}.Add(ops)
		ui.OpTransform{Transform: ui.Offset(off)}.Add(ops)
		draw.OpClip{Path: path}.Add(ops)
		draw.OpDraw{Rect: lclip}.Add(ops)
		ops.End().Add(ops)
		ui.OpPop{}.Add(ops)
	}
	return dims
}