227 lines
6.2 KiB
Go
227 lines
6.2 KiB
Go
package shortcutdialog
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/Bios-Marcel/cordless/shortcuts"
|
|
"github.com/Bios-Marcel/cordless/tview"
|
|
tcell "github.com/gdamore/tcell/v2"
|
|
)
|
|
|
|
const (
|
|
actionCellIndex int = iota
|
|
scopeCellIndex
|
|
shortcutCellIndex
|
|
)
|
|
|
|
// ShortcutTable is a component that displays shortcuts and allows changing
|
|
// them.
|
|
type ShortcutTable struct {
|
|
table *tview.Table
|
|
shortcuts []*shortcuts.Shortcut
|
|
selection int
|
|
focusNext func()
|
|
focusPrevious func()
|
|
}
|
|
|
|
// NewShortcutTable creates a new shortcut table that doesn't contain any data.
|
|
func NewShortcutTable() *ShortcutTable {
|
|
table := tview.NewTable()
|
|
shortcutsTable := &ShortcutTable{
|
|
table: table,
|
|
selection: -1,
|
|
}
|
|
|
|
table.SetSelectable(true, false)
|
|
table.SetBorder(true)
|
|
|
|
//Header + emptyrow
|
|
table.SetFixed(2, 3)
|
|
|
|
table.SetCell(0, actionCellIndex, createHeaderCell("Action"))
|
|
table.SetCell(0, scopeCellIndex, createHeaderCell("Scope"))
|
|
table.SetCell(0, shortcutCellIndex, createHeaderCell("Shortcut"))
|
|
|
|
table.SetInputCapture(shortcutsTable.handleInput)
|
|
|
|
return shortcutsTable
|
|
}
|
|
|
|
// GetPrimitive returns the primitive to be put onto a layout.
|
|
func (shortcutTable *ShortcutTable) GetPrimitive() tview.Primitive {
|
|
return shortcutTable.table
|
|
}
|
|
|
|
func createHeaderCell(text string) *tview.TableCell {
|
|
return tview.NewTableCell(text).
|
|
SetSelectable(false).
|
|
SetAlign(tview.AlignCenter).
|
|
SetExpansion(1).
|
|
SetMaxWidth(1)
|
|
}
|
|
|
|
// SetShortcuts sets the shortcut data and changes the UI accordingly.
|
|
func (shortcutTable *ShortcutTable) SetShortcuts(shortcuts []*shortcuts.Shortcut) {
|
|
shortcutTable.shortcuts = shortcuts
|
|
shortcutTable.selection = -1
|
|
|
|
row, _ := shortcutTable.table.GetFixed()
|
|
|
|
//Using clear will remove the content of the fixed rows, therefore we
|
|
// manually remove starting from the first non-fixed row.
|
|
for index := row; index < shortcutTable.table.GetRowCount(); index++ {
|
|
shortcutTable.table.RemoveRow(index)
|
|
}
|
|
|
|
for _, shortcut := range shortcuts {
|
|
nameCell := tview.NewTableCell(shortcut.Name).
|
|
SetExpansion(1).
|
|
SetMaxWidth(1)
|
|
shortcutTable.table.SetCell(row, actionCellIndex, nameCell)
|
|
|
|
scopeCell := tview.NewTableCell(shortcut.Scope.Name).
|
|
SetExpansion(1).
|
|
SetMaxWidth(1)
|
|
shortcutTable.table.SetCell(row, scopeCellIndex, scopeCell)
|
|
|
|
eventCell := tview.NewTableCell(EventToString(shortcut.Event)).
|
|
SetExpansion(1).
|
|
SetMaxWidth(1)
|
|
shortcutTable.table.SetCell(row, shortcutCellIndex, eventCell)
|
|
|
|
row++
|
|
}
|
|
}
|
|
|
|
// GetShortcuts returns the array containing the currently displayed shortcuts.
|
|
func (shortcutTable *ShortcutTable) GetShortcuts() []*shortcuts.Shortcut {
|
|
return shortcutTable.shortcuts
|
|
}
|
|
|
|
// SetFocusNext decides which component will be focused when hitting tab
|
|
func (shortcutTable *ShortcutTable) SetFocusNext(function func()) {
|
|
shortcutTable.focusNext = function
|
|
}
|
|
|
|
// SetFocusPrevious decides which component will be focused when hitting
|
|
// shift+tab
|
|
func (shortcutTable *ShortcutTable) SetFocusPrevious(function func()) {
|
|
shortcutTable.focusPrevious = function
|
|
}
|
|
|
|
func (shortcutTable *ShortcutTable) handleInput(event *tcell.EventKey) *tcell.EventKey {
|
|
if shortcutTable.selection == -1 {
|
|
if event.Key() == tcell.KeyTab {
|
|
if shortcutTable.focusNext != nil {
|
|
shortcutTable.focusNext()
|
|
}
|
|
} else if event.Key() == tcell.KeyBacktab {
|
|
if shortcutTable.focusPrevious != nil {
|
|
shortcutTable.focusPrevious()
|
|
}
|
|
}
|
|
if event.Key() == tcell.KeyUp || event.Key() == tcell.KeyDown {
|
|
return event
|
|
}
|
|
}
|
|
|
|
firstNonFixedRow, _ := shortcutTable.table.GetFixed()
|
|
selectedRow, _ := shortcutTable.table.GetSelection()
|
|
//The first row of the table isn't the first row containing data
|
|
dataIndex := selectedRow - firstNonFixedRow
|
|
if shortcutTable.selection == -1 && selectedRow >= firstNonFixedRow {
|
|
if event.Key() == tcell.KeyEnter {
|
|
if selectedRow != -1 {
|
|
shortcutTable.table.GetCell(selectedRow, shortcutCellIndex).SetText("[blue][::ub]Hit the desired keycombination")
|
|
shortcutTable.selection = selectedRow
|
|
}
|
|
} else if event.Key() == tcell.KeyRune && event.Rune() == 'r' && event.Modifiers() == tcell.ModNone {
|
|
shortcut := shortcutTable.shortcuts[dataIndex]
|
|
shortcut.Reset()
|
|
shortcutTable.table.GetCell(selectedRow, shortcutCellIndex).SetText(EventToString(shortcut.Event))
|
|
|
|
persistError := shortcuts.Persist()
|
|
if persistError != nil {
|
|
panic(persistError)
|
|
}
|
|
} else if event.Key() == tcell.KeyBackspace || event.Key() == tcell.KeyBackspace2 {
|
|
shortcutTable.table.GetCell(selectedRow, shortcutCellIndex).SetText("")
|
|
shortcutTable.shortcuts[dataIndex].Event = nil
|
|
|
|
persistError := shortcuts.Persist()
|
|
if persistError != nil {
|
|
panic(persistError)
|
|
}
|
|
}
|
|
} else if selectedRow >= firstNonFixedRow && shortcutTable.selection != -1 {
|
|
shortcutTable.table.GetCell(selectedRow, shortcutCellIndex).SetText(EventToString(event))
|
|
|
|
shortcutTable.shortcuts[dataIndex].Event = tcell.NewEventKey(
|
|
event.Key(),
|
|
event.Rune(),
|
|
event.Modifiers())
|
|
|
|
persistError := shortcuts.Persist()
|
|
if persistError != nil {
|
|
panic(persistError)
|
|
}
|
|
|
|
shortcutTable.selection = -1
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// EventToString renders a tcell.EventKey as a human readable string
|
|
func EventToString(event *tcell.EventKey) string {
|
|
if event == nil {
|
|
return ""
|
|
}
|
|
|
|
var m []string
|
|
if event.Modifiers()&tcell.ModCtrl != 0 {
|
|
m = append(m, "Ctrl")
|
|
}
|
|
if event.Modifiers()&tcell.ModShift != 0 {
|
|
m = append(m, "Shift")
|
|
}
|
|
if event.Modifiers()&tcell.ModAlt != 0 {
|
|
m = append(m, "Alt")
|
|
}
|
|
if event.Modifiers()&tcell.ModMeta != 0 {
|
|
m = append(m, "Meta")
|
|
}
|
|
|
|
var (
|
|
s string
|
|
ok bool
|
|
)
|
|
|
|
if s, ok = tcell.KeyNames[event.Key()]; !ok {
|
|
if event.Key() == tcell.KeyRune {
|
|
if event.Rune() >= 'A' && event.Rune() <= 'Z' {
|
|
s = "Shift+" + string(event.Rune())
|
|
} else {
|
|
s = strings.ToUpper(string(event.Rune()))
|
|
}
|
|
} else {
|
|
s = fmt.Sprintf("Key[%d,%d]", event.Key(), int(event.Rune()))
|
|
}
|
|
}
|
|
if len(m) != 0 {
|
|
if event.Modifiers()&tcell.ModCtrl != 0 && strings.HasPrefix(s, "Ctrl-") {
|
|
s = s[5:]
|
|
}
|
|
return fmt.Sprintf("%s+%s", strings.Join(m, "+"), s)
|
|
}
|
|
|
|
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
|
|
}
|