1
0
mirror of https://github.com/taigrr/wtf synced 2025-01-18 04:03:14 -08:00
wtf/wtf/focus_tracker.go

182 lines
3.6 KiB
Go

package wtf
import (
"github.com/rivo/tview"
)
type FocusState int
const (
widgetFocused FocusState = iota
appBoardFocused
neverFocused
)
// FocusTracker is used by the app to track which onscreen widget currently has focus,
// and to move focus between widgets.
type FocusTracker struct {
App *tview.Application
Idx int
Widgets []Wtfable
}
/* -------------------- Exported Functions -------------------- */
// AssignHotKeys assigns an alphabetic keyboard character to each focusable
// widget so that the widget can be brought into focus by pressing that keyboard key
func (tracker *FocusTracker) AssignHotKeys() {
if !tracker.withShortcuts() {
return
}
i := 0
for _, focusable := range tracker.focusables() {
focusable.SetFocusChar(string('a' + i))
i++
}
}
func (tracker *FocusTracker) FocusOn(char string) bool {
if !tracker.withShortcuts() {
return false
}
if tracker.focusState() == appBoardFocused {
return false
}
hasFocusable := false
for idx, focusable := range tracker.focusables() {
if focusable.FocusChar() == char {
tracker.blur(tracker.Idx)
tracker.Idx = idx
tracker.focus(tracker.Idx)
hasFocusable = true
break
}
}
return hasFocusable
}
// Next sets the focus on the next widget in the widget list. If the current widget is
// the last widget, sets focus on the first widget.
func (tracker *FocusTracker) Next() {
if tracker.focusState() == appBoardFocused {
return
}
tracker.blur(tracker.Idx)
tracker.increment()
tracker.focus(tracker.Idx)
}
// None removes focus from the currently-focused widget.
func (tracker *FocusTracker) None() {
if tracker.focusState() == appBoardFocused {
return
}
tracker.blur(tracker.Idx)
}
// Prev sets the focus on the previous widget in the widget list. If the current widget is
// the last widget, sets focus on the last widget.
func (tracker *FocusTracker) Prev() {
if tracker.focusState() == appBoardFocused {
return
}
tracker.blur(tracker.Idx)
tracker.decrement()
tracker.focus(tracker.Idx)
}
func (tracker *FocusTracker) Refocus() {
tracker.focus(tracker.Idx)
}
/* -------------------- Unexported Functions -------------------- */
func (tracker *FocusTracker) blur(idx int) {
widget := tracker.focusableAt(idx)
if widget == nil {
return
}
view := widget.TextView()
view.Blur()
view.SetBorderColor(colorFor(widget.BorderColor()))
}
func (tracker *FocusTracker) decrement() {
tracker.Idx = tracker.Idx - 1
if tracker.Idx < 0 {
tracker.Idx = len(tracker.focusables()) - 1
}
}
func (tracker *FocusTracker) focus(idx int) {
widget := tracker.focusableAt(idx)
if widget == nil {
return
}
view := widget.TextView()
view.SetBorderColor(colorFor(Config.UString("wtf.colors.border.focused", "gray")))
tracker.App.SetFocus(view)
tracker.App.Draw()
}
func (tracker *FocusTracker) focusables() []Wtfable {
focusable := []Wtfable{}
for _, widget := range tracker.Widgets {
if widget.Focusable() {
focusable = append(focusable, widget)
}
}
return focusable
}
func (tracker *FocusTracker) focusableAt(idx int) Wtfable {
if idx < 0 || idx >= len(tracker.focusables()) {
return nil
}
return tracker.focusables()[idx]
}
func (tracker *FocusTracker) focusState() FocusState {
if tracker.Idx < 0 {
return neverFocused
}
for _, widget := range tracker.Widgets {
if widget.TextView() == tracker.App.GetFocus() {
return widgetFocused
}
}
return appBoardFocused
}
func (tracker *FocusTracker) increment() {
tracker.Idx = tracker.Idx + 1
if tracker.Idx == len(tracker.focusables()) {
tracker.Idx = 0
}
}
func (tracker *FocusTracker) withShortcuts() bool {
return Config.UBool("wtf.navigation.shortcuts", true)
}