From 12a0ad70382c9a772adc9078de4f9c813559f82e Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Thu, 19 Oct 2023 18:10:49 -0500 Subject: [PATCH] io/key: [API] add InputHintOp for specifying the input hint for a tag We're about to replace key.InputOp with a filter; this change separates the input hint into its own operation. Signed-off-by: Elias Naur --- internal/ops/ops.go | 7 ++++++- io/input/key.go | 24 +++++++++++++++--------- io/input/router.go | 7 ++++++- io/key/key.go | 16 ++++++++++++++-- widget/editor.go | 3 ++- 5 files changed, 43 insertions(+), 14 deletions(-) diff --git a/internal/ops/ops.go b/internal/ops/ops.go index d7250f69..3fa6081d 100644 --- a/internal/ops/ops.go +++ b/internal/ops/ops.go @@ -64,6 +64,7 @@ const ( TypePopPass TypeInput TypeKeyInput + TypeKeyInputHint TypeSave TypeLoad TypeAux @@ -139,7 +140,8 @@ const ( TypePassLen = 1 TypePopPassLen = 1 TypeInputLen = 1 - TypeKeyInputLen = 1 + 1 + TypeKeyInputLen = 1 + TypeKeyInputHintLen = 1 + 1 TypeSaveLen = 1 + 4 TypeLoadLen = 1 + 4 TypeAuxLen = 1 @@ -414,6 +416,7 @@ var opProps = [0x100]opProp{ TypePopPass: {Size: TypePopPassLen, NumRefs: 0}, TypeInput: {Size: TypeInputLen, NumRefs: 1}, TypeKeyInput: {Size: TypeKeyInputLen, NumRefs: 2}, + TypeKeyInputHint: {Size: TypeKeyInputHintLen, NumRefs: 1}, TypeSave: {Size: TypeSaveLen, NumRefs: 0}, TypeLoad: {Size: TypeLoadLen, NumRefs: 0}, TypeAux: {Size: TypeAuxLen, NumRefs: 0}, @@ -477,6 +480,8 @@ func (t OpType) String() string { return "Input" case TypeKeyInput: return "KeyInput" + case TypeKeyInputHint: + return "KeyInputHint" case TypeSave: return "Save" case TypeLoad: diff --git a/io/input/key.go b/io/input/key.go index 5999652e..8f248188 100644 --- a/io/input/key.go +++ b/io/input/key.go @@ -58,6 +58,11 @@ const ( TextInputOpen ) +func (q *keyQueue) inputHint(op key.InputHintOp) { + h := q.handlerFor(op.Tag) + h.hint = op.Hint +} + // InputState returns the last text input state as // determined in Frame. func (q *keyQueue) InputState() TextInputState { @@ -66,7 +71,8 @@ func (q *keyQueue) InputState() TextInputState { return state } -// InputHint returns the input mode from the most recent key.InputOp. +// InputHint returns the input hint from the focused handler and whether it was +// changed since the last call. func (q *keyQueue) InputHint() (key.InputHint, bool) { if q.focus == nil { return q.hint, false @@ -87,6 +93,7 @@ func (q *keyQueue) Reset() { for _, h := range q.handlers { h.visible, h.new = false, false h.order = -1 + h.hint = key.HintAny } q.order = q.order[:0] q.dirOrder = q.dirOrder[:0] @@ -277,24 +284,23 @@ func (q *keyQueue) softKeyboard(show bool) { } } -func (q *keyQueue) handlerFor(tag event.Tag, area int, bounds image.Rectangle) *keyHandler { +func (q *keyQueue) handlerFor(tag event.Tag) *keyHandler { h, ok := q.handlers[tag] if !ok { h = &keyHandler{new: true, order: -1} q.handlers[tag] = h } - if h.order == -1 { - h.order = len(q.order) - q.order = append(q.order, tag) - q.dirOrder = append(q.dirOrder, dirFocusEntry{tag: tag, area: area, bounds: bounds}) - } return h } func (q *keyQueue) inputOp(op key.InputOp, t f32.Affine2D, area int, bounds image.Rectangle) { - h := q.handlerFor(op.Tag, area, bounds) + h := q.handlerFor(op.Tag) + if h.order == -1 { + h.order = len(q.order) + q.order = append(q.order, op.Tag) + q.dirOrder = append(q.dirOrder, dirFocusEntry{tag: op.Tag, area: area, bounds: bounds}) + } h.visible = true - h.hint = op.Hint h.filter = op.Keys h.trans = t } diff --git a/io/input/router.go b/io/input/router.go index 3a405f2e..92515e62 100644 --- a/io/input/router.go +++ b/io/input/router.go @@ -494,13 +494,18 @@ func (q *Router) collect() { filter := key.Set(*encOp.Refs[1].(*string)) op := key.InputOp{ Tag: encOp.Refs[0].(event.Tag), - Hint: key.InputHint(encOp.Data[1]), Keys: filter, } a := pc.currentArea() b := pc.currentAreaBounds() pc.keyInputOp(op) kq.inputOp(op, t, a, b) + case ops.TypeKeyInputHint: + op := key.InputHintOp{ + Tag: encOp.Refs[0].(event.Tag), + Hint: key.InputHint(encOp.Data[1]), + } + kq.inputHint(op) // Semantic ops. case ops.TypeSemanticLabel: diff --git a/io/key/key.go b/io/key/key.go index b71a2531..5512a485 100644 --- a/io/key/key.go +++ b/io/key/key.go @@ -23,8 +23,6 @@ import ( // focused key handler. type InputOp struct { Tag event.Tag - // Hint describes the type of text expected by Tag. - Hint InputHint // Keys is the set of keys Tag can handle. That is, Tag will only // receive an Event if its key and modifiers are accepted by Keys.Contains. // As a special case, the topmost (first added) InputOp handler receives all @@ -32,6 +30,12 @@ type InputOp struct { Keys Set } +// InputHintOp describes the type of text expected by a tag. +type InputHintOp struct { + Tag event.Tag + Hint InputHint +} + // SoftKeyboardCmd shows or hides the on-screen keyboard, if available. type SoftKeyboardCmd struct { Show bool @@ -331,6 +335,14 @@ func (h InputOp) Add(o *op.Ops) { } data := ops.Write2String(&o.Internal, ops.TypeKeyInputLen, h.Tag, string(h.Keys)) data[0] = byte(ops.TypeKeyInput) +} + +func (h InputHintOp) Add(o *op.Ops) { + if h.Tag == nil { + panic("Tag must be non-nil") + } + data := ops.Write1(&o.Internal, ops.TypeKeyInputHintLen, h.Tag) + data[0] = byte(ops.TypeKeyInputHint) data[1] = byte(h.Hint) } diff --git a/widget/editor.go b/widget/editor.go index 32328fe9..b4cfedc8 100644 --- a/widget/editor.go +++ b/widget/editor.go @@ -651,7 +651,8 @@ func (e *Editor) layout(gtx layout.Context, textMaterial, selectMaterial op.Call keys = keyFilterAllArrows } } - key.InputOp{Tag: &e.eventKey, Hint: e.InputHint, Keys: keys}.Add(gtx.Ops) + key.InputOp{Tag: &e.eventKey, Keys: keys}.Add(gtx.Ops) + key.InputHintOp{Tag: &e.eventKey, Hint: e.InputHint}.Add(gtx.Ops) e.scroller.Add(gtx.Ops)