package tui import ( "fmt" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) type TabPrimitive interface { tview.Primitive ForceRedraw() } type Tabs struct { *tview.Flex names []string items map[string]tview.Primitive selector *tview.TextView pages *tview.Pages fallover bool unlock bool } func NewTabs(selectorAtTop bool) *Tabs { widget := &Tabs{ Flex: tview.NewFlex(), names: []string{}, items: make(map[string]tview.Primitive), fallover: true, } widget.SetDirection(tview.FlexRow) // Selector widget.selector = tview.NewTextView(). SetDynamicColors(true). SetRegions(true). SetWrap(false). SetTextAlign(tview.AlignLeft) widget.selector.SetHighlightedFunc( func(added, removed, remaining []string) { if len(added) == 0 { return } widget.pages.SwitchToPage(added[0]) }, ) if selectorAtTop { widget.AddItem(widget.selector, 1, 0, false) } // Pages widget.pages = tview.NewPages() widget.AddItem(widget.pages, 0, 1, false) if !selectorAtTop { widget.AddItem(widget.selector, 1, 0, false) } return widget } func (widget *Tabs) AllowFallover(allow bool) { widget.fallover = allow } func (widget *Tabs) AddText(text string) { fmt.Fprint(widget.selector, text) } func (widget *Tabs) AddTab(name string, label string, item tview.Primitive, visible bool) { widget.names = append(widget.names, name) widget.items[name] = item fmt.Fprintf(widget.selector, `["%s"][darkcyan]%s[white][""] `, name, label) widget.pages.AddPage(name, item, true, false) if visible { widget.Select(name) } } func (widget *Tabs) Select(name string) { widget.selector.Highlight(name) } func (widget *Tabs) Next() tview.Primitive { widget.unlock = true if len(widget.names) == 0 { return nil } index := -1 highlights := widget.selector.GetHighlights() if len(highlights) > 0 { currentName := highlights[0] for currentIndex, name := range widget.names { if name == currentName { index = currentIndex break } } } index++ if index >= len(widget.names) { if widget.fallover { index = 0 } else { index = len(widget.names) - 1 } } widget.selector.Highlight(widget.names[index]) return widget.items[widget.names[index]] } func (widget *Tabs) Prev() tview.Primitive { widget.unlock = true if len(widget.names) == 0 { return nil } index := len(widget.names) highlights := widget.selector.GetHighlights() if len(highlights) > 0 { currentName := highlights[0] for currentIndex, name := range widget.names { if name == currentName { index = currentIndex break } } } index-- if index < 0 { if widget.fallover { index = len(widget.names) - 1 } else { index = 0 } } widget.selector.Highlight(widget.names[index]) return widget.items[widget.names[index]] } func (widget *Tabs) Focus(delegate func(p tview.Primitive)) { delegate(widget.pages) } func (widget *Tabs) Draw(screen tcell.Screen) { if widget.unlock { widgetX, widgetY, widgetWidth, widgetHeight := widget.GetInnerRect() screen.LockRegion(widgetX, widgetY, widgetWidth, widgetHeight, false) widget.unlock = false } widget.Flex.Draw(screen) }