diff --git a/FORK.md b/FORK.md index 43091b3..4878c95 100644 --- a/FORK.md +++ b/FORK.md @@ -42,6 +42,11 @@ tview [is not thread-safe](https://godoc.org/github.com/rivo/tview#hdr-Concurren tview [blocks until the queued function returns](https://github.com/rivo/tview/blob/fe3052019536251fd145835dbaa225b33b7d3088/application.go#L510). +## 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. + ## Double clicks are not handled by default 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). @@ -53,19 +58,13 @@ to disable this behavior. ## Lists and Forms do not wrap around by default -Call [List.SetWrapAround](https://docs.rocketnine.space/gitlab.com/tslocum/cview/#List.SetWrapAround) -to wrap around when navigating. +Call `SetWrapAround` to wrap around when navigating. ## Tables do not wrap around when selecting a cell Attempting to move outside of the range of the table results in the selection remaining unchanged. -## Setting a primitive's background color to `tcell.ColorDefault` does not result in transparency - -Call [Box.SetBackgroundTransparent](https://docs.rocketnine.space/gitlab.com/tslocum/cview/#Box.SetBackgroundTransparent) -to enable background transparency. - ## TextViews store their text as []byte instead of string This greatly improves buffer efficiency. [TextView.Write](https://docs.rocketnine.space/gitlab.com/tslocum/cview/#TextView.Write) diff --git a/tabbedpanels.go b/tabbedpanels.go index 1e61d67..a593457 100644 --- a/tabbedpanels.go +++ b/tabbedpanels.go @@ -9,7 +9,7 @@ import ( ) // TabbedPanels is a tabbed container for other primitives. The tab switcher -// may be displayed at the top or bottom of the container. +// may be positioned vertically or horizontally, before or after the content. type TabbedPanels struct { *Flex Switcher *TextView @@ -23,11 +23,12 @@ type TabbedPanels struct { tabBackgroundColor tcell.Color tabBackgroundColorFocused tcell.Color - tabDividerStart string - tabDividerMid string - tabDividerEnd string + dividerStart string + dividerMid string + dividerEnd string - bottomTabSwitcher bool + switcherVertical bool + switcherAfterContent bool width, lastWidth int @@ -46,8 +47,8 @@ func NewTabbedPanels() *TabbedPanels { tabTextColorFocused: Styles.InverseTextColor, tabBackgroundColor: ColorUnset, tabBackgroundColorFocused: Styles.PrimaryTextColor, - tabDividerMid: string(BoxDrawingsDoubleVertical), - tabDividerEnd: string(BoxDrawingsLightVertical), + dividerMid: string(BoxDrawingsDoubleVertical), + dividerEnd: string(BoxDrawingsLightVertical), tabLabels: make(map[string]string), } @@ -63,10 +64,7 @@ func NewTabbedPanels() *TabbedPanels { } }) - f := t.Flex - f.SetDirection(FlexRow) - f.AddItem(t.Switcher, 1, 1, false) - f.AddItem(t.panels, 0, 1, true) + t.rebuild() return t } @@ -161,24 +159,45 @@ func (t *TabbedPanels) SetTabBackgroundColorFocused(color tcell.Color) { func (t *TabbedPanels) SetTabSwitcherDivider(start, mid, end string) { t.Lock() defer t.Unlock() - t.tabDividerStart, t.tabDividerMid, t.tabDividerEnd = start, mid, end + t.dividerStart, t.dividerMid, t.dividerEnd = start, mid, end } -// SetTabSwitcherPosition sets the position of the tab switcher. -func (t *TabbedPanels) SetTabSwitcherPosition(bottom bool) { +// SetTabSwitcherVertical sets the orientation of the tab switcher. +func (t *TabbedPanels) SetTabSwitcherVertical(vertical bool) { t.Lock() defer t.Unlock() - if t.bottomTabSwitcher == bottom { + if t.switcherVertical == vertical { return } - t.bottomTabSwitcher = bottom + t.switcherVertical = vertical + t.rebuild() +} +// SetTabSwitcherAfterContent sets whether the tab switcher is positioned after content. +func (t *TabbedPanels) SetTabSwitcherAfterContent(after bool) { + t.Lock() + defer t.Unlock() + + if t.switcherAfterContent == after { + return + } + + t.switcherAfterContent = after + t.rebuild() +} + +func (t *TabbedPanels) rebuild() { f := t.Flex + if t.switcherVertical { + f.SetDirection(FlexColumn) + } else { + f.SetDirection(FlexRow) + } f.RemoveItem(t.panels) f.RemoveItem(t.Switcher) - if t.bottomTabSwitcher { + if t.switcherAfterContent { f.AddItem(t.panels, 0, 1, true) f.AddItem(t.Switcher, 1, 1, false) } else { @@ -196,29 +215,64 @@ func (t *TabbedPanels) updateTabLabels() { return } + maxWidth := 0 + for _, panel := range t.panels.panels { + label := t.tabLabels[panel.Name] + if len(label) > maxWidth { + maxWidth = len(label) + } + } + var b bytes.Buffer - b.WriteString(t.tabDividerStart) + if !t.switcherVertical { + b.WriteString(t.dividerStart) + } l := len(t.panels.panels) + spacer := []byte(" ") for i, panel := range t.panels.panels { + if i > 0 && t.switcherVertical { + b.WriteRune('\n') + } + + if t.switcherVertical && t.switcherAfterContent { + b.WriteString(t.dividerMid) + b.WriteRune(' ') + } + textColor := t.tabTextColor backgroundColor := t.tabBackgroundColor if panel.Name == t.currentTab { textColor = t.tabTextColorFocused backgroundColor = t.tabBackgroundColorFocused } - b.WriteString(fmt.Sprintf(`["%s"][%s:%s] %s [-:-][""]`, panel.Name, ColorHex(textColor), ColorHex(backgroundColor), t.tabLabels[panel.Name])) - if i == l-1 { - b.WriteString(t.tabDividerEnd) - } else { - b.WriteString(t.tabDividerMid) + label := t.tabLabels[panel.Name] + if !t.switcherVertical { + label = " " + label + } + + if t.switcherVertical { + spacer = bytes.Repeat([]byte(" "), maxWidth-len(label)+1) + } + + b.WriteString(fmt.Sprintf(`["%s"][%s:%s]%s%s[-:-][""]`, panel.Name, ColorHex(textColor), ColorHex(backgroundColor), label, spacer)) + + if i == l-1 && !t.switcherVertical { + b.WriteString(t.dividerEnd) + } else if !t.switcherAfterContent { + b.WriteString(t.dividerMid) } } t.Switcher.SetText(b.String()) - reqLines := len(WordWrap(t.Switcher.GetText(true), t.width)) - if reqLines < 1 { - reqLines = 1 + var reqLines int + if t.switcherVertical { + reqLines = maxWidth + 2 + } else { + reqLines = len(WordWrap(t.Switcher.GetText(true), t.width)) + if reqLines < 1 { + reqLines = 1 + } } t.Flex.ResizeItem(t.Switcher, reqLines, 1) }