1
0
mirror of https://github.com/mum4k/termdash.git synced 2025-04-25 13:48:50 +08:00

Allow button to specify multiple trigger keys.

This commit is contained in:
Jakub Sobon 2020-11-24 23:02:21 -05:00
parent 891a672716
commit 3a0d044a4d
No known key found for this signature in database
GPG Key ID: F2451A77FB05D3B7
3 changed files with 165 additions and 16 deletions

View File

@ -159,7 +159,7 @@ func (b *Button) keyActivated(k *terminalapi.Keyboard) bool {
b.mu.Lock()
defer b.mu.Unlock()
if k.Key == b.opts.key {
if b.opts.keys[k.Key] {
b.state = button.Down
now := time.Now().UTC()
b.keyTriggerTime = &now
@ -220,7 +220,7 @@ func (b *Button) Options() widgetapi.Options {
return widgetapi.Options{
MinimumSize: image.Point{width, height},
MaximumSize: image.Point{width, height},
WantKeyboard: widgetapi.KeyScopeGlobal,
WantKeyboard: b.opts.keyScope,
WantMouse: widgetapi.MouseScopeGlobal,
}
}

View File

@ -243,6 +243,105 @@ func TestButton(t *testing.T) {
count: 1,
},
},
{
desc: "draws button in down state due to a keyboard event when multiple keys are specified",
callback: &callbackTracker{},
text: "hello",
opts: []Option{
Keys(keyboard.KeyEnter, keyboard.KeyTab),
},
canvas: image.Rect(0, 0, 8, 4),
events: []terminalapi.Event{
&terminalapi.Keyboard{Key: keyboard.KeyTab},
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
cvs := testcanvas.MustNew(ft.Area())
// Button.
testcanvas.MustSetAreaCells(cvs, image.Rect(1, 1, 8, 4), 'x', cell.BgColor(cell.ColorNumber(117)))
// Text.
testdraw.MustText(cvs, "hello", image.Point{2, 2},
draw.TextCellOpts(
cell.FgColor(cell.ColorBlack),
cell.BgColor(cell.ColorNumber(117))),
)
testcanvas.MustApply(cvs, ft)
return ft
},
wantCallback: &callbackTracker{
called: true,
count: 1,
},
},
{
desc: "draws button in down state due to a keyboard event when single global key is specified",
callback: &callbackTracker{},
text: "hello",
opts: []Option{
GlobalKey(keyboard.KeyTab),
},
canvas: image.Rect(0, 0, 8, 4),
events: []terminalapi.Event{
&terminalapi.Keyboard{Key: keyboard.KeyTab},
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
cvs := testcanvas.MustNew(ft.Area())
// Button.
testcanvas.MustSetAreaCells(cvs, image.Rect(1, 1, 8, 4), 'x', cell.BgColor(cell.ColorNumber(117)))
// Text.
testdraw.MustText(cvs, "hello", image.Point{2, 2},
draw.TextCellOpts(
cell.FgColor(cell.ColorBlack),
cell.BgColor(cell.ColorNumber(117))),
)
testcanvas.MustApply(cvs, ft)
return ft
},
wantCallback: &callbackTracker{
called: true,
count: 1,
},
},
{
desc: "draws button in down state due to a keyboard event when multiple global keys are specified",
callback: &callbackTracker{},
text: "hello",
opts: []Option{
GlobalKeys(keyboard.KeyEnter, keyboard.KeyTab),
},
canvas: image.Rect(0, 0, 8, 4),
events: []terminalapi.Event{
&terminalapi.Keyboard{Key: keyboard.KeyTab},
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
cvs := testcanvas.MustNew(ft.Area())
// Button.
testcanvas.MustSetAreaCells(cvs, image.Rect(1, 1, 8, 4), 'x', cell.BgColor(cell.ColorNumber(117)))
// Text.
testdraw.MustText(cvs, "hello", image.Point{2, 2},
draw.TextCellOpts(
cell.FgColor(cell.ColorBlack),
cell.BgColor(cell.ColorNumber(117))),
)
testcanvas.MustApply(cvs, ft)
return ft
},
wantCallback: &callbackTracker{
called: true,
count: 1,
},
},
{
desc: "keyboard event ignored when no key specified",
callback: &callbackTracker{},
@ -814,6 +913,19 @@ func TestOptions(t *testing.T) {
WantMouse: widgetapi.MouseScopeGlobal,
},
},
{
desc: "registers for focused keyboard events when multiple keys are specified",
text: "hello",
opts: []Option{
Keys(keyboard.KeyEnter, keyboard.KeyTab),
},
want: widgetapi.Options{
MinimumSize: image.Point{8, 4},
MaximumSize: image.Point{8, 4},
WantKeyboard: widgetapi.KeyScopeFocused,
WantMouse: widgetapi.MouseScopeGlobal,
},
},
{
desc: "registers for global keyboard events",
text: "hello",
@ -827,6 +939,19 @@ func TestOptions(t *testing.T) {
WantMouse: widgetapi.MouseScopeGlobal,
},
},
{
desc: "registers for global keyboard events when multiple keys are specified",
text: "hello",
opts: []Option{
GlobalKeys(keyboard.KeyEnter, keyboard.KeyTab),
},
want: widgetapi.Options{
MinimumSize: image.Point{8, 4},
MaximumSize: image.Point{8, 4},
WantKeyboard: widgetapi.KeyScopeGlobal,
WantMouse: widgetapi.MouseScopeGlobal,
},
},
}
for _, tc := range tests {

View File

@ -47,7 +47,8 @@ type options struct {
shadowColor cell.Color
height int
width int
keyScopes []*keyScope
keys map[keyboard.Key]bool
keyScope widgetapi.KeyScope
keyUpDelay time.Duration
}
@ -80,6 +81,7 @@ func newOptions(text string) *options {
height: DefaultHeight,
width: widthFor(text),
keyUpDelay: DefaultKeyUpDelay,
keys: map[keyboard.Key]bool{},
}
}
@ -134,31 +136,53 @@ func WidthFor(text string) Option {
})
}
// Key configures the keyboard keys that press the button.
// Can be specified multiple times to provide multiple keys.
// Key configures the keyboard key that presses the button.
// The widget responds to this key only if its container is focused.
// When not provided, the widget ignores all keyboard events.
//
// Clears all keys set previously.
// Mutually exclusive with GlobalKey() and GlobalKeys().
func Key(k keyboard.Key) Option {
return option(func(opts *options) {
ks := &keyScope{
key: k,
scope: widgetapi.KeyScopeFocused,
}
opts.keyScopes = append(opts.keyScopes, ks)
opts.keys = map[keyboard.Key]bool{}
opts.keys[k] = true
opts.keyScope = widgetapi.KeyScopeFocused
})
}
// GlobalKey is like Key, but makes the widget respond to the keys even if its
// GlobalKey is like Key, but makes the widget respond to the key even if its
// container isn't focused.
// Can be specified multiple times to provide multiple keys.
// When not provided, the widget ignores all keyboard events.
//
// Clears all keys set previously.
// Mutually exclusive with Key() and Keys().
func GlobalKey(k keyboard.Key) Option {
return option(func(opts *options) {
ks := &keyScope{
key: k,
scope: widgetapi.KeyScopeGlobal,
opts.keys = map[keyboard.Key]bool{}
opts.keys[k] = true
opts.keyScope = widgetapi.KeyScopeGlobal
})
}
// Keys is like Key, but allows to configure multiple keys.
func Keys(keys ...keyboard.Key) Option {
return option(func(opts *options) {
opts.keys = map[keyboard.Key]bool{}
for _, k := range keys {
opts.keys[k] = true
}
opts.keyScopes = append(opts.keyScopes, ks)
opts.keyScope = widgetapi.KeyScopeFocused
})
}
// GlobalKeys is like GlobalKey, but allows to configure multiple keys.
func GlobalKeys(keys ...keyboard.Key) Option {
return option(func(opts *options) {
opts.keys = map[keyboard.Key]bool{}
for _, k := range keys {
opts.keys[k] = true
}
opts.keyScope = widgetapi.KeyScopeGlobal
})
}