~eliasnaur/gio

4fadf71992ffd469b297c1994d05acb2c5716409 — Elias Naur 1 year, 4 months ago f44ccec
ui/pointer: split AreaOp into RectAreaOp and EllipseAreaOp

Now that the pass through mode is moved into its own PassOp op,
it doesn't make sense to collect all area types into one exported
type.

Add RectAreaOp and EllipseAreaOp for clients; the internal
representation is still a single op. It can be changed later without
breaking clients.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
4 files changed, 80 insertions(+), 55 deletions(-)

M ui/input/pointer.go
M ui/layout/list.go
M ui/pointer/pointer.go
M ui/text/editor.go
M ui/input/pointer.go => ui/input/pointer.go +58 -2
@@ 3,6 3,9 @@
package input

import (
	"encoding/binary"
	"image"

	"gioui.org/ui"
	"gioui.org/ui/f32"
	"gioui.org/ui/internal/ops"


@@ 41,12 44,24 @@ type pointerHandler struct {
	wantsGrab bool
}

type areaOp struct {
	kind areaKind
	size image.Point
}

type areaNode struct {
	trans ui.Transform
	next  int
	area  pointer.AreaOp
	area  areaOp
}

type areaKind uint8

const (
	areaRect areaKind = iota
	areaEllipse
)

func (q *pointerQueue) collectHandlers(r *ui.OpsReader, events handlerEvents, t ui.Transform, area, node int, pass bool) {
	for {
		encOp, ok := r.Decode()


@@ 63,7 78,7 @@ func (q *pointerQueue) collectHandlers(r *ui.OpsReader, events handlerEvents, t 
			op.Decode(encOp.Data)
			pass = op.Pass
		case ops.TypeArea:
			var op pointer.AreaOp
			var op areaOp
			op.Decode(encOp.Data)
			q.areas = append(q.areas, areaNode{trans: t, next: area, area: op})
			area = len(q.areas) - 1


@@ 257,3 272,44 @@ func (q *pointerQueue) Push(e pointer.Event, events handlerEvents) {
		}
	}
}

func (op *areaOp) Decode(d []byte) {
	if ops.OpType(d[0]) != ops.TypeArea {
		panic("invalid op")
	}
	bo := binary.LittleEndian
	size := image.Point{
		X: int(bo.Uint32(d[2:])),
		Y: int(bo.Uint32(d[6:])),
	}
	*op = areaOp{
		kind: areaKind(d[1]),
		size: size,
	}
}

func (op *areaOp) Hit(pos f32.Point) bool {
	switch op.kind {
	case areaRect:
		if 0 <= pos.X && pos.X < float32(op.size.X) &&
			0 <= pos.Y && pos.Y < float32(op.size.Y) {
			return true
		} else {
			return false
		}
	case areaEllipse:
		rx := float32(op.size.X) / 2
		ry := float32(op.size.Y) / 2
		rx2 := rx * rx
		ry2 := ry * ry
		xh := pos.X - rx
		yk := pos.Y - ry
		if xh*xh*ry2+yk*yk*rx2 <= rx2*ry2 {
			return true
		} else {
			return false
		}
	default:
		panic("invalid area kind")
	}
}

M ui/layout/list.go => ui/layout/list.go +1 -1
@@ 209,7 209,7 @@ func (l *List) Layout() Dimens {
	}
	dims := axisPoint(l.Axis, mainc.Constrain(pos), maxCross)
	block := ops.End()
	pointer.AreaRect(dims).Add(ops)
	pointer.RectAreaOp{Size: dims}.Add(ops)
	l.scroll.Add(ops)
	block.Add(ops)
	return Dimens{Size: dims}

M ui/pointer/pointer.go => ui/pointer/pointer.go +20 -51
@@ 23,7 23,16 @@ type Event struct {
	Scroll    f32.Point
}

type AreaOp struct {
type RectAreaOp struct {
	Size image.Point
}

type EllipseAreaOp struct {
	Size image.Point
}

// Must match the structure in input.areaOp
type areaOp struct {
	kind areaKind
	size image.Point
}


@@ 46,6 55,7 @@ type Type uint8
type Priority uint8
type Source uint8

// Must match input.areaKind
type areaKind uint8

const (


@@ 71,21 81,21 @@ const (
	areaEllipse
)

func AreaRect(size image.Point) AreaOp {
	return AreaOp{
func (op RectAreaOp) Add(ops *ui.Ops) {
	areaOp{
		kind: areaRect,
		size: size,
	}
		size: op.Size,
	}.add(ops)
}

func AreaEllipse(size image.Point) AreaOp {
	return AreaOp{
func (op EllipseAreaOp) Add(ops *ui.Ops) {
	areaOp{
		kind: areaEllipse,
		size: size,
	}
		size: op.Size,
	}.add(ops)
}

func (op AreaOp) 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)


@@ 95,47 105,6 @@ func (op AreaOp) Add(o *ui.Ops) {
	o.Write(data)
}

func (op *AreaOp) Decode(d []byte) {
	if ops.OpType(d[0]) != ops.TypeArea {
		panic("invalid op")
	}
	bo := binary.LittleEndian
	size := image.Point{
		X: int(bo.Uint32(d[2:])),
		Y: int(bo.Uint32(d[6:])),
	}
	*op = AreaOp{
		kind: areaKind(d[1]),
		size: size,
	}
}

func (op *AreaOp) Hit(pos f32.Point) bool {
	switch op.kind {
	case areaRect:
		if 0 <= pos.X && pos.X < float32(op.size.X) &&
			0 <= pos.Y && pos.Y < float32(op.size.Y) {
			return true
		} else {
			return false
		}
	case areaEllipse:
		rx := float32(op.size.X) / 2
		ry := float32(op.size.Y) / 2
		rx2 := rx * rx
		ry2 := ry * ry
		xh := pos.X - rx
		yk := pos.Y - ry
		if xh*xh*ry2+yk*yk*rx2 <= rx2*ry2 {
			return true
		} else {
			return false
		}
	default:
		panic("invalid area kind")
	}
}

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

M ui/text/editor.go => ui/text/editor.go +1 -1
@@ 259,7 259,7 @@ func (e *Editor) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens {
	ui.PopOp{}.Add(ops)

	baseline := e.padTop + e.dims.Baseline
	pointer.AreaRect(e.viewSize).Add(ops)
	pointer.RectAreaOp{Size: e.viewSize}.Add(ops)
	e.scroller.Add(ops)
	e.clicker.Add(ops)
	return layout.Dimens{Size: e.viewSize, Baseline: baseline}