From ed5e6d94dd16c57267ce980f1c5b4ea809a11931 Mon Sep 17 00:00:00 2001 From: Trevor Slocum Date: Wed, 7 Oct 2020 16:34:21 -0700 Subject: [PATCH] Remove return values from methods which return their primitive (breaks chaining) --- CHANGELOG | 1 + FORK.md | 18 ++- application.go | 73 ++++------ box.go | 43 ++---- button.go | 21 ++- checkbox.go | 42 ++---- contextmenu.go | 43 +++--- demos/box/main.go | 14 +- demos/button/main.go | 12 +- demos/checkbox/main.go | 9 +- demos/dropdown/main.go | 22 +-- demos/flex/main.go | 30 ++-- demos/form/main.go | 39 ++--- demos/frame/main.go | 25 ++-- demos/grid/main.go | 37 ++--- demos/inputfield/autocomplete/main.go | 20 +-- demos/inputfield/autocompleteasync/main.go | 15 +- demos/inputfield/simple/main.go | 22 +-- demos/list/main.go | 30 ++-- demos/modal/main.go | 22 +-- demos/pages/main.go | 31 ++-- demos/presentation/center.go | 20 +-- demos/presentation/code.go | 13 +- demos/presentation/colors.go | 20 +-- demos/presentation/cover.go | 40 +++--- demos/presentation/end.go | 3 +- demos/presentation/flex.go | 63 +++++---- demos/presentation/form.go | 19 +-- demos/presentation/grid.go | 60 ++++---- demos/presentation/inputfield.go | 7 +- demos/presentation/introduction.go | 26 ++-- demos/presentation/main.go | 33 +++-- demos/presentation/table.go | 106 ++++++++------ demos/presentation/textview.go | 98 +++++++------ demos/presentation/treeview.go | 68 +++++---- demos/presentation/window.go | 33 ++--- demos/primitive/main.go | 12 +- demos/progressbar/main.go | 7 +- demos/table/main.go | 25 ++-- demos/textview/main.go | 26 ++-- demos/treeview/main.go | 22 +-- demos/unicode/main.go | 53 +++---- doc_test.go | 23 ++- dropdown.go | 103 +++++--------- flex.go | 21 ++- form.go | 157 ++++++++++----------- frame.go | 9 +- grid.go | 36 ++--- inputfield.go | 108 ++++++-------- list.go | 108 +++++--------- list_test.go | 10 +- modal.go | 50 +++---- pages.go | 27 ++-- progressbar.go | 6 +- table.go | 122 ++++++---------- textview.go | 84 ++++------- textview_test.go | 22 +-- treeview.go | 95 +++++-------- util_test.go | 7 +- window.go | 9 +- 60 files changed, 1132 insertions(+), 1188 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0b9ebf8..41bd9e8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ v1.5.1 (WIP) - Add TableCell.SetBytes, TableCell.GetBytes and TableCell.GetText - Allow modification of scroll bar render text - Optimize TextView (writing is 90% faster, drawing is 50% faster) +- Remove return values from methods which return their primitive (breaks chaining) v1.5.0 (2020-10-03) - Add scroll bar to TextView diff --git a/FORK.md b/FORK.md index d0dfd3f..f029f67 100644 --- a/FORK.md +++ b/FORK.md @@ -26,6 +26,14 @@ maintainers and allowing code changes which may be outside of tview's scope. # Differences +## Primitive methods do not return the primitive they belong to + +When chaining multiple method calls on a primitive together, application +developers might accidentally end the chain with a different return type than +the first method call. This could result in unexpected return types. For +example, ending a chain with `SetTitle` would result in a `Box` rather than the +original primitive. + ## cview is [thread-safe](https://docs.rocketnine.space/gitlab.com/tslocum/cview/#hdr-Concurrency) tview [is not thread-safe](https://godoc.org/github.com/rivo/tview#hdr-Concurrency). @@ -38,11 +46,6 @@ tview [blocks until the queued function returns](https://github.com/rivo/tview/b All clicks are handled as single clicks until an interval is set with [Application.SetDoubleClickInterval](https://docs.rocketnine.space/gitlab.com/tslocum/cview/#Application.SetDoubleClickInterval). -## Setting a primitive's background color to `tcell.ColorDefault` does not result in transparency - -Call [Box.SetBackgroundTransparent](https://docs.rocketnine.space/gitlab.com/tslocum/cview/#Box.SetBackgroundTransparent) -to enable background transparency. - ## Tables are sorted when a fixed row is clicked by default Call [Table.SetSortClicked](https://docs.rocketnine.space/gitlab.com/tslocum/cview/#Table.SetSortClicked) @@ -53,6 +56,11 @@ to disable this behavior. Call [List.SetWrapAround](https://docs.rocketnine.space/gitlab.com/tslocum/cview/#List.SetWrapAround) to wrap around when navigating. +## Setting a primitive's background color to `tcell.ColorDefault` does not result in transparency + +Call [Box.SetBackgroundTransparent](https://docs.rocketnine.space/gitlab.com/tslocum/cview/#Box.SetBackgroundTransparent) +to enable background transparency. + ## TextViews store their text as []byte instead of string This greatly improves buffer efficiency. [TextView.Write](https://docs.rocketnine.space/gitlab.com/tslocum/cview/#TextView.Write) diff --git a/application.go b/application.go index be024c0..8477d2e 100644 --- a/application.go +++ b/application.go @@ -127,12 +127,12 @@ func NewApplication() *Application { // Note that this also affects the default event handling of the application // itself: Such a handler can intercept the Ctrl-C event which closes the // application. -func (a *Application) SetInputCapture(capture func(event *tcell.EventKey) *tcell.EventKey) *Application { +func (a *Application) SetInputCapture(capture func(event *tcell.EventKey) *tcell.EventKey) { a.Lock() defer a.Unlock() a.inputCapture = capture - return a + } // GetInputCapture returns the function installed with SetInputCapture() or nil @@ -149,9 +149,9 @@ func (a *Application) GetInputCapture() func(event *tcell.EventKey) *tcell.Event // forwarded to the appropriate mouse event handler. This function can then // choose to forward that event (or a different one) by returning it or stop // the event processing by returning a nil mouse event. -func (a *Application) SetMouseCapture(capture func(event *tcell.EventMouse, action MouseAction) (*tcell.EventMouse, MouseAction)) *Application { +func (a *Application) SetMouseCapture(capture func(event *tcell.EventMouse, action MouseAction) (*tcell.EventMouse, MouseAction)) { a.mouseCapture = capture - return a + } // GetMouseCapture returns the function installed with SetMouseCapture() or nil @@ -173,9 +173,9 @@ func (a *Application) SetDoubleClickInterval(interval time.Duration) { // // This function is typically called before the first call to Run(). Init() need // not be called on the screen. -func (a *Application) SetScreen(screen tcell.Screen) *Application { +func (a *Application) SetScreen(screen tcell.Screen) { if screen == nil { - return a // Invalid input. Do nothing. + return // Invalid input. Do nothing. } a.Lock() @@ -183,7 +183,7 @@ func (a *Application) SetScreen(screen tcell.Screen) *Application { // Run() has not been called yet. a.screen = screen a.Unlock() - return a + return } // Run() is already in progress. Exchange screen. @@ -191,12 +191,10 @@ func (a *Application) SetScreen(screen tcell.Screen) *Application { a.Unlock() oldScreen.Fini() a.screenReplacement <- screen - - return a } // EnableMouse enables mouse events. -func (a *Application) EnableMouse(enable bool) *Application { +func (a *Application) EnableMouse(enable bool) { a.Lock() defer a.Unlock() if enable != a.enableMouse && a.screen != nil { @@ -207,7 +205,7 @@ func (a *Application) EnableMouse(enable bool) *Application { } } a.enableMouse = enable - return a + } // Run starts the application and thus the event loop. This function returns @@ -545,11 +543,11 @@ func (a *Application) Suspend(f func()) bool { // Draw refreshes the screen (during the next update cycle). It calls the Draw() // function of the application's root primitive and then syncs the screen // buffer. -func (a *Application) Draw() *Application { +func (a *Application) Draw() { a.QueueUpdate(func() { a.draw() }) - return a + } // ForceDraw refreshes the screen immediately. Use this function with caution as @@ -559,12 +557,12 @@ func (a *Application) Draw() *Application { // // It is safe to call this function during queued updates and direct event // handling. -func (a *Application) ForceDraw() *Application { - return a.draw() +func (a *Application) ForceDraw() { + a.draw() } // draw actually does what Draw() promises to do. -func (a *Application) draw() *Application { +func (a *Application) draw() { a.Lock() screen := a.screen @@ -576,7 +574,7 @@ func (a *Application) draw() *Application { // Maybe we're not ready yet or not anymore. if screen == nil || root == nil { a.Unlock() - return a + return } // Resize if requested. @@ -590,7 +588,7 @@ func (a *Application) draw() *Application { a.Unlock() if before(screen) { screen.Show() - return a + return } } else { a.Unlock() @@ -606,8 +604,6 @@ func (a *Application) draw() *Application { // Sync screen. screen.Show() - - return a } // SetBeforeDrawFunc installs a callback function which is invoked just before @@ -619,12 +615,11 @@ func (a *Application) draw() *Application { // you may call screen.Clear(). // // Provide nil to uninstall the callback function. -func (a *Application) SetBeforeDrawFunc(handler func(screen tcell.Screen) bool) *Application { +func (a *Application) SetBeforeDrawFunc(handler func(screen tcell.Screen) bool) { a.Lock() defer a.Unlock() a.beforeDraw = handler - return a } // GetBeforeDrawFunc returns the callback function installed with @@ -640,12 +635,11 @@ func (a *Application) GetBeforeDrawFunc() func(screen tcell.Screen) bool { // primitive was drawn during screen updates. // // Provide nil to uninstall the callback function. -func (a *Application) SetAfterDrawFunc(handler func(screen tcell.Screen)) *Application { +func (a *Application) SetAfterDrawFunc(handler func(screen tcell.Screen)) { a.Lock() defer a.Unlock() a.afterDraw = handler - return a } // GetAfterDrawFunc returns the callback function installed with @@ -664,7 +658,7 @@ func (a *Application) GetAfterDrawFunc() func(screen tcell.Screen) { // the application starts. // // It also calls SetFocus() on the primitive. -func (a *Application) SetRoot(root Primitive, fullscreen bool) *Application { +func (a *Application) SetRoot(root Primitive, fullscreen bool) { a.Lock() a.root = root a.rootFullscreen = fullscreen @@ -674,18 +668,15 @@ func (a *Application) SetRoot(root Primitive, fullscreen bool) *Application { a.Unlock() a.SetFocus(root) - - return a } // ResizeToFullScreen resizes the given primitive such that it fills the entire // screen. -func (a *Application) ResizeToFullScreen(p Primitive) *Application { +func (a *Application) ResizeToFullScreen(p Primitive) { a.RLock() width, height := a.screen.Size() a.RUnlock() p.SetRect(0, 0, width, height) - return a } // SetAfterResizeFunc installs a callback function which is invoked when the @@ -694,12 +685,11 @@ func (a *Application) ResizeToFullScreen(p Primitive) *Application { // application is drawn. // // Provide nil to uninstall the callback function. -func (a *Application) SetAfterResizeFunc(handler func(width int, height int)) *Application { +func (a *Application) SetAfterResizeFunc(handler func(width int, height int)) { a.Lock() defer a.Unlock() a.afterResize = handler - return a } // GetAfterResizeFunc returns the callback function installed with @@ -717,14 +707,14 @@ func (a *Application) GetAfterResizeFunc() func(width int, height int) { // // Blur() will be called on the previously focused primitive. Focus() will be // called on the new primitive. -func (a *Application) SetFocus(p Primitive) *Application { +func (a *Application) SetFocus(p Primitive) { a.Lock() if a.beforeFocus != nil { a.Unlock() ok := a.beforeFocus(p) if !ok { - return a + return } a.Lock() } @@ -752,8 +742,6 @@ func (a *Application) SetFocus(p Primitive) *Application { a.SetFocus(p) }) } - - return a } // GetFocus returns the primitive which has the current focus. If none has it, @@ -769,24 +757,22 @@ func (a *Application) GetFocus() Primitive { // application's focus changes. Return false to maintain the current focus. // // Provide nil to uninstall the callback function. -func (a *Application) SetBeforeFocusFunc(handler func(p Primitive) bool) *Application { +func (a *Application) SetBeforeFocusFunc(handler func(p Primitive) bool) { a.Lock() defer a.Unlock() a.beforeFocus = handler - return a } // SetAfterFocusFunc installs a callback function which is invoked after the // application's focus changes. // // Provide nil to uninstall the callback function. -func (a *Application) SetAfterFocusFunc(handler func(p Primitive)) *Application { +func (a *Application) SetAfterFocusFunc(handler func(p Primitive)) { a.Lock() defer a.Unlock() a.afterFocus = handler - return a } // QueueUpdate queues a function to be executed as part of the event loop. @@ -795,27 +781,24 @@ func (a *Application) SetAfterFocusFunc(handler func(p Primitive)) *Application // may not be desirable. You can call Draw() from f if the screen should be // refreshed after each update. Alternatively, use QueueUpdateDraw() to follow // up with an immediate refresh of the screen. -func (a *Application) QueueUpdate(f func()) *Application { +func (a *Application) QueueUpdate(f func()) { a.updates <- f - return a } // QueueUpdateDraw works like QueueUpdate() except it refreshes the screen // immediately after executing f. -func (a *Application) QueueUpdateDraw(f func()) *Application { +func (a *Application) QueueUpdateDraw(f func()) { a.QueueUpdate(func() { f() a.draw() }) - return a } // QueueEvent sends an event to the Application event loop. // // It is not recommended for event to be nil. -func (a *Application) QueueEvent(event tcell.Event) *Application { +func (a *Application) QueueEvent(event tcell.Event) { a.events <- event - return a } // RingBell sends a bell code to the terminal. diff --git a/box.go b/box.go index fa051bc..e027b14 100644 --- a/box.go +++ b/box.go @@ -98,12 +98,11 @@ func (b *Box) GetBorderPadding() (top, bottom, left, right int) { } // SetBorderPadding sets the size of the borders around the box content. -func (b *Box) SetBorderPadding(top, bottom, left, right int) *Box { +func (b *Box) SetBorderPadding(top, bottom, left, right int) { b.l.Lock() defer b.l.Unlock() b.paddingTop, b.paddingBottom, b.paddingLeft, b.paddingRight = top, bottom, left, right - return b } // GetRect returns the current position of the rectangle, x, y, width, and @@ -172,12 +171,11 @@ func (b *Box) SetRect(x, y, width, height int) { // must return the box's inner dimensions (x, y, width, height) which will be // returned by GetInnerRect(), used by descendent primitives to draw their own // content. -func (b *Box) SetDrawFunc(handler func(screen tcell.Screen, x, y, width, height int) (int, int, int, int)) *Box { +func (b *Box) SetDrawFunc(handler func(screen tcell.Screen, x, y, width, height int) (int, int, int, int)) { b.l.Lock() defer b.l.Unlock() b.draw = handler - return b } // GetDrawFunc returns the callback function which was installed with @@ -227,12 +225,11 @@ func (b *Box) InputHandler() func(event *tcell.EventKey, setFocus func(p Primiti // can have focus at a time. Composing primitives such as Form pass the focus on // to their contained primitives and thus never receive any key events // themselves. Therefore, they cannot intercept key events. -func (b *Box) SetInputCapture(capture func(event *tcell.EventKey) *tcell.EventKey) *Box { +func (b *Box) SetInputCapture(capture func(event *tcell.EventKey) *tcell.EventKey) { b.l.Lock() defer b.l.Unlock() b.inputCapture = capture - return b } // GetInputCapture returns the function installed with SetInputCapture() or nil @@ -280,9 +277,8 @@ func (b *Box) MouseHandler() func(action MouseAction, event *tcell.EventMouse, s // called. // // Providing a nil handler will remove a previously existing handler. -func (b *Box) SetMouseCapture(capture func(action MouseAction, event *tcell.EventMouse) (MouseAction, *tcell.EventMouse)) *Box { +func (b *Box) SetMouseCapture(capture func(action MouseAction, event *tcell.EventMouse) (MouseAction, *tcell.EventMouse)) { b.mouseCapture = capture - return b } // InRect returns true if the given coordinate is within the bounds of the box's @@ -299,12 +295,11 @@ func (b *Box) GetMouseCapture() func(action MouseAction, event *tcell.EventMouse } // SetBackgroundColor sets the box's background color. -func (b *Box) SetBackgroundColor(color tcell.Color) *Box { +func (b *Box) SetBackgroundColor(color tcell.Color) { b.l.Lock() defer b.l.Unlock() b.backgroundColor = color - return b } // GetBackgroundColor returns the box's background color. @@ -316,12 +311,11 @@ func (b *Box) GetBackgroundColor() tcell.Color { // SetBackgroundTransparent sets the flag indicating whether or not the box's // background is transparent. -func (b *Box) SetBackgroundTransparent(transparent bool) *Box { +func (b *Box) SetBackgroundTransparent(transparent bool) { b.l.Lock() defer b.l.Unlock() b.backgroundTransparent = transparent - return b } // GetBorder returns a value indicating whether the box have a border @@ -334,50 +328,45 @@ func (b *Box) GetBorder() bool { // SetBorder sets the flag indicating whether or not the box should have a // border. -func (b *Box) SetBorder(show bool) *Box { +func (b *Box) SetBorder(show bool) { b.l.Lock() defer b.l.Unlock() b.border = show - return b } // SetBorderColor sets the box's border color. -func (b *Box) SetBorderColor(color tcell.Color) *Box { +func (b *Box) SetBorderColor(color tcell.Color) { b.l.Lock() defer b.l.Unlock() b.borderColor = color - return b } // SetBorderColorFocused sets the box's border color when the box is focused. -func (b *Box) SetBorderColorFocused(color tcell.Color) *Box { +func (b *Box) SetBorderColorFocused(color tcell.Color) { b.l.Lock() defer b.l.Unlock() b.borderColorFocused = color - return b } // SetBorderAttributes sets the border's style attributes. You can combine // different attributes using bitmask operations: // // box.SetBorderAttributes(tcell.AttrUnderline | tcell.AttrBold) -func (b *Box) SetBorderAttributes(attr tcell.AttrMask) *Box { +func (b *Box) SetBorderAttributes(attr tcell.AttrMask) { b.l.Lock() defer b.l.Unlock() b.borderAttributes = attr - return b } // SetTitle sets the box's title. -func (b *Box) SetTitle(title string) *Box { +func (b *Box) SetTitle(title string) { b.l.Lock() defer b.l.Unlock() b.title = []byte(title) - return b } // GetTitle returns the box's current title. @@ -389,22 +378,21 @@ func (b *Box) GetTitle() string { } // SetTitleColor sets the box's title color. -func (b *Box) SetTitleColor(color tcell.Color) *Box { +func (b *Box) SetTitleColor(color tcell.Color) { b.l.Lock() defer b.l.Unlock() b.titleColor = color - return b } // SetTitleAlign sets the alignment of the title, one of AlignLeft, AlignCenter, // or AlignRight. -func (b *Box) SetTitleAlign(align int) *Box { +func (b *Box) SetTitleAlign(align int) { b.l.Lock() defer b.l.Unlock() b.titleAlign = align - return b + } // Draw draws this primitive onto the screen. @@ -527,12 +515,11 @@ func (b *Box) Draw(screen tcell.Screen) { // ShowFocus sets the flag indicating whether or not the borders of this // primitive should change thickness when focused. -func (b *Box) ShowFocus(showFocus bool) *Box { +func (b *Box) ShowFocus(showFocus bool) { b.l.Lock() defer b.l.Unlock() b.showFocus = showFocus - return b } // Focus is called when this primitive receives focus. diff --git a/button.go b/button.go index 24dbda9..955c4f2 100644 --- a/button.go +++ b/button.go @@ -34,7 +34,8 @@ type Button struct { // NewButton returns a new input field. func NewButton(label string) *Button { - box := NewBox().SetBackgroundColor(Styles.ContrastBackgroundColor) + box := NewBox() + box.SetBackgroundColor(Styles.ContrastBackgroundColor) box.SetRect(0, 0, TaggedStringWidth(label)+4, 1) return &Button{ Box: box, @@ -46,12 +47,11 @@ func NewButton(label string) *Button { } // SetLabel sets the button text. -func (b *Button) SetLabel(label string) *Button { +func (b *Button) SetLabel(label string) { b.Lock() defer b.Unlock() b.label = []byte(label) - return b } // GetLabel returns the button text. @@ -63,41 +63,37 @@ func (b *Button) GetLabel() string { } // SetLabelColor sets the color of the button text. -func (b *Button) SetLabelColor(color tcell.Color) *Button { +func (b *Button) SetLabelColor(color tcell.Color) { b.Lock() defer b.Unlock() b.labelColor = color - return b } // SetLabelColorFocused sets the color of the button text when the button is // in focus. -func (b *Button) SetLabelColorFocused(color tcell.Color) *Button { +func (b *Button) SetLabelColorFocused(color tcell.Color) { b.Lock() defer b.Unlock() b.labelColorFocused = color - return b } // SetBackgroundColorFocused sets the background color of the button text when // the button is in focus. -func (b *Button) SetBackgroundColorFocused(color tcell.Color) *Button { +func (b *Button) SetBackgroundColorFocused(color tcell.Color) { b.Lock() defer b.Unlock() b.backgroundColorFocused = color - return b } // SetSelectedFunc sets a handler which is called when the button was selected. -func (b *Button) SetSelectedFunc(handler func()) *Button { +func (b *Button) SetSelectedFunc(handler func()) { b.Lock() defer b.Unlock() b.selected = handler - return b } // SetBlurFunc sets a handler which is called when the user leaves the button. @@ -107,12 +103,11 @@ func (b *Button) SetSelectedFunc(handler func()) *Button { // - KeyEscape: Leaving the button with no specific direction. // - KeyTab: Move to the next field. // - KeyBacktab: Move to the previous field. -func (b *Button) SetBlurFunc(handler func(key tcell.Key)) *Button { +func (b *Button) SetBlurFunc(handler func(key tcell.Key)) { b.Lock() defer b.Unlock() b.blur = handler - return b } // Draw draws this primitive onto the screen. diff --git a/checkbox.go b/checkbox.go index ac2b89e..6288db0 100644 --- a/checkbox.go +++ b/checkbox.go @@ -76,21 +76,19 @@ func NewCheckBox() *CheckBox { } // SetChecked sets the state of the checkbox. -func (c *CheckBox) SetChecked(checked bool) *CheckBox { +func (c *CheckBox) SetChecked(checked bool) { c.Lock() defer c.Unlock() c.checked = checked - return c } // SetCheckedRune sets the rune to show when the checkbox is checked. -func (c *CheckBox) SetCheckedRune(rune rune) *CheckBox { +func (c *CheckBox) SetCheckedRune(rune rune) { c.Lock() defer c.Unlock() c.checkedRune = rune - return c } // IsChecked returns whether or not the box is checked. @@ -102,12 +100,11 @@ func (c *CheckBox) IsChecked() bool { } // SetLabel sets the text to be displayed before the input area. -func (c *CheckBox) SetLabel(label string) *CheckBox { +func (c *CheckBox) SetLabel(label string) { c.Lock() defer c.Unlock() c.label = []byte(label) - return c } // GetLabel returns the text to be displayed before the input area. @@ -119,12 +116,11 @@ func (c *CheckBox) GetLabel() string { } // SetMessage sets the text to be displayed after the checkbox -func (c *CheckBox) SetMessage(message string) *CheckBox { +func (c *CheckBox) SetMessage(message string) { c.Lock() defer c.Unlock() c.message = []byte(message) - return c } // GetMessage returns the text to be displayed after the checkbox @@ -137,66 +133,59 @@ func (c *CheckBox) GetMessage() string { // SetLabelWidth sets the screen width of the label. A value of 0 will cause the // primitive to use the width of the label string. -func (c *CheckBox) SetLabelWidth(width int) *CheckBox { +func (c *CheckBox) SetLabelWidth(width int) { c.Lock() defer c.Unlock() c.labelWidth = width - return c } // SetLabelColor sets the color of the label. -func (c *CheckBox) SetLabelColor(color tcell.Color) *CheckBox { +func (c *CheckBox) SetLabelColor(color tcell.Color) { c.Lock() defer c.Unlock() c.labelColor = color - return c } // SetLabelColorFocused sets the color of the label when focused. -func (c *CheckBox) SetLabelColorFocused(color tcell.Color) *CheckBox { +func (c *CheckBox) SetLabelColorFocused(color tcell.Color) { c.Lock() defer c.Unlock() c.labelColorFocused = color - return c } // SetFieldBackgroundColor sets the background color of the input area. -func (c *CheckBox) SetFieldBackgroundColor(color tcell.Color) *CheckBox { +func (c *CheckBox) SetFieldBackgroundColor(color tcell.Color) { c.Lock() defer c.Unlock() c.fieldBackgroundColor = color - return c } // SetFieldBackgroundColorFocused sets the background color of the input area when focused. -func (c *CheckBox) SetFieldBackgroundColorFocused(color tcell.Color) *CheckBox { +func (c *CheckBox) SetFieldBackgroundColorFocused(color tcell.Color) { c.Lock() defer c.Unlock() c.fieldBackgroundColorFocused = color - return c } // SetFieldTextColor sets the text color of the input area. -func (c *CheckBox) SetFieldTextColor(color tcell.Color) *CheckBox { +func (c *CheckBox) SetFieldTextColor(color tcell.Color) { c.Lock() defer c.Unlock() c.fieldTextColor = color - return c } // SetFieldTextColorFocused sets the text color of the input area when focused. -func (c *CheckBox) SetFieldTextColorFocused(color tcell.Color) *CheckBox { +func (c *CheckBox) SetFieldTextColorFocused(color tcell.Color) { c.Lock() defer c.Unlock() c.fieldTextColorFocused = color - return c } // GetFieldHeight returns the height of the field. @@ -219,12 +208,11 @@ func (c *CheckBox) GetFieldWidth() int { // SetChangedFunc sets a handler which is called when the checked state of this // checkbox was changed by the user. The handler function receives the new // state. -func (c *CheckBox) SetChangedFunc(handler func(checked bool)) *CheckBox { +func (c *CheckBox) SetChangedFunc(handler func(checked bool)) { c.Lock() defer c.Unlock() c.changed = handler - return c } // SetDoneFunc sets a handler which is called when the user is done using the @@ -234,21 +222,19 @@ func (c *CheckBox) SetChangedFunc(handler func(checked bool)) *CheckBox { // - KeyEscape: Abort text input. // - KeyTab: Move to the next field. // - KeyBacktab: Move to the previous field. -func (c *CheckBox) SetDoneFunc(handler func(key tcell.Key)) *CheckBox { +func (c *CheckBox) SetDoneFunc(handler func(key tcell.Key)) { c.Lock() defer c.Unlock() c.done = handler - return c } // SetFinishedFunc sets a callback invoked when the user leaves this form item. -func (c *CheckBox) SetFinishedFunc(handler func(key tcell.Key)) *CheckBox { +func (c *CheckBox) SetFinishedFunc(handler func(key tcell.Key)) { c.Lock() defer c.Unlock() c.finished = handler - return c } // SetAttributes applies attribute settings to a form item. diff --git a/contextmenu.go b/contextmenu.go index d619a77..5b57b2b 100644 --- a/contextmenu.go +++ b/contextmenu.go @@ -28,18 +28,17 @@ func (c *ContextMenu) initializeList() { return } - c.list = NewList(). - ShowSecondaryText(false). - SetHover(true). - SetWrapAround(true) - c.list. - ShowFocus(false). - SetBorder(true). - SetBorderPadding( - Styles.ContextMenuPaddingTop, - Styles.ContextMenuPaddingBottom, - Styles.ContextMenuPaddingLeft, - Styles.ContextMenuPaddingRight) + c.list = NewList() + c.list.ShowSecondaryText(false) + c.list.SetHover(true) + c.list.SetWrapAround(true) + c.list.ShowFocus(false) + c.list.SetBorder(true) + c.list.SetBorderPadding( + Styles.ContextMenuPaddingTop, + Styles.ContextMenuPaddingBottom, + Styles.ContextMenuPaddingLeft, + Styles.ContextMenuPaddingRight) } // ContextMenuList returns the underlying List of the context menu. @@ -54,21 +53,23 @@ func (c *ContextMenu) ContextMenuList() *List { // AddContextItem adds an item to the context menu. Adding an item with no text // or shortcut will add a divider. -func (c *ContextMenu) AddContextItem(text string, shortcut rune, selected func(index int)) *ContextMenu { +func (c *ContextMenu) AddContextItem(text string, shortcut rune, selected func(index int)) { c.l.Lock() defer c.l.Unlock() c.initializeList() - c.list.AddItem(NewListItem(text).SetShortcut(shortcut).SetSelectedFunc(c.wrap(selected))) + item := NewListItem(text) + item.SetShortcut(shortcut) + item.SetSelectedFunc(c.wrap(selected)) + + c.list.AddItem(item) if text == "" && shortcut == 0 { c.list.Lock() index := len(c.list.items) - 1 c.list.items[index].enabled = false c.list.Unlock() } - - return c } func (c *ContextMenu) wrap(f func(index int)) func() { @@ -78,27 +79,24 @@ func (c *ContextMenu) wrap(f func(index int)) func() { } // ClearContextMenu removes all items from the context menu. -func (c *ContextMenu) ClearContextMenu() *ContextMenu { +func (c *ContextMenu) ClearContextMenu() { c.l.Lock() defer c.l.Unlock() c.initializeList() c.list.Clear() - - return c } // SetContextSelectedFunc sets the function which is called when the user // selects a context menu item. The function receives the item's index in the // menu (starting with 0), its text and its shortcut rune. SetSelectedFunc must // be called before the context menu is shown. -func (c *ContextMenu) SetContextSelectedFunc(handler func(index int, text string, shortcut rune)) *ContextMenu { +func (c *ContextMenu) SetContextSelectedFunc(handler func(index int, text string, shortcut rune)) { c.l.Lock() defer c.l.Unlock() c.selected = handler - return c } // ShowContextMenu shows the context menu. Provide -1 for both to position on @@ -158,7 +156,8 @@ func (c *ContextMenu) show(item int, x int, y int, setFocus func(Primitive)) { } else { c.l.Unlock() } - }).SetDoneFunc(func() { + }) + c.list.SetDoneFunc(func() { c.l.Lock() defer c.l.Unlock() diff --git a/demos/box/main.go b/demos/box/main.go index 09d6396..ce5174f 100644 --- a/demos/box/main.go +++ b/demos/box/main.go @@ -7,11 +7,15 @@ import ( ) func main() { - box := cview.NewBox(). - SetBorder(true). - SetBorderAttributes(tcell.AttrBold). - SetTitle("A [red]c[yellow]o[green]l[darkcyan]o[blue]r[darkmagenta]f[red]u[yellow]l[white] [black:red]c[:yellow]o[:green]l[:darkcyan]o[:blue]r[:darkmagenta]f[:red]u[:yellow]l[white:] [::bu]title") - if err := cview.NewApplication().SetRoot(box, true).Run(); err != nil { + app := cview.NewApplication() + + box := cview.NewBox() + box.SetBorder(true) + box.SetBorderAttributes(tcell.AttrBold) + box.SetTitle("A [red]c[yellow]o[green]l[darkcyan]o[blue]r[darkmagenta]f[red]u[yellow]l[white] [black:red]c[:yellow]o[:green]l[:darkcyan]o[:blue]r[:darkmagenta]f[:red]u[:yellow]l[white:] [::bu]title") + + app.SetRoot(box, true) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/button/main.go b/demos/button/main.go index 039adf6..903119c 100644 --- a/demos/button/main.go +++ b/demos/button/main.go @@ -5,11 +5,17 @@ import "gitlab.com/tslocum/cview" func main() { app := cview.NewApplication() - button := cview.NewButton("Hit Enter to close").SetSelectedFunc(func() { + app.EnableMouse(true) + + button := cview.NewButton("Hit Enter to close") + button.SetBorder(true) + button.SetRect(0, 0, 22, 3) + button.SetSelectedFunc(func() { app.Stop() }) - button.SetBorder(true).SetRect(0, 0, 22, 3) - if err := app.SetRoot(button, false).EnableMouse(true).Run(); err != nil { + + app.SetRoot(button, false) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/checkbox/main.go b/demos/checkbox/main.go index 23a0942..93b3ac9 100644 --- a/demos/checkbox/main.go +++ b/demos/checkbox/main.go @@ -7,8 +7,13 @@ import ( func main() { app := cview.NewApplication() - checkbox := cview.NewCheckBox().SetLabel("Hit Enter to check box: ") - if err := app.SetRoot(checkbox, true).EnableMouse(true).Run(); err != nil { + app.EnableMouse(true) + + checkbox := cview.NewCheckBox() + checkbox.SetLabel("Hit Enter to check box: ") + + app.SetRoot(checkbox, true) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/dropdown/main.go b/demos/dropdown/main.go index 9a3317b..f500e59 100644 --- a/demos/dropdown/main.go +++ b/demos/dropdown/main.go @@ -5,15 +5,19 @@ import "gitlab.com/tslocum/cview" func main() { app := cview.NewApplication() - dropdown := cview.NewDropDown(). - SetLabel("Select an option (hit Enter): "). - SetOptions(nil, - cview.NewDropDownOption("First"), - cview.NewDropDownOption("Second"), - cview.NewDropDownOption("Third"), - cview.NewDropDownOption("Fourth"), - cview.NewDropDownOption("Fifth")) - if err := app.SetRoot(dropdown, true).EnableMouse(true).Run(); err != nil { + app.EnableMouse(true) + + dropdown := cview.NewDropDown() + dropdown.SetLabel("Select an option (hit Enter): ") + dropdown.SetOptions(nil, + cview.NewDropDownOption("First"), + cview.NewDropDownOption("Second"), + cview.NewDropDownOption("Third"), + cview.NewDropDownOption("Fourth"), + cview.NewDropDownOption("Fifth")) + + app.SetRoot(dropdown, true) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/flex/main.go b/demos/flex/main.go index a8de152..55ca07d 100644 --- a/demos/flex/main.go +++ b/demos/flex/main.go @@ -5,16 +5,30 @@ import ( "gitlab.com/tslocum/cview" ) +func demoBox(title string) *cview.Box { + b := cview.NewBox() + b.SetBorder(true) + b.SetTitle(title) + return b +} + func main() { app := cview.NewApplication() - flex := cview.NewFlex(). - AddItem(cview.NewBox().SetBorder(true).SetTitle("Left (1/2 x width of Top)"), 0, 1, false). - AddItem(cview.NewFlex().SetDirection(cview.FlexRow). - AddItem(cview.NewBox().SetBorder(true).SetTitle("Top"), 0, 1, false). - AddItem(cview.NewBox().SetBorder(true).SetTitle("Middle (3 x height of Top)"), 0, 3, false). - AddItem(cview.NewBox().SetBorder(true).SetTitle("Bottom (5 rows)"), 5, 1, false), 0, 2, false). - AddItem(cview.NewBox().SetBorder(true).SetTitle("Right (20 cols)"), 20, 1, false) - if err := app.SetRoot(flex, true).EnableMouse(true).Run(); err != nil { + app.EnableMouse(true) + + subFlex := cview.NewFlex() + subFlex.SetDirection(cview.FlexRow) + subFlex.AddItem(demoBox("Top"), 0, 1, false) + subFlex.AddItem(demoBox("Middle (3 x height of Top)"), 0, 3, false) + subFlex.AddItem(demoBox("Bottom (5 rows)"), 5, 1, false) + + flex := cview.NewFlex() + flex.AddItem(demoBox("Left (1/2 x width of Top)"), 0, 1, false) + flex.AddItem(subFlex, 0, 2, false) + flex.AddItem(demoBox("Right (20 cols)"), 20, 1, false) + + app.SetRoot(flex, true) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/form/main.go b/demos/form/main.go index a38907a..355c579 100644 --- a/demos/form/main.go +++ b/demos/form/main.go @@ -7,22 +7,29 @@ import ( func main() { app := cview.NewApplication() - form := cview.NewForm(). - AddDropDownSimple("Title", 0, nil, "Mr.", "Ms.", "Mrs.", "Dr.", "Prof."). - AddInputField("First name", "", 20, nil, nil). - AddInputField("Last name", "", 20, nil, nil). - AddFormItem(cview.NewInputField(). - SetLabel("Address"). - SetFieldWidth(30). - SetFieldNote("Your complete address")). - AddPasswordField("Password", "", 10, '*', nil). - AddCheckBox("", "Age 18+", false, nil). - AddButton("Save", nil). - AddButton("Quit", func() { - app.Stop() - }) - form.SetBorder(true).SetTitle("Enter some data").SetTitleAlign(cview.AlignLeft) - if err := app.SetRoot(form, true).EnableMouse(true).Run(); err != nil { + app.EnableMouse(true) + + form := cview.NewForm() + form.AddDropDownSimple("Title", 0, nil, "Mr.", "Ms.", "Mrs.", "Dr.", "Prof.") + form.AddInputField("First name", "", 20, nil, nil) + form.AddInputField("Last name", "", 20, nil, nil) + addressField := cview.NewInputField() + addressField.SetLabel("Address") + addressField.SetFieldWidth(30) + addressField.SetFieldNote("Your complete address") + form.AddFormItem(addressField) + form.AddPasswordField("Password", "", 10, '*', nil) + form.AddCheckBox("", "Age 18+", false, nil) + form.AddButton("Save", nil) + form.AddButton("Quit", func() { + app.Stop() + }) + form.SetBorder(true) + form.SetTitle("Enter some data") + form.SetTitleAlign(cview.AlignLeft) + + app.SetRoot(form, true) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/frame/main.go b/demos/frame/main.go index ed65c05..b1f7c47 100644 --- a/demos/frame/main.go +++ b/demos/frame/main.go @@ -8,15 +8,22 @@ import ( func main() { app := cview.NewApplication() - frame := cview.NewFrame(cview.NewBox().SetBackgroundColor(tcell.ColorBlue.TrueColor())). - SetBorders(2, 2, 2, 2, 4, 4). - AddText("Header left", true, cview.AlignLeft, tcell.ColorWhite.TrueColor()). - AddText("Header middle", true, cview.AlignCenter, tcell.ColorWhite.TrueColor()). - AddText("Header right", true, cview.AlignRight, tcell.ColorWhite.TrueColor()). - AddText("Header second middle", true, cview.AlignCenter, tcell.ColorRed.TrueColor()). - AddText("Footer middle", false, cview.AlignCenter, tcell.ColorGreen.TrueColor()). - AddText("Footer second middle", false, cview.AlignCenter, tcell.ColorGreen.TrueColor()) - if err := app.SetRoot(frame, true).EnableMouse(true).Run(); err != nil { + app.EnableMouse(true) + + box := cview.NewBox() + box.SetBackgroundColor(tcell.ColorBlue.TrueColor()) + + frame := cview.NewFrame(box) + frame.SetBorders(2, 2, 2, 2, 4, 4) + frame.AddText("Header left", true, cview.AlignLeft, tcell.ColorWhite.TrueColor()) + frame.AddText("Header middle", true, cview.AlignCenter, tcell.ColorWhite.TrueColor()) + frame.AddText("Header right", true, cview.AlignRight, tcell.ColorWhite.TrueColor()) + frame.AddText("Header second middle", true, cview.AlignCenter, tcell.ColorRed.TrueColor()) + frame.AddText("Footer middle", false, cview.AlignCenter, tcell.ColorGreen.TrueColor()) + frame.AddText("Footer second middle", false, cview.AlignCenter, tcell.ColorGreen.TrueColor()) + + app.SetRoot(frame, true) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/grid/main.go b/demos/grid/main.go index 867027d..9557d67 100644 --- a/demos/grid/main.go +++ b/demos/grid/main.go @@ -6,33 +6,38 @@ import ( ) func main() { + app := cview.NewApplication() + app.EnableMouse(true) + newPrimitive := func(text string) cview.Primitive { - return cview.NewTextView(). - SetTextAlign(cview.AlignCenter). - SetText(text) + tv := cview.NewTextView() + tv.SetTextAlign(cview.AlignCenter) + tv.SetText(text) + return tv } menu := newPrimitive("Menu") main := newPrimitive("Main content") sideBar := newPrimitive("Side Bar") - grid := cview.NewGrid(). - SetRows(3, 0, 3). - SetColumns(30, 0, 30). - SetBorders(true). - AddItem(newPrimitive("Header"), 0, 0, 1, 3, 0, 0, false). - AddItem(newPrimitive("Footer"), 2, 0, 1, 3, 0, 0, false) + grid := cview.NewGrid() + grid.SetRows(3, 0, 3) + grid.SetColumns(30, 0, 30) + grid.SetBorders(true) + grid.AddItem(newPrimitive("Header"), 0, 0, 1, 3, 0, 0, false) + grid.AddItem(newPrimitive("Footer"), 2, 0, 1, 3, 0, 0, false) // Layout for screens narrower than 100 cells (menu and side bar are hidden). - grid.AddItem(menu, 0, 0, 0, 0, 0, 0, false). - AddItem(main, 1, 0, 1, 3, 0, 0, false). - AddItem(sideBar, 0, 0, 0, 0, 0, 0, false) + grid.AddItem(menu, 0, 0, 0, 0, 0, 0, false) + grid.AddItem(main, 1, 0, 1, 3, 0, 0, false) + grid.AddItem(sideBar, 0, 0, 0, 0, 0, 0, false) // Layout for screens wider than 100 cells. - grid.AddItem(menu, 1, 0, 1, 1, 0, 100, false). - AddItem(main, 1, 1, 1, 1, 0, 100, false). - AddItem(sideBar, 1, 2, 1, 1, 0, 100, false) + grid.AddItem(menu, 1, 0, 1, 1, 0, 100, false) + grid.AddItem(main, 1, 1, 1, 1, 0, 100, false) + grid.AddItem(sideBar, 1, 2, 1, 1, 0, 100, false) - if err := cview.NewApplication().SetRoot(grid, true).EnableMouse(true).Run(); err != nil { + app.SetRoot(grid, true) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/inputfield/autocomplete/main.go b/demos/inputfield/autocomplete/main.go index caa7019..2f75db7 100644 --- a/demos/inputfield/autocomplete/main.go +++ b/demos/inputfield/autocomplete/main.go @@ -11,14 +11,16 @@ import ( const wordList = "ability,able,about,above,accept,according,account,across,act,action,activity,actually,add,address,administration,admit,adult,affect,after,again,against,age,agency,agent,ago,agree,agreement,ahead,air,all,allow,almost,alone,along,already,also,although,always,American,among,amount,analysis,and,animal,another,answer,any,anyone,anything,appear,apply,approach,area,argue,arm,around,arrive,art,article,artist,as,ask,assume,at,attack,attention,attorney,audience,author,authority,available,avoid,away,baby,back,bad,bag,ball,bank,bar,base,be,beat,beautiful,because,become,bed,before,begin,behavior,behind,believe,benefit,best,better,between,beyond,big,bill,billion,bit,black,blood,blue,board,body,book,born,both,box,boy,break,bring,brother,budget,build,building,business,but,buy,by,call,camera,campaign,can,cancer,candidate,capital,car,card,care,career,carry,case,catch,cause,cell,center,central,century,certain,certainly,chair,challenge,chance,change,character,charge,check,child,choice,choose,church,citizen,city,civil,claim,class,clear,clearly,close,coach,cold,collection,college,color,come,commercial,common,community,company,compare,computer,concern,condition,conference,Congress,consider,consumer,contain,continue,control,cost,could,country,couple,course,court,cover,create,crime,cultural,culture,cup,current,customer,cut,dark,data,daughter,day,dead,deal,death,debate,decade,decide,decision,deep,defense,degree,Democrat,democratic,describe,design,despite,detail,determine,develop,development,die,difference,different,difficult,dinner,direction,director,discover,discuss,discussion,disease,do,doctor,dog,door,down,draw,dream,drive,drop,drug,during,each,early,east,easy,eat,economic,economy,edge,education,effect,effort,eight,either,election,else,employee,end,energy,enjoy,enough,enter,entire,environment,environmental,especially,establish,even,evening,event,ever,every,everybody,everyone,everything,evidence,exactly,example,executive,exist,expect,experience,expert,explain,eye,face,fact,factor,fail,fall,family,far,fast,father,fear,federal,feel,feeling,few,field,fight,figure,fill,film,final,finally,financial,find,fine,finger,finish,fire,firm,first,fish,five,floor,fly,focus,follow,food,foot,for,force,foreign,forget,form,former,forward,four,free,friend,from,front,full,fund,future,game,garden,gas,general,generation,get,girl,give,glass,go,goal,good,government,great,green,ground,group,grow,growth,guess,gun,guy,hair,half,hand,hang,happen,happy,hard,have,he,head,health,hear,heart,heat,heavy,help,her,here,herself,high,him,himself,his,history,hit,hold,home,hope,hospital,hot,hotel,hour,house,how,however,huge,human,hundred,husband,idea,identify,if,image,imagine,impact,important,improve,in,include,including,increase,indeed,indicate,individual,industry,information,inside,instead,institution,interest,interesting,international,interview,into,investment,involve,issue,it,item,its,itself,job,join,just,keep,key,kid,kill,kind,kitchen,know,knowledge,land,language,large,last,late,later,laugh,law,lawyer,lay,lead,leader,learn,least,leave,left,leg,legal,less,let,letter,level,lie,life,light,like,likely,line,list,listen,little,live,local,long,look,lose,loss,lot,love,low,machine,magazine,main,maintain,major,majority,make,man,manage,management,manager,many,market,marriage,material,matter,may,maybe,me,mean,measure,media,medical,meet,meeting,member,memory,mention,message,method,middle,might,military,million,mind,minute,miss,mission,model,modern,moment,money,month,more,morning,most,mother,mouth,move,movement,movie,Mr,Mrs,much,music,must,my,myself,n't,name,nation,national,natural,nature,near,nearly,necessary,need,network,never,new,news,newspaper,next,nice,night,no,none,nor,north,not,note,nothing,notice,now,number,occur,of,off,offer,office,officer,official,often,oh,oil,ok,old,on,once,one,only,onto,open,operation,opportunity,option,or,order,organization,other,others,our,out,outside,over,own,owner,page,pain,painting,paper,parent,part,participant,particular,particularly,partner,party,pass,past,patient,pattern,pay,peace,people,per,perform,performance,perhaps,period,person,personal,phone,physical,pick,picture,piece,place,plan,plant,play,player,PM,point,police,policy,political,politics,poor,popular,population,position,positive,possible,power,practice,prepare,present,president,pressure,pretty,prevent,price,private,probably,problem,process,produce,product,production,professional,professor,program,project,property,protect,prove,provide,public,pull,purpose,push,put,quality,question,quickly,quite,race,radio,raise,range,rate,rather,reach,read,ready,real,reality,realize,really,reason,receive,recent,recently,recognize,record,red,reduce,reflect,region,relate,relationship,religious,remain,remember,remove,report,represent,Republican,require,research,resource,respond,response,responsibility,rest,result,return,reveal,rich,right,rise,risk,road,rock,role,room,rule,run,safe,same,save,say,scene,school,science,scientist,score,sea,season,seat,second,section,security,see,seek,seem,sell,send,senior,sense,series,serious,serve,service,set,seven,several,sex,sexual,shake,share,she,shoot,short,shot,should,shoulder,show,side,sign,significant,similar,simple,simply,since,sing,single,sister,sit,site,situation,six,size,skill,skin,small,smile,so,social,society,soldier,some,somebody,someone,something,sometimes,son,song,soon,sort,sound,source,south,southern,space,speak,special,specific,speech,spend,sport,spring,staff,stage,stand,standard,star,start,state,statement,station,stay,step,still,stock,stop,store,story,strategy,street,strong,structure,student,study,stuff,style,subject,success,successful,such,suddenly,suffer,suggest,summer,support,sure,surface,system,table,take,talk,task,tax,teach,teacher,team,technology,television,tell,ten,tend,term,test,than,thank,that,the,their,them,themselves,then,theory,there,these,they,thing,think,third,this,those,though,thought,thousand,threat,three,through,throughout,throw,thus,time,to,today,together,tonight,too,top,total,tough,toward,town,trade,traditional,training,travel,treat,treatment,tree,trial,trip,trouble,true,truth,try,turn,TV,two,type,under,understand,unit,until,up,upon,us,use,usually,value,various,very,victim,view,violence,visit,voice,vote,wait,walk,wall,want,war,watch,water,way,we,weapon,wear,week,weight,well,west,western,what,whatever,when,where,whether,which,while,white,who,whole,whom,whose,why,wide,wife,will,win,wind,window,wish,with,within,without,woman,wonder,word,work,worker,world,worry,would,write,writer,wrong,yard,yeah,year,yes,yet,you,young,your,yourself" func main() { - words := strings.Split(wordList, ",") app := cview.NewApplication() - inputField := cview.NewInputField(). - SetLabel("Enter a word: "). - SetFieldWidth(30). - SetDoneFunc(func(key tcell.Key) { - app.Stop() - }) + + words := strings.Split(wordList, ",") + + inputField := cview.NewInputField() + inputField.SetLabel("Enter a word: ") + inputField.SetFieldWidth(30) + inputField.SetDoneFunc(func(key tcell.Key) { + app.Stop() + }) inputField.SetAutocompleteFunc(func(currentText string) (entries []*cview.ListItem) { if len(currentText) == 0 { return @@ -33,7 +35,9 @@ func main() { } return }) - if err := app.SetRoot(inputField, true).Run(); err != nil { + + app.SetRoot(inputField, true) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/inputfield/autocompleteasync/main.go b/demos/inputfield/autocompleteasync/main.go index 1fe11fa..59cc8d0 100644 --- a/demos/inputfield/autocompleteasync/main.go +++ b/demos/inputfield/autocompleteasync/main.go @@ -17,12 +17,12 @@ type company struct { func main() { app := cview.NewApplication() - inputField := cview.NewInputField(). - SetLabel("Enter a company name: "). - SetFieldWidth(30). - SetDoneFunc(func(key tcell.Key) { - app.Stop() - }) + inputField := cview.NewInputField() + inputField.SetLabel("Enter a company name: ") + inputField.SetFieldWidth(30) + inputField.SetDoneFunc(func(key tcell.Key) { + app.Stop() + }) // Set up autocomplete function. var mutex sync.RWMutex @@ -75,7 +75,8 @@ func main() { return nil }) - if err := app.SetRoot(inputField, true).Run(); err != nil { + app.SetRoot(inputField, true) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/inputfield/simple/main.go b/demos/inputfield/simple/main.go index 1fce6d3..3ff1421 100644 --- a/demos/inputfield/simple/main.go +++ b/demos/inputfield/simple/main.go @@ -8,15 +8,19 @@ import ( func main() { app := cview.NewApplication() - inputField := cview.NewInputField(). - SetLabel("Enter a number: "). - SetPlaceholder("E.g. 1234"). - SetFieldWidth(10). - SetAcceptanceFunc(cview.InputFieldInteger). - SetDoneFunc(func(key tcell.Key) { - app.Stop() - }) - if err := app.SetRoot(inputField, true).EnableMouse(true).Run(); err != nil { + app.EnableMouse(true) + + inputField := cview.NewInputField() + inputField.SetLabel("Enter a number: ") + inputField.SetPlaceholder("E.g. 1234") + inputField.SetFieldWidth(10) + inputField.SetAcceptanceFunc(cview.InputFieldInteger) + inputField.SetDoneFunc(func(key tcell.Key) { + app.Stop() + }) + + app.SetRoot(inputField, true) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/list/main.go b/demos/list/main.go index f1860c8..3a18e0f 100644 --- a/demos/list/main.go +++ b/demos/list/main.go @@ -2,23 +2,32 @@ package main import ( + "fmt" + "gitlab.com/tslocum/cview" ) func main() { app := cview.NewApplication() + app.EnableMouse(true) + list := cview.NewList() reset := func() { - list. - Clear(). - AddItem(cview.NewListItem("List item 1").SetSecondaryText("Some explanatory text").SetShortcut('a')). - AddItem(cview.NewListItem("List item 2").SetSecondaryText("Some explanatory text").SetShortcut('b')). - AddItem(cview.NewListItem("List item 3").SetSecondaryText("Some explanatory text").SetShortcut('c')). - AddItem(cview.NewListItem("List item 4").SetSecondaryText("Some explanatory text").SetShortcut('d')). - AddItem(cview.NewListItem("Quit").SetSecondaryText("Press to exit").SetShortcut('q').SetSelectedFunc(func() { - app.Stop() - })) + list.Clear() + for i := 0; i < 4; i++ { + item := cview.NewListItem(fmt.Sprintf("List item %d", i+1)) + item.SetSecondaryText("Some explanatory text") + item.SetShortcut(rune('a' + i)) + list.AddItem(item) + } + quitItem := cview.NewListItem("Quit") + quitItem.SetSecondaryText("Press to exit") + quitItem.SetShortcut('q') + quitItem.SetSelectedFunc(func() { + app.Stop() + }) + list.AddItem(quitItem) list.ContextMenuList().SetItemEnabled(3, false) } @@ -52,7 +61,8 @@ func main() { }) reset() - if err := app.SetRoot(list, true).EnableMouse(true).Run(); err != nil { + app.SetRoot(list, true) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/modal/main.go b/demos/modal/main.go index 76c773f..4b7d5c0 100644 --- a/demos/modal/main.go +++ b/demos/modal/main.go @@ -7,15 +7,19 @@ import ( func main() { app := cview.NewApplication() - modal := cview.NewModal(). - SetText("Do you want to quit the application?"). - AddButtons([]string{"Quit", "Cancel"}). - SetDoneFunc(func(buttonIndex int, buttonLabel string) { - if buttonLabel == "Quit" { - app.Stop() - } - }) - if err := app.SetRoot(modal, false).EnableMouse(true).Run(); err != nil { + app.EnableMouse(true) + + modal := cview.NewModal() + modal.SetText("Do you want to quit the application?") + modal.AddButtons([]string{"Quit", "Cancel"}) + modal.SetDoneFunc(func(buttonIndex int, buttonLabel string) { + if buttonLabel == "Quit" { + app.Stop() + } + }) + + app.SetRoot(modal, false) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/pages/main.go b/demos/pages/main.go index e7c2d5e..7ed28a0 100644 --- a/demos/pages/main.go +++ b/demos/pages/main.go @@ -11,25 +11,28 @@ const pageCount = 5 func main() { app := cview.NewApplication() + app.EnableMouse(true) + pages := cview.NewPages() for page := 0; page < pageCount; page++ { func(page int) { - pages.AddPage(fmt.Sprintf("page-%d", page), - cview.NewModal(). - SetText(fmt.Sprintf("This is page %d. Choose where to go next.", page+1)). - AddButtons([]string{"Next", "Quit"}). - SetDoneFunc(func(buttonIndex int, buttonLabel string) { - if buttonIndex == 0 { - pages.SwitchToPage(fmt.Sprintf("page-%d", (page+1)%pageCount)) - } else { - app.Stop() - } - }), - false, - page == 0) + modal := cview.NewModal() + modal.SetText(fmt.Sprintf("This is page %d. Choose where to go next.", page+1)) + modal.AddButtons([]string{"Next", "Quit"}) + modal.SetDoneFunc(func(buttonIndex int, buttonLabel string) { + if buttonIndex == 0 { + pages.SwitchToPage(fmt.Sprintf("page-%d", (page+1)%pageCount)) + } else { + app.Stop() + } + }) + + pages.AddPage(fmt.Sprintf("page-%d", page), modal, false, page == 0) }(page) } - if err := app.SetRoot(pages, true).EnableMouse(true).Run(); err != nil { + + app.SetRoot(pages, true) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/presentation/center.go b/demos/presentation/center.go index 679abb3..df99037 100644 --- a/demos/presentation/center.go +++ b/demos/presentation/center.go @@ -5,12 +5,16 @@ import "gitlab.com/tslocum/cview" // Center returns a new primitive which shows the provided primitive in its // center, given the provided primitive's size. func Center(width, height int, p cview.Primitive) cview.Primitive { - return cview.NewFlex(). - AddItem(cview.NewBox(), 0, 1, false). - AddItem(cview.NewFlex(). - SetDirection(cview.FlexRow). - AddItem(cview.NewBox(), 0, 1, false). - AddItem(p, height, 1, true). - AddItem(cview.NewBox(), 0, 1, false), width, 1, true). - AddItem(cview.NewBox(), 0, 1, false) + subFlex := cview.NewFlex() + subFlex.SetDirection(cview.FlexRow) + subFlex.AddItem(cview.NewBox(), 0, 1, false) + subFlex.AddItem(p, height, 1, true) + subFlex.AddItem(cview.NewBox(), 0, 1, false) + + flex := cview.NewFlex() + flex.AddItem(cview.NewBox(), 0, 1, false) + flex.AddItem(subFlex, width, 1, true) + flex.AddItem(cview.NewBox(), 0, 1, false) + + return flex } diff --git a/demos/presentation/code.go b/demos/presentation/code.go index 81c5f6b..3736b74 100644 --- a/demos/presentation/code.go +++ b/demos/presentation/code.go @@ -13,13 +13,14 @@ const codeWidth = 56 // size) on the left side and its source code on the right side. func Code(p cview.Primitive, width, height int, code string) cview.Primitive { // Set up code view. - codeView := cview.NewTextView(). - SetWrap(false). - SetDynamicColors(true) + codeView := cview.NewTextView() + codeView.SetWrap(false) + codeView.SetDynamicColors(true) codeView.SetBorderPadding(1, 1, 2, 0) fmt.Fprint(codeView, code) - return cview.NewFlex(). - AddItem(Center(width, height, p), 0, 1, true). - AddItem(codeView, codeWidth, 1, false) + f := cview.NewFlex() + f.AddItem(Center(width, height, p), 0, 1, true) + f.AddItem(codeView, codeWidth, 1, false) + return f } diff --git a/demos/presentation/colors.go b/demos/presentation/colors.go index 8a80aa0..850321d 100644 --- a/demos/presentation/colors.go +++ b/demos/presentation/colors.go @@ -19,15 +19,15 @@ The [black:red]tags [black:green]look [black:yellow]like [::u]this: // Colors demonstrates how to use colors. func Colors(nextSlide func()) (title string, content cview.Primitive) { - tv := cview.NewTextView(). - SetWordWrap(true). - SetDynamicColors(true). - SetText(colorsText). - SetDoneFunc(func(key tcell.Key) { - nextSlide() - }) - tv. - SetBorder(true). - SetTitle("A [red]c[yellow]o[green]l[darkcyan]o[blue]r[darkmagenta]f[red]u[yellow]l[white] [black:red]c[:yellow]o[:green]l[:darkcyan]o[:blue]r[:darkmagenta]f[:red]u[:yellow]l[white:] [::bu]title") + tv := cview.NewTextView() + tv.SetBorder(true) + tv.SetTitle("A [red]c[yellow]o[green]l[darkcyan]o[blue]r[darkmagenta]f[red]u[yellow]l[white] [black:red]c[:yellow]o[:green]l[:darkcyan]o[:blue]r[:darkmagenta]f[:red]u[:yellow]l[white:] [::bu]title") + tv.SetDynamicColors(true) + tv.SetWordWrap(true) + tv.SetText(colorsText) + tv.SetDoneFunc(func(key tcell.Key) { + nextSlide() + }) + return "Colors", Center(44, 16, tv) } diff --git a/demos/presentation/cover.go b/demos/presentation/cover.go index 3aeb61e..ecb39dc 100644 --- a/demos/presentation/cover.go +++ b/demos/presentation/cover.go @@ -33,30 +33,32 @@ func Cover(nextSlide func()) (title string, content cview.Primitive) { logoWidth = len(line) } } - logoBox := cview.NewTextView(). - SetTextColor(tcell.ColorGreen.TrueColor()). - SetDoneFunc(func(key tcell.Key) { - nextSlide() - }) + logoBox := cview.NewTextView() + logoBox.SetTextColor(tcell.ColorGreen.TrueColor()) + logoBox.SetDoneFunc(func(key tcell.Key) { + nextSlide() + }) fmt.Fprint(logoBox, logo) // Create a frame for the subtitle and navigation infos. - frame := cview.NewFrame(cview.NewBox()). - SetBorders(0, 0, 0, 0, 0, 0). - AddText(subtitle, true, cview.AlignCenter, tcell.ColorWhite.TrueColor()). - AddText("", true, cview.AlignCenter, tcell.ColorWhite.TrueColor()). - AddText(mouse, true, cview.AlignCenter, tcell.ColorDarkMagenta.TrueColor()). - AddText(navigation, true, cview.AlignCenter, tcell.ColorDarkMagenta.TrueColor()) + frame := cview.NewFrame(cview.NewBox()) + frame.SetBorders(0, 0, 0, 0, 0, 0) + frame.AddText(subtitle, true, cview.AlignCenter, tcell.ColorWhite.TrueColor()) + frame.AddText("", true, cview.AlignCenter, tcell.ColorWhite.TrueColor()) + frame.AddText(mouse, true, cview.AlignCenter, tcell.ColorDarkMagenta.TrueColor()) + frame.AddText(navigation, true, cview.AlignCenter, tcell.ColorDarkMagenta.TrueColor()) // Create a Flex layout that centers the logo and subtitle. - flex := cview.NewFlex(). - SetDirection(cview.FlexRow). - AddItem(cview.NewBox(), 0, 7, false). - AddItem(cview.NewFlex(). - AddItem(cview.NewBox(), 0, 1, false). - AddItem(logoBox, logoWidth, 1, true). - AddItem(cview.NewBox(), 0, 1, false), logoHeight, 1, true). - AddItem(frame, 0, 10, false) + subFlex := cview.NewFlex() + subFlex.AddItem(cview.NewBox(), 0, 1, false) + subFlex.AddItem(logoBox, logoWidth, 1, true) + subFlex.AddItem(cview.NewBox(), 0, 1, false) + + flex := cview.NewFlex() + flex.SetDirection(cview.FlexRow) + flex.AddItem(cview.NewBox(), 0, 7, false) + flex.AddItem(subFlex, logoHeight, 1, true) + flex.AddItem(frame, 0, 10, false) return "Start", flex } diff --git a/demos/presentation/end.go b/demos/presentation/end.go index d17c2da..b5c537b 100644 --- a/demos/presentation/end.go +++ b/demos/presentation/end.go @@ -9,7 +9,8 @@ import ( // End shows the final slide. func End(nextSlide func()) (title string, content cview.Primitive) { - textView := cview.NewTextView().SetDoneFunc(func(key tcell.Key) { + textView := cview.NewTextView() + textView.SetDoneFunc(func(key tcell.Key) { nextSlide() }) url := "https://gitlab.com/tslocum/cview" diff --git a/demos/presentation/flex.go b/demos/presentation/flex.go index ac5f90e..e4d8add 100644 --- a/demos/presentation/flex.go +++ b/demos/presentation/flex.go @@ -5,35 +5,50 @@ import ( "gitlab.com/tslocum/cview" ) +func demoBox(title string) *cview.Box { + b := cview.NewBox() + b.SetBorder(true) + b.SetTitle(title) + return b +} + // Flex demonstrates flexbox layout. func Flex(nextSlide func()) (title string, content cview.Primitive) { modalShown := false pages := cview.NewPages() - textView := cview.NewTextView(). - SetDoneFunc(func(key tcell.Key) { - if modalShown { - nextSlide() - modalShown = false - } else { - pages.ShowPage("modal") - modalShown = true - } - }) - textView.SetBorder(true).SetTitle("Flexible width, twice of middle column") - flex := cview.NewFlex(). - AddItem(textView, 0, 2, true). - AddItem(cview.NewFlex(). - SetDirection(cview.FlexRow). - AddItem(cview.NewBox().SetBorder(true).SetTitle("Flexible width"), 0, 1, false). - AddItem(cview.NewBox().SetBorder(true).SetTitle("Fixed height"), 15, 1, false). - AddItem(cview.NewBox().SetBorder(true).SetTitle("Flexible height"), 0, 1, false), 0, 1, false). - AddItem(cview.NewBox().SetBorder(true).SetTitle("Fixed width"), 30, 1, false) - modal := cview.NewModal(). - SetText("Resize the window to see the effect of the flexbox parameters"). - AddButtons([]string{"Ok"}).SetDoneFunc(func(buttonIndex int, buttonLabel string) { + + textView := cview.NewTextView() + textView.SetBorder(true) + textView.SetTitle("Flexible width, twice of middle column") + textView.SetDoneFunc(func(key tcell.Key) { + if modalShown { + nextSlide() + modalShown = false + } else { + pages.ShowPage("modal") + modalShown = true + } + }) + + subFlex := cview.NewFlex() + subFlex.SetDirection(cview.FlexRow) + subFlex.AddItem(demoBox("Flexible width"), 0, 1, false) + subFlex.AddItem(demoBox("Fixed height"), 15, 1, false) + subFlex.AddItem(demoBox("Flexible height"), 0, 1, false) + + flex := cview.NewFlex() + flex.AddItem(textView, 0, 2, true) + flex.AddItem(subFlex, 0, 1, false) + flex.AddItem(demoBox("Fixed width"), 30, 1, false) + + modal := cview.NewModal() + modal.SetText("Resize the window to see the effect of the flexbox parameters") + modal.AddButtons([]string{"Ok"}) + modal.SetDoneFunc(func(buttonIndex int, buttonLabel string) { pages.HidePage("modal") }) - pages.AddPage("flex", flex, true, true). - AddPage("modal", modal, false, false) + + pages.AddPage("flex", flex, true, true) + pages.AddPage("modal", modal, false, false) return "Flex", pages } diff --git a/demos/presentation/form.go b/demos/presentation/form.go index bd6281c..81a68e2 100644 --- a/demos/presentation/form.go +++ b/demos/presentation/form.go @@ -30,14 +30,15 @@ const form = `[green]package[white] main // Form demonstrates forms. func Form(nextSlide func()) (title string, content cview.Primitive) { - f := cview.NewForm(). - AddInputField("First name:", "", 20, nil, nil). - AddInputField("Last name:", "", 20, nil, nil). - AddDropDownSimple("Role:", 0, nil, "Engineer", "Manager", "Administration"). - AddPasswordField("Password:", "", 10, '*', nil). - AddCheckBox("", "On vacation", false, nil). - AddButton("Save", nextSlide). - AddButton("Cancel", nextSlide) - f.SetBorder(true).SetTitle("Employee Information") + f := cview.NewForm() + f.AddInputField("First name:", "", 20, nil, nil) + f.AddInputField("Last name:", "", 20, nil, nil) + f.AddDropDownSimple("Role:", 0, nil, "Engineer", "Manager", "Administration") + f.AddPasswordField("Password:", "", 10, '*', nil) + f.AddCheckBox("", "On vacation", false, nil) + f.AddButton("Save", nextSlide) + f.AddButton("Cancel", nextSlide) + f.SetBorder(true) + f.SetTitle("Employee Information") return "Forms", Code(f, 36, 15, form) } diff --git a/demos/presentation/grid.go b/demos/presentation/grid.go index 006fa72..636e6ed 100644 --- a/demos/presentation/grid.go +++ b/demos/presentation/grid.go @@ -11,49 +11,51 @@ func Grid(nextSlide func()) (title string, content cview.Primitive) { pages := cview.NewPages() newPrimitive := func(text string) cview.Primitive { - return cview.NewTextView(). - SetTextAlign(cview.AlignCenter). - SetText(text). - SetDoneFunc(func(key tcell.Key) { - if modalShown { - nextSlide() - modalShown = false - } else { - pages.ShowPage("modal") - modalShown = true - } - }) + tv := cview.NewTextView() + tv.SetTextAlign(cview.AlignCenter) + tv.SetText(text) + tv.SetDoneFunc(func(key tcell.Key) { + if modalShown { + nextSlide() + modalShown = false + } else { + pages.ShowPage("modal") + modalShown = true + } + }) + return tv } menu := newPrimitive("Menu") main := newPrimitive("Main content") sideBar := newPrimitive("Side Bar") - grid := cview.NewGrid(). - SetRows(3, 0, 3). - SetColumns(0, -4, 0). - SetBorders(true). - AddItem(newPrimitive("Header"), 0, 0, 1, 3, 0, 0, true). - AddItem(newPrimitive("Footer"), 2, 0, 1, 3, 0, 0, false) + grid := cview.NewGrid() + grid.SetRows(3, 0, 3) + grid.SetColumns(0, -4, 0) + grid.SetBorders(true) + grid.AddItem(newPrimitive("Header"), 0, 0, 1, 3, 0, 0, true) + grid.AddItem(newPrimitive("Footer"), 2, 0, 1, 3, 0, 0, false) // Layout for screens narrower than 100 cells (menu and side bar are hidden). - grid.AddItem(menu, 0, 0, 0, 0, 0, 0, false). - AddItem(main, 1, 0, 1, 3, 0, 0, false). - AddItem(sideBar, 0, 0, 0, 0, 0, 0, false) + grid.AddItem(menu, 0, 0, 0, 0, 0, 0, false) + grid.AddItem(main, 1, 0, 1, 3, 0, 0, false) + grid.AddItem(sideBar, 0, 0, 0, 0, 0, 0, false) // Layout for screens wider than 100 cells. - grid.AddItem(menu, 1, 0, 1, 1, 0, 100, false). - AddItem(main, 1, 1, 1, 1, 0, 100, false). - AddItem(sideBar, 1, 2, 1, 1, 0, 100, false) + grid.AddItem(menu, 1, 0, 1, 1, 0, 100, false) + grid.AddItem(main, 1, 1, 1, 1, 0, 100, false) + grid.AddItem(sideBar, 1, 2, 1, 1, 0, 100, false) - modal := cview.NewModal(). - SetText("Resize the window to see how the grid layout adapts"). - AddButtons([]string{"Ok"}).SetDoneFunc(func(buttonIndex int, buttonLabel string) { + modal := cview.NewModal() + modal.SetText("Resize the window to see how the grid layout adapts") + modal.AddButtons([]string{"Ok"}) + modal.SetDoneFunc(func(buttonIndex int, buttonLabel string) { pages.HidePage("modal") }) - pages.AddPage("grid", grid, true, true). - AddPage("modal", modal, false, false) + pages.AddPage("grid", grid, true, true) + pages.AddPage("modal", modal, false, false) return "Grid", pages } diff --git a/demos/presentation/inputfield.go b/demos/presentation/inputfield.go index 2851d68..b4bd405 100644 --- a/demos/presentation/inputfield.go +++ b/demos/presentation/inputfield.go @@ -31,9 +31,10 @@ const inputField = `[green]package[white] main // InputField demonstrates the InputField. func InputField(nextSlide func()) (title string, content cview.Primitive) { - input := cview.NewInputField(). - SetLabel("Enter a number: "). - SetAcceptanceFunc(cview.InputFieldInteger).SetDoneFunc(func(key tcell.Key) { + input := cview.NewInputField() + input.SetLabel("Enter a number: ") + input.SetAcceptanceFunc(cview.InputFieldInteger) + input.SetDoneFunc(func(key tcell.Key) { nextSlide() }) return "Input", Code(input, 30, 1, inputField) diff --git a/demos/presentation/introduction.go b/demos/presentation/introduction.go index 63a53a8..3cf799d 100644 --- a/demos/presentation/introduction.go +++ b/demos/presentation/introduction.go @@ -6,15 +6,25 @@ import "gitlab.com/tslocum/cview" func Introduction(nextSlide func()) (title string, content cview.Primitive) { list := cview.NewList() + listText := [][]string{ + {"A Go package for terminal based UIs", "with a special focus on rich interactive widgets"}, + {"Based on github.com/gdamore/tcell", "Like termbox but better (see tcell docs)"}, + {"Designed to be simple", `"Hello world" is 5 lines of code`}, + {"Good for data entry", `For charts, use "termui" - for low-level views, use "gocui" - ...`}, + {"Supports context menus", "Right click on one of these items or press Alt+Enter"}, + {"Extensive documentation", "Demo code is available for each widget"}, + } + reset := func() { - list. - Clear(). - AddItem(cview.NewListItem("A Go package for terminal based UIs").SetSecondaryText("with a special focus on rich interactive widgets").SetShortcut('1').SetSelectedFunc(nextSlide)). - AddItem(cview.NewListItem("Based on github.com/gdamore/tcell").SetSecondaryText("Like termbox but better (see tcell docs)").SetShortcut('2').SetSelectedFunc(nextSlide)). - AddItem(cview.NewListItem("Designed to be simple").SetSecondaryText(`"Hello world" is 5 lines of code`).SetShortcut('3').SetSelectedFunc(nextSlide)). - AddItem(cview.NewListItem("Good for data entry").SetSecondaryText(`For charts, use "termui" - for low-level views, use "gocui" - ...`).SetShortcut('4').SetSelectedFunc(nextSlide)). - AddItem(cview.NewListItem("Supports context menus").SetSecondaryText("Right click on one of these items or press Alt+Enter").SetShortcut('5').SetSelectedFunc(nextSlide)). - AddItem(cview.NewListItem("Extensive documentation").SetSecondaryText("Demo code is available for each widget").SetShortcut('6').SetSelectedFunc(nextSlide)) + list.Clear() + + for i, itemText := range listText { + item := cview.NewListItem(itemText[0]) + item.SetSecondaryText(itemText[1]) + item.SetShortcut(rune('1' + i)) + item.SetSelectedFunc(nextSlide) + list.AddItem(item) + } list.ContextMenuList().SetItemEnabled(3, false) } diff --git a/demos/presentation/main.go b/demos/presentation/main.go index 16677a1..73f5558 100644 --- a/demos/presentation/main.go +++ b/demos/presentation/main.go @@ -44,6 +44,8 @@ func main() { }() } + app.EnableMouse(true) + // The presentation slides. slides := []Slide{ Cover, @@ -66,25 +68,25 @@ func main() { // The bottom row has some info on where we are. info := cview.NewTextView() info. - SetDynamicColors(true). - SetRegions(true). - SetWrap(false). - SetHighlightedFunc(func(added, removed, remaining []string) { - pages.SwitchToPage(added[0]) - }) + SetDynamicColors(true) + info.SetRegions(true) + info.SetWrap(false) + info.SetHighlightedFunc(func(added, removed, remaining []string) { + pages.SwitchToPage(added[0]) + }) // Create the pages for all slides. previousSlide := func() { slide, _ := strconv.Atoi(info.GetHighlights()[0]) slide = (slide - 1 + len(slides)) % len(slides) - info.Highlight(strconv.Itoa(slide)). - ScrollToHighlight() + info.Highlight(strconv.Itoa(slide)) + info.ScrollToHighlight() } nextSlide := func() { slide, _ := strconv.Atoi(info.GetHighlights()[0]) slide = (slide + 1) % len(slides) - info.Highlight(strconv.Itoa(slide)). - ScrollToHighlight() + info.Highlight(strconv.Itoa(slide)) + info.ScrollToHighlight() } cursor := 0 @@ -101,10 +103,10 @@ func main() { info.Highlight("0") // Create the main layout. - layout := cview.NewFlex(). - SetDirection(cview.FlexRow). - AddItem(pages, 0, 1, true). - AddItem(info, 1, 1, false) + layout := cview.NewFlex() + layout.SetDirection(cview.FlexRow) + layout.AddItem(pages, 0, 1, true) + layout.AddItem(info, 1, 1, false) // Shortcuts to navigate the slides. app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { @@ -117,7 +119,8 @@ func main() { }) // Start the application. - if err := app.SetRoot(layout, true).EnableMouse(true).Run(); err != nil { + app.SetRoot(layout, true) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/presentation/table.go b/demos/presentation/table.go index 91fb99d..4f48bb6 100644 --- a/demos/presentation/table.go +++ b/demos/presentation/table.go @@ -249,8 +249,8 @@ const tableSelectCell = `[green]func[white] [yellow]main[white]() { // Table demonstrates the Table. func Table(nextSlide func()) (title string, content cview.Primitive) { - table := cview.NewTable(). - SetFixed(1, 1) + table := cview.NewTable() + table.SetFixed(1, 1) for row, line := range strings.Split(tableData, "\n") { for column, cell := range strings.Split(line, "|") { color := tcell.ColorWhite.TrueColor() @@ -265,68 +265,69 @@ func Table(nextSlide func()) (title string, content cview.Primitive) { } else if column == 0 || column >= 4 { align = cview.AlignRight } - tableCell := cview.NewTableCell(cell). - SetTextColor(color). - SetAlign(align). - SetSelectable(row != 0 && column != 0) + tableCell := cview.NewTableCell(cell) + tableCell.SetTextColor(color) + tableCell.SetAlign(align) + tableCell.SetSelectable(row != 0 && column != 0) if column >= 1 && column <= 3 { tableCell.SetExpansion(1) } table.SetCell(row, column, tableCell) } } - table.SetBorder(true).SetTitle("Table") + table.SetBorder(true) + table.SetTitle("Table") - code := cview.NewTextView(). - SetWrap(false). - SetDynamicColors(true) + code := cview.NewTextView() + code.SetWrap(false) + code.SetDynamicColors(true) code.SetBorderPadding(1, 1, 2, 0) list := cview.NewList() basic := func() { - table.SetBorders(false). - SetSelectable(false, false). - SetSeparator(' ') + table.SetBorders(false) + table.SetSelectable(false, false) + table.SetSeparator(' ') code.Clear() fmt.Fprint(code, tableBasic) } separator := func() { - table.SetBorders(false). - SetSelectable(false, false). - SetSeparator(cview.Borders.Vertical) + table.SetBorders(false) + table.SetSelectable(false, false) + table.SetSeparator(cview.Borders.Vertical) code.Clear() fmt.Fprint(code, tableSeparator) } borders := func() { - table.SetBorders(true). - SetSelectable(false, false) + table.SetBorders(true) + table.SetSelectable(false, false) code.Clear() fmt.Fprint(code, tableBorders) } selectRow := func() { - table.SetBorders(false). - SetSelectable(true, false). - SetSeparator(' ') + table.SetBorders(false) + table.SetSelectable(true, false) + table.SetSeparator(' ') code.Clear() fmt.Fprint(code, tableSelectRow) } selectColumn := func() { - table.SetBorders(false). - SetSelectable(false, true). - SetSeparator(' ') + table.SetBorders(false) + table.SetSelectable(false, true) + table.SetSeparator(' ') code.Clear() fmt.Fprint(code, tableSelectColumn) } selectCell := func() { - table.SetBorders(false). - SetSelectable(true, true). - SetSeparator(' ') + table.SetBorders(false) + table.SetSelectable(true, true) + table.SetSeparator(' ') code.Clear() fmt.Fprint(code, tableSelectCell) } @@ -335,28 +336,47 @@ func Table(nextSlide func()) (title string, content cview.Primitive) { app.SetFocus(table) table.SetDoneFunc(func(key tcell.Key) { app.SetFocus(list) - }).SetSelectedFunc(func(row int, column int) { + }) + table.SetSelectedFunc(func(row int, column int) { app.SetFocus(list) }) } - list.ShowSecondaryText(false). - AddItem(cview.NewListItem("Basic table").SetShortcut('b').SetSelectedFunc(basic)). - AddItem(cview.NewListItem("Table with separator").SetShortcut('s').SetSelectedFunc(separator)). - AddItem(cview.NewListItem("Table with borders").SetShortcut('o').SetSelectedFunc(borders)). - AddItem(cview.NewListItem("Selectable rows").SetShortcut('r').SetSelectedFunc(selectRow)). - AddItem(cview.NewListItem("Selectable columns").SetShortcut('c').SetSelectedFunc(selectColumn)). - AddItem(cview.NewListItem("Selectable cells").SetShortcut('l').SetSelectedFunc(selectCell)). - AddItem(cview.NewListItem("Navigate").SetShortcut('n').SetSelectedFunc(navigate)). - AddItem(cview.NewListItem("Next slide").SetShortcut('x').SetSelectedFunc(nextSlide)) + list.ShowSecondaryText(false) list.SetBorderPadding(1, 1, 2, 2) + var demoTableText = []struct { + text string + shortcut rune + selected func() + }{ + {"Basic table", 'b', basic}, + {"Table with separator", 's', separator}, + {"Table with borders", 'o', borders}, + {"Selectable rows", 'r', selectRow}, + {"Selectable columns", 'c', selectColumn}, + {"Selectable cells", 'l', selectCell}, + {"Navigate", 'n', navigate}, + {"Next slide", 'x', nextSlide}, + } + + for _, tableText := range demoTableText { + item := cview.NewListItem(tableText.text) + item.SetShortcut(tableText.shortcut) + item.SetSelectedFunc(tableText.selected) + list.AddItem(item) + } + basic() - return "Table", cview.NewFlex(). - AddItem(cview.NewFlex(). - SetDirection(cview.FlexRow). - AddItem(list, 10, 1, true). - AddItem(table, 0, 1, false), 0, 1, true). - AddItem(code, codeWidth, 1, false) + subFlex := cview.NewFlex() + subFlex.SetDirection(cview.FlexRow) + subFlex.AddItem(list, 10, 1, true) + subFlex.AddItem(table, 0, 1, false) + + flex := cview.NewFlex() + flex.AddItem(subFlex, 0, 1, true) + flex.AddItem(code, codeWidth, 1, false) + + return "Table", flex } diff --git a/demos/presentation/textview.go b/demos/presentation/textview.go index 16eab95..5a1a189 100644 --- a/demos/presentation/textview.go +++ b/demos/presentation/textview.go @@ -31,12 +31,12 @@ const textView1 = `[green]func[white] [yellow]main[white]() { // TextView1 demonstrates the basic text view. func TextView1(nextSlide func()) (title string, content cview.Primitive) { - textView := cview.NewTextView(). - SetTextColor(tcell.ColorYellow.TrueColor()). - SetScrollable(false). - SetDoneFunc(func(key tcell.Key) { - nextSlide() - }) + textView := cview.NewTextView() + textView.SetTextColor(tcell.ColorYellow.TrueColor()) + textView.SetScrollable(false) + textView.SetDoneFunc(func(key tcell.Key) { + nextSlide() + }) textView.SetChangedFunc(func() { if textView.HasFocus() { app.Draw() @@ -55,7 +55,8 @@ func TextView1(nextSlide func()) (title string, content cview.Primitive) { time.Sleep(200 * time.Millisecond) } }() - textView.SetBorder(true).SetTitle("TextView implements io.Writer") + textView.SetBorder(true) + textView.SetTitle("TextView implements io.Writer") return "Text 1", Code(textView, 36, 13, textView1) } @@ -108,49 +109,54 @@ const textView2 = `[green]package[white] main // TextView2 demonstrates the extended text view. func TextView2(nextSlide func()) (title string, content cview.Primitive) { - codeView := cview.NewTextView(). - SetWrap(false) + codeView := cview.NewTextView() + codeView.SetWrap(false) fmt.Fprint(codeView, textView2) - codeView.SetBorder(true).SetTitle("Buffer content") + codeView.SetBorder(true) + codeView.SetTitle("Buffer content") textView := cview.NewTextView() - textView.SetDynamicColors(true). - SetWrap(false). - SetRegions(true). - SetDoneFunc(func(key tcell.Key) { - if key == tcell.KeyEscape { - nextSlide() - return + textView.SetDynamicColors(true) + textView.SetWrap(false) + textView.SetRegions(true) + textView.SetDoneFunc(func(key tcell.Key) { + if key == tcell.KeyEscape { + nextSlide() + return + } + highlights := textView.GetHighlights() + hasHighlights := len(highlights) > 0 + switch key { + case tcell.KeyEnter: + if hasHighlights { + textView.Highlight() + } else { + textView.Highlight("0") + textView.ScrollToHighlight() } - highlights := textView.GetHighlights() - hasHighlights := len(highlights) > 0 - switch key { - case tcell.KeyEnter: - if hasHighlights { - textView.Highlight() - } else { - textView.Highlight("0"). - ScrollToHighlight() - } - case tcell.KeyTab: - if hasHighlights { - current, _ := strconv.Atoi(highlights[0]) - next := (current + 1) % 9 - textView.Highlight(strconv.Itoa(next)). - ScrollToHighlight() - } - case tcell.KeyBacktab: - if hasHighlights { - current, _ := strconv.Atoi(highlights[0]) - next := (current - 1 + 9) % 9 - textView.Highlight(strconv.Itoa(next)). - ScrollToHighlight() - } + case tcell.KeyTab: + if hasHighlights { + current, _ := strconv.Atoi(highlights[0]) + next := (current + 1) % 9 + textView.Highlight(strconv.Itoa(next)) + textView.ScrollToHighlight() } - }) + case tcell.KeyBacktab: + if hasHighlights { + current, _ := strconv.Atoi(highlights[0]) + next := (current - 1 + 9) % 9 + textView.Highlight(strconv.Itoa(next)) + textView.ScrollToHighlight() + } + } + }) fmt.Fprint(textView, textView2) - textView.SetBorder(true).SetTitle("TextView output") - return "Text 2", cview.NewFlex(). - AddItem(textView, 0, 1, true). - AddItem(codeView, 0, 1, false) + textView.SetBorder(true) + textView.SetTitle("TextView output") + + flex := cview.NewFlex() + flex.AddItem(textView, 0, 1, true) + flex.AddItem(codeView, 0, 1, false) + + return "Text 2", flex } diff --git a/demos/presentation/treeview.go b/demos/presentation/treeview.go index a1033d0..c998d89 100644 --- a/demos/presentation/treeview.go +++ b/demos/presentation/treeview.go @@ -58,7 +58,7 @@ type node struct { var ( tree = cview.NewTreeView() treeNextSlide func() - treeCode = cview.NewTextView().SetWrap(false).SetDynamicColors(true) + treeCode = cview.NewTextView() ) var rootNode = &node{ @@ -74,7 +74,10 @@ var rootNode = &node{ {text: "Tree list starts one level down"}, {text: "Works better for lists where no top node is needed"}, {text: "Switch to this layout", selected: func() { - tree.SetAlign(false).SetTopLevel(1).SetGraphics(true).SetPrefixes(nil) + tree.SetAlign(false) + tree.SetTopLevel(1) + tree.SetGraphics(true) + tree.SetPrefixes(nil) treeCode.SetText(strings.Replace(treeAllCode, "$$$", treeTopLevelCode, -1)) }}, }}, @@ -82,7 +85,10 @@ var rootNode = &node{ {text: "For trees that are similar to lists"}, {text: "Hierarchy shown only in line drawings"}, {text: "Switch to this layout", selected: func() { - tree.SetAlign(true).SetTopLevel(0).SetGraphics(true).SetPrefixes(nil) + tree.SetAlign(true) + tree.SetTopLevel(0) + tree.SetGraphics(true) + tree.SetPrefixes(nil) treeCode.SetText(strings.Replace(treeAllCode, "$$$", treeAlignCode, -1)) }}, }}, @@ -90,7 +96,10 @@ var rootNode = &node{ {text: "Best for hierarchical bullet point lists"}, {text: "You can define your own prefixes per level"}, {text: "Switch to this layout", selected: func() { - tree.SetAlign(false).SetTopLevel(1).SetGraphics(false).SetPrefixes([]string{"[red]* ", "[darkcyan]- ", "[darkmagenta]- "}) + tree.SetAlign(false) + tree.SetTopLevel(1) + tree.SetGraphics(false) + tree.SetPrefixes([]string{"[red]* ", "[darkcyan]- ", "[darkmagenta]- "}) treeCode.SetText(strings.Replace(treeAllCode, "$$$", treePrefixCode, -1)) }}, }}, @@ -98,7 +107,10 @@ var rootNode = &node{ {text: "Lines illustrate hierarchy"}, {text: "Basic indentation"}, {text: "Switch to this layout", selected: func() { - tree.SetAlign(false).SetTopLevel(0).SetGraphics(true).SetPrefixes(nil) + tree.SetAlign(false) + tree.SetTopLevel(0) + tree.SetGraphics(true) + tree.SetPrefixes(nil) treeCode.SetText(strings.Replace(treeAllCode, "$$$", treeBasicCode, -1)) }}, }}, @@ -108,16 +120,16 @@ var rootNode = &node{ // TreeView demonstrates the tree view. func TreeView(nextSlide func()) (title string, content cview.Primitive) { treeNextSlide = nextSlide - tree.SetBorder(true). - SetTitle("TreeView") + tree.SetBorder(true) + tree.SetTitle("TreeView") // Add nodes. var add func(target *node) *cview.TreeNode add = func(target *node) *cview.TreeNode { - node := cview.NewTreeNode(target.text). - SetSelectable(target.expand || target.selected != nil). - SetExpanded(target == rootNode). - SetReference(target) + node := cview.NewTreeNode(target.text) + node.SetSelectable(target.expand || target.selected != nil) + node.SetExpanded(target == rootNode) + node.SetReference(target) if target.expand { node.SetColor(tcell.ColorGreen.TrueColor()) } else if target.selected != nil { @@ -129,21 +141,25 @@ func TreeView(nextSlide func()) (title string, content cview.Primitive) { return node } root := add(rootNode) - tree.SetRoot(root). - SetCurrentNode(root). - SetSelectedFunc(func(n *cview.TreeNode) { - original := n.GetReference().(*node) - if original.expand { - n.SetExpanded(!n.IsExpanded()) - } else if original.selected != nil { - original.selected() - } - }) + tree.SetRoot(root) + tree.SetCurrentNode(root) + tree.SetSelectedFunc(func(n *cview.TreeNode) { + original := n.GetReference().(*node) + if original.expand { + n.SetExpanded(!n.IsExpanded()) + } else if original.selected != nil { + original.selected() + } + }) - treeCode.SetText(strings.Replace(treeAllCode, "$$$", treeBasicCode, -1)). - SetBorderPadding(1, 1, 2, 0) + treeCode.SetWrap(false) + treeCode.SetDynamicColors(true) + treeCode.SetText(strings.Replace(treeAllCode, "$$$", treeBasicCode, -1)) + treeCode.SetBorderPadding(1, 1, 2, 0) - return "Tree", cview.NewFlex(). - AddItem(tree, 0, 1, true). - AddItem(treeCode, codeWidth, 1, false) + flex := cview.NewFlex() + flex.AddItem(tree, 0, 1, true) + flex.AddItem(treeCode, codeWidth, 1, false) + + return "Tree", flex } diff --git a/demos/presentation/window.go b/demos/presentation/window.go index 8ebbe4f..d8d1ed5 100644 --- a/demos/presentation/window.go +++ b/demos/presentation/window.go @@ -10,25 +10,26 @@ const loremIpsumText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, func Window(nextSlide func()) (title string, content cview.Primitive) { wm := cview.NewWindowManager() - list := cview.NewList(). - AddItem(cview.NewListItem("Item #1")). - AddItem(cview.NewListItem("Item #2")). - AddItem(cview.NewListItem("Item #3")). - AddItem(cview.NewListItem("Item #4")). - AddItem(cview.NewListItem("Item #5")). - AddItem(cview.NewListItem("Item #6")). - AddItem(cview.NewListItem("Item #7")). - ShowSecondaryText(false) + list := cview.NewList() + list.ShowSecondaryText(false) + list.AddItem(cview.NewListItem("Item #1")) + list.AddItem(cview.NewListItem("Item #2")) + list.AddItem(cview.NewListItem("Item #3")) + list.AddItem(cview.NewListItem("Item #4")) + list.AddItem(cview.NewListItem("Item #5")) + list.AddItem(cview.NewListItem("Item #6")) + list.AddItem(cview.NewListItem("Item #7")) - loremIpsum := cview.NewTextView().SetText(loremIpsumText) + loremIpsum := cview.NewTextView() + loremIpsum.SetText(loremIpsumText) - w1 := cview.NewWindow(list). - SetPosition(2, 2). - SetSize(10, 7) + w1 := cview.NewWindow(list) + w1.SetPosition(2, 2) + w1.SetSize(10, 7) - w2 := cview.NewWindow(loremIpsum). - SetPosition(7, 4). - SetSize(12, 12) + w2 := cview.NewWindow(loremIpsum) + w2.SetPosition(7, 4) + w2.SetSize(12, 12) w1.SetTitle("List") w2.SetTitle("Lorem Ipsum") diff --git a/demos/primitive/main.go b/demos/primitive/main.go index 56034da..be315af 100644 --- a/demos/primitive/main.go +++ b/demos/primitive/main.go @@ -60,11 +60,15 @@ func (r *RadioButtons) InputHandler() func(event *tcell.EventKey, setFocus func( } func main() { + app := cview.NewApplication() + radioButtons := NewRadioButtons([]string{"Lions", "Elephants", "Giraffes"}) - radioButtons.SetBorder(true). - SetTitle("Radio Button Demo"). - SetRect(0, 0, 30, 5) - if err := cview.NewApplication().SetRoot(radioButtons, false).Run(); err != nil { + radioButtons.SetBorder(true) + radioButtons.SetTitle("Radio Button Demo") + radioButtons.SetRect(0, 0, 30, 5) + + app.SetRoot(radioButtons, false) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/progressbar/main.go b/demos/progressbar/main.go index ef8cc9b..3c13169 100644 --- a/demos/progressbar/main.go +++ b/demos/progressbar/main.go @@ -10,7 +10,9 @@ import ( func main() { app := cview.NewApplication() - grid := cview.NewGrid().SetColumns(-1, 6, 4, 30, -1).SetRows(-1, 12, 4, 4, -1) + grid := cview.NewGrid() + grid.SetColumns(-1, 6, 4, 30, -1) + grid.SetRows(-1, 12, 4, 4, -1) grid.SetBackgroundColor(cview.Styles.PrimitiveBackgroundColor) verticalProgressBar := cview.NewProgressBar() @@ -51,7 +53,8 @@ func main() { } }() - if err := app.SetRoot(grid, true).Run(); err != nil { + app.SetRoot(grid, true) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/table/main.go b/demos/table/main.go index da23b90..2ab3575 100644 --- a/demos/table/main.go +++ b/demos/table/main.go @@ -12,8 +12,10 @@ const loremIpsumText = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, func main() { app := cview.NewApplication() - table := cview.NewTable(). - SetBorders(true) + app.EnableMouse(true) + + table := cview.NewTable() + table.SetBorders(true) lorem := strings.Split(loremIpsumText, " ") cols, rows := 10, 40 word := 0 @@ -23,25 +25,30 @@ func main() { if c < 1 || r < 1 { color = tcell.ColorYellow.TrueColor() } - table.SetCell(r, c, - cview.NewTableCell(lorem[word]). - SetTextColor(color). - SetAlign(cview.AlignCenter)) + cell := cview.NewTableCell(lorem[word]) + cell.SetTextColor(color) + cell.SetAlign(cview.AlignCenter) + table.SetCell(r, c, cell) word = (word + 1) % len(lorem) } } - table.Select(0, 0).SetFixed(1, 1).SetDoneFunc(func(key tcell.Key) { + table.Select(0, 0) + table.SetFixed(1, 1) + table.SetDoneFunc(func(key tcell.Key) { if key == tcell.KeyEscape { app.Stop() } if key == tcell.KeyEnter { table.SetSelectable(true, true) } - }).SetSelectedFunc(func(row int, column int) { + }) + table.SetSelectedFunc(func(row int, column int) { table.GetCell(row, column).SetTextColor(tcell.ColorRed.TrueColor()) table.SetSelectable(false, false) }) - if err := app.SetRoot(table, true).EnableMouse(true).Run(); err != nil { + + app.SetRoot(table, true) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/textview/main.go b/demos/textview/main.go index de0e316..3e5e60d 100644 --- a/demos/textview/main.go +++ b/demos/textview/main.go @@ -21,13 +21,15 @@ Capitalize on low hanging fruit to identify a ballpark value added activity to b func main() { app := cview.NewApplication() - textView := cview.NewTextView(). - SetDynamicColors(true). - SetRegions(true). - SetWordWrap(true). - SetChangedFunc(func() { - app.Draw() - }) + app.EnableMouse(true) + + textView := cview.NewTextView() + textView.SetDynamicColors(true) + textView.SetRegions(true) + textView.SetWordWrap(true) + textView.SetChangedFunc(func() { + app.Draw() + }) numSelections := 0 go func() { for _, word := range strings.Split(corporate, " ") { @@ -48,7 +50,8 @@ func main() { if len(currentSelection) > 0 { textView.Highlight() } else { - textView.Highlight("0").ScrollToHighlight() + textView.Highlight("0") + textView.ScrollToHighlight() } } else if len(currentSelection) > 0 { index, _ := strconv.Atoi(currentSelection[0]) @@ -59,11 +62,14 @@ func main() { } else { return } - textView.Highlight(strconv.Itoa(index)).ScrollToHighlight() + textView.Highlight(strconv.Itoa(index)) + textView.ScrollToHighlight() } }) textView.SetBorder(true) - if err := app.SetRoot(textView, true).EnableMouse(true).Run(); err != nil { + + app.SetRoot(textView, true) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/treeview/main.go b/demos/treeview/main.go index 2ec5da2..628d0a6 100644 --- a/demos/treeview/main.go +++ b/demos/treeview/main.go @@ -11,12 +11,15 @@ import ( // Show a navigable tree view of the current directory. func main() { + app := cview.NewApplication() + app.EnableMouse(true) + rootDir := "." - root := cview.NewTreeNode(rootDir). - SetColor(tcell.ColorRed.TrueColor()) - tree := cview.NewTreeView(). - SetRoot(root). - SetCurrentNode(root) + root := cview.NewTreeNode(rootDir) + root.SetColor(tcell.ColorRed.TrueColor()) + tree := cview.NewTreeView() + tree.SetRoot(root) + tree.SetCurrentNode(root) // A helper function which adds the files and directories of the given path // to the given target node. @@ -26,9 +29,9 @@ func main() { panic(err) } for _, file := range files { - node := cview.NewTreeNode(file.Name()). - SetReference(filepath.Join(path, file.Name())). - SetSelectable(file.IsDir()) + node := cview.NewTreeNode(file.Name()) + node.SetReference(filepath.Join(path, file.Name())) + node.SetSelectable(file.IsDir()) if file.IsDir() { node.SetColor(tcell.ColorGreen.TrueColor()) } @@ -56,7 +59,8 @@ func main() { } }) - if err := cview.NewApplication().SetRoot(tree, true).EnableMouse(true).Run(); err != nil { + app.SetRoot(tree, true) + if err := app.Run(); err != nil { panic(err) } } diff --git a/demos/unicode/main.go b/demos/unicode/main.go index c682859..fe37937 100644 --- a/demos/unicode/main.go +++ b/demos/unicode/main.go @@ -12,38 +12,39 @@ func main() { pages := cview.NewPages() form := cview.NewForm() - form.AddDropDownSimple("称谓", 0, nil, "先生", "女士", "博士", "老师", "师傅"). - AddInputField("姓名", "", 20, nil, nil). - AddPasswordField("密码", "", 10, '*', nil). - AddCheckBox("", "年龄 18+", false, nil). - AddButton("保存", func() { - _, option := form.GetFormItem(0).(*cview.DropDown).GetCurrentOption() - userName := form.GetFormItem(1).(*cview.InputField).GetText() + form.AddDropDownSimple("称谓", 0, nil, "先生", "女士", "博士", "老师", "师傅") + form.AddInputField("姓名", "", 20, nil, nil) + form.AddPasswordField("密码", "", 10, '*', nil) + form.AddCheckBox("", "年龄 18+", false, nil) + form.AddButton("保存", func() { + _, option := form.GetFormItem(0).(*cview.DropDown).GetCurrentOption() + userName := form.GetFormItem(1).(*cview.InputField).GetText() - alert(pages, "alert-dialog", fmt.Sprintf("保存成功,%s %s!", userName, option.GetText())) - }). - AddButton("退出", func() { - app.Stop() - }) - form.SetBorder(true).SetTitle("输入一些内容").SetTitleAlign(cview.AlignLeft) + alert(pages, "alert-dialog", fmt.Sprintf("保存成功,%s %s!", userName, option.GetText())) + }) + form.AddButton("退出", func() { + app.Stop() + }) + form.SetBorder(true) + form.SetTitle("输入一些内容") + form.SetTitleAlign(cview.AlignLeft) pages.AddPage("base", form, true, true) - if err := app.SetRoot(pages, true).Run(); err != nil { + app.SetRoot(pages, true) + if err := app.Run(); err != nil { panic(err) } } // alert shows a confirmation dialog. -func alert(pages *cview.Pages, id string, message string) *cview.Pages { - return pages.AddPage( - id, - cview.NewModal(). - SetText(message). - AddButtons([]string{"确定"}). - SetDoneFunc(func(buttonIndex int, buttonLabel string) { - pages.HidePage(id).RemovePage(id) - }), - false, - true, - ) +func alert(pages *cview.Pages, id string, message string) { + modal := cview.NewModal() + modal.SetText(message) + modal.AddButtons([]string{"确定"}) + modal.SetDoneFunc(func(buttonIndex int, buttonLabel string) { + pages.HidePage(id) + pages.RemovePage(id) + }) + + pages.AddPage(id, modal, false, true) } diff --git a/doc_test.go b/doc_test.go index 565810a..8b4f724 100644 --- a/doc_test.go +++ b/doc_test.go @@ -12,16 +12,24 @@ func ExampleNewApplication() { app := NewApplication() // Create shared TextView. - sharedTextView := NewTextView().SetText("Widgets may be re-used between multiple layouts.").SetTextAlign(AlignCenter) + sharedTextView := NewTextView() + sharedTextView.SetTextAlign(AlignCenter) + sharedTextView.SetText("Widgets may be re-used between multiple layouts.") // Create main layout using Grid. - mainTextView := NewTextView().SetText("This is mainLayout.\n\nPress to view aboutLayout.").SetTextAlign(AlignCenter) + mainTextView := NewTextView() + mainTextView.SetTextAlign(AlignCenter) + mainTextView.SetText("This is mainLayout.\n\nPress to view aboutLayout.") + mainLayout := NewGrid() mainLayout.AddItem(mainTextView, 0, 0, 1, 1, 0, 0, false) mainLayout.AddItem(sharedTextView, 1, 0, 1, 1, 0, 0, false) // Create about layout using Grid. - aboutTextView := NewTextView().SetText("cview muti-layout application example\n\nhttps://gitlab.com/tslocum/cview").SetTextAlign(AlignCenter) + aboutTextView := NewTextView() + aboutTextView.SetTextAlign(AlignCenter) + aboutTextView.SetText("cview muti-layout application example\n\nhttps://gitlab.com/tslocum/cview") + aboutLayout := NewGrid() aboutLayout.AddItem(aboutTextView, 0, 0, 1, 1, 0, 0, false) aboutLayout.AddItem(sharedTextView, 1, 0, 1, 1, 0, 0, false) @@ -53,7 +61,8 @@ func ExampleNewApplication() { }) // Run the application. - if err := app.SetRoot(mainLayout, true).Run(); err != nil { + app.SetRoot(mainLayout, true) + if err := app.Run(); err != nil { panic(err) } } @@ -70,7 +79,8 @@ func ExampleApplication_EnableMouse() { app.SetDoubleClickInterval(StandardDoubleClick) // Create a textview. - tv := NewTextView().SetText("Click somewhere!") + tv := NewTextView() + tv.SetText("Click somewhere!") // Set a mouse capture function which prints where the mouse was clicked. app.SetMouseCapture(func(event *tcell.EventMouse, action MouseAction) (*tcell.EventMouse, MouseAction) { @@ -93,7 +103,8 @@ func ExampleApplication_EnableMouse() { }) // Run the application. - if err := app.SetRoot(tv, true).Run(); err != nil { + app.SetRoot(tv, true) + if err := app.Run(); err != nil { panic(err) } } diff --git a/dropdown.go b/dropdown.go index 4ff2e14..b8a6192 100644 --- a/dropdown.go +++ b/dropdown.go @@ -31,15 +31,13 @@ func (d *DropDownOption) GetText() string { } // SetText returns the text of this dropdown option. -func (d *DropDownOption) SetText(text string) *DropDownOption { +func (d *DropDownOption) SetText(text string) { d.text = text - return d } // SetSelectedFunc sets the handler to be called when this option is selected. -func (d *DropDownOption) SetSelectedFunc(handler func(index int, option *DropDownOption)) *DropDownOption { +func (d *DropDownOption) SetSelectedFunc(handler func(index int, option *DropDownOption)) { d.selected = handler - return d } // GetReference returns the reference object of this dropdown option. @@ -51,9 +49,8 @@ func (d *DropDownOption) GetReference() interface{} { } // SetReference allows you to store a reference of any type in this option. -func (d *DropDownOption) SetReference(reference interface{}) *DropDownOption { +func (d *DropDownOption) SetReference(reference interface{}) { d.reference = reference - return d } // DropDown implements a selection widget whose options become visible in a @@ -146,12 +143,12 @@ type DropDown struct { // NewDropDown returns a new drop-down. func NewDropDown() *DropDown { list := NewList() - list.ShowSecondaryText(false). - SetMainTextColor(Styles.PrimitiveBackgroundColor). - SetSelectedTextColor(Styles.PrimitiveBackgroundColor). - SetSelectedBackgroundColor(Styles.PrimaryTextColor). - SetHighlightFullLine(true). - SetBackgroundColor(Styles.MoreContrastBackgroundColor) + list.ShowSecondaryText(false) + list.SetMainTextColor(Styles.PrimitiveBackgroundColor) + list.SetSelectedTextColor(Styles.PrimitiveBackgroundColor) + list.SetSelectedBackgroundColor(Styles.PrimaryTextColor) + list.SetHighlightFullLine(true) + list.SetBackgroundColor(Styles.MoreContrastBackgroundColor) d := &DropDown{ Box: NewBox(), @@ -175,17 +172,16 @@ func NewDropDown() *DropDown { // SetDropDownSymbolRune sets the rune to be drawn at the end of the dropdown field // to indicate that this field is a dropdown. -func (d *DropDown) SetDropDownSymbolRune(symbol rune) *DropDown { +func (d *DropDown) SetDropDownSymbolRune(symbol rune) { d.Lock() defer d.Unlock() d.dropDownSymbol = symbol - return d } // SetCurrentOption sets the index of the currently selected option. This may // be a negative value to indicate that no option is currently selected. Calling // this function will also trigger the "selected" callback (if there is one). -func (d *DropDown) SetCurrentOption(index int) *DropDown { +func (d *DropDown) SetCurrentOption(index int) { d.Lock() defer d.Unlock() @@ -211,7 +207,6 @@ func (d *DropDown) SetCurrentOption(index int) *DropDown { d.Lock() } } - return d } // GetCurrentOption returns the index of the currently selected option as well @@ -232,7 +227,7 @@ func (d *DropDown) GetCurrentOption() (int, *DropDownOption) { // selected option (currentPrefix/currentSuffix) as well as the text to be // displayed when no option is currently selected. Per default, all of these // strings are empty. -func (d *DropDown) SetTextOptions(prefix, suffix, currentPrefix, currentSuffix, noSelection string) *DropDown { +func (d *DropDown) SetTextOptions(prefix, suffix, currentPrefix, currentSuffix, noSelection string) { d.Lock() defer d.Unlock() @@ -244,16 +239,14 @@ func (d *DropDown) SetTextOptions(prefix, suffix, currentPrefix, currentSuffix, for index := 0; index < d.list.GetItemCount(); index++ { d.list.SetItemText(index, prefix+d.options[index].text+suffix, "") } - return d } // SetLabel sets the text to be displayed before the input area. -func (d *DropDown) SetLabel(label string) *DropDown { +func (d *DropDown) SetLabel(label string) { d.Lock() defer d.Unlock() d.label = label - return d } // GetLabel returns the text to be displayed before the input area. @@ -266,125 +259,112 @@ func (d *DropDown) GetLabel() string { // SetLabelWidth sets the screen width of the label. A value of 0 will cause the // primitive to use the width of the label string. -func (d *DropDown) SetLabelWidth(width int) *DropDown { +func (d *DropDown) SetLabelWidth(width int) { d.Lock() defer d.Unlock() d.labelWidth = width - return d } // SetLabelColor sets the color of the label. -func (d *DropDown) SetLabelColor(color tcell.Color) *DropDown { +func (d *DropDown) SetLabelColor(color tcell.Color) { d.Lock() defer d.Unlock() d.labelColor = color - return d } // SetLabelColorFocused sets the color of the label when focused. -func (d *DropDown) SetLabelColorFocused(color tcell.Color) *DropDown { +func (d *DropDown) SetLabelColorFocused(color tcell.Color) { d.Lock() defer d.Unlock() d.labelColorFocused = color - return d } // SetFieldBackgroundColor sets the background color of the options area. -func (d *DropDown) SetFieldBackgroundColor(color tcell.Color) *DropDown { +func (d *DropDown) SetFieldBackgroundColor(color tcell.Color) { d.Lock() defer d.Unlock() d.fieldBackgroundColor = color - return d } // SetFieldBackgroundColorFocused sets the background color of the options area when focused. -func (d *DropDown) SetFieldBackgroundColorFocused(color tcell.Color) *DropDown { +func (d *DropDown) SetFieldBackgroundColorFocused(color tcell.Color) { d.Lock() defer d.Unlock() d.fieldBackgroundColorFocused = color - return d } // SetFieldTextColor sets the text color of the options area. -func (d *DropDown) SetFieldTextColor(color tcell.Color) *DropDown { +func (d *DropDown) SetFieldTextColor(color tcell.Color) { d.Lock() defer d.Unlock() d.fieldTextColor = color - return d } // SetFieldTextColorFocused sets the text color of the options area when focused. -func (d *DropDown) SetFieldTextColorFocused(color tcell.Color) *DropDown { +func (d *DropDown) SetFieldTextColorFocused(color tcell.Color) { d.Lock() defer d.Unlock() d.fieldTextColorFocused = color - return d } // SetDropDownTextColor sets text color of the drop-down list. -func (d *DropDown) SetDropDownTextColor(color tcell.Color) *DropDown { +func (d *DropDown) SetDropDownTextColor(color tcell.Color) { d.Lock() defer d.Unlock() d.list.SetMainTextColor(color) - return d } // SetDropDownBackgroundColor sets the background color of the drop-down list. -func (d *DropDown) SetDropDownBackgroundColor(color tcell.Color) *DropDown { +func (d *DropDown) SetDropDownBackgroundColor(color tcell.Color) { d.Lock() defer d.Unlock() d.list.SetBackgroundColor(color) - return d } // SetDropDownSelectedTextColor sets the text color of the selected option in // the drop-down list. -func (d *DropDown) SetDropDownSelectedTextColor(color tcell.Color) *DropDown { +func (d *DropDown) SetDropDownSelectedTextColor(color tcell.Color) { d.Lock() defer d.Unlock() d.list.SetSelectedTextColor(color) - return d } // SetDropDownSelectedBackgroundColor sets the background color of the selected // option in the drop-down list. -func (d *DropDown) SetDropDownSelectedBackgroundColor(color tcell.Color) *DropDown { +func (d *DropDown) SetDropDownSelectedBackgroundColor(color tcell.Color) { d.Lock() defer d.Unlock() d.list.SetSelectedBackgroundColor(color) - return d } // SetPrefixTextColor sets the color of the prefix string. The prefix string is // shown when the user starts typing text, which directly selects the first // option that starts with the typed string. -func (d *DropDown) SetPrefixTextColor(color tcell.Color) *DropDown { +func (d *DropDown) SetPrefixTextColor(color tcell.Color) { d.Lock() defer d.Unlock() d.prefixTextColor = color - return d } // SetFieldWidth sets the screen width of the options area. A value of 0 means // extend to as long as the longest option text. -func (d *DropDown) SetFieldWidth(width int) *DropDown { +func (d *DropDown) SetFieldWidth(width int) { d.Lock() defer d.Unlock() d.fieldWidth = width - return d } // GetFieldHeight returns the height of the field. @@ -417,48 +397,45 @@ func (d *DropDown) getFieldWidth() int { } // AddOptionsSimple adds new selectable options to this drop-down. -func (d *DropDown) AddOptionsSimple(options ...string) *DropDown { +func (d *DropDown) AddOptionsSimple(options ...string) { optionsToAdd := make([]*DropDownOption, len(options)) for i, option := range options { optionsToAdd[i] = NewDropDownOption(option) } d.AddOptions(optionsToAdd...) - return d } // AddOptions adds new selectable options to this drop-down. -func (d *DropDown) AddOptions(options ...*DropDownOption) *DropDown { +func (d *DropDown) AddOptions(options ...*DropDownOption) { d.Lock() defer d.Unlock() - return d.addOptions(options...) + d.addOptions(options...) } -func (d *DropDown) addOptions(options ...*DropDownOption) *DropDown { +func (d *DropDown) addOptions(options ...*DropDownOption) { d.options = append(d.options, options...) for _, option := range options { d.list.AddItem(NewListItem(d.optionPrefix + option.text + d.optionSuffix)) } - return d } // SetOptionsSimple replaces all current options with the ones provided and installs // one callback function which is called when one of the options is selected. // It will be called with the option's index and the option itself // The "selected" parameter may be nil. -func (d *DropDown) SetOptionsSimple(selected func(index int, option *DropDownOption), options ...string) *DropDown { +func (d *DropDown) SetOptionsSimple(selected func(index int, option *DropDownOption), options ...string) { optionsToSet := make([]*DropDownOption, len(options)) for i, option := range options { optionsToSet[i] = NewDropDownOption(option) } d.SetOptions(selected, optionsToSet...) - return d } // SetOptions replaces all current options with the ones provided and installs // one callback function which is called when one of the options is selected. // It will be called with the option's index and the option itself. // The "selected" parameter may be nil. -func (d *DropDown) SetOptions(selected func(index int, option *DropDownOption), options ...*DropDownOption) *DropDown { +func (d *DropDown) SetOptions(selected func(index int, option *DropDownOption), options ...*DropDownOption) { d.Lock() defer d.Unlock() @@ -466,18 +443,16 @@ func (d *DropDown) SetOptions(selected func(index int, option *DropDownOption), d.options = nil d.addOptions(options...) d.selected = selected - return d } // SetChangedFunc sets a handler which is called when the user changes the // focused drop-down option. The handler is provided with the selected option's // index and the option itself. If "no option" was selected, these values are // -1 and nil. -func (d *DropDown) SetChangedFunc(handler func(index int, option *DropDownOption)) *DropDown { +func (d *DropDown) SetChangedFunc(handler func(index int, option *DropDownOption)) { d.list.SetChangedFunc(func(index int, item *ListItem) { handler(index, d.options[index]) }) - return d } // SetSelectedFunc sets a handler which is called when the user selects a @@ -485,12 +460,11 @@ func (d *DropDown) SetChangedFunc(handler func(index int, option *DropDownOption // an option's optional individual handler. The handler is provided with the // selected option's index and the option itself. If "no option" was selected, these values // are -1 and nil. -func (d *DropDown) SetSelectedFunc(handler func(index int, option *DropDownOption)) *DropDown { +func (d *DropDown) SetSelectedFunc(handler func(index int, option *DropDownOption)) { d.Lock() defer d.Unlock() d.selected = handler - return d } // SetDoneFunc sets a handler which is called when the user is done selecting @@ -500,21 +474,19 @@ func (d *DropDown) SetSelectedFunc(handler func(index int, option *DropDownOptio // - KeyEscape: Abort selection. // - KeyTab: Move to the next field. // - KeyBacktab: Move to the previous field. -func (d *DropDown) SetDoneFunc(handler func(key tcell.Key)) *DropDown { +func (d *DropDown) SetDoneFunc(handler func(key tcell.Key)) { d.Lock() defer d.Unlock() d.done = handler - return d } // SetFinishedFunc sets a callback invoked when the user leaves this form item. -func (d *DropDown) SetFinishedFunc(handler func(key tcell.Key)) *DropDown { +func (d *DropDown) SetFinishedFunc(handler func(key tcell.Key)) { d.Lock() defer d.Unlock() d.finished = handler - return d } // SetAttributes applies attribute settings to a form item. @@ -734,7 +706,8 @@ func (d *DropDown) openList(setFocus func(Primitive)) { if d.options[d.currentOption].selected != nil { d.options[d.currentOption].selected(d.currentOption, d.options[d.currentOption]) } - }).SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { + }) + d.list.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { if event.Key() == tcell.KeyRune { d.prefix += string(event.Rune()) d.evalPrefix() diff --git a/flex.go b/flex.go index a7bd9fb..92db2ef 100644 --- a/flex.go +++ b/flex.go @@ -51,9 +51,10 @@ type Flex struct { // flex.SetBackgroundTransparent(false) func NewFlex() *Flex { f := &Flex{ - Box: NewBox().SetBackgroundTransparent(true), + Box: NewBox(), direction: FlexColumn, } + f.SetBackgroundTransparent(true) f.focus = f return f } @@ -68,22 +69,20 @@ func (f *Flex) GetDirection() int { // SetDirection sets the direction in which the contained primitives are // distributed. This can be either FlexColumn (default) or FlexRow. -func (f *Flex) SetDirection(direction int) *Flex { +func (f *Flex) SetDirection(direction int) { f.Lock() defer f.Unlock() f.direction = direction - return f } // SetFullScreen sets the flag which, when true, causes the flex layout to use // the entire screen space instead of whatever size it is currently assigned to. -func (f *Flex) SetFullScreen(fullScreen bool) *Flex { +func (f *Flex) SetFullScreen(fullScreen bool) { f.Lock() defer f.Unlock() f.fullScreen = fullScreen - return f } // AddItem adds a new item to the container. The "fixedSize" argument is a width @@ -101,7 +100,7 @@ func (f *Flex) SetFullScreen(fullScreen bool) *Flex { // You can provide a nil value for the primitive. This will fill the empty // screen space with the default background color. To show content behind the // space, add a Box with a transparent background instead. -func (f *Flex) AddItem(item Primitive, fixedSize, proportion int, focus bool) *Flex { +func (f *Flex) AddItem(item Primitive, fixedSize, proportion int, focus bool) { f.Lock() defer f.Unlock() @@ -110,12 +109,11 @@ func (f *Flex) AddItem(item Primitive, fixedSize, proportion int, focus bool) *F } f.items = append(f.items, &flexItem{Item: item, FixedSize: fixedSize, Proportion: proportion, Focus: focus}) - return f } // AddItemAtIndex adds an item to the flex at a given index. // For more information see AddItem. -func (f *Flex) AddItemAtIndex(index int, item Primitive, fixedSize, proportion int, focus bool) *Flex { +func (f *Flex) AddItemAtIndex(index int, item Primitive, fixedSize, proportion int, focus bool) { f.Lock() defer f.Unlock() newItem := &flexItem{Item: item, FixedSize: fixedSize, Proportion: proportion, Focus: focus} @@ -125,12 +123,11 @@ func (f *Flex) AddItemAtIndex(index int, item Primitive, fixedSize, proportion i } else { f.items = append(f.items[:index], append([]*flexItem{newItem}, f.items[index:]...)...) } - return f } // RemoveItem removes all items for the given primitive from the container, // keeping the order of the remaining items intact. -func (f *Flex) RemoveItem(p Primitive) *Flex { +func (f *Flex) RemoveItem(p Primitive) { f.Lock() defer f.Unlock() @@ -139,13 +136,12 @@ func (f *Flex) RemoveItem(p Primitive) *Flex { f.items = append(f.items[:index], f.items[index+1:]...) } } - return f } // ResizeItem sets a new size for the item(s) with the given primitive. If there // are multiple Flex items with the same primitive, they will all receive the // same size. For details regarding the size parameters, see AddItem(). -func (f *Flex) ResizeItem(p Primitive, fixedSize, proportion int) *Flex { +func (f *Flex) ResizeItem(p Primitive, fixedSize, proportion int) { f.Lock() defer f.Unlock() @@ -155,7 +151,6 @@ func (f *Flex) ResizeItem(p Primitive, fixedSize, proportion int) *Flex { item.Proportion = proportion } } - return f } // Draw draws this primitive onto the screen. diff --git a/form.go b/form.go index 958b7b8..00cfcfa 100644 --- a/form.go +++ b/form.go @@ -119,7 +119,8 @@ type Form struct { // NewForm returns a new form. func NewForm() *Form { - box := NewBox().SetBorderPadding(1, 1, 1, 1) + box := NewBox() + box.SetBorderPadding(1, 1, 1, 1) f := &Form{ Box: box, @@ -143,130 +144,117 @@ func NewForm() *Form { // SetItemPadding sets the number of empty rows between form items for vertical // layouts and the number of empty cells between form items for horizontal // layouts. -func (f *Form) SetItemPadding(padding int) *Form { +func (f *Form) SetItemPadding(padding int) { f.Lock() defer f.Unlock() f.itemPadding = padding - return f } // SetHorizontal sets the direction the form elements are laid out. If set to // true, instead of positioning them from top to bottom (the default), they are // positioned from left to right, moving into the next row if there is not // enough space. -func (f *Form) SetHorizontal(horizontal bool) *Form { +func (f *Form) SetHorizontal(horizontal bool) { f.Lock() defer f.Unlock() f.horizontal = horizontal - return f } // SetLabelColor sets the color of the labels. -func (f *Form) SetLabelColor(color tcell.Color) *Form { +func (f *Form) SetLabelColor(color tcell.Color) { f.Lock() defer f.Unlock() f.labelColor = color - return f } // SetLabelColorFocused sets the color of the labels when focused. -func (f *Form) SetLabelColorFocused(color tcell.Color) *Form { +func (f *Form) SetLabelColorFocused(color tcell.Color) { f.Lock() defer f.Unlock() f.labelColorFocused = color - return f } // SetFieldBackgroundColor sets the background color of the input areas. -func (f *Form) SetFieldBackgroundColor(color tcell.Color) *Form { +func (f *Form) SetFieldBackgroundColor(color tcell.Color) { f.Lock() defer f.Unlock() f.fieldBackgroundColor = color - return f } // SetFieldBackgroundColorFocused sets the background color of the input areas when focused. -func (f *Form) SetFieldBackgroundColorFocused(color tcell.Color) *Form { +func (f *Form) SetFieldBackgroundColorFocused(color tcell.Color) { f.Lock() defer f.Unlock() f.fieldBackgroundColorFocused = color - return f } // SetFieldTextColor sets the text color of the input areas. -func (f *Form) SetFieldTextColor(color tcell.Color) *Form { +func (f *Form) SetFieldTextColor(color tcell.Color) { f.Lock() defer f.Unlock() f.fieldTextColor = color - return f } // SetFieldTextColorFocused sets the text color of the input areas when focused. -func (f *Form) SetFieldTextColorFocused(color tcell.Color) *Form { +func (f *Form) SetFieldTextColorFocused(color tcell.Color) { f.Lock() defer f.Unlock() f.fieldTextColorFocused = color - return f } // SetButtonsAlign sets how the buttons align horizontally, one of AlignLeft // (the default), AlignCenter, and AlignRight. This is only -func (f *Form) SetButtonsAlign(align int) *Form { +func (f *Form) SetButtonsAlign(align int) { f.Lock() defer f.Unlock() f.buttonsAlign = align - return f } // SetButtonBackgroundColor sets the background color of the buttons. -func (f *Form) SetButtonBackgroundColor(color tcell.Color) *Form { +func (f *Form) SetButtonBackgroundColor(color tcell.Color) { f.Lock() defer f.Unlock() f.buttonBackgroundColor = color - return f } // SetButtonBackgroundColorFocused sets the background color of the buttons when focused. -func (f *Form) SetButtonBackgroundColorFocused(color tcell.Color) *Form { +func (f *Form) SetButtonBackgroundColorFocused(color tcell.Color) { f.Lock() defer f.Unlock() f.buttonBackgroundColorFocused = color - return f } // SetButtonTextColor sets the color of the button texts. -func (f *Form) SetButtonTextColor(color tcell.Color) *Form { +func (f *Form) SetButtonTextColor(color tcell.Color) { f.Lock() defer f.Unlock() f.buttonTextColor = color - return f } // SetButtonTextColorFocused sets the color of the button texts when focused. -func (f *Form) SetButtonTextColorFocused(color tcell.Color) *Form { +func (f *Form) SetButtonTextColorFocused(color tcell.Color) { f.Lock() defer f.Unlock() f.buttonTextColorFocused = color - return f } // SetFocus shifts the focus to the form element with the given index, counting // non-button items first and buttons last. Note that this index is only used // when the form itself receives focus. -func (f *Form) SetFocus(index int) *Form { +func (f *Form) SetFocus(index int) { f.Lock() defer f.Unlock() @@ -277,7 +265,6 @@ func (f *Form) SetFocus(index int) *Form { } else { f.focusedElement = index } - return f } // AddInputField adds an input field to the form. It has a label, an optional @@ -285,17 +272,18 @@ func (f *Form) SetFocus(index int) *Form { // an optional accept function to validate the item's value (set to nil to // accept any text), and an (optional) callback function which is invoked when // the input field's text has changed. -func (f *Form) AddInputField(label, value string, fieldWidth int, accept func(textToCheck string, lastChar rune) bool, changed func(text string)) *Form { +func (f *Form) AddInputField(label, value string, fieldWidth int, accept func(textToCheck string, lastChar rune) bool, changed func(text string)) { f.Lock() defer f.Unlock() - f.items = append(f.items, NewInputField(). - SetLabel(label). - SetText(value). - SetFieldWidth(fieldWidth). - SetAcceptanceFunc(accept). - SetChangedFunc(changed)) - return f + inputField := NewInputField() + inputField.SetLabel(label) + inputField.SetText(value) + inputField.SetFieldWidth(fieldWidth) + inputField.SetAcceptanceFunc(accept) + inputField.SetChangedFunc(changed) + + f.items = append(f.items, inputField) } // AddPasswordField adds a password field to the form. This is similar to an @@ -304,75 +292,81 @@ func (f *Form) AddInputField(label, value string, fieldWidth int, accept func(te // value, a field width (a value of 0 extends it as far as possible), and an // (optional) callback function which is invoked when the input field's text has // changed. -func (f *Form) AddPasswordField(label, value string, fieldWidth int, mask rune, changed func(text string)) *Form { +func (f *Form) AddPasswordField(label, value string, fieldWidth int, mask rune, changed func(text string)) { f.Lock() defer f.Unlock() if mask == 0 { mask = '*' } - f.items = append(f.items, NewInputField(). - SetLabel(label). - SetText(value). - SetFieldWidth(fieldWidth). - SetMaskCharacter(mask). - SetChangedFunc(changed)) - return f + + passwordField := NewInputField() + passwordField.SetLabel(label) + passwordField.SetText(value) + passwordField.SetFieldWidth(fieldWidth) + passwordField.SetMaskCharacter(mask) + passwordField.SetChangedFunc(changed) + + f.items = append(f.items, passwordField) } // AddDropDownSimple adds a drop-down element to the form. It has a label, options, // and an (optional) callback function which is invoked when an option was // selected. The initial option may be a negative value to indicate that no // option is currently selected. -func (f *Form) AddDropDownSimple(label string, initialOption int, selected func(index int, option *DropDownOption), options ...string) *Form { +func (f *Form) AddDropDownSimple(label string, initialOption int, selected func(index int, option *DropDownOption), options ...string) { f.Lock() defer f.Unlock() - f.items = append(f.items, NewDropDown(). - SetLabel(label). - SetOptionsSimple(selected, options...). - SetCurrentOption(initialOption)) - return f + dd := NewDropDown() + dd.SetLabel(label) + dd.SetOptionsSimple(selected, options...) + dd.SetCurrentOption(initialOption) + + f.items = append(f.items, dd) } // AddDropDown adds a drop-down element to the form. It has a label, options, // and an (optional) callback function which is invoked when an option was // selected. The initial option may be a negative value to indicate that no // option is currently selected. -func (f *Form) AddDropDown(label string, initialOption int, selected func(index int, option *DropDownOption), options []*DropDownOption) *Form { +func (f *Form) AddDropDown(label string, initialOption int, selected func(index int, option *DropDownOption), options []*DropDownOption) { f.Lock() defer f.Unlock() - f.items = append(f.items, NewDropDown(). - SetLabel(label). - SetOptions(selected, options...). - SetCurrentOption(initialOption)) - return f + dd := NewDropDown() + dd.SetLabel(label) + dd.SetOptions(selected, options...) + dd.SetCurrentOption(initialOption) + + f.items = append(f.items, dd) } // AddCheckBox adds a checkbox to the form. It has a label, a message, an // initial state, and an (optional) callback function which is invoked when the // state of the checkbox was changed by the user. -func (f *Form) AddCheckBox(label string, message string, checked bool, changed func(checked bool)) *Form { +func (f *Form) AddCheckBox(label string, message string, checked bool, changed func(checked bool)) { f.Lock() defer f.Unlock() - f.items = append(f.items, NewCheckBox(). - SetLabel(label). - SetMessage(message). - SetChecked(checked). - SetChangedFunc(changed)) - return f + c := NewCheckBox() + c.SetLabel(label) + c.SetMessage(message) + c.SetChecked(checked) + c.SetChangedFunc(changed) + + f.items = append(f.items, c) } // AddButton adds a new button to the form. The "selected" function is called // when the user selects this button. It may be nil. -func (f *Form) AddButton(label string, selected func()) *Form { +func (f *Form) AddButton(label string, selected func()) { f.Lock() defer f.Unlock() - f.buttons = append(f.buttons, NewButton(label).SetSelectedFunc(selected)) - return f + button := NewButton(label) + button.SetSelectedFunc(selected) + f.buttons = append(f.buttons, button) } // GetButton returns the button at the specified 0-based index. Note that @@ -387,12 +381,11 @@ func (f *Form) GetButton(index int) *Button { // RemoveButton removes the button at the specified position, starting with 0 // for the button that was added first. -func (f *Form) RemoveButton(index int) *Form { +func (f *Form) RemoveButton(index int) { f.Lock() defer f.Unlock() f.buttons = append(f.buttons[:index], f.buttons[index+1:]...) - return f } // GetButtonCount returns the number of buttons in this form. @@ -420,7 +413,7 @@ func (f *Form) GetButtonIndex(label string) int { // Clear removes all input elements from the form, including the buttons if // specified. -func (f *Form) Clear(includeButtons bool) *Form { +func (f *Form) Clear(includeButtons bool) { f.Lock() defer f.Unlock() @@ -429,16 +422,14 @@ func (f *Form) Clear(includeButtons bool) *Form { f.buttons = nil } f.focusedElement = 0 - return f } // ClearButtons removes all buttons from the form. -func (f *Form) ClearButtons() *Form { +func (f *Form) ClearButtons() { f.Lock() defer f.Unlock() f.buttons = nil - return f } // AddFormItem adds a new item to the form. This can be used to add your own @@ -451,7 +442,7 @@ func (f *Form) ClearButtons() *Form { // - The background color // - The field text color // - The field background color -func (f *Form) AddFormItem(item FormItem) *Form { +func (f *Form) AddFormItem(item FormItem) { f.Lock() defer f.Unlock() @@ -460,7 +451,6 @@ func (f *Form) AddFormItem(item FormItem) *Form { } f.items = append(f.items, item) - return f } // GetFormItemCount returns the number of items in the form (not including the @@ -499,12 +489,11 @@ func (f *Form) GetFormItem(index int) FormItem { // RemoveFormItem removes the form element at the given position, starting with // index 0. Elements are referenced in the order they were added. Buttons are // not included. -func (f *Form) RemoveFormItem(index int) *Form { +func (f *Form) RemoveFormItem(index int) { f.Lock() defer f.Unlock() f.items = append(f.items[:index], f.items[index+1:]...) - return f } // GetFormItemByLabel returns the first form element with the given label. If @@ -558,22 +547,20 @@ func (f *Form) GetFocusedItemIndex() (formItem, button int) { // selection to the first item (similarly in the other direction). If set to // false, the selection won't change when navigating downwards on the last item // or navigating upwards on the first item. -func (f *Form) SetWrapAround(wrapAround bool) *Form { +func (f *Form) SetWrapAround(wrapAround bool) { f.Lock() defer f.Unlock() f.wrapAround = wrapAround - return f } // SetCancelFunc sets a handler which is called when the user hits the Escape // key. -func (f *Form) SetCancelFunc(callback func()) *Form { +func (f *Form) SetCancelFunc(callback func()) { f.Lock() defer f.Unlock() f.cancel = callback - return f } // GetAttributes returns the current attribute settings of a form. @@ -732,10 +719,10 @@ func (f *Form) Draw(screen tcell.Screen) { if buttonWidth > space { buttonWidth = space } - button.SetLabelColor(f.buttonTextColor). - SetLabelColorFocused(f.buttonTextColorFocused). - SetBackgroundColorFocused(f.buttonBackgroundColorFocused). - SetBackgroundColor(f.buttonBackgroundColor) + button.SetLabelColor(f.buttonTextColor) + button.SetLabelColorFocused(f.buttonTextColorFocused) + button.SetBackgroundColorFocused(f.buttonBackgroundColorFocused) + button.SetBackgroundColor(f.buttonBackgroundColor) buttonIndex := index + len(f.items) positions[buttonIndex].x = x diff --git a/frame.go b/frame.go index eeec6db..cf0233e 100644 --- a/frame.go +++ b/frame.go @@ -58,7 +58,7 @@ func NewFrame(primitive Primitive) *Frame { // the Align constants. Rows in the header are printed top to bottom, rows in // the footer are printed bottom to top. Note that long text can overlap as // different alignments will be placed on the same row. -func (f *Frame) AddText(text string, header bool, align int, color tcell.Color) *Frame { +func (f *Frame) AddText(text string, header bool, align int, color tcell.Color) { f.Lock() defer f.Unlock() @@ -68,27 +68,24 @@ func (f *Frame) AddText(text string, header bool, align int, color tcell.Color) Align: align, Color: color, }) - return f } // Clear removes all text from the frame. -func (f *Frame) Clear() *Frame { +func (f *Frame) Clear() { f.Lock() defer f.Unlock() f.text = nil - return f } // SetBorders sets the width of the frame borders as well as "header" and // "footer", the vertical space between the header and footer text and the // contained primitive (does not apply if there is no text). -func (f *Frame) SetBorders(top, bottom, header, footer, left, right int) *Frame { +func (f *Frame) SetBorders(top, bottom, header, footer, left, right int) { f.Lock() defer f.Unlock() f.top, f.bottom, f.header, f.footer, f.left, f.right = top, bottom, header, footer, left, right - return f } // Draw draws this primitive onto the screen. diff --git a/grid.go b/grid.go index d2027da..c9627ff 100644 --- a/grid.go +++ b/grid.go @@ -68,9 +68,10 @@ type Grid struct { // grid.SetBackgroundTransparent(false) func NewGrid() *Grid { g := &Grid{ - Box: NewBox().SetBackgroundTransparent(true), + Box: NewBox(), bordersColor: Styles.GraphicsColor, } + g.SetBackgroundTransparent(true) g.focus = g return g } @@ -104,12 +105,11 @@ func NewGrid() *Grid { // // The resulting widths would be: 30, 15, 15, 15, 20, 15, and 15 cells, a total // of 125 cells, 25 cells wider than the available grid width. -func (g *Grid) SetColumns(columns ...int) *Grid { +func (g *Grid) SetColumns(columns ...int) { g.Lock() defer g.Unlock() g.columns = columns - return g } // SetRows defines how the rows of the grid are distributed. These values behave @@ -118,17 +118,16 @@ func (g *Grid) SetColumns(columns ...int) *Grid { // // The provided values correspond to row heights, the first value defining // the height of the topmost row. -func (g *Grid) SetRows(rows ...int) *Grid { +func (g *Grid) SetRows(rows ...int) { g.Lock() defer g.Unlock() g.rows = rows - return g } // SetSize is a shortcut for SetRows() and SetColumns() where all row and column // values are set to the given size values. See SetColumns() for details on sizes. -func (g *Grid) SetSize(numRows, numColumns, rowSize, columnSize int) *Grid { +func (g *Grid) SetSize(numRows, numColumns, rowSize, columnSize int) { g.Lock() defer g.Unlock() @@ -140,12 +139,11 @@ func (g *Grid) SetSize(numRows, numColumns, rowSize, columnSize int) *Grid { for index := range g.columns { g.columns[index] = columnSize } - return g } // SetMinSize sets an absolute minimum width for rows and an absolute minimum // height for columns. Panics if negative values are provided. -func (g *Grid) SetMinSize(row, column int) *Grid { +func (g *Grid) SetMinSize(row, column int) { g.Lock() defer g.Unlock() @@ -153,13 +151,12 @@ func (g *Grid) SetMinSize(row, column int) *Grid { panic("Invalid minimum row/column size") } g.minHeight, g.minWidth = row, column - return g } // SetGap sets the size of the gaps between neighboring primitives on the grid. // If borders are drawn (see SetBorders()), these values are ignored and a gap // of 1 is assumed. Panics if negative values are provided. -func (g *Grid) SetGap(row, column int) *Grid { +func (g *Grid) SetGap(row, column int) { g.Lock() defer g.Unlock() @@ -167,27 +164,24 @@ func (g *Grid) SetGap(row, column int) *Grid { panic("Invalid gap size") } g.gapRows, g.gapColumns = row, column - return g } // SetBorders sets whether or not borders are drawn around grid items. Setting // this value to true will cause the gap values (see SetGap()) to be ignored and // automatically assumed to be 1 where the border graphics are drawn. -func (g *Grid) SetBorders(borders bool) *Grid { +func (g *Grid) SetBorders(borders bool) { g.Lock() defer g.Unlock() g.borders = borders - return g } // SetBordersColor sets the color of the item borders. -func (g *Grid) SetBordersColor(color tcell.Color) *Grid { +func (g *Grid) SetBordersColor(color tcell.Color) { g.Lock() defer g.Unlock() g.bordersColor = color - return g } // AddItem adds a primitive and its position to the grid. The top-left corner @@ -216,7 +210,7 @@ func (g *Grid) SetBordersColor(color tcell.Color) *Grid { // If the item's focus is set to true, it will receive focus when the grid // receives focus. If there are multiple items with a true focus flag, the last // visible one that was added will receive focus. -func (g *Grid) AddItem(p Primitive, row, column, rowSpan, colSpan, minGridHeight, minGridWidth int, focus bool) *Grid { +func (g *Grid) AddItem(p Primitive, row, column, rowSpan, colSpan, minGridHeight, minGridWidth int, focus bool) { g.Lock() defer g.Unlock() @@ -230,12 +224,11 @@ func (g *Grid) AddItem(p Primitive, row, column, rowSpan, colSpan, minGridHeight MinGridWidth: minGridWidth, Focus: focus, }) - return g } // RemoveItem removes all items for the given primitive from the grid, keeping // the order of the remaining items intact. -func (g *Grid) RemoveItem(p Primitive) *Grid { +func (g *Grid) RemoveItem(p Primitive) { g.Lock() defer g.Unlock() @@ -244,16 +237,14 @@ func (g *Grid) RemoveItem(p Primitive) *Grid { g.items = append(g.items[:index], g.items[index+1:]...) } } - return g } // Clear removes all items from the grid. -func (g *Grid) Clear() *Grid { +func (g *Grid) Clear() { g.Lock() defer g.Unlock() g.items = nil - return g } // SetOffset sets the number of rows and columns which are skipped before @@ -261,12 +252,11 @@ func (g *Grid) Clear() *Grid { // completely move off the screen, these values may be adjusted the next time // the grid is drawn. The actual position of the grid may also be adjusted such // that contained primitives that have focus remain visible. -func (g *Grid) SetOffset(rows, columns int) *Grid { +func (g *Grid) SetOffset(rows, columns int) { g.Lock() defer g.Unlock() g.rowOffset, g.columnOffset = rows, columns - return g } // GetOffset returns the current row and column offset (see SetOffset() for diff --git a/inputfield.go b/inputfield.go index 9bda7cc..d137830 100644 --- a/inputfield.go +++ b/inputfield.go @@ -161,7 +161,7 @@ func NewInputField() *InputField { } // SetText sets the current text of the input field. -func (i *InputField) SetText(text string) *InputField { +func (i *InputField) SetText(text string) { i.Lock() i.text = []byte(text) @@ -172,8 +172,6 @@ func (i *InputField) SetText(text string) *InputField { } else { i.Unlock() } - - return i } // GetText returns the current text of the input field. @@ -185,12 +183,11 @@ func (i *InputField) GetText() string { } // SetLabel sets the text to be displayed before the input area. -func (i *InputField) SetLabel(label string) *InputField { +func (i *InputField) SetLabel(label string) { i.Lock() defer i.Unlock() i.label = []byte(label) - return i } // GetLabel returns the text to be displayed before the input area. @@ -203,182 +200,163 @@ func (i *InputField) GetLabel() string { // SetLabelWidth sets the screen width of the label. A value of 0 will cause the // primitive to use the width of the label string. -func (i *InputField) SetLabelWidth(width int) *InputField { +func (i *InputField) SetLabelWidth(width int) { i.Lock() defer i.Unlock() i.labelWidth = width - return i } // SetPlaceholder sets the text to be displayed when the input text is empty. -func (i *InputField) SetPlaceholder(text string) *InputField { +func (i *InputField) SetPlaceholder(text string) { i.Lock() defer i.Unlock() i.placeholder = []byte(text) - return i } // SetLabelColor sets the color of the label. -func (i *InputField) SetLabelColor(color tcell.Color) *InputField { +func (i *InputField) SetLabelColor(color tcell.Color) { i.Lock() defer i.Unlock() i.labelColor = color - return i } // SetLabelColorFocused sets the color of the label when focused. -func (i *InputField) SetLabelColorFocused(color tcell.Color) *InputField { +func (i *InputField) SetLabelColorFocused(color tcell.Color) { i.Lock() defer i.Unlock() i.labelColorFocused = color - return i } // SetFieldBackgroundColor sets the background color of the input area. -func (i *InputField) SetFieldBackgroundColor(color tcell.Color) *InputField { +func (i *InputField) SetFieldBackgroundColor(color tcell.Color) { i.Lock() defer i.Unlock() i.fieldBackgroundColor = color - return i } // SetFieldBackgroundColorFocused sets the background color of the input area // when focused. -func (i *InputField) SetFieldBackgroundColorFocused(color tcell.Color) *InputField { +func (i *InputField) SetFieldBackgroundColorFocused(color tcell.Color) { i.Lock() defer i.Unlock() i.fieldBackgroundColorFocused = color - return i } // SetFieldTextColor sets the text color of the input area. -func (i *InputField) SetFieldTextColor(color tcell.Color) *InputField { +func (i *InputField) SetFieldTextColor(color tcell.Color) { i.Lock() defer i.Unlock() i.fieldTextColor = color - return i } // SetFieldTextColorFocused sets the text color of the input area when focused. -func (i *InputField) SetFieldTextColorFocused(color tcell.Color) *InputField { +func (i *InputField) SetFieldTextColorFocused(color tcell.Color) { i.Lock() defer i.Unlock() i.fieldTextColorFocused = color - return i } // SetPlaceholderTextColor sets the text color of placeholder text. -func (i *InputField) SetPlaceholderTextColor(color tcell.Color) *InputField { +func (i *InputField) SetPlaceholderTextColor(color tcell.Color) { i.Lock() defer i.Unlock() i.placeholderTextColor = color - return i } // SetPlaceholderTextColorFocused sets the text color of placeholder text when // focused. -func (i *InputField) SetPlaceholderTextColorFocused(color tcell.Color) *InputField { +func (i *InputField) SetPlaceholderTextColorFocused(color tcell.Color) { i.Lock() defer i.Unlock() i.placeholderTextColorFocused = color - return i } // SetAutocompleteListTextColor sets the text color of the ListItems. -func (i *InputField) SetAutocompleteListTextColor(color tcell.Color) *InputField { +func (i *InputField) SetAutocompleteListTextColor(color tcell.Color) { i.Lock() defer i.Unlock() i.autocompleteListTextColor = color - return i } // SetAutocompleteListBackgroundColor sets the background color of the // autocomplete list. -func (i *InputField) SetAutocompleteListBackgroundColor(color tcell.Color) *InputField { +func (i *InputField) SetAutocompleteListBackgroundColor(color tcell.Color) { i.Lock() defer i.Unlock() i.autocompleteListBackgroundColor = color - return i } // SetAutocompleteListSelectedTextColor sets the text color of the selected // ListItem. -func (i *InputField) SetAutocompleteListSelectedTextColor(color tcell.Color) *InputField { +func (i *InputField) SetAutocompleteListSelectedTextColor(color tcell.Color) { i.Lock() defer i.Unlock() i.autocompleteListSelectedTextColor = color - return i } // SetAutocompleteListSelectedBackgroundColor sets the background of the // selected ListItem. -func (i *InputField) SetAutocompleteListSelectedBackgroundColor(color tcell.Color) *InputField { +func (i *InputField) SetAutocompleteListSelectedBackgroundColor(color tcell.Color) { i.Lock() defer i.Unlock() i.autocompleteListSelectedBackgroundColor = color - return i } // SetAutocompleteSuggestionTextColor sets the text color of the autocomplete // suggestion in the input field. -func (i *InputField) SetAutocompleteSuggestionTextColor(color tcell.Color) *InputField { +func (i *InputField) SetAutocompleteSuggestionTextColor(color tcell.Color) { i.Lock() defer i.Unlock() i.autocompleteSuggestionTextColor = color - return i } // SetFieldNoteTextColor sets the text color of the note. -func (i *InputField) SetFieldNoteTextColor(color tcell.Color) *InputField { +func (i *InputField) SetFieldNoteTextColor(color tcell.Color) { i.Lock() defer i.Unlock() i.fieldNoteTextColor = color - return i } // SetFieldNote sets the text to show below the input field, e.g. when the // input is invalid. -func (i *InputField) SetFieldNote(note string) *InputField { +func (i *InputField) SetFieldNote(note string) { i.Lock() defer i.Unlock() i.fieldNote = []byte(note) - return i } // ResetFieldNote sets the note to an empty string. -func (i *InputField) ResetFieldNote() *InputField { +func (i *InputField) ResetFieldNote() { i.Lock() defer i.Unlock() i.fieldNote = nil - return i } // SetFieldWidth sets the screen width of the input area. A value of 0 means // extend as much as possible. -func (i *InputField) SetFieldWidth(width int) *InputField { +func (i *InputField) SetFieldWidth(width int) { i.Lock() defer i.Unlock() i.fieldWidth = width - return i } // GetFieldWidth returns this primitive's field width. @@ -417,12 +395,11 @@ func (i *InputField) SetCursorPosition(cursorPos int) { // SetMaskCharacter sets a character that masks user input on a screen. A value // of 0 disables masking. -func (i *InputField) SetMaskCharacter(mask rune) *InputField { +func (i *InputField) SetMaskCharacter(mask rune) { i.Lock() defer i.Unlock() i.maskCharacter = mask - return i } // SetAutocompleteFunc sets an autocomplete callback function which may return @@ -431,13 +408,12 @@ func (i *InputField) SetMaskCharacter(mask rune) *InputField { // invoked in this function and whenever the current text changes or when // Autocomplete() is called. Entries are cleared when the user selects an entry // or presses Escape. -func (i *InputField) SetAutocompleteFunc(callback func(currentText string) (entries []*ListItem)) *InputField { +func (i *InputField) SetAutocompleteFunc(callback func(currentText string) (entries []*ListItem)) { i.Lock() i.autocomplete = callback i.Unlock() i.Autocomplete() - return i } // Autocomplete invokes the autocomplete callback (if there is one). If the @@ -448,11 +424,11 @@ func (i *InputField) SetAutocompleteFunc(callback func(currentText string) (entr // It is safe to call this function from any goroutine. Note that the input // field is not redrawn automatically unless called from the main goroutine // (e.g. in response to events). -func (i *InputField) Autocomplete() *InputField { +func (i *InputField) Autocomplete() { i.Lock() if i.autocomplete == nil { i.Unlock() - return i + return } i.Unlock() @@ -464,22 +440,23 @@ func (i *InputField) Autocomplete() *InputField { i.autocompleteList = nil i.autocompleteListSuggestion = nil i.Unlock() - return i + return } i.Lock() // Make a list if we have none. if i.autocompleteList == nil { - i.autocompleteList = NewList() - i.autocompleteList. - SetChangedFunc(i.autocompleteChanged). - ShowSecondaryText(false). - SetMainTextColor(i.autocompleteListTextColor). - SetSelectedTextColor(i.autocompleteListSelectedTextColor). - SetSelectedBackgroundColor(i.autocompleteListSelectedBackgroundColor). - SetHighlightFullLine(true). - SetBackgroundColor(i.autocompleteListBackgroundColor) + l := NewList() + l.SetChangedFunc(i.autocompleteChanged) + l.ShowSecondaryText(false) + l.SetMainTextColor(i.autocompleteListTextColor) + l.SetSelectedTextColor(i.autocompleteListSelectedTextColor) + l.SetSelectedBackgroundColor(i.autocompleteListSelectedBackgroundColor) + l.SetHighlightFullLine(true) + l.SetBackgroundColor(i.autocompleteListBackgroundColor) + + i.autocompleteList = l } // Fill it with the entries. @@ -499,7 +476,6 @@ func (i *InputField) Autocomplete() *InputField { } i.Unlock() - return i } // autocompleteChanged gets called when another item in the @@ -521,22 +497,20 @@ func (i *InputField) autocompleteChanged(_ int, item *ListItem) { // // This package defines a number of variables prefixed with InputField which may // be used for common input (e.g. numbers, maximum text length). -func (i *InputField) SetAcceptanceFunc(handler func(textToCheck string, lastChar rune) bool) *InputField { +func (i *InputField) SetAcceptanceFunc(handler func(textToCheck string, lastChar rune) bool) { i.Lock() defer i.Unlock() i.accept = handler - return i } // SetChangedFunc sets a handler which is called whenever the text of the input // field has changed. It receives the current text (after the change). -func (i *InputField) SetChangedFunc(handler func(text string)) *InputField { +func (i *InputField) SetChangedFunc(handler func(text string)) { i.Lock() defer i.Unlock() i.changed = handler - return i } // SetDoneFunc sets a handler which is called when the user is done entering @@ -547,21 +521,19 @@ func (i *InputField) SetChangedFunc(handler func(text string)) *InputField { // - KeyEscape: Abort text input. // - KeyTab: Move to the next field. // - KeyBacktab: Move to the previous field. -func (i *InputField) SetDoneFunc(handler func(key tcell.Key)) *InputField { +func (i *InputField) SetDoneFunc(handler func(key tcell.Key)) { i.Lock() defer i.Unlock() i.done = handler - return i } // SetFinishedFunc sets a callback invoked when the user leaves this form item. -func (i *InputField) SetFinishedFunc(handler func(key tcell.Key)) *InputField { +func (i *InputField) SetFinishedFunc(handler func(key tcell.Key)) { i.Lock() defer i.Unlock() i.finished = handler - return i } // SetAttributes applies attribute settings to a form item. diff --git a/list.go b/list.go index 3d94fce..f2f7ca2 100644 --- a/list.go +++ b/list.go @@ -30,17 +30,16 @@ func NewListItem(mainText string) *ListItem { } // SetMainBytes sets the main text of the list item. -func (l *ListItem) SetMainBytes(val []byte) *ListItem { +func (l *ListItem) SetMainBytes(val []byte) { l.Lock() defer l.Unlock() l.mainText = val - return l } // SetMainText sets the main text of the list item. -func (l *ListItem) SetMainText(val string) *ListItem { - return l.SetMainBytes([]byte(val)) +func (l *ListItem) SetMainText(val string) { + l.SetMainBytes([]byte(val)) } // GetMainBytes returns the item's main text. @@ -57,17 +56,16 @@ func (l *ListItem) GetMainText() string { } // SetSecondaryBytes sets a secondary text to be shown underneath the main text. -func (l *ListItem) SetSecondaryBytes(val []byte) *ListItem { +func (l *ListItem) SetSecondaryBytes(val []byte) { l.Lock() defer l.Unlock() l.secondaryText = val - return l } // SetSecondaryText sets a secondary text to be shown underneath the main text. -func (l *ListItem) SetSecondaryText(val string) *ListItem { - return l.SetSecondaryBytes([]byte(val)) +func (l *ListItem) SetSecondaryText(val string) { + l.SetSecondaryBytes([]byte(val)) } // GetSecondaryBytes returns the item's secondary text. @@ -84,12 +82,11 @@ func (l *ListItem) GetSecondaryText() string { } // SetShortcut sets the key to select the ListItem directly, 0 if there is no shortcut. -func (l *ListItem) SetShortcut(val rune) *ListItem { +func (l *ListItem) SetShortcut(val rune) { l.Lock() defer l.Unlock() l.shortcut = val - return l } // GetShortcut returns the ListItem's shortcut. @@ -101,21 +98,19 @@ func (l *ListItem) GetShortcut() rune { } // SetSelectedFunc sets a function which is called when the ListItem is selected. -func (l *ListItem) SetSelectedFunc(handler func()) *ListItem { +func (l *ListItem) SetSelectedFunc(handler func()) { l.Lock() defer l.Unlock() l.selected = handler - return l } // SetReference allows you to store a reference of any type in the item -func (l *ListItem) SetReference(val interface{}) *ListItem { +func (l *ListItem) SetReference(val interface{}) { l.Lock() defer l.Unlock() l.reference = val - return l } // GetReference returns the item's reference object. @@ -228,7 +223,7 @@ func NewList() *List { // range indices are clamped to the beginning/end. // // Calling this function triggers a "changed" event if the selection changes. -func (l *List) SetCurrentItem(index int) *List { +func (l *List) SetCurrentItem(index int) { l.Lock() if index < 0 { @@ -254,7 +249,6 @@ func (l *List) SetCurrentItem(index int) *List { } l.Unlock() - return l } // GetCurrentItem returns the currently selected list item, @@ -292,12 +286,12 @@ func (l *List) GetItems() []*ListItem { // // The currently selected item is shifted accordingly. If it is the one that is // removed, a "changed" event is fired. -func (l *List) RemoveItem(index int) *List { +func (l *List) RemoveItem(index int) { l.Lock() if len(l.items) == 0 { l.Unlock() - return l + return } // Adjust index. @@ -317,7 +311,7 @@ func (l *List) RemoveItem(index int) *List { // If there is nothing left, we're done. if len(l.items) == 0 { l.Unlock() - return l + return } // Shift current item. @@ -334,13 +328,11 @@ func (l *List) RemoveItem(index int) *List { } else { l.Unlock() } - - return l } // SetOffset sets the number of list items skipped at the top before the first // item is drawn. -func (l *List) SetOffset(offset int) *List { +func (l *List) SetOffset(offset int) { l.Lock() defer l.Unlock() @@ -349,7 +341,6 @@ func (l *List) SetOffset(offset int) *List { } l.offset = offset - return l } // GetOffset returns the number of list items skipped at the top before the @@ -362,137 +353,124 @@ func (l *List) GetOffset() int { } // SetMainTextColor sets the color of the items' main text. -func (l *List) SetMainTextColor(color tcell.Color) *List { +func (l *List) SetMainTextColor(color tcell.Color) { l.Lock() defer l.Unlock() l.mainTextColor = color - return l } // SetSecondaryTextColor sets the color of the items' secondary text. -func (l *List) SetSecondaryTextColor(color tcell.Color) *List { +func (l *List) SetSecondaryTextColor(color tcell.Color) { l.Lock() defer l.Unlock() l.secondaryTextColor = color - return l } // SetShortcutColor sets the color of the items' shortcut. -func (l *List) SetShortcutColor(color tcell.Color) *List { +func (l *List) SetShortcutColor(color tcell.Color) { l.Lock() defer l.Unlock() l.shortcutColor = color - return l } // SetSelectedTextColor sets the text color of selected items. -func (l *List) SetSelectedTextColor(color tcell.Color) *List { +func (l *List) SetSelectedTextColor(color tcell.Color) { l.Lock() defer l.Unlock() l.selectedTextColor = color - return l } // SetSelectedTextAttributes sets the style attributes of selected items. -func (l *List) SetSelectedTextAttributes(attr tcell.AttrMask) *List { +func (l *List) SetSelectedTextAttributes(attr tcell.AttrMask) { l.Lock() defer l.Unlock() l.selectedTextAttributes = attr - return l } // SetSelectedBackgroundColor sets the background color of selected items. -func (l *List) SetSelectedBackgroundColor(color tcell.Color) *List { +func (l *List) SetSelectedBackgroundColor(color tcell.Color) { l.Lock() defer l.Unlock() l.selectedBackgroundColor = color - return l } // SetSelectedFocusOnly sets a flag which determines when the currently selected // list item is highlighted. If set to true, selected items are only highlighted // when the list has focus. If set to false, they are always highlighted. -func (l *List) SetSelectedFocusOnly(focusOnly bool) *List { +func (l *List) SetSelectedFocusOnly(focusOnly bool) { l.Lock() defer l.Unlock() l.selectedFocusOnly = focusOnly - return l } // SetSelectedAlwaysVisible sets a flag which determines whether the currently // selected list item must remain visible when scrolling. -func (l *List) SetSelectedAlwaysVisible(alwaysVisible bool) *List { +func (l *List) SetSelectedAlwaysVisible(alwaysVisible bool) { l.Lock() defer l.Unlock() l.selectedAlwaysVisible = alwaysVisible - return l } // SetSelectedAlwaysCentered sets a flag which determines whether the currently // selected list item must remain centered when scrolling. -func (l *List) SetSelectedAlwaysCentered(alwaysCentered bool) *List { +func (l *List) SetSelectedAlwaysCentered(alwaysCentered bool) { l.Lock() defer l.Unlock() l.selectedAlwaysCentered = alwaysCentered - return l } // SetHighlightFullLine sets a flag which determines whether the colored // background of selected items spans the entire width of the view. If set to // true, the highlight spans the entire view. If set to false, only the text of // the selected item from beginning to end is highlighted. -func (l *List) SetHighlightFullLine(highlight bool) *List { +func (l *List) SetHighlightFullLine(highlight bool) { l.Lock() defer l.Unlock() l.highlightFullLine = highlight - return l } // ShowSecondaryText determines whether or not to show secondary item texts. -func (l *List) ShowSecondaryText(show bool) *List { +func (l *List) ShowSecondaryText(show bool) { l.Lock() defer l.Unlock() l.showSecondaryText = show - return l + return } // SetScrollBarVisibility specifies the display of the scroll bar. -func (l *List) SetScrollBarVisibility(visibility ScrollBarVisibility) *List { +func (l *List) SetScrollBarVisibility(visibility ScrollBarVisibility) { l.Lock() defer l.Unlock() l.scrollBarVisibility = visibility - return l } // SetScrollBarColor sets the color of the scroll bar. -func (l *List) SetScrollBarColor(color tcell.Color) *List { +func (l *List) SetScrollBarColor(color tcell.Color) { l.Lock() defer l.Unlock() l.scrollBarColor = color - return l } // SetHover sets the flag that determines whether hovering over an item will // highlight it (without triggering callbacks set with SetSelectedFunc). -func (l *List) SetHover(hover bool) *List { +func (l *List) SetHover(hover bool) { l.Lock() defer l.Unlock() l.hover = hover - return l } // SetWrapAround sets the flag that determines whether navigating the list will @@ -500,12 +478,11 @@ func (l *List) SetHover(hover bool) *List { // selection to the first item (similarly in the other direction). If set to // false, the selection won't change when navigating downwards on the last item // or navigating upwards on the first item. -func (l *List) SetWrapAround(wrapAround bool) *List { +func (l *List) SetWrapAround(wrapAround bool) { l.Lock() defer l.Unlock() l.wrapAround = wrapAround - return l } // SetChangedFunc sets the function which is called when the user navigates to @@ -514,39 +491,35 @@ func (l *List) SetWrapAround(wrapAround bool) *List { // // This function is also called when the first item is added or when // SetCurrentItem() is called. -func (l *List) SetChangedFunc(handler func(index int, item *ListItem)) *List { +func (l *List) SetChangedFunc(handler func(index int, item *ListItem)) { l.Lock() defer l.Unlock() l.changed = handler - return l } // SetSelectedFunc sets the function which is called when the user selects a // list item by pressing Enter on the current selection. The function receives // the item's index in the list of items (starting with 0) and its struct. -func (l *List) SetSelectedFunc(handler func(int, *ListItem)) *List { +func (l *List) SetSelectedFunc(handler func(int, *ListItem)) { l.Lock() defer l.Unlock() l.selected = handler - return l } // SetDoneFunc sets a function which is called when the user presses the Escape // key. -func (l *List) SetDoneFunc(handler func()) *List { +func (l *List) SetDoneFunc(handler func()) { l.Lock() defer l.Unlock() l.done = handler - return l } // AddItem calls InsertItem() with an index of -1. -func (l *List) AddItem(item *ListItem) *List { +func (l *List) AddItem(item *ListItem) { l.InsertItem(-1, item) - return l } // InsertItem adds a new item to the list at the specified index. An index of 0 @@ -571,7 +544,7 @@ func (l *List) AddItem(item *ListItem) *List { // The currently selected item will shift its position accordingly. If the list // was previously empty, a "changed" event is fired because the new item becomes // selected. -func (l *List) InsertItem(index int, item *ListItem) *List { +func (l *List) InsertItem(index int, item *ListItem) { l.Lock() item.enabled = true @@ -606,8 +579,6 @@ func (l *List) InsertItem(index int, item *ListItem) *List { } else { l.Unlock() } - - return l } // GetItem returns the ListItem at the given index. @@ -637,25 +608,23 @@ func (l *List) GetItemText(index int) (main, secondary string) { // SetItemText sets an item's main and secondary text. Panics if the index is // out of range. -func (l *List) SetItemText(index int, main, secondary string) *List { +func (l *List) SetItemText(index int, main, secondary string) { l.Lock() defer l.Unlock() item := l.items[index] item.mainText = []byte(main) item.secondaryText = []byte(secondary) - return l } // SetItemEnabled sets whether an item is selectable. Panics if the index is // out of range. -func (l *List) SetItemEnabled(index int, enabled bool) *List { +func (l *List) SetItemEnabled(index int, enabled bool) { l.Lock() defer l.Unlock() item := l.items[index] item.enabled = enabled - return l } // FindItems searches the main and secondary texts for the given strings and @@ -705,14 +674,13 @@ func (l *List) FindItems(mainSearch, secondarySearch string, mustContainBoth, ig } // Clear removes all items from the list. -func (l *List) Clear() *List { +func (l *List) Clear() { l.Lock() defer l.Unlock() l.items = nil l.currentItem = 0 l.offset = 0 - return l } // Focus is called by the application when the primitive receives focus. diff --git a/list_test.go b/list_test.go index 4f2f2ae..5c752dc 100644 --- a/list_test.go +++ b/list_test.go @@ -24,7 +24,10 @@ func TestList(t *testing.T) { // Add item 0 - l.AddItem(NewListItem(listTextA).SetSecondaryText(listTextB).SetShortcut('a')) + itemA := NewListItem(listTextA) + itemA.SetSecondaryText(listTextB) + itemA.SetShortcut('a') + l.AddItem(itemA) if l.GetItemCount() != 1 { t.Errorf("failed to update List: expected item count 1, got %d", l.GetItemCount()) } else if l.GetCurrentItemIndex() != 0 { @@ -42,7 +45,10 @@ func TestList(t *testing.T) { // Add item 1 - l.AddItem(NewListItem(listTextB).SetSecondaryText(listTextC).SetShortcut('a')) + itemB := NewListItem(listTextB) + itemB.SetSecondaryText(listTextC) + itemB.SetShortcut('a') + l.AddItem(itemB) if l.GetItemCount() != 2 { t.Errorf("failed to update List: expected item count 1, got %v", l.GetItemCount()) } else if l.GetCurrentItemIndex() != 0 { diff --git a/modal.go b/modal.go index fb51caa..eb4d8e3 100644 --- a/modal.go +++ b/modal.go @@ -40,82 +40,81 @@ func NewModal() *Modal { Box: NewBox(), textColor: Styles.PrimaryTextColor, } - m.form = NewForm(). - SetButtonsAlign(AlignCenter). - SetButtonBackgroundColor(Styles.PrimitiveBackgroundColor). - SetButtonTextColor(Styles.PrimaryTextColor) - m.form.SetBackgroundColor(Styles.ContrastBackgroundColor).SetBorderPadding(0, 0, 0, 0) + + m.form = NewForm() + m.form.SetButtonsAlign(AlignCenter) + m.form.SetButtonBackgroundColor(Styles.PrimitiveBackgroundColor) + m.form.SetButtonTextColor(Styles.PrimaryTextColor) + m.form.SetBackgroundColor(Styles.ContrastBackgroundColor) + m.form.SetBorderPadding(0, 0, 0, 0) m.form.SetCancelFunc(func() { if m.done != nil { m.done(-1, "") } }) - m.frame = NewFrame(m.form).SetBorders(0, 0, 1, 0, 0, 0) - m.frame.SetBorder(true). - SetBackgroundColor(Styles.ContrastBackgroundColor). - SetBorderPadding(1, 1, 1, 1) + + m.frame = NewFrame(m.form) + m.frame.SetBorder(true) + m.frame.SetBorders(0, 0, 1, 0, 0, 0) + m.frame.SetBackgroundColor(Styles.ContrastBackgroundColor) + m.frame.SetBorderPadding(1, 1, 1, 1) + m.focus = m return m } // SetBackgroundColor sets the color of the Modal Frame background. -func (m *Modal) SetBackgroundColor(color tcell.Color) *Modal { +func (m *Modal) SetBackgroundColor(color tcell.Color) { m.Lock() defer m.Unlock() m.form.SetBackgroundColor(color) m.frame.SetBackgroundColor(color) - return m } // SetTextColor sets the color of the message text. -func (m *Modal) SetTextColor(color tcell.Color) *Modal { +func (m *Modal) SetTextColor(color tcell.Color) { m.Lock() defer m.Unlock() m.textColor = color - return m } // SetButtonBackgroundColor sets the background color of the buttons. -func (m *Modal) SetButtonBackgroundColor(color tcell.Color) *Modal { +func (m *Modal) SetButtonBackgroundColor(color tcell.Color) { m.Lock() defer m.Unlock() m.form.SetButtonBackgroundColor(color) - return m } // SetButtonTextColor sets the color of the button texts. -func (m *Modal) SetButtonTextColor(color tcell.Color) *Modal { +func (m *Modal) SetButtonTextColor(color tcell.Color) { m.Lock() defer m.Unlock() m.form.SetButtonTextColor(color) - return m } // SetDoneFunc sets a handler which is called when one of the buttons was // pressed. It receives the index of the button as well as its label text. The // handler is also called when the user presses the Escape key. The index will // then be negative and the label text an empty string. -func (m *Modal) SetDoneFunc(handler func(buttonIndex int, buttonLabel string)) *Modal { +func (m *Modal) SetDoneFunc(handler func(buttonIndex int, buttonLabel string)) { m.Lock() defer m.Unlock() m.done = handler - return m } // SetText sets the message text of the window. The text may contain line // breaks. Note that words are wrapped, too, based on the final size of the // window. -func (m *Modal) SetText(text string) *Modal { +func (m *Modal) SetText(text string) { m.Lock() defer m.Unlock() m.text = text - return m } // GetForm returns the Form embedded in the window. The returned Form may be @@ -137,7 +136,7 @@ func (m *Modal) GetFrame() *Frame { // AddButtons adds buttons to the window. There must be at least one button and // a "done" handler so the window can be closed again. -func (m *Modal) AddButtons(labels []string) *Modal { +func (m *Modal) AddButtons(labels []string) { m.Lock() defer m.Unlock() @@ -160,25 +159,22 @@ func (m *Modal) AddButtons(labels []string) *Modal { }) }(index, label) } - return m } // ClearButtons removes all buttons from the window. -func (m *Modal) ClearButtons() *Modal { +func (m *Modal) ClearButtons() { m.Lock() defer m.Unlock() m.form.ClearButtons() - return m } // SetFocus shifts the focus to the button with the given index. -func (m *Modal) SetFocus(index int) *Modal { +func (m *Modal) SetFocus(index int) { m.Lock() defer m.Unlock() m.form.SetFocus(index) - return m } // Focus is called when this primitive receives focus. diff --git a/pages.go b/pages.go index f4e22c8..b3f2b7b 100644 --- a/pages.go +++ b/pages.go @@ -45,12 +45,11 @@ func NewPages() *Pages { // SetChangedFunc sets a handler which is called whenever the visibility or the // order of any visible pages changes. This can be used to redraw the pages. -func (p *Pages) SetChangedFunc(handler func()) *Pages { +func (p *Pages) SetChangedFunc(handler func()) { p.Lock() defer p.Unlock() p.changed = handler - return p } // GetPageCount returns the number of pages currently stored in this object. @@ -70,7 +69,7 @@ func (p *Pages) GetPageCount() int { // was changed in one of the other functions). If "resize" is set to true, the // primitive will be set to the size available to the Pages primitive whenever // the pages are drawn. -func (p *Pages) AddPage(name string, item Primitive, resize, visible bool) *Pages { +func (p *Pages) AddPage(name string, item Primitive, resize, visible bool) { hasFocus := p.HasFocus() p.Lock() @@ -93,20 +92,18 @@ func (p *Pages) AddPage(name string, item Primitive, resize, visible bool) *Page p.Focus(p.setFocus) p.Lock() } - return p } // AddAndSwitchToPage calls AddPage(), then SwitchToPage() on that newly added // page. -func (p *Pages) AddAndSwitchToPage(name string, item Primitive, resize bool) *Pages { +func (p *Pages) AddAndSwitchToPage(name string, item Primitive, resize bool) { p.AddPage(name, item, resize, true) p.SwitchToPage(name) - return p } // RemovePage removes the page with the given name. If that page was the only // visible page, visibility is assigned to the last page. -func (p *Pages) RemovePage(name string) *Pages { +func (p *Pages) RemovePage(name string) { hasFocus := p.HasFocus() p.Lock() @@ -141,7 +138,6 @@ func (p *Pages) RemovePage(name string) *Pages { p.Focus(p.setFocus) p.Lock() } - return p } // HasPage returns true if a page with the given name exists in this object. @@ -159,7 +155,7 @@ func (p *Pages) HasPage(name string) bool { // ShowPage sets a page's visibility to "true" (in addition to any other pages // which are already visible). -func (p *Pages) ShowPage(name string) *Pages { +func (p *Pages) ShowPage(name string) { hasFocus := p.HasFocus() p.Lock() @@ -181,11 +177,10 @@ func (p *Pages) ShowPage(name string) *Pages { p.Focus(p.setFocus) p.Lock() } - return p } // HidePage sets a page's visibility to "false". -func (p *Pages) HidePage(name string) *Pages { +func (p *Pages) HidePage(name string) { hasFocus := p.HasFocus() p.Lock() @@ -207,12 +202,11 @@ func (p *Pages) HidePage(name string) *Pages { p.Focus(p.setFocus) p.Lock() } - return p } // SwitchToPage sets a page's visibility to "true" and all other pages' // visibility to "false". -func (p *Pages) SwitchToPage(name string) *Pages { +func (p *Pages) SwitchToPage(name string) { hasFocus := p.HasFocus() p.Lock() @@ -235,13 +229,12 @@ func (p *Pages) SwitchToPage(name string) *Pages { p.Focus(p.setFocus) p.Lock() } - return p } // SendToFront changes the order of the pages such that the page with the given // name comes last, causing it to be drawn last with the next update (if // visible). -func (p *Pages) SendToFront(name string) *Pages { +func (p *Pages) SendToFront(name string) { hasFocus := p.HasFocus() p.Lock() @@ -265,13 +258,12 @@ func (p *Pages) SendToFront(name string) *Pages { p.Focus(p.setFocus) p.Lock() } - return p } // SendToBack changes the order of the pages such that the page with the given // name comes first, causing it to be drawn first with the next update (if // visible). -func (p *Pages) SendToBack(name string) *Pages { +func (p *Pages) SendToBack(name string) { hasFocus := p.HasFocus() p.Lock() @@ -295,7 +287,6 @@ func (p *Pages) SendToBack(name string) *Pages { p.Focus(p.setFocus) p.Lock() } - return p } // GetFrontPage returns the front-most visible page. If there are no visible diff --git a/progressbar.go b/progressbar.go index eb8b650..6badba6 100644 --- a/progressbar.go +++ b/progressbar.go @@ -38,14 +38,16 @@ type ProgressBar struct { // NewProgressBar returns a new progress bar. func NewProgressBar() *ProgressBar { - return &ProgressBar{ - Box: NewBox().SetBackgroundColor(Styles.PrimitiveBackgroundColor), + p := &ProgressBar{ + Box: NewBox(), emptyRune: ' ', emptyColor: Styles.PrimitiveBackgroundColor, filledRune: tcell.RuneBlock, filledColor: Styles.PrimaryTextColor, max: 100, } + p.SetBackgroundColor(Styles.PrimitiveBackgroundColor) + return p } // SetEmptyRune sets the rune used for the empty area of the progress bar. diff --git a/table.go b/table.go index 1ff6099..50c7442 100644 --- a/table.go +++ b/table.go @@ -63,17 +63,16 @@ func NewTableCell(text string) *TableCell { } // SetBytes sets the cell's text. -func (c *TableCell) SetBytes(text []byte) *TableCell { +func (c *TableCell) SetBytes(text []byte) { c.Lock() defer c.Unlock() c.Text = text - return c } // SetText sets the cell's text. -func (c *TableCell) SetText(text string) *TableCell { - return c.SetBytes([]byte(text)) +func (c *TableCell) SetText(text string) { + c.SetBytes([]byte(text)) } // GetBytes returns the cell's text. @@ -91,23 +90,21 @@ func (c *TableCell) GetText() string { // SetAlign sets the cell's text alignment, one of AlignLeft, AlignCenter, or // AlignRight. -func (c *TableCell) SetAlign(align int) *TableCell { +func (c *TableCell) SetAlign(align int) { c.Lock() defer c.Unlock() c.Align = align - return c } // SetMaxWidth sets maximum width of the cell in screen space. This is used to // give a column a maximum width. Any cell text whose screen width exceeds this // width is cut off. Set to 0 if there is no maximum width. -func (c *TableCell) SetMaxWidth(maxWidth int) *TableCell { +func (c *TableCell) SetMaxWidth(maxWidth int) { c.Lock() defer c.Unlock() c.MaxWidth = maxWidth - return c } // SetExpansion sets the value by which the column of this cell expands if the @@ -123,7 +120,7 @@ func (c *TableCell) SetMaxWidth(maxWidth int) *TableCell { // in that column is used. // // This function panics if a negative value is provided. -func (c *TableCell) SetExpansion(expansion int) *TableCell { +func (c *TableCell) SetExpansion(expansion int) { c.Lock() defer c.Unlock() @@ -131,68 +128,61 @@ func (c *TableCell) SetExpansion(expansion int) *TableCell { panic("Table cell expansion values may not be negative") } c.Expansion = expansion - return c } // SetTextColor sets the cell's text color. -func (c *TableCell) SetTextColor(color tcell.Color) *TableCell { +func (c *TableCell) SetTextColor(color tcell.Color) { c.Lock() defer c.Unlock() c.Color = color - return c } // SetBackgroundColor sets the cell's background color. Set to // tcell.ColorDefault to use the table's background color. -func (c *TableCell) SetBackgroundColor(color tcell.Color) *TableCell { +func (c *TableCell) SetBackgroundColor(color tcell.Color) { c.Lock() defer c.Unlock() c.BackgroundColor = color - return c } // SetAttributes sets the cell's text attributes. You can combine different // attributes using bitmask operations: // // cell.SetAttributes(tcell.AttrUnderline | tcell.AttrBold) -func (c *TableCell) SetAttributes(attr tcell.AttrMask) *TableCell { +func (c *TableCell) SetAttributes(attr tcell.AttrMask) { c.Lock() defer c.Unlock() c.Attributes = attr - return c } // SetStyle sets the cell's style (foreground color, background color, and // attributes) all at once. -func (c *TableCell) SetStyle(style tcell.Style) *TableCell { +func (c *TableCell) SetStyle(style tcell.Style) { c.Lock() defer c.Unlock() c.Color, c.BackgroundColor, c.Attributes = style.Decompose() - return c } // SetSelectable sets whether or not this cell can be selected by the user. -func (c *TableCell) SetSelectable(selectable bool) *TableCell { +func (c *TableCell) SetSelectable(selectable bool) { c.Lock() defer c.Unlock() c.NotSelectable = !selectable - return c } // SetReference allows you to store a reference of any type in this cell. This // will allow you to establish a mapping between the cell and your // actual data. -func (c *TableCell) SetReference(reference interface{}) *TableCell { +func (c *TableCell) SetReference(reference interface{}) { c.Lock() defer c.Unlock() c.Reference = reference - return c } // GetReference returns this cell's reference object. @@ -367,50 +357,45 @@ func NewTable() *Table { } // Clear removes all table data. -func (t *Table) Clear() *Table { +func (t *Table) Clear() { t.Lock() defer t.Unlock() t.cells = nil t.lastColumn = -1 - return t } // SetBorders sets whether or not each cell in the table is surrounded by a // border. -func (t *Table) SetBorders(show bool) *Table { +func (t *Table) SetBorders(show bool) { t.Lock() defer t.Unlock() t.borders = show - return t } // SetBordersColor sets the color of the cell borders. -func (t *Table) SetBordersColor(color tcell.Color) *Table { +func (t *Table) SetBordersColor(color tcell.Color) { t.Lock() defer t.Unlock() t.bordersColor = color - return t } // SetScrollBarVisibility specifies the display of the scroll bar. -func (t *Table) SetScrollBarVisibility(visibility ScrollBarVisibility) *Table { +func (t *Table) SetScrollBarVisibility(visibility ScrollBarVisibility) { t.Lock() defer t.Unlock() t.scrollBarVisibility = visibility - return t } // SetScrollBarColor sets the color of the scroll bar. -func (t *Table) SetScrollBarColor(color tcell.Color) *Table { +func (t *Table) SetScrollBarColor(color tcell.Color) { t.Lock() defer t.Unlock() t.scrollBarColor = color - return t } // SetSelectedStyle sets a specific style for selected cells. If no such style @@ -420,12 +405,11 @@ func (t *Table) SetScrollBarColor(color tcell.Color) *Table { // To reset a previous setting to its default, make the following call: // // table.SetSelectedStyle(tcell.ColorDefault, tcell.ColorDefault, 0) -func (t *Table) SetSelectedStyle(foregroundColor, backgroundColor tcell.Color, attributes tcell.AttrMask) *Table { +func (t *Table) SetSelectedStyle(foregroundColor, backgroundColor tcell.Color, attributes tcell.AttrMask) { t.Lock() defer t.Unlock() t.selectedStyle = SetAttributes(tcell.StyleDefault.Foreground(foregroundColor).Background(backgroundColor), attributes) - return t } // SetSeparator sets the character used to fill the space between two @@ -435,23 +419,21 @@ func (t *Table) SetSelectedStyle(foregroundColor, backgroundColor tcell.Color, a // ignored. // // Separators have the same color as borders. -func (t *Table) SetSeparator(separator rune) *Table { +func (t *Table) SetSeparator(separator rune) { t.Lock() defer t.Unlock() t.separator = separator - return t } // SetFixed sets the number of fixed rows and columns which are always visible // even when the rest of the cells are scrolled out of view. Rows are always the // top-most ones. Columns are always the left-most ones. -func (t *Table) SetFixed(rows, columns int) *Table { +func (t *Table) SetFixed(rows, columns int) { t.Lock() defer t.Unlock() t.fixedRows, t.fixedColumns = rows, columns - return t } // SetSelectable sets the flags which determine what can be selected in a table. @@ -461,12 +443,11 @@ func (t *Table) SetFixed(rows, columns int) *Table { // - rows = true, columns = false: Rows can be selected. // - rows = false, columns = true: Columns can be selected. // - rows = true, columns = true: Individual cells can be selected. -func (t *Table) SetSelectable(rows, columns bool) *Table { +func (t *Table) SetSelectable(rows, columns bool) { t.Lock() defer t.Unlock() t.rowsSelectable, t.columnsSelectable = rows, columns - return t } // GetSelectable returns what can be selected in a table. Refer to @@ -493,7 +474,7 @@ func (t *Table) GetSelection() (row, column int) { // ignored completely. The "selection changed" event is fired if such a callback // is available (even if the selection ends up being the same as before and even // if cells are not selectable). -func (t *Table) Select(row, column int) *Table { +func (t *Table) Select(row, column int) { t.Lock() defer t.Unlock() @@ -503,7 +484,6 @@ func (t *Table) Select(row, column int) *Table { t.selectionChanged(row, column) t.Lock() } - return t } // SetOffset sets how many rows and columns should be skipped when drawing the @@ -511,13 +491,12 @@ func (t *Table) Select(row, column int) *Table { // Navigating a selection can change these values. // // Fixed rows and columns are never skipped. -func (t *Table) SetOffset(row, column int) *Table { +func (t *Table) SetOffset(row, column int) { t.Lock() defer t.Unlock() t.rowOffset, t.columnOffset = row, column t.trackEnd = false - return t } // GetOffset returns the current row and column offset. This indicates how many @@ -535,48 +514,44 @@ func (t *Table) GetOffset() (row, column int) { // // Set this flag to true to avoid shifting column widths when the table is // scrolled. (May be slower for large tables.) -func (t *Table) SetEvaluateAllRows(all bool) *Table { +func (t *Table) SetEvaluateAllRows(all bool) { t.Lock() defer t.Unlock() t.evaluateAllRows = all - return t } // SetSelectedFunc sets a handler which is called whenever the user presses the // Enter key on a selected cell/row/column. The handler receives the position of // the selection and its cell contents. If entire rows are selected, the column // index is undefined. Likewise for entire columns. -func (t *Table) SetSelectedFunc(handler func(row, column int)) *Table { +func (t *Table) SetSelectedFunc(handler func(row, column int)) { t.Lock() defer t.Unlock() t.selected = handler - return t } // SetSelectionChangedFunc sets a handler which is called whenever the current // selection changes. The handler receives the position of the new selection. // If entire rows are selected, the column index is undefined. Likewise for // entire columns. -func (t *Table) SetSelectionChangedFunc(handler func(row, column int)) *Table { +func (t *Table) SetSelectionChangedFunc(handler func(row, column int)) { t.Lock() defer t.Unlock() t.selectionChanged = handler - return t } // SetDoneFunc sets a handler which is called whenever the user presses the // Escape, Tab, or Backtab key. If nothing is selected, it is also called when // user presses the Enter key (because pressing Enter on a selection triggers // the "selected" handler set via SetSelectedFunc()). -func (t *Table) SetDoneFunc(handler func(key tcell.Key)) *Table { +func (t *Table) SetDoneFunc(handler func(key tcell.Key)) { t.Lock() defer t.Unlock() t.done = handler - return t } // SetCell sets the content of a cell the specified position. It is ok to @@ -588,7 +563,7 @@ func (t *Table) SetDoneFunc(handler func(key tcell.Key)) *Table { // a row of 100,000 will immediately create 100,000 empty rows. // // To avoid unnecessary garbage collection, fill columns from left to right. -func (t *Table) SetCell(row, column int, cell *TableCell) *Table { +func (t *Table) SetCell(row, column int, cell *TableCell) { t.Lock() defer t.Unlock() @@ -606,12 +581,11 @@ func (t *Table) SetCell(row, column int, cell *TableCell) *Table { if column > t.lastColumn { t.lastColumn = column } - return t } // SetCellSimple calls SetCell() with the given text, left-aligned, in white. -func (t *Table) SetCellSimple(row, column int, text string) *Table { - return t.SetCell(row, column, NewTableCell(text)) +func (t *Table) SetCellSimple(row, column int, text string) { + t.SetCell(row, column, NewTableCell(text)) } // GetCell returns the contents of the cell at the specified position. A valid @@ -631,22 +605,20 @@ func (t *Table) GetCell(row, column int) *TableCell { // RemoveRow removes the row at the given position from the table. If there is // no such row, this has no effect. -func (t *Table) RemoveRow(row int) *Table { +func (t *Table) RemoveRow(row int) { t.Lock() defer t.Unlock() if row < 0 || row >= len(t.cells) { - return t + return } t.cells = append(t.cells[:row], t.cells[row+1:]...) - - return t } // RemoveColumn removes the column at the given position from the table. If // there is no such column, this has no effect. -func (t *Table) RemoveColumn(column int) *Table { +func (t *Table) RemoveColumn(column int) { t.Lock() defer t.Unlock() @@ -656,31 +628,28 @@ func (t *Table) RemoveColumn(column int) *Table { } t.cells[row] = append(t.cells[row][:column], t.cells[row][column+1:]...) } - - return t } // InsertRow inserts a row before the row with the given index. Cells on the // given row and below will be shifted to the bottom by one row. If "row" is // equal or larger than the current number of rows, this function has no effect. -func (t *Table) InsertRow(row int) *Table { +func (t *Table) InsertRow(row int) { t.Lock() defer t.Unlock() if row >= len(t.cells) { - return t + return } t.cells = append(t.cells, nil) // Extend by one. copy(t.cells[row+1:], t.cells[row:]) // Shift down. t.cells[row] = nil // New row is uninitialized. - return t } // InsertColumn inserts a column before the column with the given index. Cells // in the given column and to its right will be shifted to the right by one // column. Rows that have fewer initialized cells than "column" will remain // unchanged. -func (t *Table) InsertColumn(column int) *Table { +func (t *Table) InsertColumn(column int) { t.Lock() defer t.Unlock() @@ -692,7 +661,6 @@ func (t *Table) InsertColumn(column int) *Table { copy(t.cells[row][column+1:], t.cells[row][column:]) // Shift to the right. t.cells[row][column] = &TableCell{} // New element is an uninitialized table cell. } - return t } // GetRowCount returns the number of rows in the table. @@ -760,58 +728,54 @@ func (t *Table) cellAt(x, y int) (row, column int) { // ScrollToBeginning scrolls the table to the beginning to that the top left // corner of the table is shown. Note that this position may be corrected if // there is a selection. -func (t *Table) ScrollToBeginning() *Table { +func (t *Table) ScrollToBeginning() { t.Lock() defer t.Unlock() t.trackEnd = false t.columnOffset = 0 t.rowOffset = 0 - return t } // ScrollToEnd scrolls the table to the beginning to that the bottom left corner // of the table is shown. Adding more rows to the table will cause it to // automatically scroll with the new data. Note that this position may be // corrected if there is a selection. -func (t *Table) ScrollToEnd() *Table { +func (t *Table) ScrollToEnd() { t.Lock() defer t.Unlock() t.trackEnd = true t.columnOffset = 0 t.rowOffset = len(t.cells) - return t } // SetSortClicked sets a flag which determines whether the table is sorted when // a fixed row is clicked. This flag is enabled by default. -func (t *Table) SetSortClicked(sortClicked bool) *Table { +func (t *Table) SetSortClicked(sortClicked bool) { t.Lock() defer t.Unlock() t.sortClicked = sortClicked - return t } // SetSortFunc sets the sorting function used for the table. When unset, a // case-sensitive string comparison is used. -func (t *Table) SetSortFunc(sortFunc func(column, i, j int) bool) *Table { +func (t *Table) SetSortFunc(sortFunc func(column, i, j int) bool) { t.Lock() defer t.Unlock() t.sortFunc = sortFunc - return t } // Sort sorts the table by the column at the given index. You may set a custom // sorting function with SetSortFunc. -func (t *Table) Sort(column int, descending bool) *Table { +func (t *Table) Sort(column int, descending bool) { t.Lock() defer t.Unlock() if len(t.cells) == 0 || column < 0 || column >= len(t.cells[0]) { - return t + return } if t.sortFunc == nil { @@ -832,8 +796,6 @@ func (t *Table) Sort(column int, descending bool) *Table { } return t.sortFunc(column, j, i) }) - - return t } // Draw draws this primitive onto the screen. diff --git a/textview.go b/textview.go index 86500f4..4201a91 100644 --- a/textview.go +++ b/textview.go @@ -221,7 +221,7 @@ func NewTextView() *TextView { // SetScrollable sets the flag that decides whether or not the text view is // scrollable. If true, text is kept in a buffer and can be navigated. If false, // the last line will always be visible. -func (t *TextView) SetScrollable(scrollable bool) *TextView { +func (t *TextView) SetScrollable(scrollable bool) { t.Lock() defer t.Unlock() @@ -229,31 +229,28 @@ func (t *TextView) SetScrollable(scrollable bool) *TextView { if !scrollable { t.trackEnd = true } - return t } // SetScrollBarVisibility specifies the display of the scroll bar. -func (t *TextView) SetScrollBarVisibility(visibility ScrollBarVisibility) *TextView { +func (t *TextView) SetScrollBarVisibility(visibility ScrollBarVisibility) { t.Lock() defer t.Unlock() t.scrollBarVisibility = visibility - return t } // SetScrollBarColor sets the color of the scroll bar. -func (t *TextView) SetScrollBarColor(color tcell.Color) *TextView { +func (t *TextView) SetScrollBarColor(color tcell.Color) { t.Lock() defer t.Unlock() t.scrollBarColor = color - return t } // SetWrap sets the flag that, if true, leads to lines that are longer than the // available width being wrapped onto the next line. If false, any characters // beyond the available width are not displayed. -func (t *TextView) SetWrap(wrap bool) *TextView { +func (t *TextView) SetWrap(wrap bool) { t.Lock() defer t.Unlock() @@ -261,7 +258,6 @@ func (t *TextView) SetWrap(wrap bool) *TextView { t.index = nil } t.wrap = wrap - return t } // SetWordWrap sets the flag that, if true and if the "wrap" flag is also true @@ -269,7 +265,7 @@ func (t *TextView) SetWrap(wrap bool) *TextView { // that trailing spaces will not be printed. // // This flag is ignored if the "wrap" flag is false. -func (t *TextView) SetWordWrap(wrapOnWords bool) *TextView { +func (t *TextView) SetWordWrap(wrapOnWords bool) { t.Lock() defer t.Unlock() @@ -277,12 +273,11 @@ func (t *TextView) SetWordWrap(wrapOnWords bool) *TextView { t.index = nil } t.wordWrap = wrapOnWords - return t } // SetTextAlign sets the text alignment within the text view. This must be // either AlignLeft, AlignCenter, or AlignRight. -func (t *TextView) SetTextAlign(align int) *TextView { +func (t *TextView) SetTextAlign(align int) { t.Lock() defer t.Unlock() @@ -290,35 +285,32 @@ func (t *TextView) SetTextAlign(align int) *TextView { t.index = nil } t.align = align - return t } // SetTextColor sets the initial color of the text (which can be changed // dynamically by sending color strings in square brackets to the text view if // dynamic colors are enabled). -func (t *TextView) SetTextColor(color tcell.Color) *TextView { +func (t *TextView) SetTextColor(color tcell.Color) { t.Lock() defer t.Unlock() t.textColor = color - return t } // SetBytes sets the text of this text view to the provided byte slice. // Previously contained text will be removed. -func (t *TextView) SetBytes(text []byte) *TextView { +func (t *TextView) SetBytes(text []byte) { t.Lock() defer t.Unlock() t.clear() t.write(text) - return t } // SetText sets the text of this text view to the provided string. Previously // contained text will be removed. -func (t *TextView) SetText(text string) *TextView { - return t.SetBytes([]byte(text)) +func (t *TextView) SetText(text string) { + t.SetBytes([]byte(text)) } // GetBytes returns the current text of this text view. If "stripTags" is set @@ -360,7 +352,7 @@ func (t *TextView) GetText(stripTags bool) string { // SetDynamicColors sets the flag that allows the text color to be changed // dynamically. See class description for details. -func (t *TextView) SetDynamicColors(dynamic bool) *TextView { +func (t *TextView) SetDynamicColors(dynamic bool) { t.Lock() defer t.Unlock() @@ -368,12 +360,11 @@ func (t *TextView) SetDynamicColors(dynamic bool) *TextView { t.index = nil } t.dynamicColors = dynamic - return t } // SetRegions sets the flag that allows to define regions in the text. See class // description for details. -func (t *TextView) SetRegions(regions bool) *TextView { +func (t *TextView) SetRegions(regions bool) { t.Lock() defer t.Unlock() @@ -381,7 +372,6 @@ func (t *TextView) SetRegions(regions bool) *TextView { t.index = nil } t.regions = regions - return t } // SetChangedFunc sets a handler function which is called when the text of the @@ -400,23 +390,21 @@ func (t *TextView) SetRegions(regions bool) *TextView { // Application.QueueUpdate(). // // See package description for details on dealing with concurrency. -func (t *TextView) SetChangedFunc(handler func()) *TextView { +func (t *TextView) SetChangedFunc(handler func()) { t.Lock() defer t.Unlock() t.changed = handler - return t } // SetDoneFunc sets a handler which is called when the user presses on the // following keys: Escape, Enter, Tab, Backtab. The key is passed to the // handler. -func (t *TextView) SetDoneFunc(handler func(key tcell.Key)) *TextView { +func (t *TextView) SetDoneFunc(handler func(key tcell.Key)) { t.Lock() defer t.Unlock() t.done = handler - return t } // SetHighlightedFunc sets a handler which is called when the list of currently @@ -426,9 +414,8 @@ func (t *TextView) SetDoneFunc(handler func(key tcell.Key)) *TextView { // // Note that because regions are only determined during drawing, this function // can only fire for regions that have existed during the last call to Draw(). -func (t *TextView) SetHighlightedFunc(handler func(added, removed, remaining []string)) *TextView { +func (t *TextView) SetHighlightedFunc(handler func(added, removed, remaining []string)) { t.highlighted = handler - return t } func (t *TextView) clipBuffer() { @@ -444,54 +431,50 @@ func (t *TextView) clipBuffer() { // SetMaxLines sets the maximum number of newlines the text view will hold // before discarding older data from the buffer. -func (t *TextView) SetMaxLines(maxLines int) *TextView { +func (t *TextView) SetMaxLines(maxLines int) { t.maxLines = maxLines t.clipBuffer() - return t } // ScrollTo scrolls to the specified row and column (both starting with 0). -func (t *TextView) ScrollTo(row, column int) *TextView { +func (t *TextView) ScrollTo(row, column int) { t.Lock() defer t.Unlock() if !t.scrollable { - return t + return } t.lineOffset = row t.columnOffset = column t.trackEnd = false - return t } // ScrollToBeginning scrolls to the top left corner of the text if the text view // is scrollable. -func (t *TextView) ScrollToBeginning() *TextView { +func (t *TextView) ScrollToBeginning() { t.Lock() defer t.Unlock() if !t.scrollable { - return t + return } t.trackEnd = false t.lineOffset = 0 t.columnOffset = 0 - return t } // ScrollToEnd scrolls to the bottom left corner of the text if the text view // is scrollable. Adding new rows to the end of the text view will cause it to // scroll with the new data. -func (t *TextView) ScrollToEnd() *TextView { +func (t *TextView) ScrollToEnd() { t.Lock() defer t.Unlock() if !t.scrollable { - return t + return } t.trackEnd = true t.columnOffset = 0 - return t } // GetScrollOffset returns the number of rows and columns that are skipped at @@ -504,20 +487,19 @@ func (t *TextView) GetScrollOffset() (row, column int) { } // Clear removes all text from the buffer. -func (t *TextView) Clear() *TextView { +func (t *TextView) Clear() { t.Lock() defer t.Unlock() - return t.clear() + t.clear() } -func (t *TextView) clear() *TextView { +func (t *TextView) clear() { t.buffer = nil t.recentBytes = nil if t.reindex { t.index = nil } - return t } // Highlight specifies which regions should be highlighted. If highlight @@ -532,7 +514,7 @@ func (t *TextView) clear() *TextView { // // Text in highlighted regions will be drawn inverted, i.e. with their // background and foreground colors swapped. -func (t *TextView) Highlight(regionIDs ...string) *TextView { +func (t *TextView) Highlight(regionIDs ...string) { t.Lock() // Toggle highlights. @@ -588,8 +570,6 @@ func (t *TextView) Highlight(regionIDs ...string) *TextView { } else { t.Unlock() } - - return t } // GetHighlights returns the IDs of all currently highlighted regions. @@ -607,9 +587,8 @@ func (t *TextView) GetHighlights() (regionIDs []string) { // When set to true, the Highlight() function (or a mouse click) will toggle the // provided/selected regions. When set to false, Highlight() (or a mouse click) // will simply highlight the provided regions. -func (t *TextView) SetToggleHighlights(toggle bool) *TextView { +func (t *TextView) SetToggleHighlights(toggle bool) { t.toggleHighlights = toggle - return t } // ScrollToHighlight will cause the visible area to be scrolled so that the @@ -620,17 +599,16 @@ func (t *TextView) SetToggleHighlights(toggle bool) *TextView { // // Nothing happens if there are no highlighted regions or if the text view is // not scrollable. -func (t *TextView) ScrollToHighlight() *TextView { +func (t *TextView) ScrollToHighlight() { t.Lock() defer t.Unlock() if len(t.highlights) == 0 || !t.scrollable || !t.regions { - return t + return } t.index = nil t.scrollToHighlights = true t.trackEnd = false - return t } // GetRegionText returns the text of the region with the given ID. If dynamic @@ -801,7 +779,7 @@ func (t *TextView) write(p []byte) (n int, err error) { // it is modified. This improves the performance of TextViews whose contents // always have line-breaks in the same location. This must be called after the // buffer has been indexed. -func (t *TextView) SetReindexBuffer(reindex bool) *TextView { +func (t *TextView) SetReindexBuffer(reindex bool) { t.Lock() defer t.Unlock() @@ -810,8 +788,6 @@ func (t *TextView) SetReindexBuffer(reindex bool) *TextView { if reindex { t.index = nil } - - return t } // reindexBuffer re-indexes the buffer such that we can use it to easily draw diff --git a/textview_test.go b/textview_test.go index 8040e90..00b9506 100644 --- a/textview_test.go +++ b/textview_test.go @@ -42,7 +42,7 @@ func TestTextViewWrite(t *testing.T) { t.Parallel() var ( - tv = tvc(NewTextView(), c) + tv = tvc(c) expectedData []byte n int err error @@ -84,7 +84,7 @@ func BenchmarkTextViewWrite(b *testing.B) { b.Run(c.String(), func(b *testing.B) { var ( - tv = tvc(NewTextView(), c) + tv = tvc(c) n int err error ) @@ -123,7 +123,7 @@ func BenchmarkTextViewIndex(b *testing.B) { b.Run(c.String(), func(b *testing.B) { var ( - tv = tvc(NewTextView(), c) + tv = tvc(c) n int err error ) @@ -195,7 +195,7 @@ func BenchmarkTextViewGetText(b *testing.B) { b.Run(c.String(), func(b *testing.B) { var ( - tv = tvc(NewTextView(), c) + tv = tvc(c) n int err error v []byte @@ -236,7 +236,7 @@ func TestTextViewDraw(t *testing.T) { t.Run(c.String(), func(t *testing.T) { t.Parallel() - tv := tvc(NewTextView(), c) + tv := tvc(c) app, err := newTestApp(tv) if err != nil { @@ -269,7 +269,7 @@ func BenchmarkTextViewDraw(b *testing.B) { c := c // Capture b.Run(c.String(), func(b *testing.B) { - tv := tvc(NewTextView(), c) + tv := tvc(c) app, err := newTestApp(tv) if err != nil { @@ -404,8 +404,14 @@ func generateRandomData() []byte { return b.Bytes() } -func tvc(tv *TextView, c *textViewTestCase) *TextView { - return tv.SetDynamicColors(c.color).SetRegions(c.region).SetScrollable(c.scroll).SetWrap(c.wrap).SetWordWrap(c.wordwrap) +func tvc(c *textViewTestCase) *TextView { + tv := NewTextView() + tv.SetDynamicColors(c.color) + tv.SetRegions(c.region) + tv.SetScrollable(c.scroll) + tv.SetWrap(c.wrap) + tv.SetWordWrap(c.wordwrap) + return tv } func cl(v bool) rune { diff --git a/treeview.go b/treeview.go index 382968b..a474d6c 100644 --- a/treeview.go +++ b/treeview.go @@ -71,14 +71,14 @@ func NewTreeNode(text string) *TreeNode { // this node) with the traversed node and its parent node (nil for this node). // The callback returns whether traversal should continue with the traversed // node's child nodes (true) or not recurse any deeper (false). -func (n *TreeNode) Walk(callback func(node, parent *TreeNode) bool) *TreeNode { +func (n *TreeNode) Walk(callback func(node, parent *TreeNode) bool) { n.Lock() defer n.Unlock() - return n.walk(callback) + n.walk(callback) } -func (n *TreeNode) walk(callback func(node, parent *TreeNode) bool) *TreeNode { +func (n *TreeNode) walk(callback func(node, parent *TreeNode) bool) { n.parent = nil nodes := []*TreeNode{n} for len(nodes) > 0 { @@ -96,19 +96,16 @@ func (n *TreeNode) walk(callback func(node, parent *TreeNode) bool) *TreeNode { nodes = append(nodes, node.children[index]) } } - - return n } // SetReference allows you to store a reference of any type in this node. This // will allow you to establish a mapping between the TreeView hierarchy and your // internal tree structure. -func (n *TreeNode) SetReference(reference interface{}) *TreeNode { +func (n *TreeNode) SetReference(reference interface{}) { n.Lock() defer n.Unlock() n.reference = reference - return n } // GetReference returns this node's reference object. @@ -120,12 +117,11 @@ func (n *TreeNode) GetReference() interface{} { } // SetChildren sets this node's child nodes. -func (n *TreeNode) SetChildren(childNodes []*TreeNode) *TreeNode { +func (n *TreeNode) SetChildren(childNodes []*TreeNode) { n.Lock() defer n.Unlock() n.children = childNodes - return n } // GetText returns this node's text. @@ -145,98 +141,88 @@ func (n *TreeNode) GetChildren() []*TreeNode { } // ClearChildren removes all child nodes from this node. -func (n *TreeNode) ClearChildren() *TreeNode { +func (n *TreeNode) ClearChildren() { n.Lock() defer n.Unlock() n.children = nil - return n } // AddChild adds a new child node to this node. -func (n *TreeNode) AddChild(node *TreeNode) *TreeNode { +func (n *TreeNode) AddChild(node *TreeNode) { n.Lock() defer n.Unlock() n.children = append(n.children, node) - return n } // SetSelectable sets a flag indicating whether this node can be focused and // selected by the user. -func (n *TreeNode) SetSelectable(selectable bool) *TreeNode { +func (n *TreeNode) SetSelectable(selectable bool) { n.Lock() defer n.Unlock() n.selectable = selectable - return n } // SetFocusedFunc sets the function which is called when the user navigates to // this node. // // This function is also called when the user selects this node. -func (n *TreeNode) SetFocusedFunc(handler func()) *TreeNode { +func (n *TreeNode) SetFocusedFunc(handler func()) { n.Lock() defer n.Unlock() n.focused = handler - return n } // SetSelectedFunc sets a function which is called when the user selects this // node by hitting Enter when it is focused. -func (n *TreeNode) SetSelectedFunc(handler func()) *TreeNode { +func (n *TreeNode) SetSelectedFunc(handler func()) { n.Lock() defer n.Unlock() n.selected = handler - return n } // SetExpanded sets whether or not this node's child nodes should be displayed. -func (n *TreeNode) SetExpanded(expanded bool) *TreeNode { +func (n *TreeNode) SetExpanded(expanded bool) { n.Lock() defer n.Unlock() n.expanded = expanded - return n } // Expand makes the child nodes of this node appear. -func (n *TreeNode) Expand() *TreeNode { +func (n *TreeNode) Expand() { n.Lock() defer n.Unlock() n.expanded = true - return n } // Collapse makes the child nodes of this node disappear. -func (n *TreeNode) Collapse() *TreeNode { +func (n *TreeNode) Collapse() { n.Lock() defer n.Unlock() n.expanded = false - return n } // ExpandAll expands this node and all descendent nodes. -func (n *TreeNode) ExpandAll() *TreeNode { +func (n *TreeNode) ExpandAll() { n.Walk(func(node, parent *TreeNode) bool { node.expanded = true return true }) - return n } // CollapseAll collapses this node and all descendent nodes. -func (n *TreeNode) CollapseAll() *TreeNode { +func (n *TreeNode) CollapseAll() { n.Walk(func(node, parent *TreeNode) bool { n.expanded = false return true }) - return n } // IsExpanded returns whether the child nodes of this node are visible. @@ -248,12 +234,11 @@ func (n *TreeNode) IsExpanded() bool { } // SetText sets the node's text which is displayed. -func (n *TreeNode) SetText(text string) *TreeNode { +func (n *TreeNode) SetText(text string) { n.Lock() defer n.Unlock() n.text = text - return n } // GetColor returns the node's color. @@ -265,23 +250,21 @@ func (n *TreeNode) GetColor() tcell.Color { } // SetColor sets the node's text color. -func (n *TreeNode) SetColor(color tcell.Color) *TreeNode { +func (n *TreeNode) SetColor(color tcell.Color) { n.Lock() defer n.Unlock() n.color = color - return n } // SetIndent sets an additional indentation for this node's text. A value of 0 // keeps the text as far left as possible with a minimum of line graphics. Any // value greater than that moves the text to the right. -func (n *TreeNode) SetIndent(indent int) *TreeNode { +func (n *TreeNode) SetIndent(indent int) { n.Lock() defer n.Unlock() n.indent = indent - return n } // TreeView displays tree structures. A tree consists of nodes (TreeNode @@ -384,12 +367,11 @@ func NewTreeView() *TreeView { } // SetRoot sets the root node of the tree. -func (t *TreeView) SetRoot(root *TreeNode) *TreeView { +func (t *TreeView) SetRoot(root *TreeNode) { t.Lock() defer t.Unlock() t.root = root - return t } // GetRoot returns the root node of the tree. If no such node was previously @@ -406,7 +388,7 @@ func (t *TreeView) GetRoot() *TreeNode { // changed to the top-most selectable and visible node. // // This function does NOT trigger the "changed" callback. -func (t *TreeView) SetCurrentNode(node *TreeNode) *TreeView { +func (t *TreeView) SetCurrentNode(node *TreeNode) { t.Lock() defer t.Unlock() @@ -416,7 +398,6 @@ func (t *TreeView) SetCurrentNode(node *TreeNode) *TreeView { t.currentNode.focused() t.Lock() } - return t } // GetCurrentNode returns the currently selected node or nil of no node is @@ -431,12 +412,11 @@ func (t *TreeView) GetCurrentNode() *TreeNode { // SetTopLevel sets the first tree level that is visible with 0 referring to the // root, 1 to the root's child nodes, and so on. Nodes above the top level are // not displayed. -func (t *TreeView) SetTopLevel(topLevel int) *TreeView { +func (t *TreeView) SetTopLevel(topLevel int) { t.Lock() defer t.Unlock() t.topLevel = topLevel - return t } // SetPrefixes defines the strings drawn before the nodes' texts. This is a @@ -448,7 +428,7 @@ func (t *TreeView) SetTopLevel(topLevel int) *TreeView { // // treeView.SetGraphics(false). // SetPrefixes([]string{"* ", "- ", "x "}) -func (t *TreeView) SetPrefixes(prefixes []string) *TreeView { +func (t *TreeView) SetPrefixes(prefixes []string) { t.Lock() defer t.Unlock() @@ -456,101 +436,90 @@ func (t *TreeView) SetPrefixes(prefixes []string) *TreeView { for i := range prefixes { t.prefixes[i] = []byte(prefixes[i]) } - return t } // SetAlign controls the horizontal alignment of the node texts. If set to true, // all texts except that of top-level nodes will be placed in the same column. // If set to false, they will indent with the hierarchy. -func (t *TreeView) SetAlign(align bool) *TreeView { +func (t *TreeView) SetAlign(align bool) { t.Lock() defer t.Unlock() t.align = align - return t } // SetGraphics sets a flag which determines whether or not line graphics are // drawn to illustrate the tree's hierarchy. -func (t *TreeView) SetGraphics(showGraphics bool) *TreeView { +func (t *TreeView) SetGraphics(showGraphics bool) { t.Lock() defer t.Unlock() t.graphics = showGraphics - return t } // SetSelectedTextColor sets the text color of selected items. -func (t *TreeView) SetSelectedTextColor(color tcell.Color) *TreeView { +func (t *TreeView) SetSelectedTextColor(color tcell.Color) { t.Lock() defer t.Unlock() t.selectedTextColor = &color - return t } // SetSelectedBackgroundColor sets the background color of selected items. -func (t *TreeView) SetSelectedBackgroundColor(color tcell.Color) *TreeView { +func (t *TreeView) SetSelectedBackgroundColor(color tcell.Color) { t.Lock() defer t.Unlock() t.selectedBackgroundColor = &color - return t } // SetGraphicsColor sets the colors of the lines used to draw the tree structure. -func (t *TreeView) SetGraphicsColor(color tcell.Color) *TreeView { +func (t *TreeView) SetGraphicsColor(color tcell.Color) { t.Lock() defer t.Unlock() t.graphicsColor = color - return t } // SetScrollBarVisibility specifies the display of the scroll bar. -func (t *TreeView) SetScrollBarVisibility(visibility ScrollBarVisibility) *TreeView { +func (t *TreeView) SetScrollBarVisibility(visibility ScrollBarVisibility) { t.Lock() defer t.Unlock() t.scrollBarVisibility = visibility - return t } // SetScrollBarColor sets the color of the scroll bar. -func (t *TreeView) SetScrollBarColor(color tcell.Color) *TreeView { +func (t *TreeView) SetScrollBarColor(color tcell.Color) { t.Lock() defer t.Unlock() t.scrollBarColor = color - return t } // SetChangedFunc sets the function which is called when the user navigates to // a new tree node. -func (t *TreeView) SetChangedFunc(handler func(node *TreeNode)) *TreeView { +func (t *TreeView) SetChangedFunc(handler func(node *TreeNode)) { t.Lock() defer t.Unlock() t.changed = handler - return t } // SetSelectedFunc sets the function which is called when the user selects a // node by pressing Enter on the current selection. -func (t *TreeView) SetSelectedFunc(handler func(node *TreeNode)) *TreeView { +func (t *TreeView) SetSelectedFunc(handler func(node *TreeNode)) { t.Lock() defer t.Unlock() t.selected = handler - return t } // SetDoneFunc sets a handler which is called whenever the user presses the // Escape, Tab, or Backtab key. -func (t *TreeView) SetDoneFunc(handler func(key tcell.Key)) *TreeView { +func (t *TreeView) SetDoneFunc(handler func(key tcell.Key)) { t.Lock() defer t.Unlock() t.done = handler - return t } // GetScrollOffset returns the number of node rows that were skipped at the top diff --git a/util_test.go b/util_test.go index b29c4dd..57b625c 100644 --- a/util_test.go +++ b/util_test.go @@ -11,8 +11,9 @@ func newTestApp(root Primitive) (*Application, error) { sc.SetSize(80, 24) // Initialize application - app := NewApplication(). - SetScreen(sc). - SetRoot(root, true) + app := NewApplication() + app.SetScreen(sc) + app.SetRoot(root, true) + return app, nil } diff --git a/window.go b/window.go index 9700d67..bbb4e52 100644 --- a/window.go +++ b/window.go @@ -36,31 +36,28 @@ func NewWindow(primitive Primitive) *Window { } // SetPosition sets the position of the window. -func (w *Window) SetPosition(x, y int) *Window { +func (w *Window) SetPosition(x, y int) { w.Lock() defer w.Unlock() w.x, w.y = x, y - return w } // SetSize sets the size of the window. -func (w *Window) SetSize(width, height int) *Window { +func (w *Window) SetSize(width, height int) { w.Lock() defer w.Unlock() w.width, w.height = width, height - return w } // SetFullscreen sets the flag indicating whether or not the the window should // be drawn fullscreen. -func (w *Window) SetFullscreen(fullscreen bool) *Window { +func (w *Window) SetFullscreen(fullscreen bool) { w.Lock() defer w.Unlock() w.fullscreen = fullscreen - return w } // Focus is called when this primitive receives focus.