Remove return values from methods which return their primitive (breaks chaining)

This commit is contained in:
Trevor Slocum 2020-10-07 16:34:21 -07:00
parent 2763609e05
commit ed5e6d94dd
60 changed files with 1132 additions and 1188 deletions

View File

@ -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

18
FORK.md
View File

@ -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)

View File

@ -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.

43
box.go
View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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()

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

File diff suppressed because one or more lines are too long

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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"

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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")

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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 <Tab> to view aboutLayout.").SetTextAlign(AlignCenter)
mainTextView := NewTextView()
mainTextView.SetTextAlign(AlignCenter)
mainTextView.SetText("This is mainLayout.\n\nPress <Tab> 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)
}
}

View File

@ -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()

21
flex.go
View File

@ -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.

157
form.go
View File

@ -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

View File

@ -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.

36
grid.go
View File

@ -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

View File

@ -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.

108
list.go
View File

@ -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.

View File

@ -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 {

View File

@ -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.

View File

@ -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

View File

@ -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.

122
table.go
View File

@ -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.

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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
}

View File

@ -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.