mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-05 09:25:38 +00:00
io/input: merge per-handler state
We're about to need per-handler state related to neither pointer nor key input. This change merges the pointer and key handler state into one state struct, tracked in the Router. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+65
-81
@@ -26,7 +26,6 @@ type TextInputState uint8
|
||||
type keyQueue struct {
|
||||
order []event.Tag
|
||||
dirOrder []dirFocusEntry
|
||||
handlers map[event.Tag]*keyHandler
|
||||
hint key.InputHint
|
||||
}
|
||||
|
||||
@@ -43,14 +42,21 @@ type keyHandler struct {
|
||||
visible bool
|
||||
// reset tracks whether the handler has seen a
|
||||
// focus reset.
|
||||
reset bool
|
||||
reset bool
|
||||
hint key.InputHint
|
||||
orderPlusOne int
|
||||
dirOrder int
|
||||
// filter are the key filters accumulated in the previous frame,
|
||||
// used for routing events in the current frame.
|
||||
filter keyFilter
|
||||
// nextFilter is the filter accumulator for the current frame.
|
||||
nextFilter keyFilter
|
||||
trans f32.Affine2D
|
||||
}
|
||||
|
||||
type keyFilter struct {
|
||||
focusable bool
|
||||
active bool
|
||||
hint key.InputHint
|
||||
order int
|
||||
dirOrder int
|
||||
filters []key.Filter
|
||||
trans f32.Affine2D
|
||||
}
|
||||
|
||||
type dirFocusEntry struct {
|
||||
@@ -66,9 +72,8 @@ const (
|
||||
TextInputOpen
|
||||
)
|
||||
|
||||
func (q *keyQueue) inputHint(op key.InputHintOp) {
|
||||
h := q.handlerFor(op.Tag)
|
||||
h.hint = op.Hint
|
||||
func (k *keyHandler) inputHint(hint key.InputHint) {
|
||||
k.hint = hint
|
||||
}
|
||||
|
||||
// InputState returns the input state and returns a state
|
||||
@@ -81,52 +86,46 @@ func (s keyState) InputState() (keyState, TextInputState) {
|
||||
|
||||
// InputHint returns the input hint from the focused handler and whether it was
|
||||
// changed since the last call.
|
||||
func (q *keyQueue) InputHint(state keyState) (key.InputHint, bool) {
|
||||
focused, ok := q.handlers[state.focus]
|
||||
func (q *keyQueue) InputHint(handlers map[event.Tag]*handler, state keyState) (key.InputHint, bool) {
|
||||
focused, ok := handlers[state.focus]
|
||||
if !ok {
|
||||
return q.hint, false
|
||||
}
|
||||
old := q.hint
|
||||
q.hint = focused.hint
|
||||
q.hint = focused.key.hint
|
||||
return q.hint, old != q.hint
|
||||
}
|
||||
|
||||
func (k *keyHandler) Reset() {
|
||||
k.filter, k.nextFilter = k.nextFilter, k.filter
|
||||
k.nextFilter = keyFilter{}
|
||||
k.visible = false
|
||||
k.orderPlusOne = 0
|
||||
k.hint = key.HintAny
|
||||
}
|
||||
|
||||
func (q *keyQueue) Reset() {
|
||||
for _, h := range q.handlers {
|
||||
h.order = -1
|
||||
h.hint = key.HintAny
|
||||
}
|
||||
q.order = q.order[:0]
|
||||
q.dirOrder = q.dirOrder[:0]
|
||||
}
|
||||
|
||||
func (q *keyQueue) ResetEvent(k event.Tag) (event.Event, bool) {
|
||||
h, ok := q.handlers[k]
|
||||
if !ok || h.reset {
|
||||
func (k *keyHandler) ResetEvent() (event.Event, bool) {
|
||||
if k.reset {
|
||||
return nil, false
|
||||
}
|
||||
h.reset = true
|
||||
k.reset = true
|
||||
return key.FocusEvent{Focus: false}, true
|
||||
}
|
||||
|
||||
func (q *keyQueue) Frame(state keyState) keyState {
|
||||
for k, h := range q.handlers {
|
||||
if !h.visible || !h.focusable {
|
||||
if state.focus == k {
|
||||
// Remove focus from the handler that is no longer focusable.
|
||||
state.focus = nil
|
||||
state.state = TextInputClose
|
||||
}
|
||||
if !h.visible && !h.focusable {
|
||||
delete(q.handlers, k)
|
||||
continue
|
||||
}
|
||||
func (q *keyQueue) Frame(handlers map[event.Tag]*handler, state keyState) keyState {
|
||||
if state.focus != nil {
|
||||
if h, ok := handlers[state.focus]; !ok || !h.key.isFocusable() {
|
||||
// Remove focus from the handler that is no longer focusable.
|
||||
state.focus = nil
|
||||
state.state = TextInputClose
|
||||
}
|
||||
h.visible = false
|
||||
h.focusable = false
|
||||
h.active = false
|
||||
}
|
||||
q.updateFocusLayout()
|
||||
q.updateFocusLayout(handlers)
|
||||
return state
|
||||
}
|
||||
|
||||
@@ -137,7 +136,7 @@ func (q *keyQueue) Frame(state keyState) keyState {
|
||||
// containing it. Then, extend the handler bounds to a horizontal beam
|
||||
// and add to the row every handler whose center intersect it. Repeat
|
||||
// until no handlers remain.
|
||||
func (q *keyQueue) updateFocusLayout() {
|
||||
func (q *keyQueue) updateFocusLayout(handlers map[event.Tag]*handler) {
|
||||
order := q.dirOrder
|
||||
// Sort by ascending y position.
|
||||
sort.SliceStable(order, func(i, j int) bool {
|
||||
@@ -165,18 +164,18 @@ func (q *keyQueue) updateFocusLayout() {
|
||||
row++
|
||||
}
|
||||
for i, o := range q.dirOrder {
|
||||
q.handlers[o.tag].dirOrder = i
|
||||
handlers[o.tag].key.dirOrder = i
|
||||
}
|
||||
}
|
||||
|
||||
// MoveFocus attempts to move the focus in the direction of dir.
|
||||
func (q *keyQueue) MoveFocus(state keyState, dir key.FocusDirection) (keyState, []taggedEvent) {
|
||||
func (q *keyQueue) MoveFocus(handlers map[event.Tag]*handler, state keyState, dir key.FocusDirection) (keyState, []taggedEvent) {
|
||||
if len(q.dirOrder) == 0 {
|
||||
return state, nil
|
||||
}
|
||||
order := 0
|
||||
if state.focus != nil {
|
||||
order = q.handlers[state.focus].dirOrder
|
||||
order = handlers[state.focus].key.dirOrder
|
||||
}
|
||||
focus := q.dirOrder[order]
|
||||
switch dir {
|
||||
@@ -189,7 +188,7 @@ func (q *keyQueue) MoveFocus(state keyState, dir key.FocusDirection) (keyState,
|
||||
order = -1
|
||||
}
|
||||
if state.focus != nil {
|
||||
order = q.handlers[state.focus].order
|
||||
order = handlers[state.focus].key.orderPlusOne - 1
|
||||
if dir == key.FocusForward {
|
||||
order++
|
||||
} else {
|
||||
@@ -197,7 +196,7 @@ func (q *keyQueue) MoveFocus(state keyState, dir key.FocusDirection) (keyState,
|
||||
}
|
||||
}
|
||||
order = (order + len(q.order)) % len(q.order)
|
||||
return q.Focus(state, q.order[order])
|
||||
return q.Focus(handlers, state, q.order[order])
|
||||
case key.FocusRight, key.FocusLeft:
|
||||
next := order
|
||||
if state.focus != nil {
|
||||
@@ -209,7 +208,7 @@ func (q *keyQueue) MoveFocus(state keyState, dir key.FocusDirection) (keyState,
|
||||
if 0 <= next && next < len(q.dirOrder) {
|
||||
newFocus := q.dirOrder[next]
|
||||
if newFocus.row == focus.row {
|
||||
return q.Focus(state, newFocus.tag)
|
||||
return q.Focus(handlers, state, newFocus.tag)
|
||||
}
|
||||
}
|
||||
case key.FocusUp, key.FocusDown:
|
||||
@@ -245,24 +244,24 @@ func (q *keyQueue) MoveFocus(state keyState, dir key.FocusDirection) (keyState,
|
||||
order += delta
|
||||
}
|
||||
if closest != nil {
|
||||
return q.Focus(state, closest)
|
||||
return q.Focus(handlers, state, closest)
|
||||
}
|
||||
}
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func (q *keyQueue) BoundsFor(t event.Tag) image.Rectangle {
|
||||
order := q.handlers[t].dirOrder
|
||||
func (q *keyQueue) BoundsFor(k *keyHandler) image.Rectangle {
|
||||
order := k.dirOrder
|
||||
return q.dirOrder[order].bounds
|
||||
}
|
||||
|
||||
func (q *keyQueue) AreaFor(t event.Tag) int {
|
||||
order := q.handlers[t].dirOrder
|
||||
func (q *keyQueue) AreaFor(k *keyHandler) int {
|
||||
order := k.dirOrder
|
||||
return q.dirOrder[order].area
|
||||
}
|
||||
|
||||
func (q *keyQueue) Accepts(t event.Tag, e key.Event) bool {
|
||||
for _, f := range q.handlers[t].filters {
|
||||
func (k *keyHandler) Accepts(e key.Event) bool {
|
||||
for _, f := range k.filter.filters {
|
||||
if keyFilterMatch(f, e) {
|
||||
return true
|
||||
}
|
||||
@@ -283,9 +282,9 @@ func keyFilterMatch(f key.Filter, e key.Event) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (q *keyQueue) Focus(state keyState, focus event.Tag) (keyState, []taggedEvent) {
|
||||
func (q *keyQueue) Focus(handlers map[event.Tag]*handler, state keyState, focus event.Tag) (keyState, []taggedEvent) {
|
||||
if focus != nil {
|
||||
if _, exists := q.handlers[focus]; !exists {
|
||||
if h, exists := handlers[focus]; !exists || !h.key.isFocusable() {
|
||||
focus = nil
|
||||
}
|
||||
}
|
||||
@@ -316,41 +315,26 @@ func (s keyState) softKeyboard(show bool) keyState {
|
||||
return s
|
||||
}
|
||||
|
||||
func (q *keyQueue) filter(tag event.Tag, f key.Filter) {
|
||||
h := q.handlerFor(tag)
|
||||
if !h.active {
|
||||
h.active = true
|
||||
h.filters = h.filters[:0]
|
||||
}
|
||||
h.filters = append(h.filters, f)
|
||||
func (k *keyHandler) Filter(f key.Filter) {
|
||||
k.nextFilter.filters = append(k.nextFilter.filters, f)
|
||||
}
|
||||
|
||||
func (q *keyQueue) focusable(tag event.Tag) {
|
||||
h := q.handlerFor(tag)
|
||||
h.focusable = true
|
||||
func (k *keyHandler) isFocusable() bool {
|
||||
return k.filter.focusable && k.visible
|
||||
}
|
||||
|
||||
func (q *keyQueue) handlerFor(tag event.Tag) *keyHandler {
|
||||
h, ok := q.handlers[tag]
|
||||
if !ok {
|
||||
h = &keyHandler{order: -1}
|
||||
if q.handlers == nil {
|
||||
q.handlers = make(map[event.Tag]*keyHandler)
|
||||
}
|
||||
q.handlers[tag] = h
|
||||
}
|
||||
return h
|
||||
func (k *keyHandler) Focusable() {
|
||||
k.nextFilter.focusable = true
|
||||
}
|
||||
|
||||
func (q *keyQueue) inputOp(tag event.Tag, t f32.Affine2D, area int, bounds image.Rectangle) {
|
||||
h := q.handlerFor(tag)
|
||||
if h.order == -1 {
|
||||
h.order = len(q.order)
|
||||
func (q *keyQueue) inputOp(tag event.Tag, state *keyHandler, t f32.Affine2D, area int, bounds image.Rectangle) {
|
||||
state.visible = true
|
||||
if state.orderPlusOne == 0 {
|
||||
state.orderPlusOne = len(q.order) + 1
|
||||
q.order = append(q.order, tag)
|
||||
q.dirOrder = append(q.dirOrder, dirFocusEntry{tag: tag, area: area, bounds: bounds})
|
||||
}
|
||||
h.visible = true
|
||||
h.trans = t
|
||||
state.trans = t
|
||||
}
|
||||
|
||||
func (q *keyQueue) setSelection(state keyState, req key.SelectionCmd) keyState {
|
||||
@@ -362,10 +346,10 @@ func (q *keyQueue) setSelection(state keyState, req key.SelectionCmd) keyState {
|
||||
return state
|
||||
}
|
||||
|
||||
func (q *keyQueue) editorState(state keyState) EditorState {
|
||||
func (q *keyQueue) editorState(handlers map[event.Tag]*handler, state keyState) EditorState {
|
||||
s := state.content
|
||||
if f := state.focus; f != nil {
|
||||
s.Selection.Transform = q.handlers[f].trans
|
||||
s.Selection.Transform = handlers[f].key.trans
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user