mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
Make every widget a keyboard widget
Signed-off-by: Chris Cummer <chriscummer@me.com>
This commit is contained in:
@@ -16,6 +16,8 @@ type BarGraph struct {
|
||||
starChar string
|
||||
|
||||
Base
|
||||
KeyboardWidget
|
||||
|
||||
View *tview.TextView
|
||||
}
|
||||
|
||||
@@ -30,7 +32,8 @@ type Bar struct {
|
||||
// NewBarGraph creates and returns an instance of BarGraph
|
||||
func NewBarGraph(app *tview.Application, name string, commonSettings *cfg.Common) BarGraph {
|
||||
widget := BarGraph{
|
||||
Base: NewBase(app, commonSettings),
|
||||
Base: NewBase(app, commonSettings),
|
||||
KeyboardWidget: NewKeyboardWidget(app, nil, commonSettings),
|
||||
|
||||
maxStars: commonSettings.Config.UInt("graphStars", 20),
|
||||
starChar: commonSettings.Config.UString("graphIcon", "|"),
|
||||
|
||||
12
view/base.go
12
view/base.go
@@ -23,20 +23,24 @@ type Base struct {
|
||||
enabledMutex *sync.Mutex
|
||||
}
|
||||
|
||||
// NewBase creates and returns an instance of the Base module, the lowest-level
|
||||
// primitive module from which all others are derived
|
||||
func NewBase(app *tview.Application, commonSettings *cfg.Common) Base {
|
||||
base := Base{
|
||||
commonSettings: commonSettings,
|
||||
commonSettings: commonSettings,
|
||||
|
||||
app: app,
|
||||
bordered: commonSettings.Bordered,
|
||||
enabled: commonSettings.Enabled,
|
||||
enabledMutex: &sync.Mutex{},
|
||||
focusChar: commonSettings.FocusChar(),
|
||||
focusable: commonSettings.Focusable,
|
||||
name: commonSettings.Name,
|
||||
quitChan: make(chan bool),
|
||||
refreshInterval: commonSettings.RefreshInterval,
|
||||
refreshing: false,
|
||||
enabledMutex: &sync.Mutex{},
|
||||
}
|
||||
|
||||
return base
|
||||
}
|
||||
|
||||
@@ -108,10 +112,6 @@ func (base *Base) FocusChar() string {
|
||||
return base.focusChar
|
||||
}
|
||||
|
||||
func (base *Base) HelpText() string {
|
||||
return fmt.Sprintf("\n There is no help available for widget %s", base.commonSettings.Module.Type)
|
||||
}
|
||||
|
||||
func (base *Base) Name() string {
|
||||
return base.name
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
"github.com/wtfutil/wtf/utils"
|
||||
)
|
||||
|
||||
const refreshKeyChar = "r"
|
||||
|
||||
type helpItem struct {
|
||||
Key string
|
||||
Text string
|
||||
@@ -41,9 +43,69 @@ func NewKeyboardWidget(app *tview.Application, pages *tview.Pages, settings *cfg
|
||||
keyHelp: []helpItem{},
|
||||
}
|
||||
|
||||
keyWidget.initializeCommonKeyboardControls()
|
||||
|
||||
return keyWidget
|
||||
}
|
||||
|
||||
/* -------------------- Exported Functions --------------------- */
|
||||
|
||||
// HelpText returns the help text and keyboard command info for this widget
|
||||
func (widget *KeyboardWidget) HelpText() string {
|
||||
str := " [green::b]Keyboard commands for " + strings.Title(widget.settings.Module.Type) + "[white]\n\n"
|
||||
|
||||
for _, item := range widget.charHelp {
|
||||
str += fmt.Sprintf(" %s\t%s\n", item.Key, item.Text)
|
||||
}
|
||||
|
||||
str += "\n\n"
|
||||
|
||||
for _, item := range widget.keyHelp {
|
||||
str += fmt.Sprintf(" %-*s\t%s\n", widget.maxKey, item.Key, item.Text)
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
// InitializeRefreshKeyboardControl assigns the module's explicit refresh function to
|
||||
// the commom refresh key value
|
||||
func (widget *KeyboardWidget) InitializeRefreshKeyboardControl(refreshFunc func()) {
|
||||
if refreshFunc != nil {
|
||||
widget.SetKeyboardChar(refreshKeyChar, refreshFunc, "Refresh widget")
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if event == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// LaunchDocumentation opens the module docs in a browser
|
||||
func (widget *KeyboardWidget) LaunchDocumentation() {
|
||||
url := "https://wtfutil.com/modules/" + widget.settings.Name
|
||||
utils.OpenFile(url)
|
||||
}
|
||||
|
||||
// SetKeyboardChar sets a character/function combination that responds to key presses
|
||||
// Example:
|
||||
//
|
||||
@@ -77,64 +139,6 @@ func (widget *KeyboardWidget) SetKeyboardKey(key tcell.Key, fn func(), helpText
|
||||
}
|
||||
}
|
||||
|
||||
// InitializeCommonControls sets up the keyboard controls that are common to
|
||||
// all widgets that accept keyboard input
|
||||
func (widget *KeyboardWidget) InitializeCommonControls(refreshFunc func()) {
|
||||
widget.SetKeyboardChar("/", widget.ShowHelp, "Show/hide this help prompt")
|
||||
widget.SetKeyboardChar("\\", widget.OpenDocs, "Open the docs in a browser")
|
||||
|
||||
if refreshFunc != nil {
|
||||
widget.SetKeyboardChar("r", refreshFunc, "Refresh widget")
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if event == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// HelpText returns the help text and keyboard command info for this widget
|
||||
func (widget *KeyboardWidget) HelpText() string {
|
||||
str := " [green::b]Keyboard commands for " + strings.Title(widget.settings.Module.Type) + "[white]\n\n"
|
||||
|
||||
for _, item := range widget.charHelp {
|
||||
str += fmt.Sprintf(" %s\t%s\n", item.Key, item.Text)
|
||||
}
|
||||
str += "\n\n"
|
||||
|
||||
for _, item := range widget.keyHelp {
|
||||
str += fmt.Sprintf(" %-*s\t%s\n", widget.maxKey, item.Key, item.Text)
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
// OpenDocs opens the module docs in a browser
|
||||
func (widget *KeyboardWidget) OpenDocs() {
|
||||
url := "https://wtfutil.com/modules/" + widget.settings.Name
|
||||
utils.OpenFile(url)
|
||||
}
|
||||
|
||||
// SetView assigns the passed-in tview.TextView view to this widget
|
||||
func (widget *KeyboardWidget) SetView(view *tview.TextView) {
|
||||
widget.view = view
|
||||
@@ -142,6 +146,10 @@ func (widget *KeyboardWidget) SetView(view *tview.TextView) {
|
||||
|
||||
// ShowHelp displays the modal help dialog for a module
|
||||
func (widget *KeyboardWidget) ShowHelp() {
|
||||
if widget.pages == nil {
|
||||
return
|
||||
}
|
||||
|
||||
closeFunc := func() {
|
||||
widget.pages.RemovePage("help")
|
||||
widget.app.SetFocus(widget.view)
|
||||
@@ -156,3 +164,12 @@ func (widget *KeyboardWidget) ShowHelp() {
|
||||
widget.app.Draw()
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------- Unexported Functions -------------------- */
|
||||
|
||||
// initializeCommonKeyboardControls sets up the keyboard controls that are common to
|
||||
// all widgets that accept keyboard input
|
||||
func (widget *KeyboardWidget) initializeCommonKeyboardControls() {
|
||||
widget.SetKeyboardChar("/", widget.ShowHelp, "Show/hide this help prompt")
|
||||
widget.SetKeyboardChar("\\", widget.LaunchDocumentation, "Open the documentation for this module in a browser")
|
||||
}
|
||||
|
||||
@@ -174,18 +174,26 @@ func Test_InputCapture(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func Test_InitializeCommonControls(t *testing.T) {
|
||||
func Test_initializeCommonKeyboardControls(t *testing.T) {
|
||||
t.Run("nil refreshFunc", func(t *testing.T) {
|
||||
keyWid := testKeyboardWidget()
|
||||
keyWid.InitializeCommonControls(nil)
|
||||
|
||||
assert.NotNil(t, keyWid.charMap["/"])
|
||||
assert.NotNil(t, keyWid.charMap["\\"])
|
||||
})
|
||||
}
|
||||
|
||||
func Test_InitializeRefreshKeyboardControl(t *testing.T) {
|
||||
t.Run("nil refreshFunc", func(t *testing.T) {
|
||||
keyWid := testKeyboardWidget()
|
||||
keyWid.InitializeRefreshKeyboardControl(nil)
|
||||
|
||||
assert.Nil(t, keyWid.charMap["r"])
|
||||
})
|
||||
|
||||
t.Run("non-nil refreshFunc", func(t *testing.T) {
|
||||
keyWid := testKeyboardWidget()
|
||||
keyWid.InitializeCommonControls(func() {})
|
||||
keyWid.InitializeRefreshKeyboardControl(func() {})
|
||||
|
||||
assert.NotNil(t, keyWid.charMap["r"])
|
||||
})
|
||||
|
||||
@@ -15,9 +15,9 @@ type ScrollableWidget struct {
|
||||
RenderFunction func()
|
||||
}
|
||||
|
||||
func NewScrollableWidget(app *tview.Application, commonSettings *cfg.Common) ScrollableWidget {
|
||||
func NewScrollableWidget(app *tview.Application, pages *tview.Pages, commonSettings *cfg.Common) ScrollableWidget {
|
||||
widget := ScrollableWidget{
|
||||
TextWidget: NewTextWidget(app, commonSettings),
|
||||
TextWidget: NewTextWidget(app, pages, commonSettings),
|
||||
}
|
||||
|
||||
widget.Unselect()
|
||||
@@ -84,7 +84,7 @@ func (widget *ScrollableWidget) Unselect() {
|
||||
func (widget *ScrollableWidget) Redraw(data func() (string, string, bool)) {
|
||||
widget.TextWidget.Redraw(data)
|
||||
|
||||
widget.app.QueueUpdateDraw(func() {
|
||||
widget.Base.app.QueueUpdateDraw(func() {
|
||||
widget.View.Highlight(strconv.Itoa(widget.Selected)).ScrollToHighlight()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -11,36 +11,39 @@ import (
|
||||
// TextWidget defines the data necessary to make a text widget
|
||||
type TextWidget struct {
|
||||
Base
|
||||
KeyboardWidget
|
||||
|
||||
View *tview.TextView
|
||||
}
|
||||
|
||||
// NewTextWidget creates and returns an instance of TextWidget
|
||||
func NewTextWidget(app *tview.Application, commonSettings *cfg.Common) TextWidget {
|
||||
func NewTextWidget(app *tview.Application, pages *tview.Pages, commonSettings *cfg.Common) TextWidget {
|
||||
widget := TextWidget{
|
||||
Base: NewBase(app, commonSettings),
|
||||
Base: NewBase(app, commonSettings),
|
||||
KeyboardWidget: NewKeyboardWidget(app, pages, commonSettings),
|
||||
}
|
||||
|
||||
widget.View = widget.createView(widget.bordered)
|
||||
widget.View.SetInputCapture(widget.InputCapture)
|
||||
|
||||
return widget
|
||||
}
|
||||
|
||||
/* -------------------- Exported Functions -------------------- */
|
||||
|
||||
// TextView returns the tview.TextView instance
|
||||
func (widget *TextWidget) TextView() *tview.TextView {
|
||||
return widget.View
|
||||
}
|
||||
|
||||
func (widget *TextWidget) Redraw(data func() (string, string, bool)) {
|
||||
widget.app.QueueUpdateDraw(func() {
|
||||
widget.Base.app.QueueUpdateDraw(func() {
|
||||
title, content, wrap := data()
|
||||
|
||||
widget.View.Clear()
|
||||
widget.View.SetWrap(wrap)
|
||||
widget.View.SetTitle(widget.ContextualTitle(title))
|
||||
// widget.View.SetText(strings.TrimSpace(content))
|
||||
widget.View.SetText(strings.TrimRight(content, "\n"))
|
||||
// widget.View.SetText(content)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
func testTextWidget() TextWidget {
|
||||
txtWid := NewTextWidget(
|
||||
tview.NewApplication(),
|
||||
tview.NewPages(),
|
||||
&cfg.Common{
|
||||
Module: cfg.Module{
|
||||
Name: "test widget",
|
||||
|
||||
Reference in New Issue
Block a user