157 lines
3.5 KiB
Go
157 lines
3.5 KiB
Go
/*
|
|
Copyright © Brian Buller <brian@bullercodeworks.com>
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
*/
|
|
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) EventKey() *tcell.EventKey { return k.ev }
|
|
|
|
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) Description() string { return k.desc }
|
|
|
|
func (k *Key) Matches(ev *tcell.EventKey) bool {
|
|
if k.ev.Key() == tcell.KeyRune {
|
|
return k.ev.Key() == ev.Key() &&
|
|
k.ev.Rune() == ev.Rune() &&
|
|
k.ev.Modifiers() == ev.Modifiers()
|
|
}
|
|
return k.ev.Key() == ev.Key() &&
|
|
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 []*Key
|
|
logger func(string, ...any)
|
|
}
|
|
|
|
func BlankKeyMap() *KeyMap { return &KeyMap{} }
|
|
func NewKeyMap(k *Key, rest ...*Key) *KeyMap {
|
|
ret := &KeyMap{}
|
|
ret.Add(k, rest...)
|
|
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 (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 {
|
|
m.Keys = append(m.Keys, k)
|
|
}
|
|
for i := range rest {
|
|
m.Add(rest[i])
|
|
}
|
|
}
|
|
|
|
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])
|
|
}
|
|
}
|
|
|
|
func (m *KeyMap) Handle(ev *tcell.EventKey) bool {
|
|
var cons bool
|
|
for _, k := range m.Keys {
|
|
cons = cons || k.Handle(ev)
|
|
}
|
|
return cons
|
|
}
|