From a9c5dc3be80f684cd51cbd0cd3efca45af13202a Mon Sep 17 00:00:00 2001 From: Chris Cummer Date: Mon, 6 May 2019 04:51:30 -0700 Subject: [PATCH] WTF-427 Add KeyboardWidget and switch Todo widget to using it --- cfg/common_settings.go | 8 ++-- go.sum | 1 + modules/todo/keyboard.go | 70 +++++++++++++++++++++++++++ modules/todo/widget.go | 100 +++++++-------------------------------- wtf/keyboard_widget.go | 58 +++++++++++++++++++++++ 5 files changed, 149 insertions(+), 88 deletions(-) create mode 100644 modules/todo/keyboard.go create mode 100644 wtf/keyboard_widget.go diff --git a/cfg/common_settings.go b/cfg/common_settings.go index 25ec723a..7f53aa67 100644 --- a/cfg/common_settings.go +++ b/cfg/common_settings.go @@ -104,11 +104,11 @@ func NewCommonSettingsFromModule(name, defaultTitle string, moduleConfig *config common.Colors.Rows.Even = moduleConfig.UString("colors.rows.even", moduleConfig.UString("rows.even", "white")) common.Colors.Rows.Odd = moduleConfig.UString("colors.rows.even", moduleConfig.UString("rows.odd", "lightblue")) - common.Sigils.Checkbox.Checked = globalSettings.UString(sigilsPath+".Checkbox.Checked", "x") - common.Sigils.Checkbox.Unchecked = globalSettings.UString(sigilsPath+".Checkbox.Unchecked", " ") + common.Sigils.Checkbox.Checked = globalSettings.UString(sigilsPath+".checkbox.checked", "x") + common.Sigils.Checkbox.Unchecked = globalSettings.UString(sigilsPath+".checkbox.unchecked", " ") - common.Sigils.Paging.Normal = globalSettings.UString(sigilsPath+".Paging.Normal", globalSettings.UString("wtf.paging.pageSigil", "*")) - common.Sigils.Paging.Selected = globalSettings.UString(sigilsPath+".Paging.Select", globalSettings.UString("wtf.paging.selectedSigil", "_")) + common.Sigils.Paging.Normal = globalSettings.UString(sigilsPath+".paging.normal", globalSettings.UString("wtf.paging.pageSigil", "*")) + common.Sigils.Paging.Selected = globalSettings.UString(sigilsPath+".paging.select", globalSettings.UString("wtf.paging.selectedSigil", "_")) return &common } diff --git a/go.sum b/go.sum index 340cbe42..67a36eaf 100644 --- a/go.sum +++ b/go.sum @@ -140,6 +140,7 @@ google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= diff --git a/modules/todo/keyboard.go b/modules/todo/keyboard.go new file mode 100644 index 00000000..fbcab2e8 --- /dev/null +++ b/modules/todo/keyboard.go @@ -0,0 +1,70 @@ +package todo + +import ( + "fmt" + + "github.com/gdamore/tcell" + "github.com/wtfutil/wtf/cfg" + "github.com/wtfutil/wtf/wtf" +) + +func (widget *Widget) initializeKeyboardControls() { + widget.SetKeyboardChar(" ", widget.toggleChecked) + widget.SetKeyboardChar("/", widget.ShowHelp) + widget.SetKeyboardChar("j", widget.displayNext) + widget.SetKeyboardChar("k", widget.displayPrev) + widget.SetKeyboardChar("n", widget.newItem) + widget.SetKeyboardChar("o", widget.openFile) + + widget.SetKeyboardKey(tcell.KeyCtrlD, widget.deleteSelected) + widget.SetKeyboardKey(tcell.KeyCtrlJ, widget.demoteSelected) + widget.SetKeyboardKey(tcell.KeyCtrlK, widget.promoteSelected) + widget.SetKeyboardKey(tcell.KeyDown, widget.displayNext) + widget.SetKeyboardKey(tcell.KeyEnter, widget.editSelected) + widget.SetKeyboardKey(tcell.KeyEsc, widget.unselect) + widget.SetKeyboardKey(tcell.KeyUp, widget.displayPrev) +} + +func (widget *Widget) deleteSelected() { + widget.list.Delete() + widget.persist() + widget.display() +} + +func (widget *Widget) demoteSelected() { + widget.list.Demote() + widget.persist() + widget.display() +} + +func (widget *Widget) displayNext() { + widget.list.Next() + widget.display() +} + +func (widget *Widget) displayPrev() { + widget.list.Prev() + widget.display() +} + +func (widget *Widget) openFile() { + confDir, _ := cfg.ConfigDir() + wtf.OpenFile(fmt.Sprintf("%s/%s", confDir, widget.filePath)) +} + +func (widget *Widget) promoteSelected() { + widget.list.Promote() + widget.persist() + widget.display() +} + +func (widget *Widget) toggleChecked() { + widget.list.Toggle() + widget.persist() + widget.display() +} + +func (widget *Widget) unselect() { + widget.list.Unselect() + widget.display() +} diff --git a/modules/todo/widget.go b/modules/todo/widget.go index a63e3ddc..a93a1162 100644 --- a/modules/todo/widget.go +++ b/modules/todo/widget.go @@ -35,8 +35,10 @@ const offscreen = -1000 const modalWidth = 80 const modalHeight = 7 +// A Widget represents a Todo widget type Widget struct { wtf.HelpfulWidget + wtf.KeyboardWidget wtf.TextWidget app *tview.Application @@ -46,10 +48,12 @@ type Widget struct { pages *tview.Pages } +// NewWidget creates a new instance of a widget func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *Widget { widget := Widget{ - HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText), - TextWidget: wtf.NewTextWidget(app, settings.common, true), + HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText), + KeyboardWidget: wtf.NewKeyboardWidget(), + TextWidget: wtf.NewTextWidget(app, settings.common, true), app: app, settings: settings, @@ -59,11 +63,13 @@ func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) * } widget.init() - widget.HelpfulWidget.SetView(widget.View) + widget.initializeKeyboardControls() - widget.View.SetScrollable(true) + widget.View.SetInputCapture(widget.InputCapture) widget.View.SetRegions(true) - widget.View.SetInputCapture(widget.keyboardIntercept) + widget.View.SetScrollable(true) + + widget.HelpfulWidget.SetView(widget.View) return &widget } @@ -74,20 +80,21 @@ func (widget *Widget) Refresh() { widget.load() widget.app.QueueUpdateDraw(func() { - widget.View.SetTitle(widget.ContextualTitle(widget.CommonSettings.Title)) + title := widget.ContextualTitle(widget.CommonSettings.Title) + widget.View.SetTitle(title) widget.display() }) } -func (widget *Widget) SetList(newList checklist.Checklist) { - widget.list = newList +func (widget *Widget) SetList(list checklist.Checklist) { + widget.list = list } /* -------------------- Unexported Functions -------------------- */ // edit opens a modal dialog that permits editing the text of the currently-selected item -func (widget *Widget) editItem() { +func (widget *Widget) editSelected() { if widget.list.SelectedItem() == nil { return } @@ -115,81 +122,6 @@ func (widget *Widget) init() { } } -func (widget *Widget) keyboardIntercept(event *tcell.EventKey) *tcell.EventKey { - switch string(event.Rune()) { - case " ": - // Check/uncheck selected item - widget.list.Toggle() - widget.persist() - widget.display() - return nil - case "/": - widget.ShowHelp() - return nil - case "j": - // Select the next item down - widget.list.Next() - widget.display() - return nil - case "k": - // Select the next item up - widget.list.Prev() - widget.display() - return nil - case "n": - // Add a new item - widget.newItem() - return nil - case "o": - // Open the file - confDir, _ := cfg.ConfigDir() - wtf.OpenFile(fmt.Sprintf("%s/%s", confDir, widget.filePath)) - return nil - } - - switch event.Key() { - case tcell.KeyCtrlD: - // Delete the selected item - widget.list.Delete() - widget.persist() - widget.display() - return nil - case tcell.KeyCtrlJ: - // Move selected item down in the list - widget.list.Demote() - widget.persist() - widget.display() - return nil - case tcell.KeyCtrlK: - // Move selected item up in the list - widget.list.Promote() - widget.persist() - widget.display() - return nil - case tcell.KeyDown: - // Select the next item down - widget.list.Next() - widget.display() - return nil - case tcell.KeyEnter: - widget.editItem() - return nil - case tcell.KeyEsc: - // Unselect the current row - widget.list.Unselect() - widget.display() - return event - case tcell.KeyUp: - // Select the next item up - widget.list.Prev() - widget.display() - return nil - default: - // Pass it along - return event - } -} - // Loads the todo list from Yaml file func (widget *Widget) load() { confDir, _ := cfg.ConfigDir() diff --git a/wtf/keyboard_widget.go b/wtf/keyboard_widget.go new file mode 100644 index 00000000..3c216fe5 --- /dev/null +++ b/wtf/keyboard_widget.go @@ -0,0 +1,58 @@ +package wtf + +import ( + "github.com/gdamore/tcell" +) + +// KeyboardWidget manages keyboard control for a widget +type KeyboardWidget struct { + charMap map[string]func() + keyMap map[tcell.Key]func() +} + +// NewKeyboardWidget creates and returns a new instance of KeyboardWidget +func NewKeyboardWidget() KeyboardWidget { + return KeyboardWidget{ + charMap: make(map[string]func()), + keyMap: make(map[tcell.Key]func()), + } +} + +// SetKeyboardChar sets a character/function combination that responds to key presses +// Example: +// +// widget.SetKeyboardChar("d", widget.deleteSelectedItem) +// +func (widget *KeyboardWidget) SetKeyboardChar(char string, fn func()) { + widget.charMap[char] = fn +} + +// SetKeyboardKey sets a tcell.Key/function combination that responds to key presses +// Example: +// +// widget.SetKeyboardKey(tcell.KeyCtrlD, widget.deleteSelectedItem) +// +func (widget *KeyboardWidget) SetKeyboardKey(key tcell.Key, fn func()) { + widget.keyMap[key] = fn +} + +// InputCapture is the function passed to tview's SetInputCapture() function +// This is done during the main widget's creation process using the following code: +// +// widget.View.SetInputCapture(widget.InputCapture) +// +func (widget *KeyboardWidget) InputCapture(event *tcell.EventKey) *tcell.EventKey { + fn := widget.charMap[string(event.Rune())] + if fn != nil { + fn() + return nil + } + + fn = widget.keyMap[event.Key()] + if fn != nil { + fn() + return nil + } + + return event +}