~eliasnaur/gio

ref: 9f58ed0fea4e7b1f8f69846d8f72bec19390d7ed gio/ui/key/queue.go -rw-r--r-- 2.1 KiB
9f58ed0fElias Naur ui: add version to OpBlock to track invalidated blocks 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// SPDX-License-Identifier: Unlicense OR MIT

package key

import (
	"gioui.org/ui"
	"gioui.org/ui/internal/ops"
)

type Queue struct {
	focus    Key
	events   []Event
	handlers map[Key]bool
	reader   ui.OpsReader
}

type listenerPriority uint8

const (
	priNone listenerPriority = iota
	priDefault
	priCurrentFocus
	priNewFocus
)

func (q *Queue) Frame(root *ui.Ops) TextInputState {
	q.events = q.events[:0]
	q.reader.Reset(root)
	f, pri, hide := resolveFocus(&q.reader, q.focus)
	changed := f != nil && f != q.focus
	for k, active := range q.handlers {
		if !active || changed {
			delete(q.handlers, k)
		} else {
			q.handlers[k] = false
		}
	}
	q.focus = f
	switch {
	case pri == priNewFocus:
		return TextInputOpen
	case hide:
		return TextInputClosed
	case changed:
		return TextInputFocus
	default:
		return TextInputKeep
	}
}

func (q *Queue) Push(e Event) {
	q.events = append(q.events, e)
}

func (q *Queue) For(k Key) []Event {
	if q.handlers == nil {
		q.handlers = make(map[Key]bool)
	}
	_, exists := q.handlers[k]
	q.handlers[k] = true
	if !exists {
		if k == q.focus {
			// Prepend focus event.
			q.events = append(q.events, nil)
			copy(q.events[1:], q.events)
			q.events[0] = Focus{Focus: true}
		} else {
			return []Event{Focus{Focus: false}}
		}
	}
	if k != q.focus {
		return nil
	}
	return q.events
}

func resolveFocus(r *ui.OpsReader, focus Key) (Key, listenerPriority, bool) {
	var k Key
	var pri listenerPriority
	var hide bool
loop:
	for {
		data, refs, ok := r.Decode()
		if !ok {
			break
		}
		switch ops.OpType(data[0]) {
		case ops.TypeKeyHandler:
			var op OpHandler
			op.Decode(data, refs)
			var newPri listenerPriority
			switch {
			case op.Focus:
				newPri = priNewFocus
			case op.Key == focus:
				newPri = priCurrentFocus
			default:
				newPri = priDefault
			}
			if newPri >= pri {
				k, pri = op.Key, newPri
			}
		case ops.TypeHideInput:
			hide = true
		case ops.TypePush:
			newK, newPri, h := resolveFocus(r, focus)
			hide = hide || h
			if newPri >= pri {
				k, pri = newK, newPri
			}
		case ops.TypePop:
			break loop
		}
	}
	return k, pri, hide
}