~eliasnaur/gio

7aa7bb3be40858efe2a98f866fcc7db2026b02fd — Elias Naur 1 year, 5 months ago b981ccf
ui: rename ops to have Op suffixed, not prefixed

Match Go's FooError name pattern.

While we're here, rename RedrawOp to InvalidateOp.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
M ui/app/internal/gpu/gpu.go => ui/app/internal/gpu/gpu.go +6 -6
@@ 78,10 78,10 @@ type drawState struct {
	rect  bool
	z     int

	// Current OpImage image and rect, if any.
	// Current ImageOp image and rect, if any.
	img     image.Image
	imgRect image.Rectangle
	// Current OpColor, if any.
	// Current ColorOp, if any.
	color color.NRGBA
}



@@ 666,7 666,7 @@ loop:
		}
		switch ops.OpType(encOp.Data[0]) {
		case ops.TypeTransform:
			var op ui.OpTransform
			var op ui.TransformOp
			op.Decode(encOp.Data)
			state.t = state.t.Mul(op.Transform)
		case ops.TypeAux:


@@ 696,17 696,17 @@ loop:
			aux = nil
			auxKey = ui.OpKey{}
		case ops.TypeColor:
			var op gdraw.OpColor
			var op gdraw.ColorOp
			op.Decode(encOp.Data, encOp.Refs)
			state.img = nil
			state.color = op.Col
		case ops.TypeImage:
			var op gdraw.OpImage
			var op gdraw.ImageOp
			op.Decode(encOp.Data, encOp.Refs)
			state.img = op.Img
			state.imgRect = op.Rect
		case ops.TypeDraw:
			var op gdraw.OpDraw
			var op gdraw.DrawOp
			op.Decode(encOp.Data, encOp.Refs)
			off := state.t.Transform(f32.Point{})
			clip := state.clip.Intersect(op.Rect.Add(off))

M ui/app/window.go => ui/app/window.go +2 -2
@@ 161,8 161,8 @@ func collectRedraws(r *ui.OpsReader) (time.Time, bool) {
			break
		}
		switch ops.OpType(encOp.Data[0]) {
		case ops.TypeRedraw:
			var op ui.OpRedraw
		case ops.TypeInvalidate:
			var op ui.InvalidateOp
			op.Decode(encOp.Data)
			if !redraw || op.At.Before(t) {
				redraw = true

M ui/draw/draw.go => ui/draw/draw.go +15 -15
@@ 13,20 13,20 @@ import (
	"gioui.org/ui/internal/ops"
)

type OpImage struct {
type ImageOp struct {
	Img  image.Image
	Rect image.Rectangle
}

type OpColor struct {
type ColorOp struct {
	Col color.NRGBA
}

type OpDraw struct {
type DrawOp struct {
	Rect f32.Rectangle
}

func (i OpImage) Add(o *ui.Ops) {
func (i ImageOp) Add(o *ui.Ops) {
	data := make([]byte, ops.TypeImageLen)
	data[0] = byte(ops.TypeImage)
	bo := binary.LittleEndian


@@ 37,7 37,7 @@ func (i OpImage) Add(o *ui.Ops) {
	o.Write(data, i.Img)
}

func (i *OpImage) Decode(data []byte, refs []interface{}) {
func (i *ImageOp) Decode(data []byte, refs []interface{}) {
	bo := binary.LittleEndian
	if ops.OpType(data[0]) != ops.TypeImage {
		panic("invalid op")


@@ 52,13 52,13 @@ func (i *OpImage) Decode(data []byte, refs []interface{}) {
			Y: int(bo.Uint32(data[13:])),
		},
	}
	*i = OpImage{
	*i = ImageOp{
		Img:  refs[0].(image.Image),
		Rect: sr,
	}
}

func (c OpColor) Add(o *ui.Ops) {
func (c ColorOp) Add(o *ui.Ops) {
	data := make([]byte, ops.TypeColorLen)
	data[0] = byte(ops.TypeColor)
	data[1] = c.Col.R


@@ 68,11 68,11 @@ func (c OpColor) Add(o *ui.Ops) {
	o.Write(data)
}

func (c *OpColor) Decode(data []byte, refs []interface{}) {
func (c *ColorOp) Decode(data []byte, refs []interface{}) {
	if ops.OpType(data[0]) != ops.TypeColor {
		panic("invalid op")
	}
	*c = OpColor{
	*c = ColorOp{
		Col: color.NRGBA{
			R: data[1],
			G: data[2],


@@ 82,7 82,7 @@ func (c *OpColor) Decode(data []byte, refs []interface{}) {
	}
}

func (d OpDraw) Add(o *ui.Ops) {
func (d DrawOp) Add(o *ui.Ops) {
	data := make([]byte, ops.TypeDrawLen)
	data[0] = byte(ops.TypeDraw)
	bo := binary.LittleEndian


@@ 93,7 93,7 @@ func (d OpDraw) Add(o *ui.Ops) {
	o.Write(data)
}

func (d *OpDraw) Decode(data []byte, refs []interface{}) {
func (d *DrawOp) Decode(data []byte, refs []interface{}) {
	bo := binary.LittleEndian
	if ops.OpType(data[0]) != ops.TypeDraw {
		panic("invalid op")


@@ 108,15 108,15 @@ func (d *OpDraw) Decode(data []byte, refs []interface{}) {
			Y: math.Float32frombits(bo.Uint32(data[13:])),
		},
	}
	*d = OpDraw{
	*d = DrawOp{
		Rect: r,
	}
}

// RectClip returns an OpClip op corresponding to
// RectClip returns a ClipOp op corresponding to
// a pixel aligned rectangular area.
func RectClip(r image.Rectangle) OpClip {
	return OpClip{bounds: toRectF(r)}
func RectClip(r image.Rectangle) ClipOp {
	return ClipOp{bounds: toRectF(r)}
}

func itof(i int) float32 {

M ui/draw/path.go => ui/draw/path.go +4 -4
@@ 23,13 23,13 @@ type PathBuilder struct {
	hasBounds bool
}

// OpClip structure must match opClip in package ui/internal/gpu.
// ClipOp structure must match opClip in package ui/internal/gpu.

type OpClip struct {
type ClipOp struct {
	bounds f32.Rectangle
}

func (p OpClip) Add(o *ui.Ops) {
func (p ClipOp) Add(o *ui.Ops) {
	data := make([]byte, ops.TypeClipLen)
	data[0] = byte(ops.TypeClip)
	bo := binary.LittleEndian


@@ 278,7 278,7 @@ func (p *PathBuilder) simpleQuadTo(ctrl, to f32.Point) {

func (p *PathBuilder) End() {
	p.end()
	OpClip{
	ClipOp{
		bounds: p.bounds,
	}.Add(p.ops)
}

M ui/gesture/gestures.go => ui/gesture/gestures.go +3 -3
@@ 77,7 77,7 @@ const (
)

func (c *Click) Add(ops *ui.Ops) {
	op := pointer.OpHandler{Key: c}
	op := pointer.HandlerOp{Key: c}
	op.Add(ops)
}



@@ 118,10 118,10 @@ func (c *Click) Update(q input.Events) []ClickEvent {
}

func (s *Scroll) Add(ops *ui.Ops) {
	oph := pointer.OpHandler{Key: s, Grab: s.grab}
	oph := pointer.HandlerOp{Key: s, Grab: s.grab}
	oph.Add(ops)
	if s.flinger.Active() {
		ui.OpRedraw{}.Add(ops)
		ui.InvalidateOp{}.Add(ops)
	}
}


M ui/input/key.go => ui/input/key.go +1 -1
@@ 92,7 92,7 @@ loop:
		}
		switch ops.OpType(encOp.Data[0]) {
		case ops.TypeKeyHandler:
			var op key.OpHandler
			var op key.HandlerOp
			op.Decode(encOp.Data, encOp.Refs)
			var newPri listenerPriority
			switch {

M ui/input/pointer.go => ui/input/pointer.go +5 -5
@@ 40,7 40,7 @@ type pointerHandler struct {

type area struct {
	trans ui.Transform
	area  pointer.OpArea
	area  pointer.AreaOp
}

type areaIntersection []area


@@ 68,15 68,15 @@ func (q *pointerQueue) collectHandlers(r *ui.OpsReader, t ui.Transform, layer in
			layer++
			q.hitTree = append(q.hitTree, hitNode{level: layer})
		case ops.TypeArea:
			var op pointer.OpArea
			var op pointer.AreaOp
			op.Decode(encOp.Data)
			q.areas.add(t, op)
		case ops.TypeTransform:
			var op ui.OpTransform
			var op ui.TransformOp
			op.Decode(encOp.Data)
			t = t.Mul(op.Transform)
		case ops.TypePointerHandler:
			var op pointer.OpHandler
			var op pointer.HandlerOp
			op.Decode(encOp.Data, encOp.Refs)
			q.hitTree = append(q.hitTree, hitNode{level: layer, key: op.Key})
			h, ok := q.handlers[op.Key]


@@ 251,7 251,7 @@ func (a areaIntersection) hit(p f32.Point) pointer.HitResult {
	return res
}

func (s *areaStack) add(t ui.Transform, a pointer.OpArea) {
func (s *areaStack) add(t ui.Transform, a pointer.AreaOp) {
	s.areas = append(s.areas, area{t, a})
}


M ui/internal/ops/ops.go => ui/internal/ops/ops.go +1 -1
@@ 10,7 10,7 @@ const (
	TypeBlock
	TypeTransform
	TypeLayer
	TypeRedraw
	TypeInvalidate
	TypeImage
	TypeDraw
	TypeColor

M ui/key/key.go => ui/key/key.go +6 -6
@@ 7,12 7,12 @@ import (
	"gioui.org/ui/internal/ops"
)

type OpHandler struct {
type HandlerOp struct {
	Key   Key
	Focus bool
}

type OpHideInput struct{}
type HideInputOp struct{}

type Key interface{}



@@ 65,7 65,7 @@ func (m Modifiers) Contain(m2 Modifiers) bool {
	return m&m2 == m2
}

func (h OpHandler) Add(o *ui.Ops) {
func (h HandlerOp) Add(o *ui.Ops) {
	data := make([]byte, ops.TypeKeyHandlerLen)
	data[0] = byte(ops.TypeKeyHandler)
	if h.Focus {


@@ 74,17 74,17 @@ func (h OpHandler) Add(o *ui.Ops) {
	o.Write(data, h.Key)
}

func (h *OpHandler) Decode(d []byte, refs []interface{}) {
func (h *HandlerOp) Decode(d []byte, refs []interface{}) {
	if ops.OpType(d[0]) != ops.TypeKeyHandler {
		panic("invalid op")
	}
	*h = OpHandler{
	*h = HandlerOp{
		Focus: d[1] != 0,
		Key:   refs[0].(Key),
	}
}

func (h OpHideInput) Add(o *ui.Ops) {
func (h HideInputOp) Add(o *ui.Ops) {
	data := make([]byte, ops.TypeHideInputLen)
	data[0] = byte(ops.TypeHideInput)
	o.Write(data)

M ui/layout/flex.go => ui/layout/flex.go +5 -5
@@ 25,7 25,7 @@ type Flex struct {
}

type FlexChild struct {
	block ui.OpBlock
	block ui.BlockOp
	dims  Dimens
}



@@ 79,7 79,7 @@ func (f *Flex) begin() {
	}
	f.begun = true
	f.ops.Begin()
	ui.OpLayer{}.Add(f.ops)
	ui.LayerOp{}.Add(f.ops)
}

func (f *Flex) Rigid() Constraints {


@@ 159,12 159,12 @@ func (f *Flex) Layout(children ...FlexChild) Dimens {
				cross = f.maxBaseline - b
			}
		}
		ui.OpPush{}.Add(f.ops)
		ui.OpTransform{
		ui.PushOp{}.Add(f.ops)
		ui.TransformOp{
			Transform: ui.Offset(toPointF(axisPoint(f.Axis, mainSize, cross))),
		}.Add(f.ops)
		child.block.Add(f.ops)
		ui.OpPop{}.Add(f.ops)
		ui.PopOp{}.Add(f.ops)
		mainSize += axisMain(f.Axis, dims.Size)
		switch f.MainAxisAlignment {
		case SpaceEvenly:

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



@@ 115,7 115,7 @@ func (in *Insets) End(dims Dimens) Dimens {
	}
	in.begun = false
	ops := in.ops
	ui.OpPop{}.Add(ops)
	ui.PopOp{}.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})),


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

M ui/layout/list.go => ui/layout/list.go +5 -5
@@ 14,7 14,7 @@ import (

type scrollChild struct {
	size  image.Point
	block ui.OpBlock
	block ui.BlockOp
}

type List struct {


@@ 91,7 91,7 @@ func (l *List) Next() (int, Constraints, bool) {
	if ok {
		cs = axisConstraints(l.Axis, Constraint{Max: ui.Inf}, l.crossConstraintChild(l.cs))
		l.ops.Begin()
		ui.OpLayer{}.Add(l.ops)
		ui.LayerOp{}.Add(l.ops)
	}
	return i, cs, ok
}


@@ 194,13 194,13 @@ func (l *List) Layout() Dimens {
			Min: axisPoint(l.Axis, min, -ui.Inf),
			Max: axisPoint(l.Axis, max, ui.Inf),
		}
		ui.OpPush{}.Add(ops)
		ui.PushOp{}.Add(ops)
		draw.RectClip(r).Add(ops)
		ui.OpTransform{
		ui.TransformOp{
			Transform: ui.Offset(toPointF(axisPoint(l.Axis, transPos, cross))),
		}.Add(ops)
		child.block.Add(ops)
		ui.OpPop{}.Add(ops)
		ui.PopOp{}.Add(ops)
		pos += childSize
	}
	atStart := l.first == 0 && l.offset <= 0

M ui/layout/stack.go => ui/layout/stack.go +5 -5
@@ 20,7 20,7 @@ type Stack struct {
}

type StackChild struct {
	block ui.OpBlock
	block ui.BlockOp
	dims  Dimens
}



@@ 54,7 54,7 @@ func (s *Stack) begin() {
	}
	s.begun = true
	s.ops.Begin()
	ui.OpLayer{}.Add(s.ops)
	ui.LayerOp{}.Add(s.ops)
}

func (s *Stack) Rigid() Constraints {


@@ 103,10 103,10 @@ func (s *Stack) Layout(children ...StackChild) Dimens {
		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)
		ui.PushOp{}.Add(s.ops)
		ui.TransformOp{Transform: ui.Offset(toPointF(p))}.Add(s.ops)
		ch.block.Add(s.ops)
		ui.OpPop{}.Add(s.ops)
		ui.PopOp{}.Add(s.ops)
	}
	b := s.baseline
	if b == 0 {

M ui/measure/measure.go => ui/measure/measure.go +3 -3
@@ 30,7 30,7 @@ type cachedLayout struct {

type cachedPath struct {
	active bool
	path   ui.OpBlock
	path   ui.BlockOp
}

type layoutKey struct {


@@ 121,7 121,7 @@ func (f *textFace) Layout(str string, singleLine bool, maxWidth int) *text.Layou
	return l
}

func (f *textFace) Path(str text.String) ui.OpBlock {
func (f *textFace) Path(str text.String) ui.BlockOp {
	ppem := fixed.Int26_6(f.faces.Config.Val(f.size)*64 + .5)
	pk := pathKey{
		f:    f.font.Font,


@@ 229,7 229,7 @@ func layoutText(ppem fixed.Int26_6, str string, f *opentype, singleLine bool, ma
	return &text.Layout{Lines: lines}
}

func textPath(ppem fixed.Int26_6, f *opentype, str text.String) ui.OpBlock {
func textPath(ppem fixed.Int26_6, f *opentype, str text.String) ui.BlockOp {
	var lastPos f32.Point
	var builder draw.PathBuilder
	ops := new(ui.Ops)

M ui/ops.go => ui/ops.go +12 -12
@@ 58,11 58,11 @@ type pc struct {
	refs int
}

type OpPush struct{}
type PushOp struct{}

type OpPop struct{}
type PopOp struct{}

type OpBlock struct {
type BlockOp struct {
	ops     *opsData
	version int
	pc      pc


@@ 76,11 76,11 @@ type opAux struct {
	len int
}

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

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



@@ 118,7 118,7 @@ func (op *opBlockDef) decode(data []byte) {

// End the most recent block and return
// an op for invoking the completed block.
func (o *Ops) End() OpBlock {
func (o *Ops) End() BlockOp {
	start := o.stack[len(o.stack)-1]
	o.stack = o.stack[:len(o.stack)-1]
	pc := o.ops.pc()


@@ 128,7 128,7 @@ func (o *Ops) End() OpBlock {
	bo := binary.LittleEndian
	bo.PutUint32(data[1:], uint32(pc.data))
	bo.PutUint32(data[5:], uint32(pc.refs))
	return OpBlock{ops: &o.ops, pc: start, version: o.ops.version}
	return BlockOp{ops: &o.ops, pc: start, version: o.ops.version}
}

// Reset the Ops, preparing it for re-use.


@@ 189,7 189,7 @@ func (d *opsData) pc() pc {
	return pc{data: len(d.data), refs: len(d.refs)}
}

func (b *OpBlock) decode(data []byte, refs []interface{}) {
func (b *BlockOp) decode(data []byte, refs []interface{}) {
	if ops.OpType(data[0]) != ops.TypeBlock {
		panic("invalid op")
	}


@@ 197,7 197,7 @@ func (b *OpBlock) decode(data []byte, refs []interface{}) {
	dataIdx := int(bo.Uint32(data[1:]))
	refsIdx := int(bo.Uint32(data[5:]))
	version := int(bo.Uint32(data[9:]))
	*b = OpBlock{
	*b = BlockOp{
		ops: refs[0].(*opsData),
		pc: pc{
			data: dataIdx,


@@ 207,7 207,7 @@ func (b *OpBlock) decode(data []byte, refs []interface{}) {
	}
}

func (b OpBlock) Add(o *Ops) {
func (b BlockOp) Add(o *Ops) {
	data := make([]byte, ops.TypeBlockLen)
	data[0] = byte(ops.TypeBlock)
	bo := binary.LittleEndian


@@ 251,14 251,14 @@ func (r *OpsReader) Decode() (EncodedOp, bool) {
			n += op.len
			data = r.ops.data[r.pc.data : r.pc.data+n]
		case ops.TypeBlock:
			var op OpBlock
			var op BlockOp
			op.decode(data, refs)
			blockOps := op.ops
			if ops.OpType(blockOps.data[op.pc.data]) != ops.TypeBlockDef {
				panic("invalid block reference")
			}
			if op.version != op.ops.version {
				panic("invalid OpBlock reference to reset Ops")
				panic("invalid BlockOp reference to reset Ops")
			}
			var opDef opBlockDef
			opDef.decode(blockOps.data[op.pc.data : op.pc.data+ops.TypeBlockDef.Size()])

M ui/pointer/pointer.go => ui/pointer/pointer.go +13 -13
@@ 23,14 23,14 @@ type Event struct {
	Scroll    f32.Point
}

type OpArea struct {
type AreaOp struct {
	Transparent bool

	kind areaKind
	size image.Point
}

type OpHandler struct {
type HandlerOp struct {
	Key  Key
	Grab bool
}


@@ 75,21 75,21 @@ const (
	areaEllipse
)

func AreaRect(size image.Point) OpArea {
	return OpArea{
func AreaRect(size image.Point) AreaOp {
	return AreaOp{
		kind: areaRect,
		size: size,
	}
}

func AreaEllipse(size image.Point) OpArea {
	return OpArea{
func AreaEllipse(size image.Point) AreaOp {
	return AreaOp{
		kind: areaEllipse,
		size: size,
	}
}

func (op OpArea) Add(o *ui.Ops) {
func (op AreaOp) Add(o *ui.Ops) {
	data := make([]byte, ops.TypeAreaLen)
	data[0] = byte(ops.TypeArea)
	data[1] = byte(op.kind)


@@ 99,7 99,7 @@ func (op OpArea) Add(o *ui.Ops) {
	o.Write(data)
}

func (op *OpArea) Decode(d []byte) {
func (op *AreaOp) Decode(d []byte) {
	if ops.OpType(d[0]) != ops.TypeArea {
		panic("invalid op")
	}


@@ 108,13 108,13 @@ func (op *OpArea) Decode(d []byte) {
		X: int(bo.Uint32(d[2:])),
		Y: int(bo.Uint32(d[6:])),
	}
	*op = OpArea{
	*op = AreaOp{
		kind: areaKind(d[1]),
		size: size,
	}
}

func (op *OpArea) Hit(pos f32.Point) HitResult {
func (op *AreaOp) Hit(pos f32.Point) HitResult {
	res := HitOpaque
	if op.Transparent {
		res = HitTransparent


@@ 144,7 144,7 @@ func (op *OpArea) Hit(pos f32.Point) HitResult {
	}
}

func (h OpHandler) Add(o *ui.Ops) {
func (h HandlerOp) Add(o *ui.Ops) {
	data := make([]byte, ops.TypePointerHandlerLen)
	data[0] = byte(ops.TypePointerHandler)
	if h.Grab {


@@ 153,11 153,11 @@ func (h OpHandler) Add(o *ui.Ops) {
	o.Write(data, h.Key)
}

func (h *OpHandler) Decode(d []byte, refs []interface{}) {
func (h *HandlerOp) Decode(d []byte, refs []interface{}) {
	if ops.OpType(d[0]) != ops.TypePointerHandler {
		panic("invalid op")
	}
	*h = OpHandler{
	*h = HandlerOp{
		Grab: d[1] != 0,
		Key:  refs[0].(Key),
	}

M ui/text/editor.go => ui/text/editor.go +7 -7
@@ 180,7 180,7 @@ func (e *Editor) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens {
		Min: image.Point{X: 0, Y: 0},
		Max: image.Point{X: e.viewSize.X, Y: e.viewSize.Y},
	}
	key.OpHandler{Key: e, Focus: e.requestFocus}.Add(ops)
	key.HandlerOp{Key: e, Focus: e.requestFocus}.Add(ops)
	e.requestFocus = false
	e.it = lineIterator{
		Lines:     lines,


@@ 194,11 194,11 @@ func (e *Editor) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens {
		if !ok {
			break
		}
		ui.OpPush{}.Add(ops)
		ui.OpTransform{Transform: ui.Offset(lineOff)}.Add(ops)
		ui.PushOp{}.Add(ops)
		ui.TransformOp{Transform: ui.Offset(lineOff)}.Add(ops)
		e.Face.Path(str).Add(ops)
		draw.OpDraw{Rect: toRectF(clip).Sub(lineOff)}.Add(ops)
		ui.OpPop{}.Add(ops)
		draw.DrawOp{Rect: toRectF(clip).Sub(lineOff)}.Add(ops)
		ui.PopOp{}.Add(ops)
	}
	if e.focused {
		now := e.Config.Now


@@ 221,11 221,11 @@ func (e *Editor) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens {
			})
			carRect = clip.Intersect(carRect)
			if !carRect.Empty() {
				draw.OpDraw{Rect: toRectF(carRect)}.Add(ops)
				draw.DrawOp{Rect: toRectF(carRect)}.Add(ops)
			}
		}
		if blinking {
			redraw := ui.OpRedraw{At: nextBlink}
			redraw := ui.InvalidateOp{At: nextBlink}
			redraw.Add(ops)
		}
	}

M ui/text/label.go => ui/text/label.go +4 -4
@@ 101,11 101,11 @@ func (l Label) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens {
			break
		}
		lclip := toRectF(clip).Sub(off)
		ui.OpPush{}.Add(ops)
		ui.OpTransform{Transform: ui.Offset(off)}.Add(ops)
		ui.PushOp{}.Add(ops)
		ui.TransformOp{Transform: ui.Offset(off)}.Add(ops)
		l.Face.Path(str).Add(ops)
		draw.OpDraw{Rect: lclip}.Add(ops)
		ui.OpPop{}.Add(ops)
		draw.DrawOp{Rect: lclip}.Add(ops)
		ui.PopOp{}.Add(ops)
	}
	return dims
}

M ui/text/measure.go => ui/text/measure.go +1 -1
@@ 35,7 35,7 @@ type Layout struct {

type Face interface {
	Layout(str string, singleLine bool, maxWidth int) *Layout
	Path(str String) ui.OpBlock
	Path(str String) ui.BlockOp
}

type Alignment uint8

M ui/ui.go => ui/ui.go +16 -16
@@ 46,18 46,18 @@ func (c *Config) Val(v Value) float32 {
	}
}

// OpLayer represents a semantic layer of UI.
type OpLayer struct {
// LayerOp represents a semantic layer of UI.
type LayerOp struct {
}

// OpRedraw requests a redraw at the given time. Use
// InvalidateOp requests a redraw at the given time. Use
// the zero value to request an immediate redraw.
type OpRedraw struct {
type InvalidateOp struct {
	At time.Time
}

// OpTransform transforms an op.
type OpTransform struct {
// TransformOp transforms an op.
type TransformOp struct {
	Transform Transform
}



@@ 66,9 66,9 @@ type Transform struct {
	offset f32.Point
}

func (r OpRedraw) Add(o *Ops) {
func (r InvalidateOp) Add(o *Ops) {
	data := make([]byte, ops.TypeRedrawLen)
	data[0] = byte(ops.TypeRedraw)
	data[0] = byte(ops.TypeInvalidate)
	bo := binary.LittleEndian
	// UnixNano cannot represent the zero time.
	if t := r.At; !t.IsZero() {


@@ 80,9 80,9 @@ func (r OpRedraw) Add(o *Ops) {
	o.Write(data)
}

func (r *OpRedraw) Decode(d []byte) {
func (r *InvalidateOp) Decode(d []byte) {
	bo := binary.LittleEndian
	if ops.OpType(d[0]) != ops.TypeRedraw {
	if ops.OpType(d[0]) != ops.TypeInvalidate {
		panic("invalid op")
	}
	if nanos := bo.Uint64(d[1:]); nanos > 0 {


@@ 104,7 104,7 @@ func (t Transform) Mul(t2 Transform) Transform {
	}
}

func (t OpTransform) Add(o *Ops) {
func (t TransformOp) Add(o *Ops) {
	data := make([]byte, ops.TypeTransformLen)
	data[0] = byte(ops.TypeTransform)
	bo := binary.LittleEndian


@@ 113,12 113,12 @@ func (t OpTransform) Add(o *Ops) {
	o.Write(data)
}

func (t *OpTransform) Decode(d []byte) {
func (t *TransformOp) Decode(d []byte) {
	bo := binary.LittleEndian
	if ops.OpType(d[0]) != ops.TypeTransform {
		panic("invalid op")
	}
	*t = OpTransform{
	*t = TransformOp{
		Transform: Offset(f32.Point{
			X: math.Float32frombits(bo.Uint32(d[1:])),
			Y: math.Float32frombits(bo.Uint32(d[5:])),


@@ 126,17 126,17 @@ func (t *OpTransform) Decode(d []byte) {
	}
}

func (l OpLayer) Add(o *Ops) {
func (l LayerOp) Add(o *Ops) {
	data := make([]byte, ops.TypeLayerLen)
	data[0] = byte(ops.TypeLayer)
	o.Write(data)
}

func (l *OpLayer) Decode(d []byte) {
func (l *LayerOp) Decode(d []byte) {
	if ops.OpType(d[0]) != ops.TypeLayer {
		panic("invalid op")
	}
	*l = OpLayer{}
	*l = LayerOp{}
}

func Offset(o f32.Point) Transform {

M ui/widget/image.go => ui/widget/image.go +2 -2
@@ 27,7 27,7 @@ func (im Image) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens {
	dr := f32.Rectangle{
		Max: f32.Point{X: float32(d.X), Y: float32(d.Y)},
	}
	draw.OpImage{Img: im.Src, Rect: im.Rect}.Add(ops)
	draw.OpDraw{Rect: dr}.Add(ops)
	draw.ImageOp{Img: im.Src, Rect: im.Rect}.Add(ops)
	draw.DrawOp{Rect: dr}.Add(ops)
	return layout.Dimens{Size: d, Baseline: d.Y}
}