mirror of
https://github.com/mum4k/termdash.git
synced 2025-04-25 13:48:50 +08:00
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 (
|
var (
|
||||||
errStr string
|
errStr string
|
||||||
targets []*keyEvTarget
|
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.
|
// All the targets that should receive this event.
|
||||||
@ -383,6 +386,10 @@ func (c *Container) keyEvTargets() []*keyEvTarget {
|
|||||||
Focused: focused,
|
Focused: focused,
|
||||||
}
|
}
|
||||||
wOpt := cur.opts.widget.Options()
|
wOpt := cur.opts.widget.Options()
|
||||||
|
if focused && wOpt.ExclusiveKeyboardOnFocus {
|
||||||
|
exclusiveWidget = cur.opts.widget
|
||||||
|
}
|
||||||
|
|
||||||
switch wOpt.WantKeyboard {
|
switch wOpt.WantKeyboard {
|
||||||
case widgetapi.KeyScopeNone:
|
case widgetapi.KeyScopeNone:
|
||||||
// Widget doesn't want any keyboard events.
|
// Widget doesn't want any keyboard events.
|
||||||
@ -398,6 +405,12 @@ func (c *Container) keyEvTargets() []*keyEvTarget {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
if exclusiveWidget != nil {
|
||||||
|
targets = []*keyEvTarget{
|
||||||
|
newKeyEvTarget(exclusiveWidget, &widgetapi.EventMeta{Focused: true}),
|
||||||
|
}
|
||||||
|
}
|
||||||
return targets
|
return targets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1219,6 +1219,152 @@ func TestKeyboard(t *testing.T) {
|
|||||||
return ft
|
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",
|
desc: "event not forwarded if the widget didn't request it",
|
||||||
termSize: image.Point{40, 20},
|
termSize: image.Point{40, 20},
|
||||||
|
@ -130,6 +130,13 @@ type Options struct {
|
|||||||
// forwarded to the widget.
|
// forwarded to the widget.
|
||||||
WantKeyboard KeyScope
|
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
|
// WantMouse allows a widget to request mouse events and specify their
|
||||||
// desired scope. If set to MouseScopeNone, no mouse events are forwarded
|
// desired scope. If set to MouseScopeNone, no mouse events are forwarded
|
||||||
// to the widget.
|
// to the widget.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user