mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 15:45:38 +00:00
5966aab77e
To prepare support for cached OpBlock to refer to other Ops lists. The exposure of OpsReader is alleviated by the removal of the Refs and Data accessors for Ops. Signed-off-by: Elias Naur <mail@eliasnaur.com>
117 lines
2.1 KiB
Go
117 lines
2.1 KiB
Go
// 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, ok := r.Decode()
|
|
if !ok {
|
|
break
|
|
}
|
|
switch ops.OpType(data[0]) {
|
|
case ops.TypeKeyHandler:
|
|
var op OpHandler
|
|
op.Decode(data, r.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
|
|
}
|