Files
terminal/tui/theme.go
T

103 lines
4.0 KiB
Go

package tui
import (
"github.com/lixenwraith/color"
"github.com/lixenwraith/terminal"
)
// Theme styles the widgets that take one. Each role is a Style whose Attr may
// carry color bits (a palette index, the terminal's own color), so one theme
// per color tier, mono included, draws every widget alike. A role with a zero
// Bg and no Bg bits draws on whatever is beneath it.
type Theme struct {
Text Style // values and body text; its Bg is the panel's
Muted Style // labels, hints, placeholders and defaults, help lines
Accent Style // marks: focus, the chosen option, a required field
Selected Style // the cursor row of a list
Input Style // the background of the field being edited
Cursor Style // the text cursor
Error Style // errors
Border Style // boxes and rules
Glyphs Glyphs
}
// Glyphs are the marks widgets draw; a selection always changes a glyph, so
// it reads without color. A text console's font takes GlyphsCP437, a
// terminal outside UTF-8 GlyphsASCII.
type Glyphs struct {
Focus rune // beside the focused control
Pointer rune // the cursor row of a list
Folded rune // a closed group
Unfolded rune // an open group
On, Off rune // a toggle
Required rune // after a required field's label
Line LineType // frames, rules and wires
}
var (
GlyphsUnicode = Glyphs{Focus: '▌', Pointer: '▸', Folded: '▸', Unfolded: '▾', On: '●', Off: '○', Required: '*'}
GlyphsCP437 = Glyphs{Focus: '▌', Pointer: '►', Folded: '►', Unfolded: '▼', On: '•', Off: '○', Required: '*'}
GlyphsASCII = Glyphs{Focus: '>', Pointer: '>', Folded: '+', Unfolded: '-', On: '*', Off: '-', Required: '*', Line: LineASCII}
)
// DefaultTheme is a dark theme for true color and 256-color terminals
var DefaultTheme = Theme{
Text: Style{Fg: color.RGB{R: 200, G: 200, B: 200}, Bg: color.RGB{R: 20, G: 20, B: 30}},
Muted: Style{Fg: color.RGB{R: 120, G: 125, B: 140}},
Accent: Style{Fg: color.RGB{R: 80, G: 160, B: 220}, Attr: terminal.AttrBold},
Selected: Style{Bg: color.RGB{R: 40, G: 45, B: 65}},
Input: Style{Bg: color.RGB{R: 30, G: 30, B: 50}},
Cursor: Style{Fg: color.RGB{R: 20, G: 20, B: 30}, Bg: color.RGB{R: 200, G: 200, B: 200}},
Error: Style{Fg: color.RGB{R: 255, G: 80, B: 80}},
Border: Style{Fg: color.RGB{R: 60, G: 80, B: 100}},
Glyphs: GlyphsUnicode,
}
// MonoTheme draws with attributes alone in the terminal's own colors: the
// theme for ColorModeNone, and one that reads on any terminal
var MonoTheme = Theme{
Text: Style{Attr: own | terminal.AttrBgDefault},
Muted: Style{Attr: own | terminal.AttrDim},
Accent: Style{Attr: own | terminal.AttrBold},
Selected: Style{Attr: own | terminal.AttrReverse},
Input: Style{Attr: own | terminal.AttrUnderline},
Cursor: Style{Attr: own | terminal.AttrReverse},
Error: Style{Attr: own | terminal.AttrBold | terminal.AttrUnderline},
Border: Style{Attr: own},
Glyphs: GlyphsUnicode,
}
// Theme16 uses the ANSI 16 colors alone, in the terminal's own shades, on
// its own background: the theme for ColorMode16, a text console's
var Theme16 = Theme{
Text: Style{Attr: own | terminal.AttrBgDefault},
Muted: ansi(color.ANSIBrightBlack, 0),
Accent: ansi(color.ANSICyan, terminal.AttrBold),
Selected: Style{Attr: own | terminal.AttrReverse},
Input: Style{Attr: own | terminal.AttrUnderline},
Cursor: Style{Attr: own | terminal.AttrReverse},
Error: ansi(color.ANSIRed, terminal.AttrBold),
Border: Style{Attr: own},
Glyphs: GlyphsUnicode,
}
// ThemeFor returns the theme for a color mode: DefaultTheme with 256 colors
// or more, Theme16 with 16, MonoTheme with none
func ThemeFor(mode terminal.ColorMode) Theme {
switch mode {
case terminal.ColorMode16:
return Theme16
case terminal.ColorModeNone:
return MonoTheme
}
return DefaultTheme
}
// own is the terminal's own foreground
const own = terminal.AttrFgDefault
// ansi is a foreground of the ANSI 16, in the terminal's shade of it
func ansi(i uint8, attr terminal.Attr) Style {
return Style{Fg: color.RGB{R: i}, Attr: terminal.AttrFg256 | attr}
}