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

Add character identifiers to focusable widgets

When no widget has focus, press the letter key to focus on the widget
assigned to that letter.

Example:

    GitHub (d)

    Press "d" to focus on the GitHub widget.
This commit is contained in:
Chris Cummer 2018-07-30 15:51:19 -07:00
parent 749318ead6
commit beb0c43b07
36 changed files with 100 additions and 44 deletions

View File

@ -12,7 +12,7 @@ type Widget struct {
func NewWidget() *Widget { func NewWidget() *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" BambooHR ", "bamboohr", false), TextWidget: wtf.NewTextWidget("BambooHR", "bamboohr", false),
} }
return &widget return &widget
@ -29,7 +29,7 @@ func (widget *Widget) Refresh() {
) )
widget.UpdateRefreshedAt() widget.UpdateRefreshedAt()
widget.View.SetTitle(fmt.Sprintf("%s (%d) ", widget.Name, len(todayItems))) widget.View.SetTitle(widget.ContextualTitle(widget.Name))
widget.View.SetText(widget.contentFrom(todayItems)) widget.View.SetText(widget.contentFrom(todayItems))
} }

View File

@ -11,7 +11,7 @@ type Widget struct {
func NewWidget() *Widget { func NewWidget() *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" CircleCI ", "circleci", false), TextWidget: wtf.NewTextWidget("CircleCI", "circleci", false),
} }
return &widget return &widget

View File

@ -15,7 +15,7 @@ type Widget struct {
func NewWidget() *Widget { func NewWidget() *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" World Clocks ", "clocks", false), TextWidget: wtf.NewTextWidget("World Clocks", "clocks", false),
} }
widget.clockColl = widget.buildClockCollection(wtf.Config.UMap("wtf.mods.clocks.locations")) widget.clockColl = widget.buildClockCollection(wtf.Config.UMap("wtf.mods.clocks.locations"))

View File

@ -17,7 +17,7 @@ type Widget struct {
func NewWidget() *Widget { func NewWidget() *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" Calendar ", "gcal", false), TextWidget: wtf.NewTextWidget("Calendar", "gcal", false),
ch: make(chan struct{}), ch: make(chan struct{}),
} }

View File

@ -68,7 +68,7 @@ func NewWidget(app *tview.Application, pages *tview.Pages) *Widget {
} }
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" Gerrit ", "gerrit", true), TextWidget: wtf.NewTextWidget("Gerrit", "gerrit", true),
app: app, app: app,
pages: pages, pages: pages,

View File

@ -15,8 +15,8 @@ func (widget *Widget) display() {
return return
} }
title := fmt.Sprintf("[green]%s[white]\n", repoData.Repository) title := fmt.Sprintf("%s - [green]%s[white]", widget.Name, repoData.Repository)
widget.View.SetTitle(fmt.Sprintf("%s- %s", widget.Name, title)) widget.View.SetTitle(widget.ContextualTitle(title))
str := wtf.SigilStr(len(widget.Data), widget.Idx, widget.View) + "\n" str := wtf.SigilStr(len(widget.Data), widget.Idx, widget.View) + "\n"
str = str + " [red]Branch[white]\n" str = str + " [red]Branch[white]\n"

View File

@ -34,7 +34,7 @@ type Widget struct {
func NewWidget(app *tview.Application, pages *tview.Pages) *Widget { func NewWidget(app *tview.Application, pages *tview.Pages) *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" Git ", "git", true), TextWidget: wtf.NewTextWidget("Git", "git", true),
app: app, app: app,
Idx: 0, Idx: 0,

View File

@ -14,7 +14,7 @@ func (widget *Widget) display() {
return return
} }
widget.View.SetTitle(fmt.Sprintf("%s- %s ", widget.Name, widget.title(repo))) widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s - %s", widget.Name, widget.title(repo))))
str := wtf.SigilStr(len(widget.GithubRepos), widget.Idx, widget.View) + "\n" str := wtf.SigilStr(len(widget.GithubRepos), widget.Idx, widget.View) + "\n"
str = str + " [red]Stats[white]\n" str = str + " [red]Stats[white]\n"

View File

@ -30,7 +30,7 @@ type Widget struct {
func NewWidget(app *tview.Application, pages *tview.Pages) *Widget { func NewWidget(app *tview.Application, pages *tview.Pages) *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" Github ", "github", true), TextWidget: wtf.NewTextWidget("Github", "github", true),
app: app, app: app,
Idx: 0, Idx: 0,

View File

@ -42,7 +42,7 @@ func NewWidget(app *tview.Application, pages *tview.Pages) *Widget {
} }
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" Gitlab ", "gitlab", true), TextWidget: wtf.NewTextWidget("Gitlab", "gitlab", true),
app: app, app: app,
pages: pages, pages: pages,

View File

@ -13,7 +13,7 @@ type Widget struct {
func NewWidget() *Widget { func NewWidget() *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" Google Spreadsheets ", "gspreadsheets", false), TextWidget: wtf.NewTextWidget("Google Spreadsheets", "gspreadsheets", false),
} }
return &widget return &widget

View File

@ -39,7 +39,7 @@ type ipinfo struct {
// NewWidget constructor // NewWidget constructor
func NewWidget() *Widget { func NewWidget() *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" IPInfo ", "ipapi", false), TextWidget: wtf.NewTextWidget("IPInfo", "ipapi", false),
} }
widget.View.SetWrap(false) widget.View.SetWrap(false)

View File

@ -32,7 +32,7 @@ type ipinfo struct {
func NewWidget() *Widget { func NewWidget() *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" IPInfo ", "ipinfo", false), TextWidget: wtf.NewTextWidget("IPInfo", "ipinfo", false),
} }
widget.View.SetWrap(false) widget.View.SetWrap(false)

View File

@ -16,7 +16,7 @@ type Widget struct {
func NewWidget() *Widget { func NewWidget() *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" Jira ", "jira", true), TextWidget: wtf.NewTextWidget("Jira", "jira", true),
} }
widget.unselect() widget.unselect()
@ -54,13 +54,10 @@ func (widget *Widget) display() {
return return
} }
widget.View.SetWrap(false) widget.View.SetWrap(false)
widget.View.SetTitle(
fmt.Sprintf( str := fmt.Sprintf("%s- [green]%s[white]", widget.Name, wtf.Config.UString("wtf.mods.jira.project"))
"%s- [green]%s[white] ",
widget.Name, widget.View.SetTitle(widget.ContextualTitle(str))
wtf.Config.UString("wtf.mods.jira.project"),
),
)
widget.View.SetText(fmt.Sprintf("%s", widget.contentFrom(widget.result))) widget.View.SetText(fmt.Sprintf("%s", widget.contentFrom(widget.result)))
} }

View File

@ -74,6 +74,8 @@ func initializeFocusTracker(app *tview.Application) {
Idx: -1, Idx: -1,
Widgets: widgets, Widgets: widgets,
} }
focusTracker.AssignHotKeys()
} }
func keyboardIntercept(event *tcell.EventKey) *tcell.EventKey { func keyboardIntercept(event *tcell.EventKey) *tcell.EventKey {
@ -86,10 +88,12 @@ func keyboardIntercept(event *tcell.EventKey) *tcell.EventKey {
focusTracker.Prev() focusTracker.Prev()
case tcell.KeyEsc: case tcell.KeyEsc:
focusTracker.None() focusTracker.None()
default: //default:
return event //return event
} }
focusTracker.FocusOn(string(event.Rune()))
return event return event
} }

View File

@ -13,7 +13,7 @@ type Widget struct {
func NewWidget() *Widget { func NewWidget() *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" New Relic ", "newrelic", false), TextWidget: wtf.NewTextWidget("New Relic", "newrelic", false),
} }
return &widget return &widget

View File

@ -13,7 +13,7 @@ type Widget struct {
func NewWidget() *Widget { func NewWidget() *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" OpsGenie ", "opsgenie", false), TextWidget: wtf.NewTextWidget("OpsGenie", "opsgenie", false),
} }
return &widget return &widget

View File

@ -14,7 +14,7 @@ type Widget struct {
func NewWidget() *Widget { func NewWidget() *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" Power ", "power", false), TextWidget: wtf.NewTextWidget("Power", "power", false),
Battery: NewBattery(), Battery: NewBattery(),
} }

View File

@ -15,7 +15,7 @@ type Widget struct {
func NewWidget() *Widget { func NewWidget() *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" Security ", "security", false), TextWidget: wtf.NewTextWidget("Security", "security", false),
} }
return &widget return &widget

View File

@ -15,7 +15,7 @@ type Widget struct {
func NewWidget() *Widget { func NewWidget() *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" Security ", "security", false), TextWidget: wtf.NewTextWidget("Security", "security", false),
} }
return &widget return &widget

View File

@ -12,7 +12,7 @@ type Widget struct {
func NewWidget() *Widget { func NewWidget() *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" Status ", "status", false), TextWidget: wtf.NewTextWidget("Status", "status", false),
CurrentIcon: 0, CurrentIcon: 0,
} }

View File

@ -17,7 +17,7 @@ type Widget struct {
func NewWidget(date, version string) *Widget { func NewWidget(date, version string) *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" System ", "system", false), TextWidget: wtf.NewTextWidget("System", "system", false),
Date: date, Date: date,
Version: version, Version: version,

View File

@ -31,7 +31,7 @@ type Widget struct {
func NewWidget(app *tview.Application, pages *tview.Pages) *Widget { func NewWidget(app *tview.Application, pages *tview.Pages) *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" Text File ", "textfile", true), TextWidget: wtf.NewTextWidget("TextFile", "textfile", true),
app: app, app: app,
filePath: wtf.Config.UString("wtf.mods.textfile.filePath"), filePath: wtf.Config.UString("wtf.mods.textfile.filePath"),
@ -50,7 +50,7 @@ func NewWidget(app *tview.Application, pages *tview.Pages) *Widget {
func (widget *Widget) Refresh() { func (widget *Widget) Refresh() {
widget.UpdateRefreshedAt() widget.UpdateRefreshedAt()
widget.View.SetTitle(fmt.Sprintf(" %s ", widget.fileName())) widget.View.SetTitle(widget.ContextualTitle(widget.fileName()))
filePath, _ := wtf.ExpandHomeDir(widget.filePath) filePath, _ := wtf.ExpandHomeDir(widget.filePath)

View File

@ -46,7 +46,7 @@ type Widget struct {
func NewWidget(app *tview.Application, pages *tview.Pages) *Widget { func NewWidget(app *tview.Application, pages *tview.Pages) *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" Todo ", "todo", true), TextWidget: wtf.NewTextWidget("Todo", "todo", true),
app: app, app: app,
filePath: wtf.Config.UString("wtf.mods.todo.filename"), filePath: wtf.Config.UString("wtf.mods.todo.filename"),
@ -68,6 +68,8 @@ func (widget *Widget) Refresh() {
widget.UpdateRefreshedAt() widget.UpdateRefreshedAt()
widget.load() widget.load()
widget.display() widget.display()
widget.View.SetTitle(widget.ContextualTitle(widget.Name))
} }
func (widget *Widget) SetList(newList checklist.Checklist) { func (widget *Widget) SetList(newList checklist.Checklist) {

View File

@ -16,7 +16,10 @@ func (widget *Widget) display() {
return return
} }
widget.View.SetTitle(fmt.Sprintf(" [green]%s[white] ", proj.Project.Name)) //widget.View.SetTitle(fmt.Sprintf(" [green]%s[white] ", proj.Project.Name))
widget.View.SetTitle(widget.ContextualTitle(proj.Project.Name))
str := wtf.SigilStr(len(widget.projects), widget.idx, widget.View) + "\n" str := wtf.SigilStr(len(widget.projects), widget.idx, widget.View) + "\n"
maxLen := proj.LongestLine() maxLen := proj.LongestLine()

View File

@ -38,7 +38,7 @@ type Widget struct {
func NewWidget(app *tview.Application, pages *tview.Pages) *Widget { func NewWidget(app *tview.Application, pages *tview.Pages) *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" Todoist ", "todoist", true), TextWidget: wtf.NewTextWidget("Todoist", "todoist", true),
app: app, app: app,
pages: pages, pages: pages,

View File

@ -11,7 +11,7 @@ type Widget struct {
func NewWidget() *Widget { func NewWidget() *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" Travis CI", "travisci", false), TextWidget: wtf.NewTextWidget("TravisCI", "travisci", false),
} }
return &widget return &widget

View File

@ -14,7 +14,7 @@ type Widget struct {
func NewWidget() *Widget { func NewWidget() *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" Trello ", "trello", false), TextWidget: wtf.NewTextWidget("Trello", "trello", false),
} }
return &widget return &widget

View File

@ -19,7 +19,7 @@ type Widget struct {
func NewWidget() *Widget { func NewWidget() *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" Pretty Weather ", "prettyweather", false), TextWidget: wtf.NewTextWidget("Pretty Weather", "prettyweather", false),
} }
return &widget return &widget

View File

@ -72,5 +72,6 @@ func (widget *Widget) temperatures(cityData *owm.CurrentWeatherData) string {
} }
func (widget *Widget) title(cityData *owm.CurrentWeatherData) string { func (widget *Widget) title(cityData *owm.CurrentWeatherData) string {
return fmt.Sprintf(" %s %s ", widget.emojiFor(cityData), cityData.Name) str := fmt.Sprintf("%s %s", widget.emojiFor(cityData), cityData.Name)
return widget.ContextualTitle(str)
} }

View File

@ -38,7 +38,7 @@ type Widget struct {
func NewWidget(app *tview.Application, pages *tview.Pages) *Widget { func NewWidget(app *tview.Application, pages *tview.Pages) *Widget {
configKey := "weather" configKey := "weather"
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" Weather ", configKey, true), TextWidget: wtf.NewTextWidget("Weather", configKey, true),
app: app, app: app,
pages: pages, pages: pages,

View File

@ -72,10 +72,18 @@ func (widget *BarGraph) Focusable() bool {
return widget.enabled && widget.focusable return widget.enabled && widget.focusable
} }
func (widget *BarGraph) FocusChar() string {
return ""
}
func (widget *BarGraph) RefreshInterval() int { func (widget *BarGraph) RefreshInterval() int {
return widget.RefreshInt return widget.RefreshInt
} }
func (widget *BarGraph) SetFocusChar(char string) {
return
}
func (widget *BarGraph) TextView() *tview.TextView { func (widget *BarGraph) TextView() *tview.TextView {
return widget.View return widget.View
} }

View File

@ -22,6 +22,28 @@ type FocusTracker struct {
/* -------------------- Exported Functions -------------------- */ /* -------------------- 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() {
i := 0
for _, focusable := range tracker.focusables() {
focusable.SetFocusChar(string('a' + i))
i++
}
}
func (tracker *FocusTracker) FocusOn(char string) {
for idx, focusable := range tracker.focusables() {
if focusable.FocusChar() == char {
tracker.blur(tracker.Idx)
tracker.Idx = idx
tracker.focus(tracker.Idx)
break
}
}
}
// Next sets the focus on the next widget in the widget list. If the current widget is // 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. // the last widget, sets focus on the first widget.
func (tracker *FocusTracker) Next() { func (tracker *FocusTracker) Next() {

View File

@ -13,6 +13,7 @@ var Config *config.Config
type TextWidget struct { type TextWidget struct {
enabled bool enabled bool
focusable bool focusable bool
focusChar string
Name string Name string
RefreshedAt time.Time RefreshedAt time.Time
@ -53,6 +54,14 @@ func (widget *TextWidget) BorderColor() string {
return Config.UString("wtf.colors.border.normal", "gray") return Config.UString("wtf.colors.border.normal", "gray")
} }
func (widget *TextWidget) ContextualTitle(defaultStr string) string {
if widget.FocusChar() == "" {
return fmt.Sprintf(" %s ", defaultStr)
} else {
return fmt.Sprintf(" %s [darkgray](%s)[white] ", defaultStr, widget.FocusChar())
}
}
func (widget *TextWidget) Disable() { func (widget *TextWidget) Disable() {
widget.enabled = false widget.enabled = false
} }
@ -69,10 +78,18 @@ func (widget *TextWidget) Focusable() bool {
return widget.enabled && widget.focusable return widget.enabled && widget.focusable
} }
func (widget *TextWidget) FocusChar() string {
return widget.focusChar
}
func (widget *TextWidget) RefreshInterval() int { func (widget *TextWidget) RefreshInterval() int {
return widget.RefreshInt return widget.RefreshInt
} }
func (widget *TextWidget) SetFocusChar(char string) {
widget.focusChar = char
}
func (widget *TextWidget) TextView() *tview.TextView { func (widget *TextWidget) TextView() *tview.TextView {
return widget.View return widget.View
} }
@ -86,7 +103,7 @@ func (widget *TextWidget) addView() {
view.SetBorder(true) view.SetBorder(true)
view.SetBorderColor(colorFor(widget.BorderColor())) view.SetBorderColor(colorFor(widget.BorderColor()))
view.SetDynamicColors(true) view.SetDynamicColors(true)
view.SetTitle(widget.Name) view.SetTitle(widget.ContextualTitle(widget.Name))
view.SetWrap(false) view.SetWrap(false)
widget.View = view widget.View = view

View File

@ -10,6 +10,8 @@ type Wtfable interface {
BorderColor() string BorderColor() string
Focusable() bool Focusable() bool
FocusChar() string
SetFocusChar(string)
TextView() *tview.TextView TextView() *tview.TextView
Top() int Top() int

View File

@ -18,7 +18,7 @@ type Widget struct {
func NewWidget() *Widget { func NewWidget() *Widget {
widget := Widget{ widget := Widget{
TextWidget: wtf.NewTextWidget(" Zendesk ", "zendesk", true), TextWidget: wtf.NewTextWidget("Zendesk", "zendesk", true),
} }
widget.View.SetInputCapture(widget.keyboardIntercept) widget.View.SetInputCapture(widget.keyboardIntercept)