mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
app,widget,io: implement IME positioning
This change implements reporting of the caret position from Editor, as well as Windows, macOS, Android support. As a result, the IME composition window on Windows and macOS is now positioned correctly. References: https://todo.sr.ht/~eliasnaur/gio/246 Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
@@ -12,8 +12,10 @@ package key
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"gioui.org/f32"
|
||||
"gioui.org/internal/ops"
|
||||
"gioui.org/io/event"
|
||||
"gioui.org/op"
|
||||
@@ -45,6 +47,7 @@ type FocusOp struct {
|
||||
type SelectionOp struct {
|
||||
Tag event.Tag
|
||||
Range
|
||||
Caret
|
||||
}
|
||||
|
||||
// SnippetOp updates the content snippet for an input handler.
|
||||
@@ -67,6 +70,16 @@ type Snippet struct {
|
||||
Text string
|
||||
}
|
||||
|
||||
// Caret represents the position of a caret.
|
||||
type Caret struct {
|
||||
// Pos is the intersection point of the caret and its baseline.
|
||||
Pos f32.Point
|
||||
// Ascent is the length of the caret above its baseline.
|
||||
Ascent float32
|
||||
// Descent is the length of the caret below its baseline.
|
||||
Descent float32
|
||||
}
|
||||
|
||||
// SelectionEvent is generated when an input method changes the selection.
|
||||
type SelectionEvent Range
|
||||
|
||||
@@ -229,6 +242,10 @@ func (s SelectionOp) Add(o *op.Ops) {
|
||||
bo := binary.LittleEndian
|
||||
bo.PutUint32(data[1:], uint32(s.Start))
|
||||
bo.PutUint32(data[5:], uint32(s.End))
|
||||
bo.PutUint32(data[9:], math.Float32bits(s.Pos.X))
|
||||
bo.PutUint32(data[13:], math.Float32bits(s.Pos.Y))
|
||||
bo.PutUint32(data[17:], math.Float32bits(s.Ascent))
|
||||
bo.PutUint32(data[21:], math.Float32bits(s.Descent))
|
||||
}
|
||||
|
||||
func (EditEvent) ImplementsEvent() {}
|
||||
|
||||
+11
-4
@@ -3,14 +3,19 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"gioui.org/f32"
|
||||
"gioui.org/io/event"
|
||||
"gioui.org/io/key"
|
||||
)
|
||||
|
||||
// EditorState represents the state of an editor needed by input handlers.
|
||||
type EditorState struct {
|
||||
Selection key.Range
|
||||
Snippet key.Snippet
|
||||
Selection struct {
|
||||
Transform f32.Affine2D
|
||||
key.Range
|
||||
key.Caret
|
||||
}
|
||||
Snippet key.Snippet
|
||||
}
|
||||
|
||||
type TextInputState uint8
|
||||
@@ -143,9 +148,11 @@ func (k *keyCollector) inputOp(op key.InputOp) {
|
||||
h.hint = op.Hint
|
||||
}
|
||||
|
||||
func (k *keyCollector) selectionOp(op key.SelectionOp) {
|
||||
func (k *keyCollector) selectionOp(t f32.Affine2D, op key.SelectionOp) {
|
||||
if op.Tag == k.q.focus {
|
||||
k.q.content.Selection = op.Range
|
||||
k.q.content.Selection.Range = op.Range
|
||||
k.q.content.Selection.Caret = op.Caret
|
||||
k.q.content.Selection.Transform = t
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-1
@@ -14,6 +14,7 @@ import (
|
||||
"encoding/binary"
|
||||
"image"
|
||||
"io"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -335,8 +336,16 @@ func (q *Router) collect() {
|
||||
Start: int(int32(bo.Uint32(encOp.Data[1:]))),
|
||||
End: int(int32(bo.Uint32(encOp.Data[5:]))),
|
||||
},
|
||||
Caret: key.Caret{
|
||||
Pos: f32.Point{
|
||||
X: math.Float32frombits(bo.Uint32(encOp.Data[9:])),
|
||||
Y: math.Float32frombits(bo.Uint32(encOp.Data[13:])),
|
||||
},
|
||||
Ascent: math.Float32frombits(bo.Uint32(encOp.Data[17:])),
|
||||
Descent: math.Float32frombits(bo.Uint32(encOp.Data[21:])),
|
||||
},
|
||||
}
|
||||
kc.selectionOp(op)
|
||||
kc.selectionOp(t, op)
|
||||
|
||||
// Semantic ops.
|
||||
case ops.TypeSemanticLabel:
|
||||
|
||||
Reference in New Issue
Block a user