diff --git a/CHANGELOG.md b/CHANGELOG.md index 909e43ec..9c1ad255 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Breaking API changes + +- The `widgetapi.Widget.Keyboard` and `widgetapi.Widget.Mouse` method now + accepts a second argument which provides widgets with additional metadata. + This affects all implemented widgets. + ### Added - ability to configure keyboard keys that move focus to the next or the diff --git a/container/container.go b/container/container.go index adb147d4..ad26483a 100644 --- a/container/container.go +++ b/container/container.go @@ -320,7 +320,7 @@ func (c *Container) prepareEvTargets(ev terminalapi.Event) (func() error, error) } return func() error { for _, mt := range targets { - if err := mt.widget.Mouse(mt.ev); err != nil { + if err := mt.widget.Mouse(mt.ev, mt.meta); err != nil { return err } } @@ -328,16 +328,12 @@ func (c *Container) prepareEvTargets(ev terminalapi.Event) (func() error, error) }, nil case *terminalapi.Keyboard: - targets := c.keyEvTargets() - - // Update the focused container based on the pressed key. - // Done after collecting "targets" above. If the key changes which - // container is focused, they key press itself should go to the widget - // that was focused when the key was pressed. c.updateFocusFromKeyboard(ev.(*terminalapi.Keyboard)) + + targets := c.keyEvTargets() return func() error { - for _, w := range targets { - if err := w.Keyboard(e); err != nil { + for _, kt := range targets { + if err := kt.widget.Keyboard(e, kt.meta); err != nil { return err } } @@ -349,22 +345,43 @@ func (c *Container) prepareEvTargets(ev terminalapi.Event) (func() error, error) } } +// keyEvTarget contains a widget that should receive an event and the metadata +// for the event. +type keyEvTarget struct { + // widget is the widget that should receive the keyboard event. + widget widgetapi.Widget + // meta is the metadata about the event. + meta *widgetapi.EventMeta +} + +// newKeyEvTarget returns a new keyEvTarget. +func newKeyEvTarget(w widgetapi.Widget, meta *widgetapi.EventMeta) *keyEvTarget { + return &keyEvTarget{ + widget: w, + meta: meta, + } +} + // keyEvTargets returns those widgets found in the container that should // receive this keyboard event. // Caller must hold c.mu. -func (c *Container) keyEvTargets() []widgetapi.Widget { +func (c *Container) keyEvTargets() []*keyEvTarget { var ( errStr string - widgets []widgetapi.Widget + targets []*keyEvTarget ) - // All the widgets that should receive this event. + // All the targets that should receive this event. // For now stable ordering (preOrder). preOrder(c, &errStr, visitFunc(func(cur *Container) error { if !cur.hasWidget() { return nil } + focused := cur.focusTracker.isActive(cur) + meta := &widgetapi.EventMeta{ + Focused: focused, + } wOpt := cur.opts.widget.Options() switch wOpt.WantKeyboard { case widgetapi.KeyScopeNone: @@ -372,32 +389,35 @@ func (c *Container) keyEvTargets() []widgetapi.Widget { return nil case widgetapi.KeyScopeFocused: - if cur.focusTracker.isActive(cur) { - widgets = append(widgets, cur.opts.widget) + if focused { + targets = append(targets, newKeyEvTarget(cur.opts.widget, meta)) } case widgetapi.KeyScopeGlobal: - widgets = append(widgets, cur.opts.widget) + targets = append(targets, newKeyEvTarget(cur.opts.widget, meta)) } return nil })) - return widgets + return targets } -// mouseEvTarget contains a mouse event adjusted relative to the widget's area -// and the widget that should receive it. +// mouseEvTarget contains a mouse event adjusted relative to the widget's area, +// the widget that should receive it and metadata about the event. type mouseEvTarget struct { // widget is the widget that should receive the mouse event. widget widgetapi.Widget // ev is the adjusted mouse event. ev *terminalapi.Mouse + // meta is the metadata about the event. + meta *widgetapi.EventMeta } -// newMouseEvTarget returns a new newMouseEvTarget. -func newMouseEvTarget(w widgetapi.Widget, wArea image.Rectangle, ev *terminalapi.Mouse) *mouseEvTarget { +// newMouseEvTarget returns a new mouseEvTarget. +func newMouseEvTarget(w widgetapi.Widget, wArea image.Rectangle, ev *terminalapi.Mouse, meta *widgetapi.EventMeta) *mouseEvTarget { return &mouseEvTarget{ widget: w, ev: adjustMouseEv(ev, wArea), + meta: meta, } } @@ -423,6 +443,9 @@ func (c *Container) mouseEvTargets(m *terminalapi.Mouse) ([]*mouseEvTarget, erro return err } + meta := &widgetapi.EventMeta{ + Focused: cur.focusTracker.isActive(cur), + } switch wOpts.WantMouse { case widgetapi.MouseScopeNone: // Widget doesn't want any mouse events. @@ -431,18 +454,18 @@ func (c *Container) mouseEvTargets(m *terminalapi.Mouse) ([]*mouseEvTarget, erro case widgetapi.MouseScopeWidget: // Only if the event falls inside of the widget's canvas. if m.Position.In(wa) { - widgets = append(widgets, newMouseEvTarget(cur.opts.widget, wa, m)) + widgets = append(widgets, newMouseEvTarget(cur.opts.widget, wa, m, meta)) } case widgetapi.MouseScopeContainer: // Only if the event falls inside the widget's parent container. if m.Position.In(cur.area) { - widgets = append(widgets, newMouseEvTarget(cur.opts.widget, wa, m)) + widgets = append(widgets, newMouseEvTarget(cur.opts.widget, wa, m, meta)) } case widgetapi.MouseScopeGlobal: // Widget wants all mouse events. - widgets = append(widgets, newMouseEvTarget(cur.opts.widget, wa, m)) + widgets = append(widgets, newMouseEvTarget(cur.opts.widget, wa, m, meta)) } return nil })) diff --git a/container/container_test.go b/container/container_test.go index 6ee2b21f..6ea5b9ec 100644 --- a/container/container_test.go +++ b/container/container_test.go @@ -1143,7 +1143,10 @@ func TestKeyboard(t *testing.T) { testcanvas.MustNew(image.Rect(20, 10, 40, 20)), &widgetapi.Meta{Focused: true}, widgetapi.Options{WantKeyboard: widgetapi.KeyScopeFocused}, - &terminalapi.Keyboard{Key: keyboard.KeyEnter}, + &fakewidget.Event{ + Ev: &terminalapi.Keyboard{Key: keyboard.KeyEnter}, + Meta: &widgetapi.EventMeta{}, + }, ) return ft }, @@ -1188,7 +1191,10 @@ func TestKeyboard(t *testing.T) { testcanvas.MustNew(image.Rect(0, 0, 20, 20)), &widgetapi.Meta{}, widgetapi.Options{WantKeyboard: widgetapi.KeyScopeGlobal}, - &terminalapi.Keyboard{Key: keyboard.KeyEnter}, + &fakewidget.Event{ + Ev: &terminalapi.Keyboard{Key: keyboard.KeyEnter}, + Meta: &widgetapi.EventMeta{}, + }, ) // Widget that isn't focused and only wants focused events. @@ -1205,7 +1211,10 @@ func TestKeyboard(t *testing.T) { testcanvas.MustNew(image.Rect(20, 10, 40, 20)), &widgetapi.Meta{Focused: true}, widgetapi.Options{WantKeyboard: widgetapi.KeyScopeFocused}, - &terminalapi.Keyboard{Key: keyboard.KeyEnter}, + &fakewidget.Event{ + Ev: &terminalapi.Keyboard{Key: keyboard.KeyEnter}, + Meta: &widgetapi.EventMeta{}, + }, ) return ft }, @@ -1412,7 +1421,6 @@ func TestMouse(t *testing.T) { testcanvas.MustNew(image.Rect(25, 10, 50, 20)), &widgetapi.Meta{}, widgetapi.Options{WantMouse: widgetapi.MouseScopeWidget}, - &terminalapi.Keyboard{}, ) // The target widget receives the mouse event. @@ -1421,8 +1429,14 @@ func TestMouse(t *testing.T) { testcanvas.MustNew(image.Rect(25, 0, 50, 10)), &widgetapi.Meta{Focused: true}, widgetapi.Options{WantMouse: widgetapi.MouseScopeWidget}, - &terminalapi.Mouse{Position: image.Point{24, 9}, Button: mouse.ButtonLeft}, - &terminalapi.Mouse{Position: image.Point{24, 9}, Button: mouse.ButtonRelease}, + &fakewidget.Event{ + Ev: &terminalapi.Mouse{Position: image.Point{24, 9}, Button: mouse.ButtonLeft}, + Meta: &widgetapi.EventMeta{}, + }, + &fakewidget.Event{ + Ev: &terminalapi.Mouse{Position: image.Point{24, 9}, Button: mouse.ButtonRelease}, + Meta: &widgetapi.EventMeta{}, + }, ) return ft }, @@ -1495,7 +1509,6 @@ func TestMouse(t *testing.T) { testcanvas.MustNew(image.Rect(25, 10, 50, 20)), &widgetapi.Meta{}, widgetapi.Options{WantMouse: widgetapi.MouseScopeWidget}, - &terminalapi.Keyboard{}, ) // The target widget receives the mouse event. @@ -1504,14 +1517,20 @@ func TestMouse(t *testing.T) { testcanvas.MustNew(image.Rect(26, 1, 49, 9)), &widgetapi.Meta{Focused: true}, widgetapi.Options{WantMouse: widgetapi.MouseScopeWidget}, - &terminalapi.Mouse{Position: image.Point{22, 7}, Button: mouse.ButtonLeft}, - &terminalapi.Mouse{Position: image.Point{22, 7}, Button: mouse.ButtonRelease}, + &fakewidget.Event{ + Ev: &terminalapi.Mouse{Position: image.Point{22, 7}, Button: mouse.ButtonLeft}, + Meta: &widgetapi.EventMeta{}, + }, + &fakewidget.Event{ + Ev: &terminalapi.Mouse{Position: image.Point{22, 7}, Button: mouse.ButtonRelease}, + Meta: &widgetapi.EventMeta{}, + }, ) return ft }, }, { - desc: "key event focuses the next container, widget with KeyScopeFocused does not get the key as it was not focused yet", + desc: "key event focuses the next container, widget with KeyScopeFocused gets the key as it is now focused", termSize: image.Point{50, 20}, container: func(ft *faketerm.Terminal) (*Container, error) { c, err := New( @@ -1542,6 +1561,10 @@ func TestMouse(t *testing.T) { testcanvas.MustNew(image.Rect(0, 0, 25, 20)), &widgetapi.Meta{Focused: true}, widgetapi.Options{WantKeyboard: widgetapi.KeyScopeFocused}, + &fakewidget.Event{ + Ev: &terminalapi.Keyboard{Key: keyboard.KeyTab}, + Meta: &widgetapi.EventMeta{}, + }, ) fakewidget.MustDraw( ft, @@ -1591,6 +1614,10 @@ func TestMouse(t *testing.T) { testcanvas.MustNew(image.Rect(25, 0, 50, 20)), &widgetapi.Meta{Focused: true}, widgetapi.Options{WantKeyboard: widgetapi.KeyScopeFocused}, + &fakewidget.Event{ + Ev: &terminalapi.Keyboard{Key: keyboard.KeyTab}, + Meta: &widgetapi.EventMeta{}, + }, ) return ft }, @@ -1627,19 +1654,26 @@ func TestMouse(t *testing.T) { testcanvas.MustNew(image.Rect(0, 0, 25, 20)), &widgetapi.Meta{Focused: true}, widgetapi.Options{WantKeyboard: widgetapi.KeyScopeFocused}, + &fakewidget.Event{ + Ev: &terminalapi.Keyboard{Key: keyboard.KeyTab}, + Meta: &widgetapi.EventMeta{}, + }, ) fakewidget.MustDraw( ft, testcanvas.MustNew(image.Rect(25, 0, 50, 20)), &widgetapi.Meta{}, widgetapi.Options{WantKeyboard: widgetapi.KeyScopeGlobal}, - &terminalapi.Keyboard{Key: keyboard.KeyTab}, + &fakewidget.Event{ + Ev: &terminalapi.Keyboard{Key: keyboard.KeyTab}, + Meta: &widgetapi.EventMeta{}, + }, ) return ft }, }, { - desc: "key event moves focus from a widget with KeyScopeFocused, the originally focused widget gets the key", + desc: "key event moves focus from a widget with KeyScopeFocused, the newly focused widget gets the key", termSize: image.Point{50, 20}, container: func(ft *faketerm.Terminal) (*Container, error) { c, err := New( @@ -1673,13 +1707,21 @@ func TestMouse(t *testing.T) { testcanvas.MustNew(image.Rect(0, 0, 25, 20)), &widgetapi.Meta{}, widgetapi.Options{WantKeyboard: widgetapi.KeyScopeFocused}, - &terminalapi.Keyboard{Key: keyboard.KeyTab}, + // Also gets the key, since we are sending two events above. + &fakewidget.Event{ + Ev: &terminalapi.Keyboard{Key: keyboard.KeyTab}, + Meta: &widgetapi.EventMeta{}, + }, ) fakewidget.MustDraw( ft, testcanvas.MustNew(image.Rect(25, 0, 50, 20)), &widgetapi.Meta{Focused: true}, widgetapi.Options{WantKeyboard: widgetapi.KeyScopeFocused}, + &fakewidget.Event{ + Ev: &terminalapi.Keyboard{Key: keyboard.KeyTab}, + Meta: &widgetapi.EventMeta{}, + }, ) return ft }, @@ -1774,7 +1816,10 @@ func TestMouse(t *testing.T) { testcanvas.MustNew(image.Rect(1, 1, 20, 19)), &widgetapi.Meta{Focused: true}, widgetapi.Options{WantMouse: widgetapi.MouseScopeWidget}, - &terminalapi.Mouse{Position: image.Point{-1, -1}, Button: mouse.ButtonLeft}, + &fakewidget.Event{ + Ev: &terminalapi.Mouse{Position: image.Point{-1, -1}, Button: mouse.ButtonLeft}, + Meta: &widgetapi.EventMeta{}, + }, ) return ft }, @@ -1810,7 +1855,10 @@ func TestMouse(t *testing.T) { testcanvas.MustNew(image.Rect(1, 1, 20, 19)), &widgetapi.Meta{Focused: true}, widgetapi.Options{WantMouse: widgetapi.MouseScopeWidget}, - &terminalapi.Mouse{Position: image.Point{-1, -1}, Button: mouse.ButtonLeft}, + &fakewidget.Event{ + Ev: &terminalapi.Mouse{Position: image.Point{-1, -1}, Button: mouse.ButtonLeft}, + Meta: &widgetapi.EventMeta{}, + }, ) return ft }, @@ -1873,7 +1921,10 @@ func TestMouse(t *testing.T) { testcanvas.MustNew(image.Rect(0, 5, 20, 15)), &widgetapi.Meta{Focused: true}, widgetapi.Options{WantMouse: widgetapi.MouseScopeWidget}, - &terminalapi.Mouse{Position: image.Point{-1, -1}, Button: mouse.ButtonLeft}, + &fakewidget.Event{ + Ev: &terminalapi.Mouse{Position: image.Point{-1, -1}, Button: mouse.ButtonLeft}, + Meta: &widgetapi.EventMeta{}, + }, ) return ft }, @@ -1905,7 +1956,10 @@ func TestMouse(t *testing.T) { testcanvas.MustNew(image.Rect(0, 5, 20, 15)), &widgetapi.Meta{Focused: true}, widgetapi.Options{WantMouse: widgetapi.MouseScopeWidget}, - &terminalapi.Mouse{Position: image.Point{-1, -1}, Button: mouse.ButtonLeft}, + &fakewidget.Event{ + Ev: &terminalapi.Mouse{Position: image.Point{-1, -1}, Button: mouse.ButtonLeft}, + Meta: &widgetapi.EventMeta{}, + }, ) return ft }, @@ -2014,7 +2068,10 @@ func TestMouse(t *testing.T) { testcanvas.MustNew(image.Rect(0, 10, 20, 20)), &widgetapi.Meta{}, widgetapi.Options{WantMouse: widgetapi.MouseScopeWidget}, - &terminalapi.Mouse{Position: image.Point{-1, -1}, Button: mouse.ButtonLeft}, + &fakewidget.Event{ + Ev: &terminalapi.Mouse{Position: image.Point{-1, -1}, Button: mouse.ButtonLeft}, + Meta: &widgetapi.EventMeta{}, + }, ) return ft }, @@ -2046,7 +2103,10 @@ func TestMouse(t *testing.T) { testcanvas.MustNew(image.Rect(0, 5, 20, 15)), &widgetapi.Meta{Focused: true}, widgetapi.Options{WantMouse: widgetapi.MouseScopeWidget}, - &terminalapi.Mouse{Position: image.Point{0, 0}, Button: mouse.ButtonLeft}, + &fakewidget.Event{ + Ev: &terminalapi.Mouse{Position: image.Point{0, 0}, Button: mouse.ButtonLeft}, + Meta: &widgetapi.EventMeta{}, + }, ) return ft }, @@ -2078,7 +2138,10 @@ func TestMouse(t *testing.T) { testcanvas.MustNew(image.Rect(6, 0, 24, 20)), &widgetapi.Meta{Focused: true}, widgetapi.Options{WantMouse: widgetapi.MouseScopeWidget}, - &terminalapi.Mouse{Position: image.Point{0, 0}, Button: mouse.ButtonLeft}, + &fakewidget.Event{ + Ev: &terminalapi.Mouse{Position: image.Point{0, 0}, Button: mouse.ButtonLeft}, + Meta: &widgetapi.EventMeta{}, + }, ) return ft }, @@ -2510,7 +2573,10 @@ func TestUpdate(t *testing.T) { cvs, &widgetapi.Meta{Focused: true}, widgetapi.Options{WantKeyboard: widgetapi.KeyScopeFocused}, - &terminalapi.Keyboard{Key: keyboard.KeyEnter}, + &fakewidget.Event{ + Ev: &terminalapi.Keyboard{Key: keyboard.KeyEnter}, + Meta: &widgetapi.EventMeta{}, + }, ) testcanvas.MustApply(cvs, ft) return ft @@ -2542,7 +2608,10 @@ func TestUpdate(t *testing.T) { cvs, &widgetapi.Meta{Focused: true}, widgetapi.Options{WantMouse: widgetapi.MouseScopeWidget}, - &terminalapi.Mouse{Position: image.Point{0, 0}, Button: mouse.ButtonRelease}, + &fakewidget.Event{ + Ev: &terminalapi.Mouse{Position: image.Point{0, 0}, Button: mouse.ButtonRelease}, + Meta: &widgetapi.EventMeta{}, + }, ) testcanvas.MustApply(cvs, ft) return ft diff --git a/private/fakewidget/fakewidget.go b/private/fakewidget/fakewidget.go index 5392aced..70c65b1f 100644 --- a/private/fakewidget/fakewidget.go +++ b/private/fakewidget/fakewidget.go @@ -43,6 +43,14 @@ const ( // MinimumSize is the minimum size required to draw this widget. var MinimumSize = image.Point{24, 5} +// Event is an event that should be delivered to the fake widget. +type Event struct { + // Ev is the event to deliver. + Ev terminalapi.Event + // Meta is metadata about the event. + Meta *widgetapi.EventMeta +} + // Mirror is a fake widget. The fake widget draws a border around its assigned // canvas and writes the size of its assigned canvas on the first line of the // canvas. It writes the last received keyboard event onto the second line. It @@ -126,7 +134,7 @@ func (mi *Mirror) Text(txt string) { // Sending the keyboard.KeyEsc causes this widget to forget the last keyboard // event and return an error instead. // Keyboard implements widgetapi.Widget.Keyboard. -func (mi *Mirror) Keyboard(k *terminalapi.Keyboard) error { +func (mi *Mirror) Keyboard(k *terminalapi.Keyboard, meta *widgetapi.EventMeta) error { mi.mu.Lock() defer mi.mu.Unlock() @@ -143,7 +151,7 @@ func (mi *Mirror) Keyboard(k *terminalapi.Keyboard) error { // Sending the mouse.ButtonRight causes this widget to forget the last mouse // event and return an error instead. // Mouse implements widgetapi.Widget.Mouse. -func (mi *Mirror) Mouse(m *terminalapi.Mouse) error { +func (mi *Mirror) Mouse(m *terminalapi.Mouse, meta *widgetapi.EventMeta) error { mi.mu.Lock() defer mi.mu.Unlock() @@ -162,34 +170,34 @@ func (mi *Mirror) Options() widgetapi.Options { // Draw draws the content that would be expected after placing the Mirror // widget onto the provided canvas and forwarding the given events. -func Draw(t terminalapi.Terminal, cvs *canvas.Canvas, meta *widgetapi.Meta, opts widgetapi.Options, events ...terminalapi.Event) error { +func Draw(t terminalapi.Terminal, cvs *canvas.Canvas, meta *widgetapi.Meta, opts widgetapi.Options, events ...*Event) error { mirror := New(opts) return DrawWithMirror(mirror, t, cvs, meta, events...) } // MustDraw is like Draw, but panics on all errors. -func MustDraw(t terminalapi.Terminal, cvs *canvas.Canvas, meta *widgetapi.Meta, opts widgetapi.Options, events ...terminalapi.Event) { +func MustDraw(t terminalapi.Terminal, cvs *canvas.Canvas, meta *widgetapi.Meta, opts widgetapi.Options, events ...*Event) { if err := Draw(t, cvs, meta, opts, events...); err != nil { panic(fmt.Sprintf("Draw => %v", err)) } } // DrawWithMirror is like Draw, but uses the provided Mirror instead of creating one. -func DrawWithMirror(mirror *Mirror, t terminalapi.Terminal, cvs *canvas.Canvas, meta *widgetapi.Meta, events ...terminalapi.Event) error { +func DrawWithMirror(mirror *Mirror, t terminalapi.Terminal, cvs *canvas.Canvas, meta *widgetapi.Meta, events ...*Event) error { for _, ev := range events { - switch e := ev.(type) { + switch e := ev.Ev.(type) { case *terminalapi.Mouse: if mirror.opts.WantMouse == widgetapi.MouseScopeNone { continue } - if err := mirror.Mouse(e); err != nil { + if err := mirror.Mouse(e, ev.Meta); err != nil { return err } case *terminalapi.Keyboard: if mirror.opts.WantKeyboard == widgetapi.KeyScopeNone { continue } - if err := mirror.Keyboard(e); err != nil { + if err := mirror.Keyboard(e, ev.Meta); err != nil { return err } default: @@ -204,7 +212,7 @@ func DrawWithMirror(mirror *Mirror, t terminalapi.Terminal, cvs *canvas.Canvas, } // MustDrawWithMirror is like DrawWithMirror, but panics on all errors. -func MustDrawWithMirror(mirror *Mirror, t terminalapi.Terminal, cvs *canvas.Canvas, meta *widgetapi.Meta, events ...terminalapi.Event) { +func MustDrawWithMirror(mirror *Mirror, t terminalapi.Terminal, cvs *canvas.Canvas, meta *widgetapi.Meta, events ...*Event) { if err := DrawWithMirror(mirror, t, cvs, meta, events...); err != nil { panic(fmt.Sprintf("DrawWithMirror => %v", err)) } diff --git a/private/fakewidget/fakewidget_test.go b/private/fakewidget/fakewidget_test.go index 223471f6..730c7cad 100644 --- a/private/fakewidget/fakewidget_test.go +++ b/private/fakewidget/fakewidget_test.go @@ -276,14 +276,14 @@ func TestMirror(t *testing.T) { } for _, keyEv := range tc.keyEvents { - err := w.Keyboard(keyEv.k) + err := w.Keyboard(keyEv.k, &widgetapi.EventMeta{}) if (err != nil) != keyEv.wantErr { t.Errorf("Keyboard => got error:%v, wantErr: %v", err, keyEv.wantErr) } } for _, mouseEv := range tc.mouseEvents { - err := w.Mouse(mouseEv.m) + err := w.Mouse(mouseEv.m, &widgetapi.EventMeta{}) if (err != nil) != mouseEv.wantErr { t.Errorf("Mouse => got error:%v, wantErr: %v", err, mouseEv.wantErr) } @@ -325,7 +325,7 @@ func TestDraw(t *testing.T) { opts widgetapi.Options cvs *canvas.Canvas meta *widgetapi.Meta - events []terminalapi.Event + events []*Event want func(size image.Point) *faketerm.Terminal wantErr bool }{ @@ -359,9 +359,15 @@ func TestDraw(t *testing.T) { }, cvs: testcanvas.MustNew(image.Rect(0, 0, 17, 5)), meta: &widgetapi.Meta{}, - events: []terminalapi.Event{ - &terminalapi.Keyboard{Key: keyboard.KeyEnter}, - &terminalapi.Mouse{Button: mouse.ButtonLeft}, + events: []*Event{ + { + Ev: &terminalapi.Keyboard{Key: keyboard.KeyEnter}, + Meta: &widgetapi.EventMeta{}, + }, + { + Ev: &terminalapi.Mouse{Button: mouse.ButtonLeft}, + Meta: &widgetapi.EventMeta{}, + }, }, want: func(size image.Point) *faketerm.Terminal { ft := faketerm.MustNew(size) diff --git a/termdash_test.go b/termdash_test.go index 7165eb2d..2839415b 100644 --- a/termdash_test.go +++ b/termdash_test.go @@ -253,7 +253,10 @@ func TestRun(t *testing.T) { widgetapi.Options{ WantMouse: widgetapi.MouseScopeWidget, }, - &terminalapi.Mouse{Position: image.Point{0, 0}, Button: mouse.ButtonLeft}, + &fakewidget.Event{ + Ev: &terminalapi.Mouse{Position: image.Point{0, 0}, Button: mouse.ButtonLeft}, + Meta: &widgetapi.EventMeta{}, + }, ) return ft }, @@ -281,7 +284,10 @@ func TestRun(t *testing.T) { WantKeyboard: widgetapi.KeyScopeFocused, WantMouse: widgetapi.MouseScopeWidget, }, - &terminalapi.Keyboard{Key: keyboard.KeyEnter}, + &fakewidget.Event{ + Ev: &terminalapi.Keyboard{Key: keyboard.KeyEnter}, + Meta: &widgetapi.EventMeta{}, + }, ) return ft }, @@ -347,7 +353,10 @@ func TestRun(t *testing.T) { widgetapi.Options{ WantKeyboard: widgetapi.KeyScopeFocused, }, - &terminalapi.Keyboard{Key: keyboard.KeyF1}, + &fakewidget.Event{ + Ev: &terminalapi.Keyboard{Key: keyboard.KeyF1}, + Meta: &widgetapi.EventMeta{}, + }, ) return ft }, @@ -382,7 +391,10 @@ func TestRun(t *testing.T) { widgetapi.Options{ WantMouse: widgetapi.MouseScopeWidget, }, - &terminalapi.Mouse{Position: image.Point{0, 0}, Button: mouse.ButtonWheelUp}, + &fakewidget.Event{ + Ev: &terminalapi.Mouse{Position: image.Point{0, 0}, Button: mouse.ButtonWheelUp}, + Meta: &widgetapi.EventMeta{}, + }, ) return ft }, @@ -491,7 +503,10 @@ func TestController(t *testing.T) { WantKeyboard: widgetapi.KeyScopeFocused, WantMouse: widgetapi.MouseScopeWidget, }, - &terminalapi.Keyboard{Key: keyboard.KeyEnter}, + &fakewidget.Event{ + Ev: &terminalapi.Keyboard{Key: keyboard.KeyEnter}, + Meta: &widgetapi.EventMeta{}, + }, ) return ft diff --git a/widgetapi/widgetapi.go b/widgetapi/widgetapi.go index ee27136a..6f31c879 100644 --- a/widgetapi/widgetapi.go +++ b/widgetapi/widgetapi.go @@ -145,6 +145,14 @@ type Meta struct { Focused bool } +// EventMeta provides additional metadata about events to widgets. +type EventMeta struct { + // Focused asserts whether the widget's container is focused at the time of the event. + // If the event itself changes focus, the value here reflects the state of + // the focus after the change. + Focused bool +} + // Widget is a single widget on the dashboard. // Implementations must be thread safe. type Widget interface { @@ -159,15 +167,17 @@ type Widget interface { // The argument meta is guaranteed to be valid (i.e. non-nil). Draw(cvs *canvas.Canvas, meta *Meta) error - // Keyboard is called when the widget is focused on the dashboard and a key - // shortcut the widget registered for was pressed. Only called if the widget - // registered for keyboard events. - Keyboard(k *terminalapi.Keyboard) error + // Keyboard is called with every keyboard event whose scope the widget + // registered for. + // + // The argument meta is guaranteed to be valid (i.e. non-nil). + Keyboard(k *terminalapi.Keyboard, meta *EventMeta) error - // Mouse is called when the widget is focused on the dashboard and a mouse - // event happens on its canvas. Only called if the widget registered for mouse - // events. - Mouse(m *terminalapi.Mouse) error + // Mouse is called with every mouse event whose scope the widget registered + // for. + // + // The argument meta is guaranteed to be valid (i.e. non-nil). + Mouse(m *terminalapi.Mouse, meta *EventMeta) error // Options returns registration options for the widget. // This is how the widget indicates to the infrastructure whether it is diff --git a/widgets/barchart/barchart.go b/widgets/barchart/barchart.go index 413d3e2e..c439299e 100644 --- a/widgets/barchart/barchart.go +++ b/widgets/barchart/barchart.go @@ -280,12 +280,12 @@ func (bc *BarChart) Values(values []int, max int, opts ...Option) error { } // Keyboard input isn't supported on the BarChart widget. -func (*BarChart) Keyboard(k *terminalapi.Keyboard) error { +func (*BarChart) Keyboard(k *terminalapi.Keyboard, meta *widgetapi.EventMeta) error { return errors.New("the BarChart widget doesn't support keyboard events") } // Mouse input isn't supported on the BarChart widget. -func (*BarChart) Mouse(m *terminalapi.Mouse) error { +func (*BarChart) Mouse(m *terminalapi.Mouse, meta *widgetapi.EventMeta) error { return errors.New("the BarChart widget doesn't support mouse events") } diff --git a/widgets/button/button.go b/widgets/button/button.go index d0c848f2..441103c9 100644 --- a/widgets/button/button.go +++ b/widgets/button/button.go @@ -172,7 +172,7 @@ func (b *Button) keyActivated(k *terminalapi.Keyboard) bool { // Key. // // Implements widgetapi.Widget.Keyboard. -func (b *Button) Keyboard(k *terminalapi.Keyboard) error { +func (b *Button) Keyboard(k *terminalapi.Keyboard, meta *widgetapi.EventMeta) error { if b.keyActivated(k) { // Mutex must be released when calling the callback. // Users might call container methods from the callback like the @@ -198,7 +198,7 @@ func (b *Button) mouseActivated(m *terminalapi.Mouse) bool { // the release happen inside the button. // // Implements widgetapi.Widget.Mouse. -func (b *Button) Mouse(m *terminalapi.Mouse) error { +func (b *Button) Mouse(m *terminalapi.Mouse, meta *widgetapi.EventMeta) error { if b.mouseActivated(m) { // Mutex must be released when calling the callback. // Users might call container methods from the callback like the diff --git a/widgets/button/button_test.go b/widgets/button/button_test.go index 20721b7e..d455f011 100644 --- a/widgets/button/button_test.go +++ b/widgets/button/button_test.go @@ -648,7 +648,7 @@ func TestButton(t *testing.T) { for i, ev := range tc.events { switch e := ev.(type) { case *terminalapi.Mouse: - err := b.Mouse(e) + err := b.Mouse(e, &widgetapi.EventMeta{}) // Only the last event in test cases is the one that triggers the callback. if i == len(tc.events)-1 { if (err != nil) != tc.wantCallbackErr { @@ -664,7 +664,7 @@ func TestButton(t *testing.T) { } case *terminalapi.Keyboard: - err := b.Keyboard(e) + err := b.Keyboard(e, &widgetapi.EventMeta{}) // Only the last event in test cases is the one that triggers the callback. if i == len(tc.events)-1 { if (err != nil) != tc.wantCallbackErr { diff --git a/widgets/donut/donut.go b/widgets/donut/donut.go index 52c2fbfa..7d987921 100644 --- a/widgets/donut/donut.go +++ b/widgets/donut/donut.go @@ -273,12 +273,12 @@ func (d *Donut) Draw(cvs *canvas.Canvas, meta *widgetapi.Meta) error { } // Keyboard input isn't supported on the Donut widget. -func (*Donut) Keyboard(k *terminalapi.Keyboard) error { +func (*Donut) Keyboard(k *terminalapi.Keyboard, meta *widgetapi.EventMeta) error { return errors.New("the Donut widget doesn't support keyboard events") } // Mouse input isn't supported on the Donut widget. -func (*Donut) Mouse(m *terminalapi.Mouse) error { +func (*Donut) Mouse(m *terminalapi.Mouse, meta *widgetapi.EventMeta) error { return errors.New("the Donut widget doesn't support mouse events") } diff --git a/widgets/donut/donut_test.go b/widgets/donut/donut_test.go index bdb0d505..2ff8ddb7 100644 --- a/widgets/donut/donut_test.go +++ b/widgets/donut/donut_test.go @@ -883,7 +883,7 @@ func TestKeyboard(t *testing.T) { if err != nil { t.Fatalf("New => unexpected error: %v", err) } - if err := d.Keyboard(&terminalapi.Keyboard{}); err == nil { + if err := d.Keyboard(&terminalapi.Keyboard{}, &widgetapi.EventMeta{}); err == nil { t.Errorf("Keyboard => got nil err, wanted one") } } @@ -893,7 +893,7 @@ func TestMouse(t *testing.T) { if err != nil { t.Fatalf("New => unexpected error: %v", err) } - if err := d.Mouse(&terminalapi.Mouse{}); err == nil { + if err := d.Mouse(&terminalapi.Mouse{}, &widgetapi.EventMeta{}); err == nil { t.Errorf("Mouse => got nil err, wanted one") } } diff --git a/widgets/gauge/gauge.go b/widgets/gauge/gauge.go index fd7f8523..e850b596 100644 --- a/widgets/gauge/gauge.go +++ b/widgets/gauge/gauge.go @@ -288,12 +288,12 @@ func (g *Gauge) Draw(cvs *canvas.Canvas, meta *widgetapi.Meta) error { } // Keyboard input isn't supported on the Gauge widget. -func (g *Gauge) Keyboard(k *terminalapi.Keyboard) error { +func (g *Gauge) Keyboard(k *terminalapi.Keyboard, meta *widgetapi.EventMeta) error { return errors.New("the Gauge widget doesn't support keyboard events") } // Mouse input isn't supported on the Gauge widget. -func (g *Gauge) Mouse(m *terminalapi.Mouse) error { +func (g *Gauge) Mouse(m *terminalapi.Mouse, meta *widgetapi.EventMeta) error { return errors.New("the Gauge widget doesn't support mouse events") } diff --git a/widgets/gauge/gauge_test.go b/widgets/gauge/gauge_test.go index ac6331d4..cb43297b 100644 --- a/widgets/gauge/gauge_test.go +++ b/widgets/gauge/gauge_test.go @@ -908,7 +908,7 @@ func TestKeyboard(t *testing.T) { if err != nil { t.Fatalf("New => unexpected error: %v", err) } - if err := g.Keyboard(&terminalapi.Keyboard{}); err == nil { + if err := g.Keyboard(&terminalapi.Keyboard{}, &widgetapi.EventMeta{}); err == nil { t.Errorf("Keyboard => got nil err, wanted one") } } @@ -918,7 +918,7 @@ func TestMouse(t *testing.T) { if err != nil { t.Fatalf("New => unexpected error: %v", err) } - if err := g.Mouse(&terminalapi.Mouse{}); err == nil { + if err := g.Mouse(&terminalapi.Mouse{}, &widgetapi.EventMeta{}); err == nil { t.Errorf("Mouse => got nil err, wanted one") } } diff --git a/widgets/heatmap/heatmap.go b/widgets/heatmap/heatmap.go index f3400534..12f3293f 100644 --- a/widgets/heatmap/heatmap.go +++ b/widgets/heatmap/heatmap.go @@ -128,12 +128,12 @@ func (hp *HeatMap) minSize() image.Point { } // Keyboard input isn't supported on the HeatMap widget. -func (*HeatMap) Keyboard(k *terminalapi.Keyboard) error { +func (*HeatMap) Keyboard(k *terminalapi.Keyboard, meta *widgetapi.EventMeta) error { return errors.New("the HeatMap widget doesn't support keyboard events") } // Mouse input isn't supported on the HeatMap widget. -func (*HeatMap) Mouse(m *terminalapi.Mouse) error { +func (*HeatMap) Mouse(m *terminalapi.Mouse, meta *widgetapi.EventMeta) error { return errors.New("the HeatMap widget doesn't support mouse events") } diff --git a/widgets/linechart/linechart.go b/widgets/linechart/linechart.go index 0a4f83d1..5880d450 100644 --- a/widgets/linechart/linechart.go +++ b/widgets/linechart/linechart.go @@ -478,12 +478,12 @@ func (lc *LineChart) highlightRange(bc *braille.Canvas, hRange *zoom.Range) erro } // Keyboard implements widgetapi.Widget.Keyboard. -func (lc *LineChart) Keyboard(k *terminalapi.Keyboard) error { +func (lc *LineChart) Keyboard(k *terminalapi.Keyboard, meta *widgetapi.EventMeta) error { return errors.New("the LineChart widget doesn't support keyboard events") } // Mouse implements widgetapi.Widget.Mouse. -func (lc *LineChart) Mouse(m *terminalapi.Mouse) error { +func (lc *LineChart) Mouse(m *terminalapi.Mouse, meta *widgetapi.EventMeta) error { lc.mu.Lock() defer lc.mu.Unlock() diff --git a/widgets/linechart/linechart_test.go b/widgets/linechart/linechart_test.go index 6c6ad631..3d44fbeb 100644 --- a/widgets/linechart/linechart_test.go +++ b/widgets/linechart/linechart_test.go @@ -1171,7 +1171,7 @@ func TestLineChartDraws(t *testing.T) { return lc.Mouse(&terminalapi.Mouse{ Position: image.Point{6, 5}, Button: mouse.ButtonLeft, - }) + }, &widgetapi.EventMeta{}) }, wantCapacity: 28, want: func(size image.Point) *faketerm.Terminal { @@ -1222,7 +1222,7 @@ func TestLineChartDraws(t *testing.T) { return lc.Mouse(&terminalapi.Mouse{ Position: image.Point{6, 5}, Button: mouse.ButtonLeft, - }) + }, &widgetapi.EventMeta{}) }, wantCapacity: 28, want: func(size image.Point) *faketerm.Terminal { @@ -1273,7 +1273,7 @@ func TestLineChartDraws(t *testing.T) { return lc.Mouse(&terminalapi.Mouse{ Position: image.Point{8, 5}, Button: mouse.ButtonWheelUp, - }) + }, &widgetapi.EventMeta{}) }, wantCapacity: 28, want: func(size image.Point) *faketerm.Terminal { @@ -1331,7 +1331,7 @@ func TestLineChartDraws(t *testing.T) { return lc.Mouse(&terminalapi.Mouse{ Position: image.Point{6, 7}, Button: mouse.ButtonLeft, - }) + }, &widgetapi.EventMeta{}) }, wantCapacity: 28, want: func(size image.Point) *faketerm.Terminal { @@ -1388,7 +1388,7 @@ func TestLineChartDraws(t *testing.T) { return lc.Mouse(&terminalapi.Mouse{ Position: image.Point{5, 0}, Button: mouse.ButtonWheelUp, - }) + }, &widgetapi.EventMeta{}) }, wantCapacity: 10, want: func(size image.Point) *faketerm.Terminal { @@ -1443,7 +1443,7 @@ func TestLineChartDraws(t *testing.T) { if err := lc.Mouse(&terminalapi.Mouse{ Position: image.Point{5, 0}, Button: mouse.ButtonWheelUp, - }); err != nil { + }, &widgetapi.EventMeta{}); err != nil { return err } @@ -1901,7 +1901,7 @@ func TestKeyboard(t *testing.T) { if err != nil { t.Fatalf("New => unexpected error: %v", err) } - if err := lc.Keyboard(&terminalapi.Keyboard{}); err == nil { + if err := lc.Keyboard(&terminalapi.Keyboard{}, &widgetapi.EventMeta{}); err == nil { t.Errorf("Keyboard => got nil err, wanted one") } } @@ -1911,7 +1911,7 @@ func TestMouseDoesNothingWithoutZoomTracker(t *testing.T) { if err != nil { t.Fatalf("New => unexpected error: %v", err) } - if err := lc.Mouse(&terminalapi.Mouse{}); err != nil { + if err := lc.Mouse(&terminalapi.Mouse{}, &widgetapi.EventMeta{}); err != nil { t.Errorf("Mouse => unexpected error: %v", err) } } diff --git a/widgets/segmentdisplay/segmentdisplay.go b/widgets/segmentdisplay/segmentdisplay.go index ed6b7501..cb4c1f2a 100644 --- a/widgets/segmentdisplay/segmentdisplay.go +++ b/widgets/segmentdisplay/segmentdisplay.go @@ -292,12 +292,12 @@ func (sd *SegmentDisplay) drawChar(dCvs *canvas.Canvas, c rune, wOpts *writeOpti } // Keyboard input isn't supported on the SegmentDisplay widget. -func (*SegmentDisplay) Keyboard(k *terminalapi.Keyboard) error { +func (*SegmentDisplay) Keyboard(k *terminalapi.Keyboard, meta *widgetapi.EventMeta) error { return errors.New("the SegmentDisplay widget doesn't support keyboard events") } // Mouse input isn't supported on the SegmentDisplay widget. -func (*SegmentDisplay) Mouse(m *terminalapi.Mouse) error { +func (*SegmentDisplay) Mouse(m *terminalapi.Mouse, meta *widgetapi.EventMeta) error { return errors.New("the SegmentDisplay widget doesn't support mouse events") } diff --git a/widgets/segmentdisplay/segmentdisplay_test.go b/widgets/segmentdisplay/segmentdisplay_test.go index b2dcbf63..a0114fde 100644 --- a/widgets/segmentdisplay/segmentdisplay_test.go +++ b/widgets/segmentdisplay/segmentdisplay_test.go @@ -982,7 +982,7 @@ func TestKeyboard(t *testing.T) { if err != nil { t.Fatalf("New => unexpected error: %v", err) } - if err := sd.Keyboard(&terminalapi.Keyboard{}); err == nil { + if err := sd.Keyboard(&terminalapi.Keyboard{}, &widgetapi.EventMeta{}); err == nil { t.Errorf("Keyboard => got nil err, wanted one") } } @@ -992,7 +992,7 @@ func TestMouse(t *testing.T) { if err != nil { t.Fatalf("New => unexpected error: %v", err) } - if err := sd.Mouse(&terminalapi.Mouse{}); err == nil { + if err := sd.Mouse(&terminalapi.Mouse{}, &widgetapi.EventMeta{}); err == nil { t.Errorf("Mouse => got nil err, wanted one") } } diff --git a/widgets/sparkline/sparkline.go b/widgets/sparkline/sparkline.go index 117248cd..aaab9d42 100644 --- a/widgets/sparkline/sparkline.go +++ b/widgets/sparkline/sparkline.go @@ -183,12 +183,12 @@ func (sl *SparkLine) Clear() { } // Keyboard input isn't supported on the SparkLine widget. -func (*SparkLine) Keyboard(k *terminalapi.Keyboard) error { +func (*SparkLine) Keyboard(k *terminalapi.Keyboard, meta *widgetapi.EventMeta) error { return errors.New("the SparkLine widget doesn't support keyboard events") } // Mouse input isn't supported on the SparkLine widget. -func (*SparkLine) Mouse(m *terminalapi.Mouse) error { +func (*SparkLine) Mouse(m *terminalapi.Mouse, meta *widgetapi.EventMeta) error { return errors.New("the SparkLine widget doesn't support mouse events") } diff --git a/widgets/text/text.go b/widgets/text/text.go index 645a3db6..913874b3 100644 --- a/widgets/text/text.go +++ b/widgets/text/text.go @@ -234,7 +234,7 @@ func (t *Text) Draw(cvs *canvas.Canvas, meta *widgetapi.Meta) error { } // Keyboard implements widgetapi.Widget.Keyboard. -func (t *Text) Keyboard(k *terminalapi.Keyboard) error { +func (t *Text) Keyboard(k *terminalapi.Keyboard, meta *widgetapi.EventMeta) error { t.mu.Lock() defer t.mu.Unlock() @@ -252,7 +252,7 @@ func (t *Text) Keyboard(k *terminalapi.Keyboard) error { } // Mouse implements widgetapi.Widget.Mouse. -func (t *Text) Mouse(m *terminalapi.Mouse) error { +func (t *Text) Mouse(m *terminalapi.Mouse, meta *widgetapi.EventMeta) error { t.mu.Lock() defer t.mu.Unlock() diff --git a/widgets/text/text_test.go b/widgets/text/text_test.go index b6b9111a..2c96a339 100644 --- a/widgets/text/text_test.go +++ b/widgets/text/text_test.go @@ -310,7 +310,7 @@ func TestTextDraws(t *testing.T) { events: func(widget *Text) { widget.Mouse(&terminalapi.Mouse{ Button: mouse.ButtonWheelDown, - }) + }, &widgetapi.EventMeta{}) }, want: func(size image.Point) *faketerm.Terminal { ft := faketerm.MustNew(size) @@ -332,7 +332,7 @@ func TestTextDraws(t *testing.T) { events: func(widget *Text) { widget.Mouse(&terminalapi.Mouse{ Button: mouse.ButtonWheelDown, - }) + }, &widgetapi.EventMeta{}) }, want: func(size image.Point) *faketerm.Terminal { ft := faketerm.MustNew(size) @@ -353,7 +353,7 @@ func TestTextDraws(t *testing.T) { events: func(widget *Text) { widget.Keyboard(&terminalapi.Keyboard{ Key: keyboard.KeyArrowDown, - }) + }, &widgetapi.EventMeta{}) }, want: func(size image.Point) *faketerm.Terminal { ft := faketerm.MustNew(size) @@ -375,7 +375,7 @@ func TestTextDraws(t *testing.T) { events: func(widget *Text) { widget.Keyboard(&terminalapi.Keyboard{ Key: keyboard.KeyPgDn, - }) + }, &widgetapi.EventMeta{}) }, want: func(size image.Point) *faketerm.Terminal { ft := faketerm.MustNew(size) @@ -400,7 +400,7 @@ func TestTextDraws(t *testing.T) { events: func(widget *Text) { widget.Mouse(&terminalapi.Mouse{ Button: mouse.ButtonRight, - }) + }, &widgetapi.EventMeta{}) }, want: func(size image.Point) *faketerm.Terminal { ft := faketerm.MustNew(size) @@ -425,7 +425,7 @@ func TestTextDraws(t *testing.T) { events: func(widget *Text) { widget.Keyboard(&terminalapi.Keyboard{ Key: 'd', - }) + }, &widgetapi.EventMeta{}) }, want: func(size image.Point) *faketerm.Terminal { ft := faketerm.MustNew(size) @@ -450,7 +450,7 @@ func TestTextDraws(t *testing.T) { events: func(widget *Text) { widget.Keyboard(&terminalapi.Keyboard{ Key: 'l', - }) + }, &widgetapi.EventMeta{}) }, want: func(size image.Point) *faketerm.Terminal { ft := faketerm.MustNew(size) @@ -648,7 +648,7 @@ func TestTextDraws(t *testing.T) { } widget.Mouse(&terminalapi.Mouse{ Button: mouse.ButtonWheelUp, - }) + }, &widgetapi.EventMeta{}) }, want: func(size image.Point) *faketerm.Terminal { ft := faketerm.MustNew(size) @@ -677,7 +677,7 @@ func TestTextDraws(t *testing.T) { } widget.Keyboard(&terminalapi.Keyboard{ Key: keyboard.KeyArrowUp, - }) + }, &widgetapi.EventMeta{}) }, want: func(size image.Point) *faketerm.Terminal { ft := faketerm.MustNew(size) @@ -706,7 +706,7 @@ func TestTextDraws(t *testing.T) { } widget.Keyboard(&terminalapi.Keyboard{ Key: keyboard.KeyPgUp, - }) + }, &widgetapi.EventMeta{}) }, want: func(size image.Point) *faketerm.Terminal { ft := faketerm.MustNew(size) @@ -736,7 +736,7 @@ func TestTextDraws(t *testing.T) { } widget.Mouse(&terminalapi.Mouse{ Button: mouse.ButtonLeft, - }) + }, &widgetapi.EventMeta{}) }, want: func(size image.Point) *faketerm.Terminal { ft := faketerm.MustNew(size) @@ -766,7 +766,7 @@ func TestTextDraws(t *testing.T) { } widget.Keyboard(&terminalapi.Keyboard{ Key: 'u', - }) + }, &widgetapi.EventMeta{}) }, want: func(size image.Point) *faketerm.Terminal { ft := faketerm.MustNew(size) @@ -796,7 +796,7 @@ func TestTextDraws(t *testing.T) { } widget.Keyboard(&terminalapi.Keyboard{ Key: 'k', - }) + }, &widgetapi.EventMeta{}) }, want: func(size image.Point) *faketerm.Terminal { ft := faketerm.MustNew(size) diff --git a/widgets/textinput/textinput.go b/widgets/textinput/textinput.go index 13f7beef..a13c860c 100644 --- a/widgets/textinput/textinput.go +++ b/widgets/textinput/textinput.go @@ -267,7 +267,7 @@ func (ti *TextInput) keyboard(k *terminalapi.Keyboard) (bool, string) { // Keyboard processes keyboard events. // Implements widgetapi.Widget.Keyboard. -func (ti *TextInput) Keyboard(k *terminalapi.Keyboard) error { +func (ti *TextInput) Keyboard(k *terminalapi.Keyboard, meta *widgetapi.EventMeta) error { if submitted, text := ti.keyboard(k); submitted { // Mutex must be released when calling the callback. // Users might call container methods from the callback like the @@ -279,7 +279,7 @@ func (ti *TextInput) Keyboard(k *terminalapi.Keyboard) error { // Mouse processes mouse events. // Implements widgetapi.Widget.Mouse. -func (ti *TextInput) Mouse(m *terminalapi.Mouse) error { +func (ti *TextInput) Mouse(m *terminalapi.Mouse, meta *widgetapi.EventMeta) error { ti.mu.Lock() defer ti.mu.Unlock() diff --git a/widgets/textinput/textinput_test.go b/widgets/textinput/textinput_test.go index 1af333e9..852ab7c0 100644 --- a/widgets/textinput/textinput_test.go +++ b/widgets/textinput/textinput_test.go @@ -1441,7 +1441,7 @@ func TestTextInput(t *testing.T) { for i, ev := range tc.events { switch e := ev.(type) { case *terminalapi.Mouse: - err := ti.Mouse(e) + err := ti.Mouse(e, &widgetapi.EventMeta{}) // Only the last event in test cases is the one that triggers the callback. if i == len(tc.events)-1 { if (err != nil) != tc.wantEventErr { @@ -1457,7 +1457,7 @@ func TestTextInput(t *testing.T) { } case *terminalapi.Keyboard: - err := ti.Keyboard(e) + err := ti.Keyboard(e, &widgetapi.EventMeta{}) // Only the last event in test cases is the one that triggers the callback. if i == len(tc.events)-1 { if (err != nil) != tc.wantEventErr { @@ -1551,7 +1551,7 @@ func TestTextInputRead(t *testing.T) { for _, ev := range tc.events { switch e := ev.(type) { case *terminalapi.Keyboard: - err := ti.Keyboard(e) + err := ti.Keyboard(e, &widgetapi.EventMeta{}) if err != nil { t.Fatalf("Keyboard => unexpected error: %v", err) }