app,io/router: scroll focused widgets into view

A focused widget may be partially or completely off-screen in which case
the user will have difficulty interacting with it. This change attempts to
scroll the focused widget into view by issuing synthetic scroll events.

For https://github.com/tailscale/tailscale/issues/4278, but doesn't completely
solve it because layout.Lists won't layout focusable widgets outside its visible
bounds. A follow-up change deals with that.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2022-03-30 11:52:51 +02:00
parent 2069d5cb2e
commit 4326fee704
5 changed files with 139 additions and 5 deletions
+34
View File
@@ -597,6 +597,40 @@ func (q *pointerQueue) pointerOf(e pointer.Event) int {
return len(q.pointers) - 1
}
// Deliver is like Push, but delivers an event to a particular area.
func (q *pointerQueue) Deliver(areaIdx int, e pointer.Event, events *handlerEvents) {
var sx, sy = e.Scroll.X, e.Scroll.Y
for areaIdx != -1 {
a := &q.areas[areaIdx]
areaIdx = a.parent
if !a.semantic.valid {
continue
}
cnt := a.semantic.content
if cnt.tag == nil {
continue
}
h := q.handlers[cnt.tag]
if e.Type == pointer.Scroll {
if sx == 0 && sy == 0 {
break
}
// Distribute the scroll to the handler based on its ScrollRange.
sx, e.Scroll.X = setScrollEvent(sx, h.scrollRange.Min.X, h.scrollRange.Max.X)
sy, e.Scroll.Y = setScrollEvent(sy, h.scrollRange.Min.Y, h.scrollRange.Max.Y)
}
if e.Type&h.types == 0 {
continue
}
e := e
e.Position = q.invTransform(h.area, e.Position)
events.Add(cnt.tag, e)
if e.Type != pointer.Scroll {
break
}
}
}
func (q *pointerQueue) Push(e pointer.Event, events *handlerEvents) {
if e.Type == pointer.Cancel {
q.pointers = q.pointers[:0]