mirror of https://github.com/mum4k/termdash.git
Allow widgets to request keyboard events exclusively.
This commit is contained in:
parent
5c2597d4db
commit
2c1b1a4bfe
|
@ -369,6 +369,9 @@ func (c *Container) keyEvTargets() []*keyEvTarget {
|
|||
var (
|
||||
errStr string
|
||||
targets []*keyEvTarget
|
||||
// If the currently focused widget set the ExclusiveKeyboardOnFocus
|
||||
// option, this pointer is set to that widget.
|
||||
exclusiveWidget widgetapi.Widget
|
||||
)
|
||||
|
||||
// All the targets that should receive this event.
|
||||
|
@ -383,6 +386,10 @@ func (c *Container) keyEvTargets() []*keyEvTarget {
|
|||
Focused: focused,
|
||||
}
|
||||
wOpt := cur.opts.widget.Options()
|
||||
if focused && wOpt.ExclusiveKeyboardOnFocus {
|
||||
exclusiveWidget = cur.opts.widget
|
||||
}
|
||||
|
||||
switch wOpt.WantKeyboard {
|
||||
case widgetapi.KeyScopeNone:
|
||||
// Widget doesn't want any keyboard events.
|
||||
|
@ -398,6 +405,12 @@ func (c *Container) keyEvTargets() []*keyEvTarget {
|
|||
}
|
||||
return nil
|
||||
}))
|
||||
|
||||
if exclusiveWidget != nil {
|
||||
targets = []*keyEvTarget{
|
||||
newKeyEvTarget(exclusiveWidget, &widgetapi.EventMeta{Focused: true}),
|
||||
}
|
||||
}
|
||||
return targets
|
||||
}
|
||||
|
||||
|
|
|
@ -1219,6 +1219,152 @@ func TestKeyboard(t *testing.T) {
|
|||
return ft
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "keyboard event forwarded to exclusive widget only when focused",
|
||||
termSize: image.Point{40, 20},
|
||||
container: func(ft *faketerm.Terminal) (*Container, error) {
|
||||
return New(
|
||||
ft,
|
||||
SplitVertical(
|
||||
Left(
|
||||
PlaceWidget(fakewidget.New(widgetapi.Options{WantKeyboard: widgetapi.KeyScopeGlobal})),
|
||||
),
|
||||
Right(
|
||||
SplitHorizontal(
|
||||
Top(
|
||||
PlaceWidget(fakewidget.New(widgetapi.Options{WantKeyboard: widgetapi.KeyScopeFocused})),
|
||||
),
|
||||
Bottom(
|
||||
PlaceWidget(fakewidget.New(
|
||||
widgetapi.Options{
|
||||
WantKeyboard: widgetapi.KeyScopeFocused,
|
||||
ExclusiveKeyboardOnFocus: true,
|
||||
},
|
||||
)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
},
|
||||
events: []terminalapi.Event{
|
||||
// Move focus to the target container.
|
||||
&terminalapi.Mouse{Position: image.Point{39, 19}, Button: mouse.ButtonLeft},
|
||||
&terminalapi.Mouse{Position: image.Point{39, 19}, Button: mouse.ButtonRelease},
|
||||
// Send the keyboard event.
|
||||
&terminalapi.Keyboard{Key: keyboard.KeyEnter},
|
||||
},
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(size)
|
||||
|
||||
// Widget that isn't focused, but registered for global
|
||||
// keyboard events.
|
||||
fakewidget.MustDraw(
|
||||
ft,
|
||||
testcanvas.MustNew(image.Rect(0, 0, 20, 20)),
|
||||
&widgetapi.Meta{},
|
||||
widgetapi.Options{WantKeyboard: widgetapi.KeyScopeGlobal},
|
||||
)
|
||||
|
||||
// Widget that isn't focused and only wants focused events.
|
||||
fakewidget.MustDraw(
|
||||
ft,
|
||||
testcanvas.MustNew(image.Rect(20, 0, 40, 10)),
|
||||
&widgetapi.Meta{},
|
||||
widgetapi.Options{WantKeyboard: widgetapi.KeyScopeFocused},
|
||||
)
|
||||
|
||||
// The focused widget receives the key.
|
||||
fakewidget.MustDraw(
|
||||
ft,
|
||||
testcanvas.MustNew(image.Rect(20, 10, 40, 20)),
|
||||
&widgetapi.Meta{Focused: true},
|
||||
widgetapi.Options{WantKeyboard: widgetapi.KeyScopeFocused},
|
||||
&fakewidget.Event{
|
||||
Ev: &terminalapi.Keyboard{Key: keyboard.KeyEnter},
|
||||
Meta: &widgetapi.EventMeta{Focused: true},
|
||||
},
|
||||
)
|
||||
return ft
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "the ExclusiveKeyboardOnFocus option has no effect when widget not focused",
|
||||
termSize: image.Point{40, 20},
|
||||
container: func(ft *faketerm.Terminal) (*Container, error) {
|
||||
return New(
|
||||
ft,
|
||||
SplitVertical(
|
||||
Left(
|
||||
PlaceWidget(fakewidget.New(widgetapi.Options{WantKeyboard: widgetapi.KeyScopeGlobal})),
|
||||
),
|
||||
Right(
|
||||
SplitHorizontal(
|
||||
Top(
|
||||
PlaceWidget(fakewidget.New(
|
||||
widgetapi.Options{
|
||||
WantKeyboard: widgetapi.KeyScopeFocused,
|
||||
ExclusiveKeyboardOnFocus: true,
|
||||
},
|
||||
)),
|
||||
),
|
||||
Bottom(
|
||||
PlaceWidget(fakewidget.New(
|
||||
widgetapi.Options{
|
||||
WantKeyboard: widgetapi.KeyScopeFocused,
|
||||
},
|
||||
)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
},
|
||||
events: []terminalapi.Event{
|
||||
// Move focus to the target container.
|
||||
&terminalapi.Mouse{Position: image.Point{39, 19}, Button: mouse.ButtonLeft},
|
||||
&terminalapi.Mouse{Position: image.Point{39, 19}, Button: mouse.ButtonRelease},
|
||||
// Send the keyboard event.
|
||||
&terminalapi.Keyboard{Key: keyboard.KeyEnter},
|
||||
},
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(size)
|
||||
|
||||
// Widget that isn't focused, but registered for global
|
||||
// keyboard events.
|
||||
fakewidget.MustDraw(
|
||||
ft,
|
||||
testcanvas.MustNew(image.Rect(0, 0, 20, 20)),
|
||||
&widgetapi.Meta{},
|
||||
widgetapi.Options{WantKeyboard: widgetapi.KeyScopeGlobal},
|
||||
&fakewidget.Event{
|
||||
Ev: &terminalapi.Keyboard{Key: keyboard.KeyEnter},
|
||||
Meta: &widgetapi.EventMeta{Focused: false},
|
||||
},
|
||||
)
|
||||
|
||||
// Widget that isn't focused and only wants focused events.
|
||||
fakewidget.MustDraw(
|
||||
ft,
|
||||
testcanvas.MustNew(image.Rect(20, 0, 40, 10)),
|
||||
&widgetapi.Meta{},
|
||||
widgetapi.Options{WantKeyboard: widgetapi.KeyScopeFocused},
|
||||
)
|
||||
|
||||
// The focused widget receives the key.
|
||||
fakewidget.MustDraw(
|
||||
ft,
|
||||
testcanvas.MustNew(image.Rect(20, 10, 40, 20)),
|
||||
&widgetapi.Meta{Focused: true},
|
||||
widgetapi.Options{WantKeyboard: widgetapi.KeyScopeFocused},
|
||||
&fakewidget.Event{
|
||||
Ev: &terminalapi.Keyboard{Key: keyboard.KeyEnter},
|
||||
Meta: &widgetapi.EventMeta{Focused: true},
|
||||
},
|
||||
)
|
||||
return ft
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "event not forwarded if the widget didn't request it",
|
||||
termSize: image.Point{40, 20},
|
||||
|
|
|
@ -130,6 +130,13 @@ type Options struct {
|
|||
// forwarded to the widget.
|
||||
WantKeyboard KeyScope
|
||||
|
||||
// ExclusiveKeyboardOnFocus allows a widget to request exclusive access to
|
||||
// keyboard events when its container is focused. When set to true, no
|
||||
// other widgets will receive any keyboard events that happen while the
|
||||
// container of this widget is focused even if they registered for
|
||||
// KeyScopeGlobal.
|
||||
ExclusiveKeyboardOnFocus bool
|
||||
|
||||
// WantMouse allows a widget to request mouse events and specify their
|
||||
// desired scope. If set to MouseScopeNone, no mouse events are forwarded
|
||||
// to the widget.
|
||||
|
|
Loading…
Reference in New Issue