diff --git a/box.go b/box.go index 547945b..904184a 100644 --- a/box.go +++ b/box.go @@ -130,10 +130,12 @@ func (b *Box) GetDrawFunc() func(screen tcell.Screen, x, y, width, height int) ( return b.draw } -// wrapInputHandler wraps an input handler (see InputHandler()) with the +// WrapInputHandler wraps an input handler (see InputHandler()) with the // functionality to capture input (see SetInputCapture()) before passing it // on to the provided (default) input handler. -func (b *Box) wrapInputHandler(inputHandler func(*tcell.EventKey, func(p Primitive))) func(*tcell.EventKey, func(p Primitive)) { +// +// This is only meant to be used by subclassing primitives. +func (b *Box) WrapInputHandler(inputHandler func(*tcell.EventKey, func(p Primitive))) func(*tcell.EventKey, func(p Primitive)) { return func(event *tcell.EventKey, setFocus func(p Primitive)) { if b.inputCapture != nil { event = b.inputCapture(event) @@ -146,7 +148,7 @@ func (b *Box) wrapInputHandler(inputHandler func(*tcell.EventKey, func(p Primiti // InputHandler returns nil. func (b *Box) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) { - return b.wrapInputHandler(nil) + return b.WrapInputHandler(nil) } // SetInputCapture installs a function which captures key events before they are diff --git a/button.go b/button.go index f89b4c0..5efc31a 100644 --- a/button.go +++ b/button.go @@ -121,7 +121,7 @@ func (b *Button) Draw(screen tcell.Screen) { // InputHandler returns the handler for this primitive. func (b *Button) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) { - return b.wrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { + return b.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { // Process key event. switch key := event.Key(); key { case tcell.KeyEnter: // Selected. diff --git a/checkbox.go b/checkbox.go index 94d5abf..3dbeade 100644 --- a/checkbox.go +++ b/checkbox.go @@ -155,7 +155,7 @@ func (c *Checkbox) Draw(screen tcell.Screen) { // InputHandler returns the handler for this primitive. func (c *Checkbox) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) { - return c.wrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { + return c.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { // Process key event. switch key := event.Key(); key { case tcell.KeyRune, tcell.KeyEnter: // Check. diff --git a/demos/primitive/README.md b/demos/primitive/README.md new file mode 100644 index 0000000..4a14e6c --- /dev/null +++ b/demos/primitive/README.md @@ -0,0 +1 @@ +![Screenshot](screenshot.png) diff --git a/demos/primitive/boxwithcenterline.png b/demos/primitive/boxwithcenterline.png new file mode 100644 index 0000000..104ee5b Binary files /dev/null and b/demos/primitive/boxwithcenterline.png differ diff --git a/demos/primitive/main.go b/demos/primitive/main.go new file mode 100644 index 0000000..e2d911a --- /dev/null +++ b/demos/primitive/main.go @@ -0,0 +1,70 @@ +// Demo code which illustrates how to implement your own primitive. +package main + +import ( + "fmt" + + "github.com/gdamore/tcell" + "github.com/rivo/tview" +) + +// RadioButtons implements a simple primitive for radio button selections. +type RadioButtons struct { + *tview.Box + options []string + currentOption int +} + +// NewRadioButtons returns a new radio button primitive. +func NewRadioButtons(options []string) *RadioButtons { + return &RadioButtons{ + Box: tview.NewBox(), + options: options, + } +} + +// Draw draws this primitive onto the screen. +func (r *RadioButtons) Draw(screen tcell.Screen) { + r.Box.Draw(screen) + x, y, width, height := r.GetInnerRect() + + for index, option := range r.options { + if index >= height { + break + } + radioButton := "\u25ef" // Unchecked. + if index == r.currentOption { + radioButton = "\u25c9" // Checked. + } + line := fmt.Sprintf(`%s[white] %s`, radioButton, option) + tview.Print(screen, line, x, y+index, width, tview.AlignLeft, tcell.ColorYellow) + } +} + +// InputHandler returns the handler for this primitive. +func (r *RadioButtons) InputHandler() func(event *tcell.EventKey, setFocus func(p tview.Primitive)) { + return r.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p tview.Primitive)) { + switch event.Key() { + case tcell.KeyUp: + r.currentOption-- + if r.currentOption < 0 { + r.currentOption = 0 + } + case tcell.KeyDown: + r.currentOption++ + if r.currentOption >= len(r.options) { + r.currentOption = len(r.options) - 1 + } + } + }) +} + +func main() { + radioButtons := NewRadioButtons([]string{"Lions", "Elephants", "Giraffes"}) + radioButtons.SetBorder(true). + SetTitle("Radio Button Demo"). + SetRect(0, 0, 30, 5) + if err := tview.NewApplication().SetRoot(radioButtons, false).Run(); err != nil { + panic(err) + } +} diff --git a/demos/primitive/screenshot.png b/demos/primitive/screenshot.png new file mode 100644 index 0000000..1c04526 Binary files /dev/null and b/demos/primitive/screenshot.png differ diff --git a/demos/primitive/textviewwithcenterline.png b/demos/primitive/textviewwithcenterline.png new file mode 100644 index 0000000..0376ff5 Binary files /dev/null and b/demos/primitive/textviewwithcenterline.png differ diff --git a/dropdown.go b/dropdown.go index 9f68b4b..0960e07 100644 --- a/dropdown.go +++ b/dropdown.go @@ -299,7 +299,7 @@ func (d *DropDown) Draw(screen tcell.Screen) { // InputHandler returns the handler for this primitive. func (d *DropDown) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) { - return d.wrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { + return d.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { // A helper function which selects an item in the drop-down list based on // the current prefix. evalPrefix := func() { diff --git a/grid.go b/grid.go index 5fc6ec3..f068d32 100644 --- a/grid.go +++ b/grid.go @@ -263,7 +263,7 @@ func (g *Grid) HasFocus() bool { // InputHandler returns the handler for this primitive. func (g *Grid) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) { - return g.wrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { + return g.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { switch event.Key() { case tcell.KeyRune: switch event.Rune() { diff --git a/inputfield.go b/inputfield.go index 4633207..bb6b024 100644 --- a/inputfield.go +++ b/inputfield.go @@ -289,7 +289,7 @@ func (i *InputField) setCursor(screen tcell.Screen) { // InputHandler returns the handler for this primitive. func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) { - return i.wrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { + return i.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { // Trigger changed events. currentText := i.text defer func() { diff --git a/list.go b/list.go index 6edf8c4..f4973fe 100644 --- a/list.go +++ b/list.go @@ -259,7 +259,7 @@ func (l *List) Draw(screen tcell.Screen) { // InputHandler returns the handler for this primitive. func (l *List) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) { - return l.wrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { + return l.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { previousItem := l.currentItem switch key := event.Key(); key { diff --git a/primitive.go b/primitive.go index 38f9e82..88a9d46 100644 --- a/primitive.go +++ b/primitive.go @@ -31,7 +31,7 @@ type Primitive interface { // // The Box class provides functionality to intercept keyboard input. If you // subclass from Box, it is recommended that you wrap your handler using - // Box.wrapInputHandler() so you inherit that functionality. + // Box.WrapInputHandler() so you inherit that functionality. InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) // Focus is called by the application when the primitive receives focus. diff --git a/table.go b/table.go index 003bd43..334cd43 100644 --- a/table.go +++ b/table.go @@ -818,7 +818,7 @@ ColumnLoop: // InputHandler returns the handler for this primitive. func (t *Table) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) { - return t.wrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { + return t.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { key := event.Key() if (!t.rowsSelectable && !t.columnsSelectable && key == tcell.KeyEnter) || diff --git a/textview.go b/textview.go index 228c87f..981004b 100644 --- a/textview.go +++ b/textview.go @@ -839,7 +839,7 @@ func (t *TextView) Draw(screen tcell.Screen) { // InputHandler returns the handler for this primitive. func (t *TextView) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) { - return t.wrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { + return t.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { key := event.Key() if key == tcell.KeyEscape || key == tcell.KeyEnter || key == tcell.KeyTab || key == tcell.KeyBacktab {