2
0
mirror of https://github.com/rivo/tview.git synced 2024-11-15 06:12:46 +00:00

Add ContextMenu

Initially supported by List
This commit is contained in:
Trevor Slocum 2020-04-18 20:00:36 -07:00
parent 8e06c826b3
commit c111597668
7 changed files with 565 additions and 62 deletions

View File

@ -13,7 +13,7 @@ Among these components are:
- Navigable multi-color __text views__
- Sophisticated navigable __table views__
- Flexible __tree views__
- Selectable __lists__
- Selectable __lists__ with __context menus__
- __Grid__, __Flexbox__ and __page layouts__
- Modal __message windows__
- An __application__ wrapper

12
box.go
View File

@ -52,6 +52,9 @@ type Box struct {
// Whether or not this box has focus.
hasFocus bool
// Whether or not this box shows its focus.
showFocus bool
// An optional capture function which receives a key event and returns the
// event to be forwarded to the primitive's default input handler (nil if
// nothing should be forwarded).
@ -76,6 +79,7 @@ func NewBox() *Box {
borderColor: Styles.BorderColor,
titleColor: Styles.TitleColor,
titleAlign: AlignCenter,
showFocus: true,
}
b.focus = b
return b
@ -342,7 +346,13 @@ func (b *Box) Draw(screen tcell.Screen) {
if b.border && b.width >= 2 && b.height >= 2 {
border := background.Foreground(b.borderColor) | tcell.Style(b.borderAttributes)
var vertical, horizontal, topLeft, topRight, bottomLeft, bottomRight rune
if b.focus.HasFocus() {
var hasFocus bool
if b.focus == b {
hasFocus = b.hasFocus
} else {
hasFocus = b.focus.HasFocus()
}
if hasFocus && b.showFocus {
horizontal = Borders.HorizontalFocus
vertical = Borders.VerticalFocus
topLeft = Borders.TopLeftFocus

171
contextmenu.go Normal file
View File

@ -0,0 +1,171 @@
package tview
import "sync"
// ContextMenu is a menu that appears upon user interaction, such as right
// clicking or pressing Alt+Enter.
type ContextMenu struct {
parent Primitive
item int
open bool
drag bool
list *List
x, y int
selected func(int, string, rune)
l sync.Mutex
}
// NewContextMenu returns a new context menu.
func NewContextMenu(parent Primitive) *ContextMenu {
return &ContextMenu{
parent: parent,
}
}
func (c *ContextMenu) initializeList() {
if c.list != nil {
return
}
c.list = NewList().
ShowSecondaryText(false).
SetHover(true).
SetWrapAround(true)
c.list.
SetBorder(true).
SetBorderPadding(
Styles.ContextMenuPaddingTop,
Styles.ContextMenuPaddingBottom,
Styles.ContextMenuPaddingLeft,
Styles.ContextMenuPaddingRight)
c.list.showFocus = false
}
// ContextMenuList returns the underlying List of the context menu.
func (c *ContextMenu) ContextMenuList() *List {
c.l.Lock()
defer c.l.Unlock()
c.initializeList()
return c.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 {
c.l.Lock()
defer c.l.Unlock()
c.initializeList()
c.list.AddItem(text, "", shortcut, c.wrap(selected))
if text == "" && shortcut == 0 {
index := len(c.list.items) - 1
c.list.items[index].Enabled = false
}
return c
}
func (c *ContextMenu) wrap(f func(index int)) func() {
return func() {
f(c.item)
}
}
// ClearContextMenu removes all items from the context menu.
func (c *ContextMenu) ClearContextMenu() *ContextMenu {
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 {
c.l.Lock()
defer c.l.Unlock()
c.selected = handler
return c
}
// ShowContextMenu shows the context menu.
func (c *ContextMenu) ShowContextMenu(item int, x int, y int, setFocus func(Primitive)) {
c.l.Lock()
defer c.l.Unlock()
c.show(item, x, y, setFocus)
}
// HideContextMenu hides the context menu.
func (c *ContextMenu) HideContextMenu(setFocus func(Primitive)) {
c.l.Lock()
defer c.l.Unlock()
c.hide(setFocus)
}
// ContextMenuVisible returns whether or not the context menu is visible.
func (c *ContextMenu) ContextMenuVisible() bool {
c.l.Lock()
defer c.l.Unlock()
return c.open
}
func (c *ContextMenu) show(item int, x int, y int, setFocus func(Primitive)) {
c.initializeList()
if len(c.list.items) == 0 {
return
}
c.open = true
c.item = item
c.x, c.y = x, y
for i, item := range c.list.items {
if item.Enabled {
c.list.currentItem = i
break
}
}
c.list.SetSelectedFunc(func(index int, mainText, secondaryText string, shortcut rune) {
c.l.Lock()
// A context item was selected. Close the menu.
c.hide(setFocus)
if c.selected != nil {
c.l.Unlock()
c.selected(index, mainText, shortcut)
} else {
c.l.Unlock()
}
}).SetDoneFunc(func() {
c.hide(setFocus)
})
setFocus(c.list)
}
func (c *ContextMenu) hide(setFocus func(Primitive)) {
c.initializeList()
c.open = false
if c.list.HasFocus() {
setFocus(c.parent)
}
}

View File

@ -7,14 +7,51 @@ import (
func main() {
app := tview.NewApplication()
list := tview.NewList().
AddItem("List item 1", "Some explanatory text", 'a', nil).
AddItem("List item 2", "Some explanatory text", 'b', nil).
AddItem("List item 3", "Some explanatory text", 'c', nil).
AddItem("List item 4", "Some explanatory text", 'd', nil).
AddItem("Quit", "Press to exit", 'q', func() {
app.Stop()
})
list := tview.NewList()
reset := func() {
list.
Clear().
AddItem("List item 1", "Some explanatory text", 'a', nil).
AddItem("List item 2", "Some explanatory text", 'b', nil).
AddItem("List item 3", "Some explanatory text", 'c', nil).
AddItem("List item 4", "Some explanatory text", 'd', nil).
AddItem("Quit", "Press to exit", 'q', func() {
app.Stop()
})
list.ContextMenuList().SetItemEnabled(3, false)
}
list.AddContextItem("Delete item", 'i', func(index int) {
list.RemoveItem(index)
if list.GetItemCount() == 0 {
list.ContextMenuList().SetItemEnabled(0, false)
list.ContextMenuList().SetItemEnabled(1, false)
}
list.ContextMenuList().SetItemEnabled(3, true)
})
list.AddContextItem("Delete all", 'a', func(index int) {
list.Clear()
list.ContextMenuList().SetItemEnabled(0, false)
list.ContextMenuList().SetItemEnabled(1, false)
list.ContextMenuList().SetItemEnabled(3, true)
})
list.AddContextItem("", 0, nil)
list.AddContextItem("Reset", 'r', func(index int) {
reset()
list.ContextMenuList().SetItemEnabled(0, true)
list.ContextMenuList().SetItemEnabled(1, true)
list.ContextMenuList().SetItemEnabled(3, false)
})
reset()
if err := app.SetRoot(list, true).EnableMouse(true).Run(); err != nil {
panic(err)
}

View File

@ -4,11 +4,49 @@ import "github.com/rivo/tview"
// Introduction returns a tview.List with the highlights of the tview package.
func Introduction(nextSlide func()) (title string, content tview.Primitive) {
list := tview.NewList().
AddItem("A Go package for terminal based UIs", "with a special focus on rich interactive widgets", '1', nextSlide).
AddItem("Based on github.com/gdamore/tcell", "Like termbox but better (see tcell docs)", '2', nextSlide).
AddItem("Designed to be simple", `"Hello world" is 5 lines of code`, '3', nextSlide).
AddItem("Good for data entry", `For charts, use "termui" - for low-level views, use "gocui" - ...`, '4', nextSlide).
AddItem("Extensive documentation", "Everything is documented, examples in GitHub wiki, demo code for each widget", '5', nextSlide)
return "Introduction", Center(80, 10, list)
list := tview.NewList()
reset := func() {
list.
Clear().
AddItem("A Go package for terminal based UIs", "with a special focus on rich interactive widgets", '1', nextSlide).
AddItem("Based on github.com/gdamore/tcell", "Like termbox but better (see tcell docs)", '2', nextSlide).
AddItem("Designed to be simple", `"Hello world" is 5 lines of code`, '3', nextSlide).
AddItem("Good for data entry", `For charts, use "termui" - for low-level views, use "gocui" - ...`, '4', nextSlide).
AddItem("Supports context menus", "Right click on one of these items or press Alt+Enter", '5', nextSlide).
AddItem("Extensive documentation", "Everything is documented, examples in GitHub wiki, demo code for each widget", '6', nextSlide)
list.ContextMenuList().SetItemEnabled(3, false)
}
list.AddContextItem("Delete item", 'i', func(index int) {
list.RemoveItem(index)
if list.GetItemCount() == 0 {
list.ContextMenuList().SetItemEnabled(0, false)
list.ContextMenuList().SetItemEnabled(1, false)
}
list.ContextMenuList().SetItemEnabled(3, true)
})
list.AddContextItem("Delete all", 'a', func(index int) {
list.Clear()
list.ContextMenuList().SetItemEnabled(0, false)
list.ContextMenuList().SetItemEnabled(1, false)
list.ContextMenuList().SetItemEnabled(3, true)
})
list.AddContextItem("", 0, nil)
list.AddContextItem("Reset", 'r', func(index int) {
reset()
list.ContextMenuList().SetItemEnabled(0, true)
list.ContextMenuList().SetItemEnabled(1, true)
list.ContextMenuList().SetItemEnabled(3, false)
})
reset()
return "Introduction", Center(80, 12, list)
}

287
list.go
View File

@ -9,6 +9,7 @@ import (
// listItem represents one item in a List.
type listItem struct {
Enabled bool // Whether or not the list item is selectable.
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.
@ -20,6 +21,7 @@ type listItem struct {
// See https://github.com/rivo/tview/wiki/List for an example.
type List struct {
*Box
*ContextMenu
// The items of the list.
items []*listItem
@ -54,6 +56,9 @@ type List struct {
// Whether or not navigating the list will wrap around.
wrapAround bool
// Whether or not hovering over an item will highlight it.
hover bool
// The number of list items skipped at the top before the first item is drawn.
offset int
@ -71,7 +76,7 @@ type List struct {
// NewList returns a new form.
func NewList() *List {
return &List{
l := &List{
Box: NewBox(),
showSecondaryText: true,
wrapAround: true,
@ -81,6 +86,11 @@ func NewList() *List {
selectedTextColor: Styles.PrimitiveBackgroundColor,
selectedBackgroundColor: Styles.PrimaryTextColor,
}
l.ContextMenu = NewContextMenu(l)
l.focus = l
return l
}
// SetCurrentItem sets the currently selected item by its index, starting at 0
@ -150,7 +160,7 @@ func (l *List) RemoveItem(index int) *List {
// Shift current item.
previousCurrentItem := l.currentItem
if l.currentItem >= index {
if l.currentItem >= index && l.currentItem > 0 {
l.currentItem--
}
@ -216,6 +226,13 @@ func (l *List) ShowSecondaryText(show bool) *List {
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 {
l.hover = hover
return l
}
// SetWrapAround sets the flag that determines whether navigating the list will
// wrap around. That is, navigating downwards on the last item will move the
// selection to the first item (similarly in the other direction). If set to
@ -283,6 +300,7 @@ func (l *List) AddItem(mainText, secondaryText string, shortcut rune, selected f
// selected.
func (l *List) InsertItem(index int, mainText, secondaryText string, shortcut rune, selected func()) *List {
item := &listItem{
Enabled: true,
MainText: mainText,
SecondaryText: secondaryText,
Shortcut: shortcut,
@ -340,6 +358,14 @@ func (l *List) SetItemText(index int, main, secondary string) *List {
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 {
item := l.items[index]
item.Enabled = enabled
return l
}
// FindItems searches the main and secondary texts for the given strings and
// returns a list of item indices in which those strings are found. One of the
// two search strings may be empty, it will then be ignored. Indices are always
@ -387,9 +413,26 @@ func (l *List) Clear() *List {
return l
}
// Focus is called by the application when the primitive receives focus.
func (l *List) Focus(delegate func(p Primitive)) {
l.Box.Focus(delegate)
if l.ContextMenu.open {
delegate(l.ContextMenu.list)
}
}
// HasFocus returns whether or not this primitive has focus.
func (l *List) HasFocus() bool {
if l.ContextMenu.open {
return l.ContextMenu.list.HasFocus()
}
return l.hasFocus
}
// Draw draws this primitive onto the screen.
func (l *List) Draw(screen tcell.Screen) {
l.Box.Draw(screen)
hasFocus := l.GetFocusable().HasFocus()
// Determine the dimensions.
x, y, width, height := l.GetInnerRect()
@ -433,6 +476,26 @@ func (l *List) Draw(screen tcell.Screen) {
break
}
if item.MainText == "" && item.SecondaryText == "" && item.Shortcut == 0 { // Divider
Print(screen, string(tcell.RuneLTee), (x-5)-l.paddingLeft, y, 1, AlignLeft, l.mainTextColor)
Print(screen, strings.Repeat(string(tcell.RuneHLine), width+4+l.paddingLeft+l.paddingRight), (x-4)-l.paddingLeft, y, width+4+l.paddingLeft+l.paddingRight, AlignLeft, l.mainTextColor)
Print(screen, string(tcell.RuneRTee), (x-5)+width+5+l.paddingRight, y, 1, AlignLeft, l.mainTextColor)
y++
continue
} else if !item.Enabled { // Disabled item
// Shortcuts.
if showShortcuts && item.Shortcut != 0 {
Print(screen, fmt.Sprintf("(%s)", string(item.Shortcut)), x-5, y, 4, AlignRight, tcell.ColorDarkSlateGray)
}
// Main text.
Print(screen, item.MainText, x, y, width, AlignLeft, tcell.ColorGray)
y++
continue
}
// Shortcuts.
if showShortcuts && item.Shortcut != 0 {
Print(screen, fmt.Sprintf("(%s)", string(item.Shortcut)), x-5, y, 4, AlignRight, l.shortcutColor)
@ -473,17 +536,71 @@ func (l *List) Draw(screen tcell.Screen) {
y++
}
}
// Draw context menu.
if hasFocus && l.ContextMenu.open {
ctx := l.ContextMenu.list
x, y, width, height = l.GetInnerRect()
// What's the longest option text?
maxWidth := 0
for _, option := range ctx.items {
strWidth := TaggedStringWidth(option.MainText)
if option.Shortcut != 0 {
strWidth += 4
}
if strWidth > maxWidth {
maxWidth = strWidth
}
}
lheight := len(ctx.items)
lwidth := maxWidth
// Add space for borders
lwidth += 2
lheight += 2
lwidth += ctx.paddingLeft + ctx.paddingRight
lheight += ctx.paddingTop + ctx.paddingBottom
cx, cy := l.ContextMenu.x, l.ContextMenu.y
if cx < 0 || cy < 0 {
cx = x + (width / 2)
cy = y + (height / 2)
}
_, sheight := screen.Size()
if cy+lheight >= sheight && cy-2 > lheight-cy {
cy = y - lheight
if cy < 0 {
cy = 0
}
}
if cy+lheight >= sheight {
lheight = sheight - cy
}
ctx.SetRect(cx, cy, lwidth, lheight)
ctx.Draw(screen)
}
}
// 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)) {
if event.Key() == tcell.KeyEscape {
if l.ContextMenu.open {
l.ContextMenu.hide(setFocus)
return
}
if l.done != nil {
l.done()
}
return
} else if len(l.items) == 0 {
} else if len(l.items) == 0 && (event.Key() != tcell.KeyEnter || event.Modifiers()&tcell.ModAlt == 0) {
return
}
@ -505,13 +622,36 @@ func (l *List) InputHandler() func(event *tcell.EventKey, setFocus func(p Primit
_, _, _, height := l.GetInnerRect()
l.currentItem -= height
case tcell.KeyEnter:
if l.currentItem >= 0 && l.currentItem < len(l.items) {
item := l.items[l.currentItem]
if item.Selected != nil {
item.Selected()
if event.Modifiers()&tcell.ModAlt != 0 {
// Do we show any shortcuts?
var showShortcuts bool
for _, item := range l.items {
if item.Shortcut != 0 {
showShortcuts = true
break
}
}
if l.selected != nil {
l.selected(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut)
offsetX := 7
if showShortcuts {
offsetX += 4
}
offsetY := l.currentItem
if l.showSecondaryText {
offsetY *= 2
}
x, y, _, _ := l.GetInnerRect()
l.ContextMenu.show(l.currentItem, x+offsetX, y+offsetY, setFocus)
} else if l.currentItem >= 0 && l.currentItem < len(l.items) {
item := l.items[l.currentItem]
if item.Enabled {
if item.Selected != nil {
item.Selected()
}
if l.selected != nil {
l.selected(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut)
}
}
}
case tcell.KeyRune:
@ -520,7 +660,7 @@ func (l *List) InputHandler() func(event *tcell.EventKey, setFocus func(p Primit
// It's not a space bar. Is it a shortcut?
var found bool
for index, item := range l.items {
if item.Shortcut == ch {
if item.Enabled && item.Shortcut == ch {
// We have a shortcut.
found = true
l.currentItem = index
@ -540,17 +680,31 @@ func (l *List) InputHandler() func(event *tcell.EventKey, setFocus func(p Primit
}
}
if l.currentItem < 0 {
if l.wrapAround {
l.currentItem = len(l.items) - 1
} else {
l.currentItem = 0
decreasing := l.currentItem < previousItem
for i := 0; i < len(l.items); i++ {
if l.currentItem < 0 {
if l.wrapAround {
l.currentItem = len(l.items) - 1
} else {
l.currentItem = 0
}
} else if l.currentItem >= len(l.items) {
if l.wrapAround {
l.currentItem = 0
} else {
l.currentItem = len(l.items) - 1
}
}
} else if l.currentItem >= len(l.items) {
if l.wrapAround {
l.currentItem = 0
item := l.items[l.currentItem]
if item.Enabled {
break
}
if decreasing {
l.currentItem--
} else {
l.currentItem = len(l.items) - 1
l.currentItem++
}
}
@ -561,11 +715,31 @@ func (l *List) InputHandler() func(event *tcell.EventKey, setFocus func(p Primit
})
}
// indexAtY returns the index of the list item found at the given Y position
// or a negative value if there is no such list item.
func (l *List) indexAtY(y int) int {
_, rectY, _, height := l.GetInnerRect()
if y < rectY || y >= rectY+height {
return -1
}
index := y - rectY
if l.showSecondaryText {
index /= 2
}
index += l.offset
if index >= len(l.items) {
return -1
}
return index
}
// indexAtPoint returns the index of the list item found at the given position
// or a negative value if there is no such list item.
func (l *List) indexAtPoint(x, y int) int {
rectX, rectY, width, height := l.GetInnerRect()
if rectX < 0 || rectX >= rectX+width || y < rectY || y >= rectY+height {
if x < rectX || x >= rectX+width || y < rectY || y >= rectY+height {
return -1
}
@ -584,6 +758,13 @@ func (l *List) indexAtPoint(x, y int) int {
// MouseHandler returns the mouse handler for this primitive.
func (l *List) MouseHandler() func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) {
return l.WrapMouseHandler(func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) {
// Pass events to context menu.
if l.ContextMenuVisible() && l.ContextMenuList().InRect(event.Position()) {
defer l.ContextMenuList().MouseHandler()(action, event, setFocus)
consumed = true
return
}
if !l.InRect(event.Position()) {
return false, nil
}
@ -591,22 +772,70 @@ func (l *List) MouseHandler() func(action MouseAction, event *tcell.EventMouse,
// Process mouse event.
switch action {
case MouseLeftClick:
if l.ContextMenuVisible() {
defer l.ContextMenu.hide(setFocus)
consumed = true
return
}
setFocus(l)
index := l.indexAtPoint(event.Position())
if index != -1 {
item := l.items[index]
if item.Selected != nil {
item.Selected()
if item.Enabled {
if item.Selected != nil {
item.Selected()
}
if l.selected != nil {
l.selected(index, item.MainText, item.SecondaryText, item.Shortcut)
}
if index != l.currentItem && l.changed != nil {
l.changed(index, item.MainText, item.SecondaryText, item.Shortcut)
}
l.currentItem = index
}
if l.selected != nil {
l.selected(index, item.MainText, item.SecondaryText, item.Shortcut)
}
if index != l.currentItem && l.changed != nil {
l.changed(index, item.MainText, item.SecondaryText, item.Shortcut)
}
l.currentItem = index
}
consumed = true
case MouseMiddleClick:
if l.ContextMenuVisible() {
defer l.ContextMenu.hide(setFocus)
consumed = true
return
}
case MouseRightDown:
if len(l.ContextMenuList().items) == 0 {
return
}
x, y := event.Position()
index := l.indexAtPoint(event.Position())
if index != -1 {
item := l.items[index]
if item.Enabled {
l.currentItem = index
if index != l.currentItem && l.changed != nil {
l.changed(index, item.MainText, item.SecondaryText, item.Shortcut)
}
}
}
defer l.ContextMenu.show(l.currentItem, x, y, setFocus)
l.ContextMenu.drag = true
consumed = true
case MouseMove:
if l.hover {
_, y := event.Position()
index := l.indexAtY(y)
if index >= 0 {
item := l.items[index]
if item.Enabled {
l.currentItem = index
}
}
consumed = true
}
case MouseScrollUp:
if l.offset > 0 {
l.offset--

View File

@ -4,32 +4,50 @@ import "github.com/gdamore/tcell"
// Theme defines the colors used when primitives are initialized.
type Theme struct {
// Title, border and other lines
TitleColor tcell.Color // Box titles.
BorderColor tcell.Color // Box borders.
GraphicsColor tcell.Color // Graphics.
// Text
PrimaryTextColor tcell.Color // Primary text.
SecondaryTextColor tcell.Color // Secondary text (e.g. labels).
TertiaryTextColor tcell.Color // Tertiary text (e.g. subtitles, notes).
InverseTextColor tcell.Color // Text on primary-colored backgrounds.
ContrastSecondaryTextColor tcell.Color // Secondary text on ContrastBackgroundColor-colored backgrounds.
// Background
PrimitiveBackgroundColor tcell.Color // Main background color for primitives.
ContrastBackgroundColor tcell.Color // Background color for contrasting elements.
MoreContrastBackgroundColor tcell.Color // Background color for even more contrasting elements.
BorderColor tcell.Color // Box borders.
TitleColor tcell.Color // Box titles.
GraphicsColor tcell.Color // Graphics.
PrimaryTextColor tcell.Color // Primary text.
SecondaryTextColor tcell.Color // Secondary text (e.g. labels).
TertiaryTextColor tcell.Color // Tertiary text (e.g. subtitles, notes).
InverseTextColor tcell.Color // Text on primary-colored backgrounds.
ContrastSecondaryTextColor tcell.Color // Secondary text on ContrastBackgroundColor-colored backgrounds.
// Context menu
ContextMenuPaddingTop int // Top padding.
ContextMenuPaddingBottom int // Bottom padding.
ContextMenuPaddingLeft int // Left padding.
ContextMenuPaddingRight int // Right padding.
}
// Styles defines the theme for applications. The default is for a black
// background and some basic colors: black, white, yellow, green, cyan, and
// blue.
var Styles = Theme{
TitleColor: tcell.ColorWhite,
BorderColor: tcell.ColorWhite,
GraphicsColor: tcell.ColorWhite,
PrimaryTextColor: tcell.ColorWhite,
SecondaryTextColor: tcell.ColorYellow,
TertiaryTextColor: tcell.ColorGreen,
InverseTextColor: tcell.ColorBlue,
ContrastSecondaryTextColor: tcell.ColorDarkCyan,
PrimitiveBackgroundColor: tcell.ColorBlack,
ContrastBackgroundColor: tcell.ColorBlue,
MoreContrastBackgroundColor: tcell.ColorGreen,
BorderColor: tcell.ColorWhite,
TitleColor: tcell.ColorWhite,
GraphicsColor: tcell.ColorWhite,
PrimaryTextColor: tcell.ColorWhite,
SecondaryTextColor: tcell.ColorYellow,
TertiaryTextColor: tcell.ColorGreen,
InverseTextColor: tcell.ColorBlue,
ContrastSecondaryTextColor: tcell.ColorDarkCyan,
ContextMenuPaddingTop: 0,
ContextMenuPaddingBottom: 0,
ContextMenuPaddingLeft: 1,
ContextMenuPaddingRight: 1,
}