~eliasnaur/gio

7c5bcd3db8204eb8809ae92f9e625a9f6cb7b6fc — pierre 7 months ago 675e86b
io/pointer: added CursorNameOp

The cursor can now be customized for a given area.

Signed-off-by: pierre <pierre.curto@gmail.com>
M app/window.go => app/window.go +6 -1
@@ 48,7 48,8 @@ type Window struct {
	nextFrame    time.Time
	delayedDraw  *time.Timer

	queue queue
	queue  queue
	cursor pointer.CursorName

	callbacks callbacks
}


@@ 414,6 415,10 @@ func (w *Window) run(opts *window.Options) {
					w.setNextFrame(time.Time{})
					w.updateAnimation()
				}
				if c := w.queue.q.Cursor(); c != w.cursor {
					w.cursor = c
					w.SetCursorName(c)
				}
				w.out <- e
			}
			w.ack <- struct{}{}

M internal/opconst/ops.go => internal/opconst/ops.go +4 -1
@@ 30,6 30,7 @@ const (
	TypeAux
	TypeClip
	TypeProfile
	TypeCursor
)

const (


@@ 55,6 56,7 @@ const (
	TypeAuxLen             = 1
	TypeClipLen            = 1 + 4*4 + 4 + 2 + 4
	TypeProfileLen         = 1
	TypeCursorLen          = 1 + 1
)

func (t OpType) Size() int {


@@ 81,12 83,13 @@ func (t OpType) Size() int {
		TypeAuxLen,
		TypeClipLen,
		TypeProfileLen,
		TypeCursorLen,
	}[t-firstOpIndex]
}

func (t OpType) NumRefs() int {
	switch t {
	case TypeKeyInput, TypePointerInput, TypeProfile, TypeCall, TypeClipboardRead, TypeClipboardWrite:
	case TypeKeyInput, TypePointerInput, TypeProfile, TypeCall, TypeClipboardRead, TypeClipboardWrite, TypeCursor:
		return 1
	case TypeImage:
		return 2

M io/pointer/pointer.go => io/pointer/pointer.go +10 -0
@@ 49,6 49,11 @@ type AreaOp struct {
	rect image.Rectangle
}

// CursorNameOp sets the cursor for the current area.
type CursorNameOp struct {
	Name CursorName
}

// InputOp declares an input handler ready for pointer
// events.
type InputOp struct {


@@ 178,6 183,11 @@ func (op AreaOp) Add(o *op.Ops) {
	bo.PutUint32(data[14:], uint32(op.rect.Max.Y))
}

func (op CursorNameOp) Add(o *op.Ops) {
	data := o.Write1(opconst.TypeCursorLen, op.Name)
	data[0] = byte(opconst.TypeCursor)
}

func (h InputOp) Add(o *op.Ops) {
	data := o.Write1(opconst.TypePointerInputLen, h.Tag)
	data[0] = byte(opconst.TypePointerInput)

M io/router/pointer.go => io/router/pointer.go +28 -0
@@ 17,6 17,8 @@ import (
type pointerQueue struct {
	hitTree  []hitNode
	areas    []areaNode
	cursors  []cursorNode
	cursor   pointer.CursorName
	handlers map[event.Tag]*pointerHandler
	pointers []pointerInfo
	reader   ops.Reader


@@ 34,6 36,11 @@ type hitNode struct {
	tag event.Tag
}

type cursorNode struct {
	name pointer.CursorName
	area int
}

type pointerInfo struct {
	id       pointer.ID
	pressed  bool


@@ 114,6 121,11 @@ func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents, t f
			h.area = area
			h.wantsGrab = h.wantsGrab || op.Grab
			h.types = h.types | op.Types
		case opconst.TypeCursor:
			q.cursors = append(q.cursors, cursorNode{
				name: encOp.Refs[0].(pointer.CursorName),
				area: len(q.areas) - 1,
			})
		}
	}
}


@@ 177,6 189,7 @@ func (q *pointerQueue) Frame(root *op.Ops, events *handlerEvents) {
	}
	q.hitTree = q.hitTree[:0]
	q.areas = q.areas[:0]
	q.cursors = q.cursors[:0]
	q.reader.Reset(root)
	q.collectHandlers(&q.reader, events, f32.Affine2D{}, -1, -1, false)
	for k, h := range q.handlers {


@@ 314,6 327,7 @@ func (q *pointerQueue) deliverEnterLeaveEvents(p *pointerInfo, hits []event.Tag,

		if e.Type&h.types == e.Type {
			events.Add(k, e)
			q.cursor = pointer.CursorDefault
		}
	}
	// Deliver Enter events.


@@ 327,11 341,25 @@ func (q *pointerQueue) deliverEnterLeaveEvents(p *pointerInfo, hits []event.Tag,

		if e.Type&h.types == e.Type {
			events.Add(k, e)
			q.hitCursor(h.area)
		}
	}
	p.entered = append(p.entered[:0], hits...)
}

func (q *pointerQueue) hitCursor(want int) {
	for _, c := range q.cursors {
		idx := c.area
		for idx != -1 {
			if idx == want {
				q.cursor = c.name
				return
			}
			idx = q.areas[idx].next
		}
	}
}

func searchTag(tags []event.Tag, tag event.Tag) (int, bool) {
	for i, t := range tags {
		if t == tag {

M io/router/router.go => io/router/router.go +5 -0
@@ 115,6 115,11 @@ func (q *Router) ReadClipboard() bool {
	return q.cqueue.ReadClipboard()
}

// Cursor returns the last cursor set.
func (q *Router) Cursor() pointer.CursorName {
	return q.pqueue.cursor
}

func (q *Router) collect() {
	for encOp, ok := q.reader.Decode(); ok; encOp, ok = q.reader.Decode() {
		switch opconst.OpType(encOp.Data[0]) {

M widget/editor.go => widget/editor.go +4 -1
@@ 379,7 379,10 @@ func (e *Editor) Layout(gtx layout.Context, sh text.Shaper, font text.Font, size
	}
	e.makeValid()

	return e.layout(gtx)
	dims := e.layout(gtx)
	pointer.Rect(image.Rectangle{Max: dims.Size}).Add(gtx.Ops)
	pointer.CursorNameOp{Name: pointer.CursorText}.Add(gtx.Ops)
	return dims
}

func (e *Editor) layout(gtx layout.Context) layout.Dimensions {