1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
|
// Copyright 2019-2022 Graham Clark. All rights reserved. Use of this source
// code is governed by the MIT license that can be found in the LICENSE
// file.
// Package keypress provides a widget which responds to keyboard input.
package keypress
import (
"fmt"
"github.com/gcla/gowid"
tcell "github.com/gdamore/tcell/v2"
)
//======================================================================
type ICustomKeys interface {
CustomSelectKeys() bool
SelectKeys() []gowid.IKey // can't be nil
}
type KeyPressFunction func(app gowid.IApp, widget gowid.IWidget, key gowid.IKey)
func (f KeyPressFunction) Changed(app gowid.IApp, widget gowid.IWidget, data ...interface{}) {
k := data[0].(gowid.IKey)
f(app, widget, k)
}
// WidgetCallback is a simple struct with a name field for IIdentity and
// that embeds a WidgetChangedFunction to be issued as a callback when a widget
// property changes.
type WidgetCallback struct {
Name interface{}
KeyPressFunction
}
func MakeCallback(name interface{}, fn KeyPressFunction) WidgetCallback {
return WidgetCallback{
Name: name,
KeyPressFunction: fn,
}
}
func (f WidgetCallback) ID() interface{} {
return f.Name
}
// IWidget is implemented by any widget that contains exactly one
// exposed subwidget (ICompositeWidget) and that is decorated on its left
// and right (IDecoratedAround).
type IWidget interface {
gowid.ICompositeWidget
}
type Options struct {
Keys []gowid.IKey
}
type Widget struct {
inner gowid.IWidget
opts Options
*gowid.Callbacks
gowid.SubWidgetCallbacks
gowid.KeyPressCallbacks
gowid.IsSelectable
}
func New(inner gowid.IWidget, opts ...Options) *Widget {
var opt Options
if len(opts) > 0 {
opt = opts[0]
}
res := &Widget{
inner: inner,
opts: opt,
}
res.SubWidgetCallbacks = gowid.SubWidgetCallbacks{CB: &res.Callbacks}
res.KeyPressCallbacks = gowid.KeyPressCallbacks{CB: &res.Callbacks}
var _ gowid.IWidget = res
var _ gowid.ICompositeWidget = res
var _ IWidget = res
var _ ICustomKeys = res
return res
}
func (w *Widget) String() string {
return fmt.Sprintf("keypress[%v]", w.SubWidget())
}
func (w *Widget) KeyPress(key gowid.IKey, app gowid.IApp) {
gowid.RunWidgetCallbacks(w.Callbacks, gowid.KeyPressCB{}, app, w, key)
}
func (w *Widget) SubWidget() gowid.IWidget {
return w.inner
}
func (w *Widget) SetSubWidget(wi gowid.IWidget, app gowid.IApp) {
w.inner = wi
gowid.RunWidgetCallbacks(w.Callbacks, gowid.SubWidgetCB{}, app, w)
}
func (w *Widget) SubWidgetSize(size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) gowid.IRenderSize {
return SubWidgetSize(w, size, focus, app)
}
func (w *Widget) RenderSize(size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) gowid.IRenderBox {
return RenderSize(w, size, focus, app)
}
func (w *Widget) Render(size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) gowid.ICanvas {
return Render(w, size, focus, app)
}
func (w *Widget) UserInput(ev interface{}, size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) bool {
return UserInput(w, ev, size, focus, app)
}
func (w *Widget) CustomSelectKeys() bool {
return true
}
func (w *Widget) SelectKeys() []gowid.IKey {
return w.opts.Keys
}
//======================================================================
func SubWidgetSize(w gowid.ICompositeWidget, size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) gowid.IRenderSize {
return size
}
func RenderSize(w IWidget, size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) gowid.IRenderBox {
return gowid.RenderSize(w.SubWidget(), size, focus, app)
}
type IKeyPresser interface {
gowid.IKeyPress
ICustomKeys
gowid.IComposite
}
func UserInput(w IKeyPresser, ev interface{}, size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) bool {
res := false
switch ev := ev.(type) {
case *tcell.EventKey:
if w.CustomSelectKeys() {
for _, k := range w.SelectKeys() {
if gowid.KeysEqual(k, ev) {
w.KeyPress(ev, app)
res = true
break
}
}
}
}
if !res {
res = w.SubWidget().UserInput(ev, size, focus, app)
}
return res
}
func Render(w IWidget, size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) gowid.ICanvas {
return w.SubWidget().Render(size, focus, app)
}
//======================================================================
// Local Variables:
// mode: Go
// fill-column: 110
// End:
|