Fixes several focus issues
* When a dialog is open, focus will now be held on the dialog
* Tab / Backtab works again in the shortcuts dialog
* The Chatview now has a separate set of "global" shortcuts. For example
you can't accidentally activate the baremode inside of the shortcut view
anymore.
MODIFY
shortcuts/shortcuts.go
shortcuts/shortcuts.go
@@ -11,6 +11,8 @@ import (
"github.com/gdamore/tcell"
"github.com/Bios-Marcel/cordless/config"
+ "github.com/Bios-Marcel/cordless/tview"
+ "github.com/Bios-Marcel/cordless/ui/tviewutil"
)
var (
@@ -372,3 +374,19 @@ func Persist() error {
return nil
}
+
+func DirectionalFocusHandling(event *tcell.EventKey, app *tview.Application) *tcell.EventKey {
+ focused := app.GetFocus()
+ if FocusUp.Equals(event) {
+ tviewutil.FocusNextIfPossible(tview.Up, app, focused)
+ } else if FocusDown.Equals(event) {
+ tviewutil.FocusNextIfPossible(tview.Down, app, focused)
+ } else if FocusLeft.Equals(event) {
+ tviewutil.FocusNextIfPossible(tview.Left, app, focused)
+ } else if FocusRight.Equals(event) {
+ tviewutil.FocusNextIfPossible(tview.Right, app, focused)
+ } else {
+ return event
+ }
+ return nil
+}

MODIFY
tools/layout/main.go
tools/layout/main.go
@@ -65,7 +65,7 @@ func (c *CoreLayout) SetRect(x, y, width, height int) {
c.height = height
}
-func (c *CoreLayout) InputHandler() func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
+func (c *CoreLayout) InputHandler() tview.InputHandlerFunc {
panic("implement me")
}
@@ -93,6 +93,14 @@ func (c *CoreLayout) NextFocusableComponent(direction tview.FocusDirection) tvie
panic("implement me")
}
+func (c *CoreLayout) SetParent(parent tview.Primitive) {
+ //Do nothing
+}
+
+func (c *CoreLayout) GetParent() tview.Primitive {
+ return nil
+}
+
func NewDemoComponent(r rune) *demoComponent {
return &demoComponent{visible: true, fillWith: r}
}
@@ -144,9 +152,9 @@ func (d *demoComponent) SetRect(x, y, width, height int) {
d.height = height
}
-func (d *demoComponent) InputHandler() func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
- return func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
-
+func (d *demoComponent) InputHandler() tview.InputHandlerFunc {
+ return func(event *tcell.EventKey, setFocus func(p tview.Primitive)) *tcell.EventKey {
+ return event
}
}
@@ -173,3 +181,11 @@ func (d *demoComponent) GetFocusable() tview.Focusable {
func (d *demoComponent) NextFocusableComponent(direction tview.FocusDirection) tview.Primitive {
return nil
}
+
+func (d *demoComponent) SetParent(parent tview.Primitive) {
+ //Do nothing
+}
+
+func (d *demoComponent) GetParent() tview.Primitive {
+ return nil
+}

RENAME
ui/tviewutil/dialogs.go
ui/dialogs.go
-package tviewutil
+package ui
import (
"github.com/Bios-Marcel/cordless/shortcuts"

MODIFY
ui/shortcutdialog/dialog.go
ui/shortcutdialog/dialog.go
@@ -20,8 +20,6 @@ func ShowShortcutsDialog(app *tview.Application, onClose func()) {
table = NewShortcutTable()
table.SetShortcuts(shortcuts.Shortcuts)
- table.SetOnClose(onClose)
-
exitButton = tview.NewButton("Go back")
exitButton.SetSelectedFunc(onClose)
exitButton.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
@@ -29,11 +27,11 @@ func ShowShortcutsDialog(app *tview.Application, onClose func()) {
app.SetFocus(table.GetPrimitive())
} else if event.Key() == tcell.KeyBacktab {
app.SetFocus(resetButton)
- } else if event.Key() == tcell.KeyESC {
- onClose()
+ } else {
+ return event
}
- return event
+ return nil
})
resetButton = tview.NewButton("Restore all defaults")
@@ -51,11 +49,11 @@ func ShowShortcutsDialog(app *tview.Application, onClose func()) {
app.SetFocus(exitButton)
} else if event.Key() == tcell.KeyBacktab {
app.SetFocus(table.GetPrimitive())
- } else if event.Key() == tcell.KeyESC {
- onClose()
+ } else {
+ return event
}
- return event
+ return nil
})
primitiveBGColor := tviewutil.ColorToHex(config.GetTheme().PrimitiveBackgroundColor)
@@ -86,7 +84,18 @@ func ShowShortcutsDialog(app *tview.Application, onClose func()) {
shortcutsView := tview.NewFlex()
shortcutsView.SetDirection(tview.FlexRow)
+ shortcutsView.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
+ if table.IsDefiningShortcut() {
+ return event
+ }
+
+ if event.Key() == tcell.KeyESC {
+ onClose()
+ return nil
+ }
+ return event
+ })
shortcutsView.AddItem(table.GetPrimitive(), 0, 1, false)
shortcutsView.AddItem(buttonBar, 1, 0, false)
shortcutsView.AddItem(shortcutDescription, 2, 0, false)

MODIFY
ui/shortcutdialog/table.go
ui/shortcutdialog/table.go
@@ -20,7 +20,6 @@ const (
type ShortcutTable struct {
table *tview.Table
shortcuts []*shortcuts.Shortcut
- onClose func()
selection int
focusNext func()
focusPrevious func()
@@ -116,13 +115,6 @@ func (shortcutTable *ShortcutTable) SetFocusPrevious(function func()) {
func (shortcutTable *ShortcutTable) handleInput(event *tcell.EventKey) *tcell.EventKey {
if shortcutTable.selection == -1 {
- if event.Key() == tcell.KeyESC {
- if shortcutTable.onClose != nil {
- shortcutTable.onClose()
- }
- return nil
- }
-
if event.Key() == tcell.KeyTab {
if shortcutTable.focusNext != nil {
shortcutTable.focusNext()
@@ -132,7 +124,6 @@ func (shortcutTable *ShortcutTable) handleInput(event *tcell.EventKey) *tcell.Ev
shortcutTable.focusPrevious()
}
}
-
if event.Key() == tcell.KeyUp || event.Key() == tcell.KeyDown {
return event
}
@@ -185,12 +176,6 @@ func (shortcutTable *ShortcutTable) handleInput(event *tcell.EventKey) *tcell.Ev
return nil
}
-// SetOnClose sets the handler that will be run when someone attempts closing
-// the shortcuts table.
-func (shortcutTable *ShortcutTable) SetOnClose(onClose func()) {
- shortcutTable.onClose = onClose
-}
-
// EventToString renders a tcell.EventKey as a human readable string
func EventToString(event *tcell.EventKey) string {
if event == nil {
@@ -236,3 +221,9 @@ func EventToString(event *tcell.EventKey) string {
return tview.Escape(s)
}
+
+// IsDefiningShortcut indicates whether the user is currently selecting a
+// shortcut for any function.
+func (shortcutTable *ShortcutTable) IsDefiningShortcut() bool {
+ return shortcutTable.selection != -1
+}

ADD
ui/tviewutil/focus.go
+package tviewutil
+
+import "github.com/Bios-Marcel/cordless/tview"
+
+func FocusNextIfPossible(direction tview.FocusDirection, app *tview.Application, focused tview.Primitive) {
+ if focused == nil {
+ return
+ }
+
+ focusNext := focused.NextFocusableComponent(direction)
+ if focusNext != nil {
+ app.SetFocus(focusNext)
+ }
+}

MODIFY
ui/window.go
ui/window.go
@@ -890,8 +890,9 @@ func NewWindow(doRestart chan bool, app *tview.Application, session *discordgo.S
window.rootContainer.AddItem(bottomBar, 1, 0, false)
}
- app.SetRoot(window.rootContainer, true)
+ window.rootContainer.SetInputCapture(window.handleChatWindowShortcuts)
app.SetInputCapture(window.handleGlobalShortcuts)
+ app.SetRoot(window.rootContainer, true)
if config.Current.UseFixedLayout {
window.middleContainer.AddItem(window.leftArea, config.Current.FixedSizeLeft, 0, true)
@@ -925,11 +926,6 @@ func NewWindow(doRestart chan bool, app *tview.Application, session *discordgo.S
window.SwitchToGuildsPage()
- app.SetFocusDirectionHandler(tview.Up, shortcuts.FocusUp.Equals)
- app.SetFocusDirectionHandler(tview.Down, shortcuts.FocusDown.Equals)
- app.SetFocusDirectionHandler(tview.Left, shortcuts.FocusLeft.Equals)
- app.SetFocusDirectionHandler(tview.Right, shortcuts.FocusRight.Equals)
-
window.messageInput.internalTextView.SetNextFocusableComponents(tview.Up, window.chatView.internalTextView)
window.messageInput.internalTextView.SetNextFocusableComponents(tview.Down, window.commandView.commandOutput, window.chatView.internalTextView)
window.messageInput.internalTextView.SetNextFocusableComponents(tview.Right, window.userList.internalTreeView, window.channelTree, window.privateList.internalTreeView)
@@ -1509,6 +1505,7 @@ func (window *Window) ShowDialog(color tcell.Color, text string, buttonHandler f
buttonHandler(newButton.GetLabel())
window.dialogReplacement.SetVisible(false)
window.app.SetFocus(previousFocus)
+ window.app.ForceDraw()
})
buttonWidgets = append(buttonWidgets, newButton)
@@ -2162,32 +2159,33 @@ func (window *Window) handleGlobalShortcuts(event *tcell.EventKey) *tcell.EventK
window.userActiveTimer.Reset(time.Duration(config.Current.DesktopNotificationsUserInactivityThreshold) * time.Second)
}
- if shortcuts.ToggleBareChat.Equals(event) {
- window.toggleBareChat()
- return nil
+ return event
}
- //This two have to work in baremode as well, since otherwise only the mouse
- //can be used for focus switching, which sucks in a terminal app.
- if shortcuts.FocusMessageInput.Equals(event) {
- window.app.SetFocus(window.messageInput.GetPrimitive())
- return nil
+func (window *Window) handleChatWindowShortcuts(event *tcell.EventKey) *tcell.EventKey {
+ if window.dialogReplacement.IsVisible() {
+ //Delegate to focused component which is the dialog.
+ //We do this, cause we don't want people to focus anything else than
+ //the dialog.
+ return event
}
- if shortcuts.FocusMessageContainer.Equals(event) {
- window.app.SetFocus(window.chatView.internalTextView)
+ if event.Key() == tcell.KeyCtrlE {
+ window.ShowErrorDialog("Oopsie woopsie")
return nil
}
- if window.app.GetRoot() != window.rootContainer {
- return event
- }
-
- if window.dialogReplacement.IsVisible() {
- return event
+ if shortcuts.DirectionalFocusHandling(event, window.app) == nil {
+ return nil
}
- if shortcuts.EventsEqual(event, shortcutsDialogShortcut) {
+ if shortcuts.ToggleBareChat.Equals(event) {
+ window.toggleBareChat()
+ } else if shortcuts.FocusMessageInput.Equals(event) {
+ window.app.SetFocus(window.messageInput.GetPrimitive())
+ } else if shortcuts.FocusMessageContainer.Equals(event) {
+ window.app.SetFocus(window.chatView.internalTextView)
+ } else if shortcuts.EventsEqual(event, shortcutsDialogShortcut) {
shortcutdialog.ShowShortcutsDialog(window.app, func() {
window.app.SetRoot(window.rootContainer, true)
window.app.ForceDraw()
@@ -2619,6 +2617,8 @@ func (window *Window) LoadChannel(channel *discordgo.Channel) error {
}
discordutil.SortMessagesByTimestamp(messages)
+ //FIXME Only slow function here. 200-500 MS depending on content.
+ //That's horrible!
window.chatView.SetMessages(messages)
window.chatView.internalTextView.ScrollToEnd()
window.UpdateChatHeader(channel)
@@ -2700,7 +2700,7 @@ func (window *Window) GetSelectedChannel() *discordgo.Channel {
// PromptSecretInput shows a fullscreen input dialog that masks the user input.
// The returned value will either be empty or what the user has entered.
func (window *Window) PromptSecretInput(title, message string) string {
- return tviewutil.PrompSecretSingleLineInput(window.app, title, message)
+ return PrompSecretSingleLineInput(window.app, title, message)
}
// ForceRedraw triggers ForceDraw on the underlying tview application, causing

Fixes several focus issues

* When a dialog is open, focus will now be held on the dialog
* Tab / Backtab works again in the shortcuts dialog
* The Chatview now has a separate set of "global" shortcuts. For example
you can't accidentally activate the baremode inside of the shortcut view
anymore.