From d63e3a414ad7daa9c95799fa0f640d145964485e Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Sun, 26 Oct 2025 08:47:07 -0500 Subject: [PATCH] Reworking Keymaps --- keymap.go | 160 ++++++++++++++++++++++++++-------------- wdgt_absolute_layout.go | 15 +--- wdgt_alert.go | 47 +++--------- wdgt_asciiarttext.go | 18 ++--- wdgt_blank.go | 20 ++--- wdgt_bordered.go | 10 +-- wdgt_buffer.go | 14 +--- wdgt_button.go | 35 ++------- wdgt_chat.go | 65 ++++++---------- wdgt_checkbox.go | 39 +++------- wdgt_cli.go | 67 +++++++---------- wdgt_datepicker.go | 53 +++++-------- wdgt_debug.go | 14 +--- wdgt_field.go | 39 +++------- wdgt_filepicker.go | 25 +------ wdgt_form.go | 25 +------ wdgt_linear_layout.go | 30 ++------ wdgt_menu.go | 40 +++------- wdgt_menu_item.go | 36 +++------ wdgt_prompt.go | 24 +----- wdgt_relative_layout.go | 14 +--- wdgt_searcher.go | 50 ++++--------- wdgt_shrinkwrap.go | 6 +- wdgt_simple_list.go | 108 ++++++++++++--------------- wdgt_spinner.go | 16 ++-- wdgt_table.go | 24 +----- wdgt_text.go | 15 +--- wdgt_timefield.go | 34 +++------ wdgt_top_menu_layout.go | 46 ++++-------- widget.go | 10 +-- 30 files changed, 384 insertions(+), 715 deletions(-) diff --git a/keymap.go b/keymap.go index 799b7dd..ea8b6c9 100644 --- a/keymap.go +++ b/keymap.go @@ -23,71 +23,119 @@ package widgets import "github.com/gdamore/tcell" +type Key struct { + ev *tcell.EventKey + do []func(*tcell.EventKey) bool + desc string +} + +func BuildEK(k tcell.Key) *tcell.EventKey { return tcell.NewEventKey(k, 0, 0) } +func BuildEKr(r rune) *tcell.EventKey { return tcell.NewEventKey(tcell.KeyRune, r, 0) } + +func NewKey(ev *tcell.EventKey, do func(*tcell.EventKey) bool) *Key { + return &Key{ + ev: ev, + do: []func(*tcell.EventKey) bool{do}, + } +} + +func (k *Key) AddBinding(do func(*tcell.EventKey) bool) *Key { + k.do = append(k.do, do) + return k +} + +func (k *Key) SetDescription(d string) *Key { + k.desc = d + return k +} + +func (k *Key) Matches(ev *tcell.EventKey) bool { + return k.ev.Key() == ev.Key() && + k.ev.Rune() == ev.Rune() && + k.ev.Modifiers() == ev.Modifiers() +} + +func (k *Key) Handle(ev *tcell.EventKey) bool { + if !k.Matches(ev) { + return false + } + var cons bool + for _, d := range k.do { + cons = cons || d(ev) + } + return cons +} + type KeyMap struct { - Keys map[tcell.Key]func(*tcell.EventKey) bool - Runes map[rune]func(*tcell.EventKey) bool + Keys []*Key } -func BlankKeyMap() KeyMap { - return KeyMap{ - Keys: make(map[tcell.Key]func(*tcell.EventKey) bool), - Runes: make(map[rune]func(*tcell.EventKey) bool), +func BlankKeyMap() *KeyMap { return &KeyMap{} } +func NewKeyMap(k *Key, rest ...*Key) *KeyMap { + ret := &KeyMap{} + return ret +} + +// Search through 'Keys', and return all that matches +func (m *KeyMap) Get(k *Key) *Key { + for _, key := range m.Keys { + if k.Matches(key.ev) { + return key + } + } + return nil +} + +func (m *KeyMap) Merge(n *KeyMap) { + switch len(n.Keys) { + case 0: + return + case 1: + m.Add(n.Keys[0]) + default: + m.Add(n.Keys[0], n.Keys[1:]...) } } -func NewKeyMap(m map[tcell.Key]func(*tcell.EventKey) bool) KeyMap { - return KeyMap{ - Keys: m, - Runes: make(map[rune]func(*tcell.EventKey) bool), - } -} - -func NewRuneMap(m map[rune]func(*tcell.EventKey) bool) KeyMap { - return KeyMap{ - Keys: make(map[tcell.Key]func(*tcell.EventKey) bool), - Runes: m, - } -} - -func (m KeyMap) Merge(km KeyMap) { - for k, v := range km.Keys { - m.Keys[k] = v - } - for r, v := range km.Runes { - m.Runes[r] = v - } -} - -func (m KeyMap) Add(k tcell.Key, do func(*tcell.EventKey) bool) { m.Keys[k] = do } -func (m KeyMap) Remove(k tcell.Key) { delete(m.Keys, k) } - -func (m KeyMap) AddAll(all map[tcell.Key]func(*tcell.EventKey) bool) { - for k, v := range all { - m.Add(k, v) - } -} -func (m KeyMap) AddRune(k rune, do func(*tcell.EventKey) bool) { m.Runes[k] = do } -func (m KeyMap) RemoveRune(k rune) { delete(m.Runes, k) } - -func (m KeyMap) AddRunes(all map[rune]func(*tcell.EventKey) bool) { - for k, v := range all { - m.AddRune(k, v) - } -} - -func (m KeyMap) Handle(ev *tcell.EventKey) bool { - if ev.Key() == tcell.KeyRune { - for k, v := range m.Runes { - if ev.Rune() == k { - return v(ev) - } +func (m *KeyMap) Add(k *Key, rest ...*Key) { + p := m.Get(k) + if p != nil { + for dIdx := range k.do { + p.AddBinding(k.do[dIdx]) + } + if k.desc != "" { + p.SetDescription(k.desc) } } else { - for k, v := range m.Keys { - if ev.Key() == k { - return v(ev) + m.Keys = append(m.Keys, k) + } +} + +func (m *KeyMap) Remove(k *Key, rest ...*Key) { + do := func(k *Key) { + idx := -1 + for i := range m.Keys { + if m.Keys[i].Matches(k.ev) { + idx = i + break } } + if idx == -1 { + return + } + m.Keys = append(m.Keys[:idx], m.Keys[idx+1:]...) + } + + do(k) + for i := range rest { + do(rest[i]) } - return false +} + +func (m *KeyMap) Handle(ev *tcell.EventKey) bool { + var cons bool + for _, k := range m.Keys { + cons = cons || k.Handle(ev) + } + return cons } diff --git a/wdgt_absolute_layout.go b/wdgt_absolute_layout.go index 686553c..1b37eb3 100644 --- a/wdgt_absolute_layout.go +++ b/wdgt_absolute_layout.go @@ -45,7 +45,7 @@ type AbsoluteLayout struct { visible bool focusable bool - keyMap KeyMap + keyMap *KeyMap cursor int disableTab bool @@ -80,17 +80,8 @@ func (w *AbsoluteLayout) HandleResize(ev *tcell.EventResize) { w.updateWidgetLayouts() } -// AbsoluteLayout doesn't have a default keymap -func (w *AbsoluteLayout) SetKeyMap(km KeyMap, def bool) { w.keyMap = km } -func (w *AbsoluteLayout) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) } -func (w *AbsoluteLayout) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.keyMap.Remove(k) - } - for r := range km.Runes { - w.keyMap.RemoveRune(r) - } -} +func (w *AbsoluteLayout) GetKeyMap() *KeyMap { return w.keyMap } +func (w *AbsoluteLayout) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *AbsoluteLayout) HandleKey(ev *tcell.EventKey) bool { if !w.disableTab && ev.Key() == tcell.KeyTab { diff --git a/wdgt_alert.go b/wdgt_alert.go index 8fa6486..ce0e42a 100644 --- a/wdgt_alert.go +++ b/wdgt_alert.go @@ -44,7 +44,7 @@ type Alert struct { btnLayout *LinearLayout btnOk, btnCancel *Button - keyMap, customKeyMap KeyMap + keyMap *KeyMap logger func(string, ...any) } @@ -82,15 +82,14 @@ func (w *Alert) Init(id string, style tcell.Style) { w.btnOk.SetActive(true) w.btnLayout.Add(w.btnOk) - w.keyMap = NewKeyMap(map[tcell.Key]func(ev *tcell.EventKey) bool{ - tcell.KeyTab: w.SelectNext, - tcell.KeyRight: w.SelectNext, - tcell.KeyDown: w.SelectNext, - tcell.KeyLeft: w.SelectNext, - tcell.KeyUp: w.SelectNext, - tcell.KeyEnter: w.Do, - }) - w.customKeyMap = BlankKeyMap() + w.keyMap = NewKeyMap( + NewKey(BuildEK(tcell.KeyTab), w.SelectNext), + NewKey(BuildEK(tcell.KeyRight), w.SelectNext), + NewKey(BuildEK(tcell.KeyDown), w.SelectNext), + NewKey(BuildEK(tcell.KeyLeft), w.SelectNext), + NewKey(BuildEK(tcell.KeyUp), w.SelectNext), + NewKey(BuildEK(tcell.KeyEnter), w.Do), + ) w.focusable = true } func (w *Alert) Id() string { return w.id } @@ -101,36 +100,14 @@ func (w *Alert) HandleResize(ev *tcell.EventResize) { w.layout.HandleResize(tcell.NewEventResize(w.w-2, w.h-2)) } -func (w *Alert) SetKeyMap(km KeyMap, def bool) { - if def { - w.keyMap = km - } else { - w.customKeyMap = km - } -} - -func (w *Alert) AddToKeyMap(km KeyMap) { - w.customKeyMap.Merge(km) -} - -func (w *Alert) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.keyMap.Remove(k) - w.customKeyMap.Remove(k) - } - for r := range km.Runes { - w.keyMap.RemoveRune(r) - w.customKeyMap.RemoveRune(r) - } -} +func (w *Alert) GetKeyMap() *KeyMap { return w.keyMap } +func (w *Alert) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *Alert) HandleKey(ev *tcell.EventKey) bool { if !w.active { return false } - b1 := w.keyMap.Handle(ev) - b2 := w.customKeyMap.Handle(ev) - return b1 || b2 + return w.keyMap.Handle(ev) } func (w *Alert) HandleTime(ev *tcell.EventTime) { diff --git a/wdgt_asciiarttext.go b/wdgt_asciiarttext.go index 2af2bb7..cc0b8cd 100644 --- a/wdgt_asciiarttext.go +++ b/wdgt_asciiarttext.go @@ -44,7 +44,7 @@ type ArtWidget struct { font string text string - keyMap KeyMap + keyMap *KeyMap allFonts []ArtWidgetFont currFont ArtWidgetFont @@ -69,18 +69,10 @@ func (w *ArtWidget) Init(id string, st tcell.Style) { } func (w *ArtWidget) Id() string { return w.id } func (w *ArtWidget) HandleResize(ev *tcell.EventResize) { w.w, w.h = ev.Size() } -func (w *ArtWidget) SetKeyMap(km KeyMap, def bool) { w.keyMap = km } -func (w *ArtWidget) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) } -func (w *ArtWidget) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.keyMap.Remove(k) - } - for r := range km.Runes { - w.keyMap.RemoveRune(r) - } -} -func (w *ArtWidget) HandleKey(ev *tcell.EventKey) bool { return false } -func (w *ArtWidget) HandleTime(ev *tcell.EventTime) {} +func (w *ArtWidget) GetKeyMap() *KeyMap { return w.keyMap } +func (w *ArtWidget) SetKeyMap(km *KeyMap) { w.keyMap = km } +func (w *ArtWidget) HandleKey(ev *tcell.EventKey) bool { return false } +func (w *ArtWidget) HandleTime(ev *tcell.EventTime) {} func (w *ArtWidget) Draw(screen tcell.Screen) { if !w.visible { return diff --git a/wdgt_blank.go b/wdgt_blank.go index 102daf7..43c7d86 100644 --- a/wdgt_blank.go +++ b/wdgt_blank.go @@ -27,7 +27,7 @@ import "github.com/gdamore/tcell" type BlankWidget struct { id string x, y int - keyMap KeyMap + keyMap *KeyMap wantH, wantW int } @@ -45,19 +45,11 @@ func NewBlankWidget(id string) *BlankWidget { func (w *BlankWidget) Init(id string, st tcell.Style) { w.keyMap = BlankKeyMap() } func (w *BlankWidget) Id() string { return w.id } func (w *BlankWidget) HandleResize(ev *tcell.EventResize) {} -func (w *BlankWidget) SetKeyMap(km KeyMap, def bool) { w.keyMap = km } -func (w *BlankWidget) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) } -func (w *BlankWidget) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.keyMap.Remove(k) - } - for r := range km.Runes { - w.keyMap.RemoveRune(r) - } -} -func (w *BlankWidget) HandleKey(ev *tcell.EventKey) bool { return false } -func (w *BlankWidget) HandleTime(ev *tcell.EventTime) {} -func (w *BlankWidget) Draw(screen tcell.Screen) {} +func (w *BlankWidget) GetKeyMap() *KeyMap { return w.keyMap } +func (w *BlankWidget) SetKeyMap(km *KeyMap) { w.keyMap = km } +func (w *BlankWidget) HandleKey(ev *tcell.EventKey) bool { return false } +func (w *BlankWidget) HandleTime(ev *tcell.EventTime) {} +func (w *BlankWidget) Draw(screen tcell.Screen) {} func (w *BlankWidget) Active() bool { return false } func (w *BlankWidget) SetActive(a bool) {} diff --git a/wdgt_bordered.go b/wdgt_bordered.go index 8ed2778..5bd2cf2 100644 --- a/wdgt_bordered.go +++ b/wdgt_bordered.go @@ -69,13 +69,9 @@ func (w *BorderedWidget) HandleResize(ev *tcell.EventResize) { w.widget.HandleResize(tcell.NewEventResize(w.w-2, w.h-2)) } -func (w *BorderedWidget) SetKeyMap(km KeyMap, def bool) { w.widget.SetKeyMap(km, def) } -func (w *BorderedWidget) AddToKeyMap(km KeyMap) { w.widget.AddToKeyMap(km) } -func (w *BorderedWidget) RemoveFromKeyMap(km KeyMap) { w.widget.RemoveFromKeyMap(km) } -func (w *BorderedWidget) HandleKey(ev *tcell.EventKey) bool { - w.Log("BW(%s) Active(%s) Handlekey", w.Id(), w.widget.Id()) - return w.widget.HandleKey(ev) -} +func (w *BorderedWidget) GetKeyMap() *KeyMap { return w.widget.GetKeyMap() } +func (w *BorderedWidget) SetKeyMap(km *KeyMap) { w.widget.SetKeyMap(km) } +func (w *BorderedWidget) HandleKey(ev *tcell.EventKey) bool { return w.widget.HandleKey(ev) } func (w *BorderedWidget) HandleTime(ev *tcell.EventTime) { w.widget.HandleTime(ev) } diff --git a/wdgt_buffer.go b/wdgt_buffer.go index b77e50a..08b7b09 100644 --- a/wdgt_buffer.go +++ b/wdgt_buffer.go @@ -38,7 +38,7 @@ type BufferWidget struct { buffer *Buffer - keyMap KeyMap + keyMap *KeyMap timeMap *TimeMap } @@ -64,16 +64,8 @@ func (w *BufferWidget) Id() string { return w.id } func (w *BufferWidget) HandleResize(ev *tcell.EventResize) { } -func (w *BufferWidget) SetKeyMap(km KeyMap, def bool) { w.keyMap = km } -func (w *BufferWidget) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) } -func (w *BufferWidget) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.keyMap.Remove(k) - } - for r := range km.Runes { - w.keyMap.RemoveRune(r) - } -} +func (w *BufferWidget) GetKeyMap() *KeyMap { return w.keyMap } +func (w *BufferWidget) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *BufferWidget) HandleKey(ev *tcell.EventKey) bool { if !w.active { diff --git a/wdgt_button.go b/wdgt_button.go index 6692a24..d41f4aa 100644 --- a/wdgt_button.go +++ b/wdgt_button.go @@ -36,10 +36,10 @@ type Button struct { x, y int w, h int - active bool - visible bool - focusable bool - keyMap, customKeyMap KeyMap + active bool + visible bool + focusable bool + keyMap *KeyMap onPressed func() bool logger func(string, ...any) @@ -57,10 +57,7 @@ func (w *Button) Init(id string, style tcell.Style) { w.id = id w.style = style w.visible = true - w.keyMap = NewKeyMap(map[tcell.Key]func(ev *tcell.EventKey) bool{ - tcell.KeyEnter: func(ev *tcell.EventKey) bool { return w.onPressed() }, - }) - w.customKeyMap = BlankKeyMap() + w.keyMap = NewKeyMap(NewKey(BuildEK(tcell.KeyEnter), func(ev *tcell.EventKey) bool { return w.onPressed() })) w.onPressed = func() bool { return false } w.focusable = true } @@ -69,30 +66,14 @@ func (w *Button) HandleResize(ev *tcell.EventResize) { w.w, w.h = ev.Size() } -func (w *Button) SetKeyMap(km KeyMap, def bool) { - if def { - w.keyMap = km - } else { - w.customKeyMap = km - } -} -func (w *Button) AddToKeyMap(km KeyMap) { w.customKeyMap.Merge(km) } -func (w *Button) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.customKeyMap.Remove(k) - } - for r := range km.Runes { - w.customKeyMap.RemoveRune(r) - } -} +func (w *Button) GetKeyMap() *KeyMap { return w.keyMap } +func (w *Button) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *Button) HandleKey(ev *tcell.EventKey) bool { if !w.active { return false } - b1 := w.keyMap.Handle(ev) - b2 := w.customKeyMap.Handle(ev) - return b1 || b2 + return w.keyMap.Handle(ev) } func (w *Button) HandleTime(ev *tcell.EventTime) {} diff --git a/wdgt_chat.go b/wdgt_chat.go index e9afac3..8c473d9 100644 --- a/wdgt_chat.go +++ b/wdgt_chat.go @@ -51,7 +51,7 @@ type Chat struct { history []ChatMsg historyPosition int - keyMap, customKeyMap KeyMap + keyMap *KeyMap } var _ Widget = (*Chat)(nil) @@ -74,26 +74,8 @@ func (w *Chat) HandleResize(ev *tcell.EventResize) { w.w, w.h = ev.Size() } -func (w *Chat) SetKeyMap(km KeyMap, def bool) { - if def { - w.keyMap = km - } else { - w.customKeyMap = km - } -} - -func (w *Chat) AddToKeyMap(km KeyMap) { - w.customKeyMap.Merge(km) -} - -func (w *Chat) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.customKeyMap.Remove(k) - } - for r := range km.Runes { - w.customKeyMap.RemoveRune(r) - } -} +func (w *Chat) GetKeyMap() *KeyMap { return w.keyMap } +func (w *Chat) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *Chat) HandleKey(ev *tcell.EventKey) bool { if !w.active { @@ -111,9 +93,7 @@ func (w *Chat) HandleKey(ev *tcell.EventKey) bool { w.value = w.value[:w.cursor] + w.value[w.cursor+1:] } } - b1 := w.keyMap.Handle(ev) - b2 := w.customKeyMap.Handle(ev) - if b1 || b2 { + if w.keyMap.Handle(ev) { return true } @@ -201,12 +181,12 @@ func (w *Chat) MinW() int { return 2 + 20 } func (w *Chat) MinH() int { return 6 } func (w *Chat) initKeyMap() { - w.keyMap = NewKeyMap(map[tcell.Key]func(ev *tcell.EventKey) bool{ - tcell.KeyEsc: func(ev *tcell.EventKey) bool { + w.keyMap = NewKeyMap( + NewKey(BuildEK(tcell.KeyEsc), func(ev *tcell.EventKey) bool { w.SetActive(false) return true - }, - tcell.KeyUp: func(ev *tcell.EventKey) bool { + }), + NewKey(BuildEK(tcell.KeyUp), func(ev *tcell.EventKey) bool { if w.historyPosition < len(w.history)-1 { w.historyPosition++ w.value = w.history[w.historyPosition].Message @@ -214,8 +194,8 @@ func (w *Chat) initKeyMap() { return true } return false - }, - tcell.KeyDown: func(ev *tcell.EventKey) bool { + }), + NewKey(BuildEK(tcell.KeyDown), func(ev *tcell.EventKey) bool { if w.historyPosition > -1 { w.historyPosition-- if w.historyPosition == -1 { @@ -227,37 +207,36 @@ func (w *Chat) initKeyMap() { return true } return false - }, - tcell.KeyLeft: func(ev *tcell.EventKey) bool { + }), + NewKey(BuildEK(tcell.KeyLeft), func(ev *tcell.EventKey) bool { if w.cursor > 0 { w.cursor-- return true } return false - }, - tcell.KeyRight: func(ev *tcell.EventKey) bool { + }), + NewKey(BuildEK(tcell.KeyRight), func(ev *tcell.EventKey) bool { if w.cursor < len(w.value) { w.cursor++ return true } return false - }, - tcell.KeyCtrlU: func(ev *tcell.EventKey) bool { + }), + NewKey(BuildEK(tcell.KeyCtrlU), func(ev *tcell.EventKey) bool { w.value = w.value[w.cursor:] w.cursor = 0 return true - }, - tcell.KeyTab: func(ev *tcell.EventKey) bool { + }), + NewKey(BuildEK(tcell.KeyTab), func(ev *tcell.EventKey) bool { // Auto-complete // TODO: Find best guess for current word return false - }, - tcell.KeyEnter: func(ev *tcell.EventKey) bool { + }), + NewKey(BuildEK(tcell.KeyEnter), func(ev *tcell.EventKey) bool { // TODO: Submit the message return false - }, - }) - w.customKeyMap = BlankKeyMap() + }), + ) } func (w *Chat) SetTitle(ttl string) { w.title = ttl } func (w *Chat) Title() string { return w.title } diff --git a/wdgt_checkbox.go b/wdgt_checkbox.go index 8c4ed49..8aedf2b 100644 --- a/wdgt_checkbox.go +++ b/wdgt_checkbox.go @@ -45,8 +45,8 @@ type Checkbox struct { x, y int w, h int - keyMap, customKeyMap KeyMap - stateRunes []rune + keyMap *KeyMap + stateRunes []rune } var _ Widget = (*Checkbox)(nil) @@ -63,43 +63,22 @@ func (w *Checkbox) Init(id string, style tcell.Style) { w.visible = true w.stateRunes = []rune{'X', ' ', '-'} w.focusable = true - w.keyMap = KeyMap{ - Keys: map[tcell.Key]func(ev *tcell.EventKey) bool{ - tcell.KeyEnter: w.ToggleState, - }, - Runes: map[rune]func(ev *tcell.EventKey) bool{ - ' ': w.ToggleState, - }, - } - w.customKeyMap = BlankKeyMap() + w.keyMap = NewKeyMap( + NewKey(BuildEK(tcell.KeyEnter), w.ToggleState), + NewKey(BuildEKr(' '), w.ToggleState), + ) } func (w *Checkbox) Id() string { return w.id } func (w *Checkbox) HandleResize(ev *tcell.EventResize) { w.w, w.h = ev.Size() } -func (w *Checkbox) SetKeyMap(km KeyMap, def bool) { - if def { - w.keyMap = km - } else { - w.customKeyMap = km - } -} -func (w *Checkbox) AddToKeyMap(km KeyMap) { w.customKeyMap.Merge(km) } -func (w *Checkbox) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.customKeyMap.Remove(k) - } - for r := range km.Runes { - w.customKeyMap.RemoveRune(r) - } -} +func (w *Checkbox) GetKeyMap() *KeyMap { return w.keyMap } +func (w *Checkbox) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *Checkbox) HandleKey(ev *tcell.EventKey) bool { if !w.active { return false } - b1 := w.keyMap.Handle(ev) - b2 := w.customKeyMap.Handle(ev) - return b1 || b2 + return w.keyMap.Handle(ev) } func (w *Checkbox) HandleTime(ev *tcell.EventTime) {} func (w *Checkbox) Draw(screen tcell.Screen) { diff --git a/wdgt_cli.go b/wdgt_cli.go index c72aeef..bd2e13c 100644 --- a/wdgt_cli.go +++ b/wdgt_cli.go @@ -54,7 +54,7 @@ type Cli struct { commands []*CliCommand - keyMap, customKeyMap KeyMap + keyMap *KeyMap } // TODO: Fix Command/SubCommand finding @@ -81,22 +81,8 @@ func (w *Cli) HandleResize(ev *tcell.EventResize) { } } -func (w *Cli) SetKeyMap(km KeyMap, def bool) { - if def { - w.keyMap = km - } else { - w.customKeyMap = km - } -} -func (w *Cli) AddToKeyMap(km KeyMap) { w.customKeyMap.Merge(km) } -func (w *Cli) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.customKeyMap.Remove(k) - } - for r := range km.Runes { - w.customKeyMap.RemoveRune(r) - } -} +func (w *Cli) GetKeyMap() *KeyMap { return w.keyMap } +func (w *Cli) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *Cli) HandleKey(ev *tcell.EventKey) bool { if !w.active { @@ -114,8 +100,7 @@ func (w *Cli) HandleKey(ev *tcell.EventKey) bool { w.value = w.value[:w.cursor] + w.value[w.cursor+1:] } } - b1, b2 := w.keyMap.Handle(ev), w.customKeyMap.Handle(ev) - if b1 || b2 { + if w.keyMap.Handle(ev) { return true } @@ -216,12 +201,12 @@ func (w *Cli) MinW() int { return 20 } func (w *Cli) MinH() int { return 6 } func (w *Cli) initKeyMap() { - w.keyMap = NewKeyMap(map[tcell.Key]func(ev *tcell.EventKey) bool{ - tcell.KeyEsc: func(ev *tcell.EventKey) bool { + w.keyMap = NewKeyMap( + NewKey(BuildEK(tcell.KeyEsc), func(ev *tcell.EventKey) bool { w.SetActive(false) return true - }, - tcell.KeyUp: func(ev *tcell.EventKey) bool { + }), + NewKey(BuildEK(tcell.KeyUp), func(ev *tcell.EventKey) bool { if w.historyPosition < len(w.history)-1 { w.historyPosition++ w.value = w.history[w.historyPosition] @@ -229,8 +214,8 @@ func (w *Cli) initKeyMap() { return true } return false - }, - tcell.KeyDown: func(ev *tcell.EventKey) bool { + }), + NewKey(BuildEK(tcell.KeyDown), func(ev *tcell.EventKey) bool { if w.historyPosition > -1 { w.historyPosition-- if w.historyPosition == -1 { @@ -242,27 +227,27 @@ func (w *Cli) initKeyMap() { return true } return false - }, - tcell.KeyLeft: func(ev *tcell.EventKey) bool { + }), + NewKey(BuildEK(tcell.KeyLeft), func(ev *tcell.EventKey) bool { if w.cursor > 0 { w.cursor-- return true } return false - }, - tcell.KeyRight: func(ev *tcell.EventKey) bool { + }), + NewKey(BuildEK(tcell.KeyRight), func(ev *tcell.EventKey) bool { if w.cursor < len(w.value) { w.cursor++ return true } return false - }, - tcell.KeyCtrlU: func(ev *tcell.EventKey) bool { + }), + NewKey(BuildEK(tcell.KeyCtrlU), func(ev *tcell.EventKey) bool { w.value = w.value[w.cursor:] w.cursor = 0 return true - }, - tcell.KeyTab: func(ev *tcell.EventKey) bool { + }), + NewKey(BuildEK(tcell.KeyTab), func(ev *tcell.EventKey) bool { // Auto-complete guess := w.findBestGuess() if guess != nil { @@ -273,8 +258,8 @@ func (w *Cli) initKeyMap() { return true } return false - }, - tcell.KeyEnter: func(ev *tcell.EventKey) bool { + }), + NewKey(BuildEK(tcell.KeyEnter), func(ev *tcell.EventKey) bool { args := strings.Split(w.value, " ") w.historyPosition = -1 w.value = "" @@ -289,8 +274,8 @@ func (w *Cli) initKeyMap() { } w.history = append(w.history, fmt.Sprintf("%s: command not found", w.value)) return true - }, - tcell.KeyPgUp: func(ev *tcell.EventKey) bool { + }), + NewKey(BuildEK(tcell.KeyPgUp), func(ev *tcell.EventKey) bool { if w.logPosition < len(w.log)-w.h-2 { w.logPosition += (w.h - 2) if w.logPosition > len(w.log) { @@ -299,8 +284,8 @@ func (w *Cli) initKeyMap() { return true } return false - }, - tcell.KeyPgDn: func(ev *tcell.EventKey) bool { + }), + NewKey(BuildEK(tcell.KeyPgDn), func(ev *tcell.EventKey) bool { if w.logPosition > 0 { w.logPosition -= (w.h - 2) if w.logPosition < 0 { @@ -309,8 +294,8 @@ func (w *Cli) initKeyMap() { return true } return false - }, - }) + }), + ) } func (w *Cli) SetTitle(ttl string) { w.title = ttl } func (w *Cli) Title() string { return w.title } diff --git a/wdgt_datepicker.go b/wdgt_datepicker.go index 11783dc..950594a 100644 --- a/wdgt_datepicker.go +++ b/wdgt_datepicker.go @@ -45,7 +45,7 @@ type DatePicker struct { dateFld *Field dateNow *Button - keyMap, customKeyMap KeyMap + keyMap *KeyMap logger func(string, ...any) } @@ -96,38 +96,15 @@ func (w *DatePicker) HandleResize(ev *tcell.EventResize) { w.dateNow.SetPos(Coord{X: wd - 6, Y: 0}) } -func (w *DatePicker) SetKeyMap(km KeyMap, def bool) { - if def { - w.keyMap = km - } else { - w.customKeyMap = km - } -} -func (w *DatePicker) AddToKeyMap(km KeyMap) { w.customKeyMap.Merge(km) } -func (w *DatePicker) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.customKeyMap.Remove(k) - } - for r := range km.Runes { - w.customKeyMap.RemoveRune(r) - } -} +func (w *DatePicker) GetKeyMap() *KeyMap { return w.keyMap } +func (w *DatePicker) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *DatePicker) HandleKey(ev *tcell.EventKey) bool { if !w.active { return false } - if ev.Key() == tcell.KeyTab { - if w.dateFld.Active() { - w.dateFld.SetActive(false) - w.dateNow.SetActive(true) - return true - } else if w.dateNow.Active() { - w.dateFld.SetActive(false) - w.dateNow.SetActive(false) - return false - } - return false + if w.keyMap.Handle(ev) { + return true } if w.dateFld.Active() { if w.dateFld.HandleKey(ev) { @@ -140,9 +117,7 @@ func (w *DatePicker) HandleKey(ev *tcell.EventKey) bool { } else if w.dateNow.Active() { return w.dateNow.HandleKey(ev) } - b1 := w.keyMap.Handle(ev) - b2 := w.customKeyMap.Handle(ev) - return b1 || b2 + return false } func (w *DatePicker) HandleTime(ev *tcell.EventTime) {} func (w *DatePicker) Draw(screen tcell.Screen) { @@ -198,8 +173,20 @@ func (w *DatePicker) updateUI() { } func (w *DatePicker) initKeyMap() { - w.keyMap = NewKeyMap(map[tcell.Key]func(ev *tcell.EventKey) bool{}) - w.customKeyMap = BlankKeyMap() + w.keyMap = NewKeyMap( + NewKey(BuildEK(tcell.KeyTab), func(ev *tcell.EventKey) bool { + if w.dateFld.Active() { + w.dateFld.SetActive(false) + w.dateNow.SetActive(true) + return true + } else if w.dateNow.Active() { + w.dateFld.SetActive(false) + w.dateNow.SetActive(false) + return true + } + return false + }), + ) } func (w *DatePicker) Format() string { return w.format } diff --git a/wdgt_debug.go b/wdgt_debug.go index 9686cca..a85f197 100644 --- a/wdgt_debug.go +++ b/wdgt_debug.go @@ -43,7 +43,7 @@ type DebugWidget struct { focusable bool mTL, mBR Coord // Margins (Top-Right & Bottom Left) - keyMap KeyMap + keyMap *KeyMap logger func(string, ...any) } @@ -106,16 +106,8 @@ func (w *DebugWidget) HandleResize(ev *tcell.EventResize) { w.widget.HandleResize(tcell.NewEventResize(w.w-w.mTL.X-w.mBR.X, w.h-w.mTL.Y-w.mBR.Y)) } -func (w *DebugWidget) SetKeyMap(km KeyMap, def bool) { w.keyMap = km } -func (w *DebugWidget) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) } -func (w *DebugWidget) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.keyMap.Remove(k) - } - for r := range km.Runes { - w.keyMap.RemoveRune(r) - } -} +func (w *DebugWidget) GetKeyMap() *KeyMap { return w.keyMap } +func (w *DebugWidget) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *DebugWidget) HandleKey(ev *tcell.EventKey) bool { if ok := w.keyMap.Handle(ev); ok { diff --git a/wdgt_field.go b/wdgt_field.go index 7e83c9f..7274cfc 100644 --- a/wdgt_field.go +++ b/wdgt_field.go @@ -47,7 +47,7 @@ type Field struct { filter func(tcell.EventKey) bool onChange func(prev, curr string) - keyMap, customKeyMap KeyMap + keyMap *KeyMap } var _ Widget = (*Field)(nil) @@ -66,36 +66,21 @@ func (w *Field) Init(id string, style tcell.Style) { return wh.IsBS(ev) || wh.KeyIsDisplayable(ev) } - w.keyMap = NewKeyMap(map[tcell.Key]func(ev *tcell.EventKey) bool{ - tcell.KeyLeft: w.handleLeft, - tcell.KeyRight: w.handleRight, - tcell.KeyHome: w.handleHome, - tcell.KeyEnd: w.handleEnd, - tcell.KeyCtrlU: w.clearValueBeforeCursor, - }) - w.customKeyMap = BlankKeyMap() + w.keyMap = NewKeyMap( + NewKey(BuildEK(tcell.KeyLeft), w.handleLeft), + NewKey(BuildEK(tcell.KeyRight), w.handleRight), + NewKey(BuildEK(tcell.KeyHome), w.handleHome), + NewKey(BuildEK(tcell.KeyEnd), w.handleEnd), + NewKey(BuildEK(tcell.KeyCtrlU), w.clearValueBeforeCursor), + ) w.focusable = true } func (w *Field) Id() string { return w.id } func (w *Field) HandleResize(ev *tcell.EventResize) { w.w, w.h = ev.Size() } -func (w *Field) SetKeyMap(km KeyMap, def bool) { - if def { - w.keyMap = km - } else { - w.customKeyMap = km - } -} -func (w *Field) AddToKeyMap(km KeyMap) { w.customKeyMap.Merge(km) } -func (w *Field) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.customKeyMap.Remove(k) - } - for r := range km.Runes { - w.customKeyMap.RemoveRune(r) - } -} +func (w *Field) GetKeyMap() *KeyMap { return w.keyMap } +func (w *Field) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *Field) HandleKey(ev *tcell.EventKey) bool { if !w.active { @@ -114,9 +99,7 @@ func (w *Field) HandleKey(ev *tcell.EventKey) bool { return w.handleBackspace(ev) } } - b1 := w.keyMap.Handle(ev) - b2 := w.customKeyMap.Handle(ev) - if b1 || b2 { + if w.keyMap.Handle(ev) { return true } if w.filter != nil && !w.filter(*ev) { diff --git a/wdgt_filepicker.go b/wdgt_filepicker.go index 99ad3d4..16d09b3 100644 --- a/wdgt_filepicker.go +++ b/wdgt_filepicker.go @@ -49,7 +49,7 @@ type FilePicker struct { error error - keyMap, customKeyMap KeyMap + keyMap *KeyMap logger func(string, ...any) } @@ -77,7 +77,6 @@ func (w *FilePicker) Init(id string, style tcell.Style) { w.focusable = true w.keyMap = BlankKeyMap() - w.customKeyMap = BlankKeyMap() w.refreshFileList() } @@ -96,30 +95,14 @@ func (w *FilePicker) HandleResize(ev *tcell.EventResize) { w.Log("%s: HandleResize(%d, %d)", w.id, wd, ht) } -func (w *FilePicker) SetKeyMap(km KeyMap, def bool) { - if def { - w.keyMap = km - } else { - w.customKeyMap = km - } -} -func (w *FilePicker) AddToKeyMap(km KeyMap) { w.customKeyMap.Merge(km) } -func (w *FilePicker) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.customKeyMap.Remove(k) - } - for r := range km.Runes { - w.customKeyMap.RemoveRune(r) - } -} +func (w *FilePicker) GetKeyMap() *KeyMap { return w.keyMap } +func (w *FilePicker) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *FilePicker) HandleKey(ev *tcell.EventKey) bool { if !w.active { return false } - b1 := w.keyMap.Handle(ev) - b2 := w.customKeyMap.Handle(ev) - return b1 || b2 + return w.keyMap.Handle(ev) } func (w *FilePicker) HandleTime(ev *tcell.EventTime) { diff --git a/wdgt_form.go b/wdgt_form.go index 581946d..c774ec0 100644 --- a/wdgt_form.go +++ b/wdgt_form.go @@ -45,7 +45,7 @@ type Form struct { hasSubmit bool hasCancel bool - keyMap, customKeyMap KeyMap + keyMap *KeyMap } var _ Widget = (*Form)(nil) @@ -64,7 +64,6 @@ func (w *Form) Init(id string, style tcell.Style) { w.submit = NewButton(fmt.Sprintf("%s-submit", id), style) w.cancel = NewButton(fmt.Sprintf("%s-cancel", id), style) w.keyMap = BlankKeyMap() - w.customKeyMap = BlankKeyMap() } func (w *Form) Id() string { return w.id } @@ -92,22 +91,8 @@ func (w *Form) HandleResize(ev *tcell.EventResize) { } } -func (w *Form) SetKeyMap(km KeyMap, def bool) { - if def { - w.keyMap = km - } else { - w.customKeyMap = km - } -} -func (w *Form) AddToKeyMap(km KeyMap) { w.customKeyMap.Merge(km) } -func (w *Form) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.customKeyMap.Remove(k) - } - for r := range km.Runes { - w.customKeyMap.RemoveRune(r) - } -} +func (w *Form) GetKeyMap() *KeyMap { return w.keyMap } +func (w *Form) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *Form) HandleKey(ev *tcell.EventKey) bool { if !w.active { @@ -129,9 +114,7 @@ func (w *Form) HandleKey(ev *tcell.EventKey) bool { w.updateWidgets() return w.cursor > pre } - b1 := w.keyMap.Handle(ev) - b2 := w.customKeyMap.Handle(ev) - return b1 || b2 + return w.keyMap.Handle(ev) } func (w *Form) HandleTime(ev *tcell.EventTime) {} func (w *Form) Draw(screen tcell.Screen) { diff --git a/wdgt_linear_layout.go b/wdgt_linear_layout.go index 7cd0e40..982c74e 100644 --- a/wdgt_linear_layout.go +++ b/wdgt_linear_layout.go @@ -56,7 +56,7 @@ type LinearLayout struct { disableTab bool insetBorder bool - keyMap, customKeyMap KeyMap + keyMap *KeyMap logger func(string, ...any) } @@ -84,8 +84,7 @@ func (w *LinearLayout) Init(id string, s tcell.Style) { w.defFlags = LayoutFlag(LFAlignHCenter | LFAlignVCenter) w.layoutFlags = make(map[Widget]LayoutFlag) w.layoutWeights = make(map[Widget]int) - w.keyMap = BlankKeyMap() - w.keyMap.Add(tcell.KeyTab, func(ev *tcell.EventKey) bool { + w.keyMap = NewKeyMap(NewKey(BuildEK(tcell.KeyTab), func(ev *tcell.EventKey) bool { active := w.findActive() if active == nil && len(w.widgets) > 0 { // No widget is active, but we do have some @@ -97,8 +96,7 @@ func (w *LinearLayout) Init(id string, s tcell.Style) { return false } return w.ActivateNext() - }) - w.customKeyMap = BlankKeyMap() + })) } func (w *LinearLayout) Id() string { return w.id } @@ -107,22 +105,8 @@ func (w *LinearLayout) HandleResize(ev *tcell.EventResize) { w.updateWidgetLayouts() } -func (w *LinearLayout) SetKeyMap(km KeyMap, def bool) { - if def { - w.keyMap = km - } else { - w.customKeyMap = km - } -} -func (w *LinearLayout) AddToKeyMap(km KeyMap) { w.customKeyMap.Merge(km) } -func (w *LinearLayout) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.customKeyMap.Remove(k) - } - for r := range km.Runes { - w.customKeyMap.RemoveRune(r) - } -} +func (w *LinearLayout) GetKeyMap() *KeyMap { return w.keyMap } +func (w *LinearLayout) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *LinearLayout) HandleKey(ev *tcell.EventKey) bool { if !w.active || w.disableTab { @@ -134,8 +118,7 @@ func (w *LinearLayout) HandleKey(ev *tcell.EventKey) bool { return true } } - b1, b2 := w.keyMap.Handle(ev), w.customKeyMap.Handle(ev) - return b1 || b2 + return w.keyMap.Handle(ev) } func (w *LinearLayout) GetActiveWidgetIdx() int { return w.findActiveIdx() } @@ -335,6 +318,7 @@ func (w *LinearLayout) FindById(id string) Widget { } return nil } + func (w *LinearLayout) Contains(n Widget) bool { return w.IndexOf(n) >= 0 } diff --git a/wdgt_menu.go b/wdgt_menu.go index fa4a6e9..1b1ee32 100644 --- a/wdgt_menu.go +++ b/wdgt_menu.go @@ -47,7 +47,7 @@ type Menu struct { expanded bool vimMode bool - keyMap, customKeyMap KeyMap + keyMap *KeyMap } type MenuType int @@ -69,19 +69,18 @@ func (w *Menu) Init(id string, style tcell.Style) { w.id = id w.style = style w.visible = true - w.keyMap = NewKeyMap(map[tcell.Key]func(ev *tcell.EventKey) bool{ - tcell.KeyRight: w.MoveRight, - tcell.KeyLeft: w.MoveLeft, - tcell.KeyUp: w.MoveUp, - tcell.KeyDown: w.MoveDown, - tcell.KeyEnter: func(ev *tcell.EventKey) bool { + w.keyMap = NewKeyMap( + NewKey(BuildEK(tcell.KeyRight), w.MoveRight), + NewKey(BuildEK(tcell.KeyLeft), w.MoveLeft), + NewKey(BuildEK(tcell.KeyUp), w.MoveUp), + NewKey(BuildEK(tcell.KeyDown), w.MoveDown), + NewKey(BuildEK(tcell.KeyEnter), func(ev *tcell.EventKey) bool { if w.onPressed != nil { return w.onPressed() } return false - }, - }) - w.customKeyMap = BlankKeyMap() + }), + ) w.focusable = true } func (w *Menu) Id() string { return w.id } @@ -124,22 +123,8 @@ func (w *Menu) handleResizeV(_ *tcell.EventResize) { } } -func (w *Menu) SetKeyMap(km KeyMap, def bool) { - if def { - w.keyMap = km - } else { - w.customKeyMap = km - } -} -func (w *Menu) AddToKeyMap(km KeyMap) { w.customKeyMap.Merge(km) } -func (w *Menu) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.customKeyMap.Remove(k) - } - for r := range km.Runes { - w.customKeyMap.RemoveRune(r) - } -} +func (w *Menu) GetKeyMap() *KeyMap { return w.keyMap } +func (w *Menu) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *Menu) HandleKey(ev *tcell.EventKey) bool { if !w.active { @@ -152,8 +137,7 @@ func (w *Menu) HandleKey(ev *tcell.EventKey) bool { } return true } - b1, b2 := w.keyMap.Handle(ev), w.customKeyMap.Handle(ev) - if b1 || b2 { + if w.keyMap.Handle(ev) { return true } diff --git a/wdgt_menu_item.go b/wdgt_menu_item.go index 0c49737..47f0846 100644 --- a/wdgt_menu_item.go +++ b/wdgt_menu_item.go @@ -51,7 +51,7 @@ type MenuItem struct { expanded bool disabled bool - keyMap, customKeyMap KeyMap + keyMap *KeyMap } var _ Widget = (*MenuItem)(nil) @@ -66,19 +66,18 @@ func (w *MenuItem) Init(id string, style tcell.Style) { w.id = id w.style = style w.visible = true - w.keyMap = NewKeyMap(map[tcell.Key]func(ev *tcell.EventKey) bool{ - tcell.KeyUp: w.MoveUp, - tcell.KeyDown: w.MoveDown, - tcell.KeyEnter: func(ev *tcell.EventKey) bool { + w.keyMap = NewKeyMap( + NewKey(BuildEK(tcell.KeyUp), w.MoveUp), + NewKey(BuildEK(tcell.KeyDown), w.MoveDown), + NewKey(BuildEK(tcell.KeyEnter), func(ev *tcell.EventKey) bool { if w.onPressed != nil { return w.onPressed() } else if len(w.items) > w.cursor && w.items[w.cursor].HandleKey(ev) { return true } return false - }, - }) - w.customKeyMap = BlankKeyMap() + }), + ) for i := range w.items { w.items[i].SetActive(i == w.cursor) @@ -91,22 +90,8 @@ func (w *MenuItem) HandleResize(ev *tcell.EventResize) { // TODO: Trickle-down HandleResize } -func (w *MenuItem) SetKeyMap(km KeyMap, def bool) { - if def { - w.keyMap = km - } else { - w.customKeyMap = km - } -} -func (w *MenuItem) AddToKeyMap(km KeyMap) { w.customKeyMap.Merge(km) } -func (w *MenuItem) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.customKeyMap.Remove(k) - } - for r := range km.Runes { - w.customKeyMap.RemoveRune(r) - } -} +func (w *MenuItem) GetKeyMap() *KeyMap { return w.keyMap } +func (w *MenuItem) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *MenuItem) HandleKey(ev *tcell.EventKey) bool { if !w.active { @@ -127,8 +112,7 @@ func (w *MenuItem) HandleKey(ev *tcell.EventKey) bool { } } // Look for a sub-item that's selected - b1, b2 := w.keyMap.Handle(ev), w.customKeyMap.Handle(ev) - return b1 || b2 + return w.keyMap.Handle(ev) } func (w *MenuItem) HandleTime(ev *tcell.EventTime) { diff --git a/wdgt_prompt.go b/wdgt_prompt.go index a095a25..22813be 100644 --- a/wdgt_prompt.go +++ b/wdgt_prompt.go @@ -46,7 +46,7 @@ type Prompt struct { btnOk, btnCancel *Button onOk func(string) bool - keyMap, customKeyMap KeyMap + keyMap *KeyMap } var _ Widget = (*Prompt)(nil) @@ -68,7 +68,6 @@ func (w *Prompt) Init(id string, style tcell.Style) { w.btnCancel.SetLabel("Cancel") w.focusable = true w.keyMap = BlankKeyMap() - w.customKeyMap = BlankKeyMap() } func (w *Prompt) Id() string { return w.id } func (w *Prompt) HandleResize(ev *tcell.EventResize) { @@ -84,29 +83,14 @@ func (w *Prompt) HandleResize(ev *tcell.EventResize) { w.btnCancel.SetPos(Coord{X: w.x + 1, Y: w.y + w.h - 1}) } -func (w *Prompt) SetKeyMap(km KeyMap, def bool) { - if def { - w.keyMap = km - } else { - w.customKeyMap = km - } -} -func (w *Prompt) AddToKeyMap(km KeyMap) { w.customKeyMap.Merge(km) } -func (w *Prompt) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.customKeyMap.Remove(k) - } - for r := range km.Runes { - w.customKeyMap.RemoveRune(r) - } -} +func (w *Prompt) GetKeyMap() *KeyMap { return w.keyMap } +func (w *Prompt) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *Prompt) HandleKey(ev *tcell.EventKey) bool { if !w.active { return false } - b1, b2 := w.keyMap.Handle(ev), w.customKeyMap.Handle(ev) - return b1 || b2 + return w.keyMap.Handle(ev) } func (w *Prompt) HandleTime(ev *tcell.EventTime) { diff --git a/wdgt_relative_layout.go b/wdgt_relative_layout.go index b3fbfae..03062f0 100644 --- a/wdgt_relative_layout.go +++ b/wdgt_relative_layout.go @@ -37,7 +37,7 @@ type RelativeLayout struct { visible bool focusable bool - keyMap KeyMap + keyMap *KeyMap } var _ Widget = (*RelativeLayout)(nil) @@ -85,16 +85,8 @@ func (w *RelativeLayout) HandleResize(ev *tcell.EventResize) { // TODO: Trickle-down HandleResize } -func (w *RelativeLayout) SetKeyMap(km KeyMap, def bool) { w.keyMap = km } -func (w *RelativeLayout) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) } -func (w *RelativeLayout) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.keyMap.Remove(k) - } - for r := range km.Runes { - w.keyMap.RemoveRune(r) - } -} +func (w *RelativeLayout) GetKeyMap() *KeyMap { return w.keyMap } +func (w *RelativeLayout) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *RelativeLayout) HandleKey(ev *tcell.EventKey) bool { return w.keyMap.Handle(ev) } func (w *RelativeLayout) HandleTime(ev *tcell.EventTime) { for i := range w.widgets { diff --git a/wdgt_searcher.go b/wdgt_searcher.go index 2ce8e2c..1abfa45 100644 --- a/wdgt_searcher.go +++ b/wdgt_searcher.go @@ -54,7 +54,7 @@ type Searcher struct { hideOnSelect bool logger func(string, ...any) - keyMap, customKeyMap KeyMap + keyMap *KeyMap } var _ Widget = (*Searcher)(nil) @@ -74,16 +74,15 @@ func (w *Searcher) Init(id string, style tcell.Style) { w.search.SetOnChange(func(prev, curr string) { w.updateFilter() }) - w.keyMap = NewKeyMap(map[tcell.Key]func(ev *tcell.EventKey) bool{ - tcell.KeyUp: w.handleKeyUp, - tcell.KeyDown: w.handleKeyDown, - tcell.KeyHome: w.handleKeyHome, - tcell.KeyEnd: w.handleKeyEnd, - tcell.KeyPgUp: w.handleKeyPgUp, - tcell.KeyPgDn: w.handleKeyPgDn, - tcell.KeyEnter: w.handleKeyEnter, - }) - w.customKeyMap = BlankKeyMap() + w.keyMap = NewKeyMap( + NewKey(BuildEK(tcell.KeyUp), w.handleKeyUp), + NewKey(BuildEK(tcell.KeyDown), w.handleKeyDown), + NewKey(BuildEK(tcell.KeyHome), w.handleKeyHome), + NewKey(BuildEK(tcell.KeyEnd), w.handleKeyEnd), + NewKey(BuildEK(tcell.KeyPgUp), w.handleKeyPgUp), + NewKey(BuildEK(tcell.KeyPgDn), w.handleKeyPgDn), + NewKey(BuildEK(tcell.KeyEnter), w.handleKeyEnter), + ) w.focusable = true w.filteredToTrue = make(map[int]int) } @@ -101,41 +100,22 @@ func (w *Searcher) HandleResize(ev *tcell.EventResize) { // w.buildBuffer() } -func (w *Searcher) SetKeyMap(km KeyMap, def bool) { - if def { - w.keyMap = km - } else { - w.customKeyMap = km - } -} -func (w *Searcher) AddToKeyMap(km KeyMap) { w.customKeyMap.Merge(km) } -func (w *Searcher) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.customKeyMap.Remove(k) - } - for r := range km.Runes { - w.customKeyMap.RemoveRune(r) - } -} +func (w *Searcher) GetKeyMap() *KeyMap { return w.keyMap } +func (w *Searcher) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *Searcher) HandleKey(ev *tcell.EventKey) bool { if !w.active { return false } sel := w.cursor - b1, b2 := w.keyMap.Handle(ev), w.customKeyMap.Handle(ev) - var ret bool - if !b1 && !b2 { + ret := w.keyMap.Handle(ev) + if !ret { ret = w.search.HandleKey(ev) } if w.cursor != sel && w.onChange != nil { w.onChange(w.cursor, w.filteredData[w.cursor]) } - if b1 || b2 || ret { - // w.buildBuffer() - return true - } - return false + return ret } func (w *Searcher) handleKeyUp(ev *tcell.EventKey) bool { diff --git a/wdgt_shrinkwrap.go b/wdgt_shrinkwrap.go index 45e6735..f9de35c 100644 --- a/wdgt_shrinkwrap.go +++ b/wdgt_shrinkwrap.go @@ -39,9 +39,9 @@ func (w *ShrinkWrap) Init(id string, st tcell.Style) { w.widget.Init(id, st) func (w *ShrinkWrap) Id() string { return w.widget.Id() } func (w *ShrinkWrap) HandleResize(ev *tcell.EventResize) { w.widget.HandleResize(ev) } -func (w *ShrinkWrap) SetKeyMap(km KeyMap, def bool) { w.widget.SetKeyMap(km, def) } -func (w *ShrinkWrap) AddToKeyMap(km KeyMap) { w.widget.AddToKeyMap(km) } -func (w *ShrinkWrap) RemoveFromKeyMap(km KeyMap) { w.widget.RemoveFromKeyMap(km) } +func (w *ShrinkWrap) GetKeyMap() *KeyMap { return w.widget.GetKeyMap() } +func (w *ShrinkWrap) SetKeyMap(km *KeyMap) { w.widget.SetKeyMap(km) } + func (w *ShrinkWrap) HandleKey(ev *tcell.EventKey) bool { return w.widget.HandleKey(ev) } func (w *ShrinkWrap) HandleTime(ev *tcell.EventTime) { w.widget.HandleTime(ev) } func (w *ShrinkWrap) Draw(screen tcell.Screen) { w.widget.Draw(screen) } diff --git a/wdgt_simple_list.go b/wdgt_simple_list.go index c31ecab..ad00176 100644 --- a/wdgt_simple_list.go +++ b/wdgt_simple_list.go @@ -44,10 +44,10 @@ type SimpleList struct { list []string itemsStyle map[int]tcell.Style - onChange func(int, string) bool - onSelect func(int, string) bool - keyMap, customKeyMap KeyMap - vimMode bool + onChange func(int, string) bool + onSelect func(int, string) bool + keyMap *KeyMap + vimMode bool logger func(string, ...any) } @@ -64,49 +64,48 @@ func (w *SimpleList) Init(id string, style tcell.Style) { w.id = id w.style = style w.focusable = true - w.keyMap = NewKeyMap(map[tcell.Key]func(ev *tcell.EventKey) bool{ - tcell.KeyUp: func(_ *tcell.EventKey) bool { return w.MoveUp() }, - tcell.KeyDown: func(_ *tcell.EventKey) bool { return w.MoveDown() }, - tcell.KeyEnter: func(ev *tcell.EventKey) bool { + w.keyMap = NewKeyMap( + NewKey(BuildEK(tcell.KeyUp), func(_ *tcell.EventKey) bool { return w.MoveUp() }), + NewKey(BuildEK(tcell.KeyDown), func(_ *tcell.EventKey) bool { return w.MoveDown() }), + NewKey(BuildEK(tcell.KeyEnter), func(ev *tcell.EventKey) bool { if w.onSelect != nil && w.cursor < len(w.list) { return w.onSelect(w.cursor, w.list[w.cursor]) } return false - }, - tcell.KeyPgDn: func(_ *tcell.EventKey) bool { return w.PageDn() }, - tcell.KeyPgUp: func(_ *tcell.EventKey) bool { return w.PageUp() }, - }) - w.keyMap.AddRune('j', func(ev *tcell.EventKey) bool { - if !w.vimMode { + }), + NewKey(BuildEK(tcell.KeyPgDn), func(_ *tcell.EventKey) bool { return w.PageDn() }), + NewKey(BuildEK(tcell.KeyPgUp), func(_ *tcell.EventKey) bool { return w.PageUp() }), + NewKey(BuildEKr('j'), func(ev *tcell.EventKey) bool { + if !w.vimMode { + return false + } + return w.MoveDown() + }), + NewKey(BuildEKr('k'), func(ev *tcell.EventKey) bool { + if !w.vimMode { + return false + } + return w.MoveUp() + }), + NewKey(BuildEKr('b'), func(ev *tcell.EventKey) bool { + if !w.vimMode { + return false + } + if ev.Modifiers()&tcell.ModCtrl != 0 { + return w.PageUp() + } return false - } - return w.MoveDown() - }) - w.keyMap.AddRune('k', func(ev *tcell.EventKey) bool { - if !w.vimMode { + }), + NewKey(BuildEKr('f'), func(ev *tcell.EventKey) bool { + if !w.vimMode { + return false + } + if ev.Modifiers()&tcell.ModCtrl != 0 { + return w.PageDn() + } return false - } - return w.MoveUp() - }) - w.keyMap.AddRune('b', func(ev *tcell.EventKey) bool { - if !w.vimMode { - return false - } - if ev.Modifiers()&tcell.ModCtrl != 0 { - return w.PageUp() - } - return false - }) - w.keyMap.AddRune('f', func(ev *tcell.EventKey) bool { - if !w.vimMode { - return false - } - if ev.Modifiers()&tcell.ModCtrl != 0 { - return w.PageDn() - } - return false - }) - w.customKeyMap = BlankKeyMap() + }), + ) w.itemsStyle = make(map[int]tcell.Style) w.focusable = true } @@ -114,29 +113,14 @@ func (w *SimpleList) Init(id string, style tcell.Style) { func (w *SimpleList) Id() string { return w.id } func (w *SimpleList) HandleResize(ev *tcell.EventResize) { w.w, w.h = ev.Size() } -func (w *SimpleList) SetKeyMap(km KeyMap, def bool) { - if def { - w.keyMap = km - } else { - w.customKeyMap = km - } -} -func (w *SimpleList) AddToKeyMap(km KeyMap) { w.customKeyMap.Merge(km) } -func (w *SimpleList) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.customKeyMap.Remove(k) - } - for r := range km.Runes { - w.customKeyMap.RemoveRune(r) - } -} +func (w *SimpleList) GetKeyMap() *KeyMap { return w.keyMap } +func (w *SimpleList) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *SimpleList) HandleKey(ev *tcell.EventKey) bool { if !w.active || !w.focusable { return false } - b1, b2 := w.keyMap.Handle(ev), w.customKeyMap.Handle(ev) - return b1 || b2 + return w.keyMap.Handle(ev) } func (w *SimpleList) HandleTime(ev *tcell.EventTime) {} @@ -294,10 +278,10 @@ func (w *SimpleList) PageUp() bool { func (w *SimpleList) PageDn() bool { w.cursor += w.h if len(w.border) > 0 { - w.cursor -= 2 + w.cursor -= 1 } - if w.cursor > len(w.list)-2 { - w.cursor = len(w.list) - 2 + if w.cursor > len(w.list)-1 { + w.cursor = len(w.list) - 1 } return true } diff --git a/wdgt_spinner.go b/wdgt_spinner.go index 4504960..a63054e 100644 --- a/wdgt_spinner.go +++ b/wdgt_spinner.go @@ -36,7 +36,7 @@ type Spinner struct { frames []rune lastTick time.Time tickInterval time.Duration - keyMap KeyMap + keyMap *KeyMap } var _ Widget = (*Spinner)(nil) @@ -60,16 +60,10 @@ func (w *Spinner) Init(id string, st tcell.Style) { } func (w *Spinner) Id() string { return w.id } func (w *Spinner) HandleResize(ev *tcell.EventResize) {} -func (w *Spinner) SetKeyMap(km KeyMap, def bool) { w.keyMap = km } -func (w *Spinner) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) } -func (w *Spinner) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.keyMap.Remove(k) - } - for r := range km.Runes { - w.keyMap.RemoveRune(r) - } -} + +func (w *Spinner) GetKeyMap() *KeyMap { return w.keyMap } +func (w *Spinner) SetKeyMap(km *KeyMap) { w.keyMap = km } + func (w *Spinner) HandleKey(ev *tcell.EventKey) bool { return false } func (w *Spinner) HandleTime(ev *tcell.EventTime) { w.currentFrame = (w.currentFrame + 1) % len(w.frames) diff --git a/wdgt_table.go b/wdgt_table.go index efc1b70..79bec88 100644 --- a/wdgt_table.go +++ b/wdgt_table.go @@ -52,7 +52,7 @@ type Table struct { columnWidths []int - keyMap, customKeyMap KeyMap + keyMap *KeyMap } var _ Widget = (*Table)(nil) @@ -85,36 +85,20 @@ func (w *Table) Init(id string, style tcell.Style) { w.border = wh.BRD_CSIMPLE w.focusable = true w.keyMap = BlankKeyMap() - w.customKeyMap = BlankKeyMap() } func (w *Table) Id() string { return w.id } func (w *Table) HandleResize(ev *tcell.EventResize) { w.w, w.h = ev.Size() } -func (w *Table) SetKeyMap(km KeyMap, def bool) { - if def { - w.keyMap = km - } else { - w.customKeyMap = km - } -} -func (w *Table) AddToKeyMap(km KeyMap) { w.customKeyMap.Merge(km) } -func (w *Table) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.customKeyMap.Remove(k) - } - for r := range km.Runes { - w.customKeyMap.RemoveRune(r) - } -} +func (w *Table) GetKeyMap() *KeyMap { return w.keyMap } +func (w *Table) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *Table) HandleKey(ev *tcell.EventKey) bool { if !w.active { return false } - b1, b2 := w.keyMap.Handle(ev), w.customKeyMap.Handle(ev) - return b1 || b2 + return w.keyMap.Handle(ev) } func (w *Table) HandleTime(ev *tcell.EventTime) {} func (w *Table) Draw(screen tcell.Screen) { diff --git a/wdgt_text.go b/wdgt_text.go index 42ee396..046e063 100644 --- a/wdgt_text.go +++ b/wdgt_text.go @@ -40,7 +40,7 @@ type Text struct { visible bool active bool focusable bool - keyMap KeyMap + keyMap *KeyMap } var _ Widget = (*Text)(nil) @@ -62,16 +62,9 @@ func (w *Text) Init(id string, style tcell.Style) { func (w *Text) Id() string { return w.id } func (w *Text) HandleResize(ev *tcell.EventResize) { w.w, w.h = ev.Size() } -func (w *Text) SetKeyMap(km KeyMap, def bool) { w.keyMap = km } -func (w *Text) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) } -func (w *Text) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.keyMap.Remove(k) - } - for r := range km.Runes { - w.keyMap.RemoveRune(r) - } -} +func (w *Text) GetKeyMap() *KeyMap { return w.keyMap } +func (w *Text) SetKeyMap(km *KeyMap) { w.keyMap = km } + func (w *Text) HandleKey(ev *tcell.EventKey) bool { return w.keyMap.Handle(ev) } func (w *Text) HandleTime(ev *tcell.EventTime) {} func (w *Text) Draw(screen tcell.Screen) { diff --git a/wdgt_timefield.go b/wdgt_timefield.go index e549ad2..41b4afc 100644 --- a/wdgt_timefield.go +++ b/wdgt_timefield.go @@ -57,8 +57,8 @@ type TimeField struct { widgets []Widget - cursor int - keyMap, customKeyMap KeyMap + cursor int + keyMap *KeyMap } // TODO: Allow changing the format. @@ -87,11 +87,10 @@ func (w *TimeField) Init(id string, style tcell.Style) { w.fldHour, w.fldMinute, w.fldSecond, w.btnNow, ) - w.keyMap = NewKeyMap(map[tcell.Key]func(ev *tcell.EventKey) bool{ - tcell.KeyHome: w.handleHome, - tcell.KeyEnd: w.handleEnd, - }) - w.customKeyMap = BlankKeyMap() + w.keyMap = NewKeyMap( + NewKey(BuildEK(tcell.KeyHome), w.handleHome), + NewKey(BuildEK(tcell.KeyEnd), w.handleEnd), + ) w.visible = true w.focusable = true } @@ -139,22 +138,8 @@ func (w *TimeField) HandleResize(ev *tcell.EventResize) { } } -func (w *TimeField) SetKeyMap(km KeyMap, def bool) { - if def { - w.keyMap = km - } else { - w.customKeyMap = km - } -} -func (w *TimeField) AddToKeyMap(km KeyMap) { w.customKeyMap.Merge(km) } -func (w *TimeField) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.customKeyMap.Remove(k) - } - for r := range km.Runes { - w.customKeyMap.RemoveRune(r) - } -} +func (w *TimeField) GetKeyMap() *KeyMap { return w.keyMap } +func (w *TimeField) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *TimeField) HandleKey(ev *tcell.EventKey) bool { if !w.active { @@ -162,8 +147,7 @@ func (w *TimeField) HandleKey(ev *tcell.EventKey) bool { } else if ev.Key() == tcell.KeyTab { return w.handleTab(ev) } - b1, b2 := w.keyMap.Handle(ev), w.customKeyMap.Handle(ev) - if b1 || b2 { + if w.keyMap.Handle(ev) { return true } if w.cursor <= len(w.widgets) { diff --git a/wdgt_top_menu_layout.go b/wdgt_top_menu_layout.go index 1628184..a4df2c0 100644 --- a/wdgt_top_menu_layout.go +++ b/wdgt_top_menu_layout.go @@ -43,8 +43,8 @@ type TopMenuLayout struct { visible bool focusable bool - layoutFlags LayoutFlag - keyMap, customKeyMap KeyMap + layoutFlags LayoutFlag + keyMap *KeyMap logger func(string, ...any) } @@ -68,18 +68,17 @@ func (w *TopMenuLayout) Init(id string, s tcell.Style) { w.menu.SetType(MenuTypeH) w.widget = NewBlankWidget("blank") - w.keyMap = NewKeyMap(map[tcell.Key]func(ev *tcell.EventKey) bool{ - tcell.KeyEscape: func(ev *tcell.EventKey) bool { + w.keyMap = NewKeyMap( + NewKey(BuildEK(tcell.KeyEscape), func(ev *tcell.EventKey) bool { return w.ToggleMenu() - }, - }) - w.keyMap.AddRune(' ', func(ev *tcell.EventKey) bool { - if ev.Modifiers()&tcell.ModAlt != 0 { - return w.ToggleMenu() - } - return false - }) - w.customKeyMap = BlankKeyMap() + }), + NewKey(BuildEKr(' '), func(ev *tcell.EventKey) bool { + if ev.Modifiers()&tcell.ModAlt != 0 { + return w.ToggleMenu() + } + return false + }), + ) } func (w *TopMenuLayout) ToggleMenu() bool { @@ -122,29 +121,14 @@ func (w *TopMenuLayout) HandleResize(ev *tcell.EventResize) { } } -func (w *TopMenuLayout) SetKeyMap(km KeyMap, def bool) { - if def { - w.keyMap = km - } else { - w.customKeyMap = km - } -} -func (w *TopMenuLayout) AddToKeyMap(km KeyMap) { w.customKeyMap.Merge(km) } -func (w *TopMenuLayout) RemoveFromKeyMap(km KeyMap) { - for k := range km.Keys { - w.customKeyMap.Remove(k) - } - for r := range km.Runes { - w.customKeyMap.RemoveRune(r) - } -} +func (w *TopMenuLayout) GetKeyMap() *KeyMap { return w.keyMap } +func (w *TopMenuLayout) SetKeyMap(km *KeyMap) { w.keyMap = km } func (w *TopMenuLayout) HandleKey(ev *tcell.EventKey) bool { if !w.active { return false } - b1, b2 := w.keyMap.Handle(ev), w.customKeyMap.Handle(ev) - if b1 || b2 { + if w.keyMap.Handle(ev) { return true } if w.menu != nil && w.menu.Active() { diff --git a/widget.go b/widget.go index e904cd8..db9af8b 100644 --- a/widget.go +++ b/widget.go @@ -33,12 +33,10 @@ type Widget interface { HandleKey(*tcell.EventKey) bool HandleTime(*tcell.EventTime) // KeyMap Handling - // SetKeyMap sets a new keymap - // if 'def' is true, the default keymap is overwritten - // otherwise, it should be treated as a custom keymap - SetKeyMap(km KeyMap, def bool) - AddToKeyMap(km KeyMap) - RemoveFromKeyMap(km KeyMap) + // SetKeyMap overwrites the keymap + GetKeyMap() *KeyMap + SetKeyMap(km *KeyMap) + Draw(tcell.Screen) Active() bool SetActive(bool)