diff options
Diffstat (limited to 'vendor/maunium.net/go/tview/list.go')
-rw-r--r-- | vendor/maunium.net/go/tview/list.go | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/vendor/maunium.net/go/tview/list.go b/vendor/maunium.net/go/tview/list.go new file mode 100644 index 0000000..7395985 --- /dev/null +++ b/vendor/maunium.net/go/tview/list.go @@ -0,0 +1,327 @@ +package tview + +import ( + "fmt" + + "maunium.net/go/tcell" +) + +// listItem represents one item in a List. +type listItem struct { + MainText string // The main text of the list item. + SecondaryText string // A secondary text to be shown underneath the main text. + Shortcut rune // The key to select the list item directly, 0 if there is no shortcut. + Selected func() // The optional function which is called when the item is selected. +} + +// List displays rows of items, each of which can be selected. +// +// See https://github.com/rivo/tview/wiki/List for an example. +type List struct { + *Box + + // The items of the list. + items []*listItem + + // The index of the currently selected item. + currentItem int + + // Whether or not to show the secondary item texts. + showSecondaryText bool + + // The item main text color. + mainTextColor tcell.Color + + // The item secondary text color. + secondaryTextColor tcell.Color + + // The item shortcut text color. + shortcutColor tcell.Color + + // The text color for selected items. + selectedTextColor tcell.Color + + // The background color for selected items. + selectedBackgroundColor tcell.Color + + // An optional function which is called when the user has navigated to a list + // item. + changed func(index int, mainText, secondaryText string, shortcut rune) + + // An optional function which is called when a list item was selected. This + // function will be called even if the list item defines its own callback. + selected func(index int, mainText, secondaryText string, shortcut rune) + + // An optional function which is called when the user presses the Escape key. + done func() +} + +// NewList returns a new form. +func NewList() *List { + return &List{ + Box: NewBox(), + showSecondaryText: true, + mainTextColor: Styles.PrimaryTextColor, + secondaryTextColor: Styles.TertiaryTextColor, + shortcutColor: Styles.SecondaryTextColor, + selectedTextColor: Styles.PrimitiveBackgroundColor, + selectedBackgroundColor: Styles.PrimaryTextColor, + } +} + +// SetCurrentItem sets the currently selected item by its index. This triggers +// a "changed" event. +func (l *List) SetCurrentItem(index int) *List { + l.currentItem = index + if l.currentItem < len(l.items) && l.changed != nil { + item := l.items[l.currentItem] + l.changed(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut) + } + return l +} + +// GetCurrentItem returns the index of the currently selected list item. +func (l *List) GetCurrentItem() int { + return l.currentItem +} + +// SetMainTextColor sets the color of the items' main text. +func (l *List) SetMainTextColor(color tcell.Color) *List { + l.mainTextColor = color + return l +} + +// SetSecondaryTextColor sets the color of the items' secondary text. +func (l *List) SetSecondaryTextColor(color tcell.Color) *List { + l.secondaryTextColor = color + return l +} + +// SetShortcutColor sets the color of the items' shortcut. +func (l *List) SetShortcutColor(color tcell.Color) *List { + l.shortcutColor = color + return l +} + +// SetSelectedTextColor sets the text color of selected items. +func (l *List) SetSelectedTextColor(color tcell.Color) *List { + l.selectedTextColor = color + return l +} + +// SetSelectedBackgroundColor sets the background color of selected items. +func (l *List) SetSelectedBackgroundColor(color tcell.Color) *List { + l.selectedBackgroundColor = color + return l +} + +// ShowSecondaryText determines whether or not to show secondary item texts. +func (l *List) ShowSecondaryText(show bool) *List { + l.showSecondaryText = show + return l +} + +// SetChangedFunc sets the function which is called when the user navigates to +// a list item. The function receives the item's index in the list of items +// (starting with 0), its main text, secondary text, and its shortcut rune. +// +// This function is also called when the first item is added or when +// SetCurrentItem() is called. +func (l *List) SetChangedFunc(handler func(int, string, string, rune)) *List { + 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), its main text, +// secondary text, and its shortcut rune. +func (l *List) SetSelectedFunc(handler func(int, string, string, rune)) *List { + 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 { + l.done = handler + return l +} + +// AddItem adds a new item to the list. An item has a main text which will be +// highlighted when selected. It also has a secondary text which is shown +// underneath the main text (if it is set to visible) but which may remain +// empty. +// +// The shortcut is a key binding. If the specified rune is entered, the item +// is selected immediately. Set to 0 for no binding. +// +// The "selected" callback will be invoked when the user selects the item. You +// may provide nil if no such item is needed or if all events are handled +// through the selected callback set with SetSelectedFunc(). +func (l *List) AddItem(mainText, secondaryText string, shortcut rune, selected func()) *List { + l.items = append(l.items, &listItem{ + MainText: mainText, + SecondaryText: secondaryText, + Shortcut: shortcut, + Selected: selected, + }) + if len(l.items) == 1 && l.changed != nil { + item := l.items[0] + l.changed(0, item.MainText, item.SecondaryText, item.Shortcut) + } + return l +} + +// Clear removes all items from the list. +func (l *List) Clear() *List { + l.items = nil + l.currentItem = 0 + return l +} + +// Draw draws this primitive onto the screen. +func (l *List) Draw(screen tcell.Screen) { + l.Box.Draw(screen) + + // Determine the dimensions. + x, y, width, height := l.GetInnerRect() + bottomLimit := y + height + + // Do we show any shortcuts? + var showShortcuts bool + for _, item := range l.items { + if item.Shortcut != 0 { + showShortcuts = true + x += 4 + width -= 4 + break + } + } + + // We want to keep the current selection in view. What is our offset? + var offset int + if l.showSecondaryText { + if l.currentItem >= height/2 { + offset = l.currentItem + 1 - (height / 2) + } + } else { + if l.currentItem >= height { + offset = l.currentItem + 1 - height + } + } + + // Draw the list items. + for index, item := range l.items { + if index < offset { + continue + } + + if y >= bottomLimit { + break + } + + // Shortcuts. + if showShortcuts && item.Shortcut != 0 { + Print(screen, fmt.Sprintf("(%s)", string(item.Shortcut)), x-5, y, 4, AlignRight, l.shortcutColor) + } + + // Main text. + Print(screen, item.MainText, x, y, width, AlignLeft, l.mainTextColor) + + // Background color of selected text. + if index == l.currentItem { + textWidth := StringWidth(item.MainText) + for bx := 0; bx < textWidth && bx < width; bx++ { + m, c, style, _ := screen.GetContent(x+bx, y) + fg, _, _ := style.Decompose() + if fg == l.mainTextColor { + fg = l.selectedTextColor + } + style = style.Background(l.selectedBackgroundColor).Foreground(fg) + screen.SetContent(x+bx, y, m, c, style) + } + } + + y++ + + if y >= bottomLimit { + break + } + + // Secondary text. + if l.showSecondaryText { + Print(screen, item.SecondaryText, x, y, width, AlignLeft, l.secondaryTextColor) + y++ + } + } +} + +// InputHandler returns the handler for this primitive. +func (l *List) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) { + return l.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { + previousItem := l.currentItem + + switch key := event.Key(); key { + case tcell.KeyTab, tcell.KeyDown, tcell.KeyRight: + l.currentItem++ + case tcell.KeyBacktab, tcell.KeyUp, tcell.KeyLeft: + l.currentItem-- + case tcell.KeyHome: + l.currentItem = 0 + case tcell.KeyEnd: + l.currentItem = len(l.items) - 1 + case tcell.KeyPgDn: + l.currentItem += 5 + case tcell.KeyPgUp: + l.currentItem -= 5 + case tcell.KeyEnter: + item := l.items[l.currentItem] + if item.Selected != nil { + item.Selected() + } + if l.selected != nil { + l.selected(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut) + } + case tcell.KeyEscape: + if l.done != nil { + l.done() + } + case tcell.KeyRune: + ch := event.Rune() + if ch != ' ' { + // It's not a space bar. Is it a shortcut? + var found bool + for index, item := range l.items { + if item.Shortcut == ch { + // We have a shortcut. + found = true + l.currentItem = index + break + } + } + if !found { + break + } + } + item := l.items[l.currentItem] + if item.Selected != nil { + item.Selected() + } + if l.selected != nil { + l.selected(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut) + } + } + + if l.currentItem < 0 { + l.currentItem = len(l.items) - 1 + } else if l.currentItem >= len(l.items) { + l.currentItem = 0 + } + + if l.currentItem != previousItem && l.currentItem < len(l.items) && l.changed != nil { + item := l.items[l.currentItem] + l.changed(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut) + } + }) +} |