mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-07 10:25:37 +00:00
io/router,app: move Tab-to-focus conversion to app.Window
This is a refactor to make it easier to add higher level logic to focus moves. A follow-up will add automatic scrolling to bring focused widgets into view. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+15
-4
@@ -498,9 +498,13 @@ func (c *callbacks) SetEditorSnippet(r key.Range) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *callbacks) MoveFocus(dir router.FocusDirection) {
|
func (c *callbacks) MoveFocus(dir router.FocusDirection) {
|
||||||
c.w.queue.q.MoveFocus(dir)
|
c.w.moveFocus(dir, c.d)
|
||||||
c.w.setNextFrame(time.Time{})
|
}
|
||||||
c.w.updateAnimation(c.d)
|
|
||||||
|
func (w *Window) moveFocus(dir router.FocusDirection, d driver) {
|
||||||
|
w.queue.q.MoveFocus(dir)
|
||||||
|
w.setNextFrame(time.Time{})
|
||||||
|
w.updateAnimation(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *callbacks) ClickFocus() {
|
func (c *callbacks) ClickFocus() {
|
||||||
@@ -793,7 +797,14 @@ func (w *Window) processEvent(d driver, e event.Event) {
|
|||||||
e2.Config.Size = e2.Config.Size.Sub(w.decorations.size)
|
e2.Config.Size = e2.Config.Size.Sub(w.decorations.size)
|
||||||
w.out <- e2
|
w.out <- e2
|
||||||
case event.Event:
|
case event.Event:
|
||||||
if w.queue.q.Queue(e2) {
|
// Convert tab or shift+tab presses to focus moves.
|
||||||
|
if e, ok := e.(key.Event); ok && e.State == key.Press && e.Name == key.NameTab && e.Modifiers&^key.ModShift == 0 {
|
||||||
|
dir := router.FocusForward
|
||||||
|
if e.Modifiers.Contain(key.ModShift) {
|
||||||
|
dir = router.FocusBackward
|
||||||
|
}
|
||||||
|
w.moveFocus(dir, d)
|
||||||
|
} else if w.queue.q.Queue(e2) {
|
||||||
w.setNextFrame(time.Time{})
|
w.setNextFrame(time.Time{})
|
||||||
w.updateAnimation(d)
|
w.updateAnimation(d)
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-22
@@ -70,6 +70,8 @@ const (
|
|||||||
FocusLeft
|
FocusLeft
|
||||||
FocusUp
|
FocusUp
|
||||||
FocusDown
|
FocusDown
|
||||||
|
FocusForward
|
||||||
|
FocusBackward
|
||||||
)
|
)
|
||||||
|
|
||||||
// InputState returns the last text input state as
|
// InputState returns the last text input state as
|
||||||
@@ -173,6 +175,24 @@ func (q *keyQueue) MoveFocus(dir FocusDirection, events *handlerEvents) {
|
|||||||
}
|
}
|
||||||
focus := q.dirOrder[order]
|
focus := q.dirOrder[order]
|
||||||
switch dir {
|
switch dir {
|
||||||
|
case FocusForward, FocusBackward:
|
||||||
|
if len(q.order) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
order := 0
|
||||||
|
if dir == FocusBackward {
|
||||||
|
order = -1
|
||||||
|
}
|
||||||
|
if q.focus != nil {
|
||||||
|
order = q.handlers[q.focus].order
|
||||||
|
if dir == FocusForward {
|
||||||
|
order++
|
||||||
|
} else {
|
||||||
|
order--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
order = (order + len(q.order)) % len(q.order)
|
||||||
|
q.setFocus(q.order[order], events)
|
||||||
case FocusRight, FocusLeft:
|
case FocusRight, FocusLeft:
|
||||||
next := order
|
next := order
|
||||||
if q.focus != nil {
|
if q.focus != nil {
|
||||||
@@ -226,28 +246,6 @@ func (q *keyQueue) MoveFocus(dir FocusDirection, events *handlerEvents) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (q *keyQueue) Push(e event.Event, events *handlerEvents) {
|
func (q *keyQueue) Push(e event.Event, events *handlerEvents) {
|
||||||
// Convert tab or shift+tab presses to focus moves.
|
|
||||||
if e, ok := e.(key.Event); ok && e.Name == key.NameTab && e.Modifiers&^key.ModShift == 0 {
|
|
||||||
if e.State == key.Release || len(q.order) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
forward := !e.Modifiers.Contain(key.ModShift)
|
|
||||||
order := 0
|
|
||||||
if !forward {
|
|
||||||
order = -1
|
|
||||||
}
|
|
||||||
if q.focus != nil {
|
|
||||||
order = q.handlers[q.focus].order
|
|
||||||
if forward {
|
|
||||||
order++
|
|
||||||
} else {
|
|
||||||
order--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
order = (order + len(q.order)) % len(q.order)
|
|
||||||
q.setFocus(q.order[order], events)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if q.focus != nil {
|
if q.focus != nil {
|
||||||
events.Add(q.focus, e)
|
events.Add(q.focus, e)
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-21
@@ -227,27 +227,6 @@ func TestNoOps(t *testing.T) {
|
|||||||
r.Frame(nil)
|
r.Frame(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTabFocus(t *testing.T) {
|
|
||||||
handlers := make([]int, 3)
|
|
||||||
ops := new(op.Ops)
|
|
||||||
r := new(Router)
|
|
||||||
|
|
||||||
for i := range handlers {
|
|
||||||
key.InputOp{Tag: &handlers[i]}.Add(ops)
|
|
||||||
}
|
|
||||||
r.Frame(ops)
|
|
||||||
|
|
||||||
tab := func(mod key.Modifiers) {
|
|
||||||
r.Queue(
|
|
||||||
key.Event{Name: key.NameTab, State: key.Press, Modifiers: mod},
|
|
||||||
key.Event{Name: key.NameTab, State: key.Release, Modifiers: mod},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
tab(0)
|
|
||||||
tab(key.ModShift)
|
|
||||||
assertFocus(t, r, &handlers[2])
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDirectionalFocus(t *testing.T) {
|
func TestDirectionalFocus(t *testing.T) {
|
||||||
ops := new(op.Ops)
|
ops := new(op.Ops)
|
||||||
r := new(Router)
|
r := new(Router)
|
||||||
@@ -281,6 +260,11 @@ func TestDirectionalFocus(t *testing.T) {
|
|||||||
assertFocus(t, r, &handlers[3])
|
assertFocus(t, r, &handlers[3])
|
||||||
r.MoveFocus(FocusUp)
|
r.MoveFocus(FocusUp)
|
||||||
assertFocus(t, r, &handlers[0])
|
assertFocus(t, r, &handlers[0])
|
||||||
|
|
||||||
|
r.MoveFocus(FocusForward)
|
||||||
|
assertFocus(t, r, &handlers[1])
|
||||||
|
r.MoveFocus(FocusBackward)
|
||||||
|
assertFocus(t, r, &handlers[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertKeyEvent(t *testing.T, events []event.Event, expected bool, expectedInputs ...event.Event) {
|
func assertKeyEvent(t *testing.T, events []event.Event, expected bool, expectedInputs ...event.Event) {
|
||||||
|
|||||||
Reference in New Issue
Block a user