Merge pull request #93 from dorileo/navigation

Navigation with arrow keys
This commit is contained in:
Vladimir Markelov 2018-04-19 13:15:17 -07:00 committed by GitHub
commit 4f279ead6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 55 additions and 74 deletions

View File

@ -148,37 +148,25 @@ func IsMouseClickEvent(ev Event) bool {
// FindFirstControl returns the first child for that fn returns true. // FindFirstControl returns the first child for that fn returns true.
// The function is used to find active or tab-stop control // The function is used to find active or tab-stop control
func FindFirstControl(parent Control, fn func(Control) bool) Control { func FindFirstControl(parent Control, fn func(Control) bool) Control {
for _, child := range parent.Children() { linear := getLinearControlList(parent, fn)
if fn(child) { if len(linear) == 0 {
return child
}
ch := FindFirstControl(child, fn)
if ch != nil {
return ch
}
}
return nil return nil
} }
return linear[0]
}
// FindLastControl returns the first child for that fn returns true. // FindLastControl returns the first child for that fn returns true.
// The function is used by TAB processing method if a user goes backwards // The function is used by TAB processing method if a user goes backwards
// with TAB key - not supported now // with TAB key - not supported now
func FindLastControl(parent Control, fn func(Control) bool) Control { func FindLastControl(parent Control, fn func(Control) bool) Control {
var last Control linear := getLinearControlList(parent, fn)
for _, child := range parent.Children() {
if fn(child) { if len(linear) == 0 {
last = child return nil
} }
ch := FindLastControl(child, fn) return linear[len(linear)-1]
if ch != nil {
last = ch
}
}
return last
} }
// ActiveControl returns the active child of the parent or nil if no child is // ActiveControl returns the active child of the parent or nil if no child is
@ -190,72 +178,61 @@ func ActiveControl(parent Control) Control {
return FindFirstControl(parent, fnActive) return FindFirstControl(parent, fnActive)
} }
func _nextControl(parent Control, curr, prev Control, foundPrev, next bool) (bool, Control) { func getLinearControlList(parent Control, fn func(Control) bool) []Control {
found := foundPrev result := []Control{}
if parent == curr {
if next { for _, curr := range parent.Children() {
found = true if fn(curr) {
} else { result = append(result, curr)
return false, prev
}
} }
p := prev if len(curr.Children()) == 0 {
for _, ctrl := range parent.Children() {
if ctrl == curr {
if next {
found = true
continue continue
} else { }
return found, p
ch := getLinearControlList(curr, fn)
if len(ch) != 0 {
result = append(result, ch...)
} }
} }
if ctrl.Enabled() && ctrl.TabStop() && ctrl.Visible() { return result
if found {
return found, ctrl
} else if !next {
p = ctrl
}
}
fnd, nn := _nextControl(ctrl, curr, p, found, next)
if nn != nil {
return fnd, nn
}
found = fnd
}
return found, nil
} }
// NextControl returns the next or previous child (depends on next parameter) // NextControl returns the next or previous child (depends on next parameter)
// that has tab-stop feature on. Used by library when processing TAB key // that has tab-stop feature on. Used by library when processing TAB key
func NextControl(parent Control, curr Control, next bool) Control { func NextControl(parent Control, curr Control, next bool) Control {
fnTab := func(c Control) bool { fnTab := func(c Control) bool {
return c.TabStop() && c.Visible() return c.TabStop() && c.Visible() && c.Enabled()
}
linear := getLinearControlList(parent, fnTab)
var pIndex, nIndex int
for i, ch := range linear {
if ch != curr {
continue
}
pIndex = i - 1
nIndex = i + 1
break
}
if nIndex > len(linear)-1 {
nIndex = 0
}
if pIndex < 0 {
pIndex = len(linear) - 1
} }
var defControl Control
if next { if next {
defControl = FindFirstControl(parent, fnTab) return linear[nIndex]
} else { } else {
defControl = FindLastControl(parent, fnTab) return linear[pIndex]
} }
if defControl == nil {
return nil
}
if curr == nil {
return defControl
}
_, cNext := _nextControl(parent, curr, nil, false, next)
if cNext == nil {
cNext = defControl
}
return cNext
} }
// SendEventToChild tries to find a child control that should recieve the evetn // SendEventToChild tries to find a child control that should recieve the evetn

View File

@ -226,9 +226,13 @@ func (c *Window) ProcessEvent(ev Event) bool {
} }
return true return true
case EventKey: case EventKey:
if ev.Key == term.KeyTab { if ev.Key == term.KeyTab || ev.Key == term.KeyArrowUp || ev.Key == term.KeyArrowDown {
if SendEventToChild(c, ev) {
return true
}
aC := ActiveControl(c) aC := ActiveControl(c)
nC := NextControl(c, aC, true) nC := NextControl(c, aC, ev.Key != term.KeyArrowUp)
if nC != aC { if nC != aC {
if aC != nil { if aC != nil {
aC.SetActive(false) aC.SetActive(false)