Add theme support
Fix some minor bugs Add default and helloworld themes Update README
This commit is contained in:
parent
affd0d9c07
commit
bc325c986d
26
README.md
26
README.md
@ -13,9 +13,9 @@ __Demo:__
|
||||
|
||||
## Usage
|
||||
|
||||
Each component's layout is a bit like HTML block, which has border and padding.
|
||||
Each component's layout is a bit like HTML block (box model), which has border and padding.
|
||||
|
||||
The `Border` property can be chosen to hide or display (with its border label), when it comes to display, in this case the space it takes is counted as padding space (i.e. `PaddingTop=PaddingBottom=PaddingLeft=PaddingRight=1`).
|
||||
The `Border` property can be chosen to hide or display (with its border label), when it comes to display, the label takes 1 padding space (i.e. in css: `padding: 1;`, innerHeight and innerWidth therefore shrunk by 1).
|
||||
|
||||
`````go
|
||||
import ui "github.com/gizak/termui" // <- ui shortcut, optional
|
||||
@ -50,11 +50,29 @@ The `Border` property can be chosen to hide or display (with its border label),
|
||||
}
|
||||
`````
|
||||
|
||||
Note that components can be overlapped (I'd rather call this as a feature...), `Render(rs ...Renderer)` renders its args from left to right (i.e. each component's weight is arising from left to right).
|
||||
Note that components can be overlapped (I'd rather call this a feature...), `Render(rs ...Renderer)` renders its args from left to right (i.e. each component's weight is arising from left to right).
|
||||
|
||||
## Themes
|
||||
|
||||
All colors in all components call be changed at any time, while there provides some predefined color scheme.
|
||||
|
||||
```
|
||||
// for now there are only two themes: default and helloworld
|
||||
termui.UseTheme("helloworld")
|
||||
|
||||
// create components...
|
||||
```
|
||||
The `default ` theme's settings depend on the user's terminal color scheme, which is saying if your terminal default font color is white and background is white, it will be like:
|
||||
|
||||
<img src="./example/themedefault.gif" alt="default" type="image/tiff" width="600">
|
||||
|
||||
The `helloworld` color scheme drops in some colors!
|
||||
|
||||
<img src="./example/themehelloworld.gif" alt="helloworld" type="image/tiff" width="600">
|
||||
|
||||
## Widgets
|
||||
|
||||
_APIs are subject to change, docs will be added after 2 or 3 commits_
|
||||
_APIs are subject to change, docs will be added after 1 or 2 commits_
|
||||
|
||||
## GoDoc
|
||||
|
||||
|
12
bar.go
12
bar.go
@ -20,9 +20,9 @@ type BarChart struct {
|
||||
|
||||
func NewBarChart() *BarChart {
|
||||
bc := &BarChart{Block: *NewBlock()}
|
||||
bc.BarColor = ColorCyan
|
||||
bc.NumColor = ColorWhite
|
||||
bc.TextColor = ColorWhite
|
||||
bc.BarColor = theme.BarChartBar
|
||||
bc.NumColor = theme.BarChartNum
|
||||
bc.TextColor = theme.BarChartText
|
||||
bc.BarGap = 1
|
||||
bc.BarWidth = 3
|
||||
return bc
|
||||
@ -62,6 +62,9 @@ func (bc *BarChart) Buffer() []Point {
|
||||
p := Point{}
|
||||
p.Ch = ' '
|
||||
p.Bg = bc.BarColor
|
||||
if bc.BarColor == ColorDefault { // when color is default, space char treated as transparent!
|
||||
p.Bg |= AttrReverse
|
||||
}
|
||||
p.X = bc.innerX + i*(bc.BarWidth+bc.BarGap) + j
|
||||
p.Y = bc.innerY + bc.innerHeight - 2 - k
|
||||
ps = append(ps, p)
|
||||
@ -83,6 +86,9 @@ func (bc *BarChart) Buffer() []Point {
|
||||
p.Ch = bc.dataNum[i][j]
|
||||
p.Fg = bc.NumColor
|
||||
p.Bg = bc.BarColor
|
||||
if bc.BarColor == ColorDefault { // the same as above
|
||||
p.Bg |= AttrReverse
|
||||
}
|
||||
if h == 0 {
|
||||
p.Bg = bc.BgColor
|
||||
}
|
||||
|
8
block.go
8
block.go
@ -1,5 +1,6 @@
|
||||
package termui
|
||||
|
||||
// basic struct, consider it as css: display:block
|
||||
type Block struct {
|
||||
X int
|
||||
Y int
|
||||
@ -22,7 +23,12 @@ type Block struct {
|
||||
func NewBlock() *Block {
|
||||
d := Block{}
|
||||
d.IsDisplay = true
|
||||
d.HasBorder = true
|
||||
d.HasBorder = theme.HasBorder
|
||||
d.Border.BgColor = theme.BorderBg
|
||||
d.Border.FgColor = theme.BorderFg
|
||||
d.Border.LabelBgColor = theme.BorderLabelTextBg
|
||||
d.Border.LabelFgColor = theme.BorderLabelTextFg
|
||||
d.BgColor = theme.BlockBg
|
||||
d.Width = 2
|
||||
d.Height = 2
|
||||
return &d
|
||||
|
2
chart.go
2
chart.go
@ -55,6 +55,8 @@ type LineChart struct {
|
||||
|
||||
func NewLineChart() *LineChart {
|
||||
lc := &LineChart{Block: *NewBlock()}
|
||||
lc.AxesColor = theme.LineChartAxes
|
||||
lc.LineColor = theme.LineChartLine
|
||||
lc.Mode = "braille"
|
||||
lc.DotStyle = '•'
|
||||
lc.axisXLebelGap = 2
|
||||
|
@ -13,7 +13,7 @@ func main() {
|
||||
}
|
||||
defer ui.Close()
|
||||
|
||||
p := ui.NewP(":PRESS q TO QUIT DEMO")
|
||||
p := ui.NewPar(":PRESS q TO QUIT DEMO")
|
||||
p.Height = 3
|
||||
p.Width = 50
|
||||
p.TextFgColor = ui.ColorWhite
|
||||
@ -96,7 +96,7 @@ func main() {
|
||||
lc1 := ui.NewLineChart()
|
||||
lc1.Border.Label = "Line Chart"
|
||||
rndwalk := (func() []float64 {
|
||||
n := 100
|
||||
n := 150
|
||||
d := make([]float64, n)
|
||||
for i := 1; i < n; i++ {
|
||||
if i < 20 {
|
||||
@ -116,7 +116,7 @@ func main() {
|
||||
lc1.AxesColor = ui.ColorWhite
|
||||
lc1.LineColor = ui.ColorYellow | ui.AttrBold
|
||||
|
||||
p1 := ui.NewP("Hey!\nI am a borderless block!")
|
||||
p1 := ui.NewPar("Hey!\nI am a borderless block!")
|
||||
p1.HasBorder = false
|
||||
p1.Width = 26
|
||||
p1.Height = 2
|
||||
|
144
example/theme.go
Normal file
144
example/theme.go
Normal file
@ -0,0 +1,144 @@
|
||||
package main
|
||||
|
||||
import ui "github.com/gizak/termui"
|
||||
import tm "github.com/nsf/termbox-go"
|
||||
import "math"
|
||||
|
||||
import "time"
|
||||
|
||||
func main() {
|
||||
err := ui.Init()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer ui.Close()
|
||||
|
||||
ui.UseTheme("helloworld")
|
||||
|
||||
p := ui.NewPar(":PRESS q TO QUIT DEMO")
|
||||
p.Height = 3
|
||||
p.Width = 50
|
||||
p.Border.Label = "Text Box"
|
||||
|
||||
strs := []string{"[0] gizak/termui", "[1] editbox.go", "[2] iterrupt.go", "[3] keyboard.go", "[4] output.go", "[5] random_out.go", "[6] dashboard.go", "[7] nsf/termbox-go"}
|
||||
list := ui.NewList()
|
||||
list.Items = strs
|
||||
list.Border.Label = "List"
|
||||
list.Height = 7
|
||||
list.Width = 25
|
||||
list.Y = 4
|
||||
|
||||
g := ui.NewGauge()
|
||||
g.Percent = 50
|
||||
g.Width = 50
|
||||
g.Height = 3
|
||||
g.Y = 11
|
||||
g.Border.Label = "Gauge"
|
||||
|
||||
spark := ui.NewSparkline()
|
||||
spark.Title = "srv 0:"
|
||||
spdata := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6}
|
||||
spark.Data = spdata
|
||||
|
||||
spark1 := ui.NewSparkline()
|
||||
spark1.Title = "srv 1:"
|
||||
spark1.Data = spdata
|
||||
|
||||
sp := ui.NewSparklines(spark, spark1)
|
||||
sp.Width = 25
|
||||
sp.Height = 7
|
||||
sp.Border.Label = "Sparkline"
|
||||
sp.Y = 4
|
||||
sp.X = 25
|
||||
|
||||
lc := ui.NewLineChart()
|
||||
sinps := (func() []float64 {
|
||||
n := 100
|
||||
ps := make([]float64, n)
|
||||
for i := range ps {
|
||||
ps[i] = 1 + math.Sin(float64(i)/4)
|
||||
}
|
||||
return ps
|
||||
})()
|
||||
|
||||
lc.Border.Label = "Line Chart"
|
||||
lc.Data = sinps
|
||||
lc.Width = 50
|
||||
lc.Height = 11
|
||||
lc.X = 0
|
||||
lc.Y = 14
|
||||
lc.Mode = "dot"
|
||||
|
||||
bc := ui.NewBarChart()
|
||||
bcdata := []int{3, 2, 5, 3, 9, 5, 3, 2, 5, 8, 3, 2, 4, 5, 3, 2, 5, 7, 5, 3, 2, 6, 7, 4, 6, 3, 6, 7, 8, 3, 6, 4, 5, 3, 2, 4, 6, 4, 8, 5, 9, 4, 3, 6, 5, 3, 6}
|
||||
bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
|
||||
bc.Border.Label = "Bar Chart"
|
||||
bc.Width = 26
|
||||
bc.Height = 10
|
||||
bc.X = 51
|
||||
bc.Y = 0
|
||||
bc.DataLabels = bclabels
|
||||
|
||||
lc1 := ui.NewLineChart()
|
||||
lc1.Border.Label = "Line Chart"
|
||||
rndwalk := (func() []float64 {
|
||||
n := 150
|
||||
d := make([]float64, n)
|
||||
for i := 1; i < n; i++ {
|
||||
if i < 20 {
|
||||
d[i] = d[i-1] + 0.01
|
||||
}
|
||||
if i > 20 {
|
||||
d[i] = d[i-1] - 0.05
|
||||
}
|
||||
}
|
||||
return d
|
||||
})()
|
||||
lc1.Data = rndwalk
|
||||
lc1.Width = 26
|
||||
lc1.Height = 11
|
||||
lc1.X = 51
|
||||
lc1.Y = 14
|
||||
|
||||
p1 := ui.NewPar("Hey!\nI am a borderless block!")
|
||||
p1.HasBorder = false
|
||||
p1.Width = 26
|
||||
p1.Height = 2
|
||||
p1.X = 52
|
||||
p1.Y = 11
|
||||
|
||||
draw := func(t int) {
|
||||
g.Percent = t % 101
|
||||
list.Items = strs[t%9:]
|
||||
sp.Lines[0].Data = spdata[t%10:]
|
||||
sp.Lines[1].Data = spdata[t/2%10:]
|
||||
lc.Data = sinps[t/2:]
|
||||
lc1.Data = rndwalk[t:]
|
||||
bc.Data = bcdata[t/2%10:]
|
||||
ui.Render(p, list, g, sp, lc, bc, lc1, p1)
|
||||
}
|
||||
|
||||
evt := make(chan tm.Event)
|
||||
go func() {
|
||||
for {
|
||||
evt <- tm.PollEvent()
|
||||
}
|
||||
}()
|
||||
|
||||
i := 0
|
||||
for {
|
||||
select {
|
||||
case e := <-evt:
|
||||
if e.Type == tm.EventKey && e.Ch == 'q' {
|
||||
return
|
||||
}
|
||||
default:
|
||||
draw(i)
|
||||
i++
|
||||
if i == 102 {
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Second / 2)
|
||||
}
|
||||
}
|
||||
}
|
BIN
example/themedefault.tiff
Normal file
BIN
example/themedefault.tiff
Normal file
Binary file not shown.
BIN
example/themehelloworld.tiff
Normal file
BIN
example/themehelloworld.tiff
Normal file
Binary file not shown.
12
gauge.go
12
gauge.go
@ -10,7 +10,10 @@ type Gauge struct {
|
||||
}
|
||||
|
||||
func NewGauge() *Gauge {
|
||||
g := &Gauge{Block: *NewBlock(), PercentColor: ColorWhite, BarColor: ColorGreen}
|
||||
g := &Gauge{
|
||||
Block: *NewBlock(),
|
||||
PercentColor: theme.GaugePercent,
|
||||
BarColor: theme.GaugeBar}
|
||||
g.Width = 12
|
||||
g.Height = 5
|
||||
return g
|
||||
@ -34,6 +37,9 @@ func (g *Gauge) Buffer() []Point {
|
||||
p.Y = g.innerY + i
|
||||
p.Ch = ' '
|
||||
p.Bg = g.BarColor
|
||||
if p.Bg == ColorDefault {
|
||||
p.Bg |= AttrReverse
|
||||
}
|
||||
ps = append(ps, p)
|
||||
}
|
||||
}
|
||||
@ -47,6 +53,10 @@ func (g *Gauge) Buffer() []Point {
|
||||
p.Fg = g.PercentColor
|
||||
if w > g.innerWidth/2-1+i {
|
||||
p.Bg = g.BarColor
|
||||
if p.Bg == ColorDefault {
|
||||
p.Bg |= AttrReverse
|
||||
}
|
||||
|
||||
} else {
|
||||
p.Bg = g.Block.BgColor
|
||||
}
|
||||
|
2
list.go
2
list.go
@ -13,6 +13,8 @@ type List struct {
|
||||
func NewList() *List {
|
||||
l := &List{Block: *NewBlock()}
|
||||
l.Overflow = "hidden"
|
||||
l.ItemFgColor = theme.ListItemFg
|
||||
l.ItemBgColor = theme.ListItemBg
|
||||
return l
|
||||
}
|
||||
|
||||
|
12
p.go
12
p.go
@ -1,17 +1,21 @@
|
||||
package termui
|
||||
|
||||
type P struct {
|
||||
type Par struct {
|
||||
Block
|
||||
Text string
|
||||
TextFgColor Attribute
|
||||
TextBgColor Attribute
|
||||
}
|
||||
|
||||
func NewP(s string) *P {
|
||||
return &P{Block: *NewBlock(), Text: s}
|
||||
func NewPar(s string) *Par {
|
||||
return &Par{
|
||||
Block: *NewBlock(),
|
||||
Text: s,
|
||||
TextFgColor: theme.ParTextFg,
|
||||
TextBgColor: theme.ParTextBg}
|
||||
}
|
||||
|
||||
func (p *P) Buffer() []Point {
|
||||
func (p *Par) Buffer() []Point {
|
||||
ps := p.Block.Buffer()
|
||||
|
||||
rs := str2runes(p.Text)
|
||||
|
@ -2,6 +2,7 @@ package termui
|
||||
|
||||
import tm "github.com/nsf/termbox-go"
|
||||
|
||||
// all renderable components should implement this
|
||||
type Bufferer interface {
|
||||
Buffer() []Point
|
||||
}
|
||||
@ -14,7 +15,9 @@ func Close() {
|
||||
tm.Close()
|
||||
}
|
||||
|
||||
// render all from left to right, right could overlap on left ones
|
||||
func Render(rs ...Bufferer) {
|
||||
tm.Clear(tm.ColorDefault, toTmAttr(theme.BodyBg))
|
||||
for _, r := range rs {
|
||||
buf := r.Buffer()
|
||||
for _, v := range buf {
|
||||
|
@ -26,6 +26,14 @@ func (s *Sparklines) Add(sl Sparkline) {
|
||||
s.Lines = append(s.Lines, sl)
|
||||
}
|
||||
|
||||
// return unrenderable single sparkline, need to add it into Sparklines
|
||||
func NewSparkline() Sparkline {
|
||||
return Sparkline{
|
||||
Height: 1,
|
||||
TitleColor: theme.SparklineTitle,
|
||||
LineColor: theme.SparklineLine}
|
||||
}
|
||||
|
||||
func NewSparklines(ss ...Sparkline) *Sparklines {
|
||||
s := &Sparklines{Block: *NewBlock(), Lines: ss}
|
||||
return s
|
||||
|
61
theme.go
Normal file
61
theme.go
Normal file
@ -0,0 +1,61 @@
|
||||
package termui
|
||||
|
||||
type colorScheme struct {
|
||||
BodyBg Attribute
|
||||
BlockBg Attribute
|
||||
HasBorder bool
|
||||
BorderFg Attribute
|
||||
BorderBg Attribute
|
||||
BorderLabelTextFg Attribute
|
||||
BorderLabelTextBg Attribute
|
||||
ParTextFg Attribute
|
||||
ParTextBg Attribute
|
||||
SparklineLine Attribute
|
||||
SparklineTitle Attribute
|
||||
GaugeBar Attribute
|
||||
GaugePercent Attribute
|
||||
LineChartLine Attribute
|
||||
LineChartAxes Attribute
|
||||
ListItemFg Attribute
|
||||
ListItemBg Attribute
|
||||
BarChartBar Attribute
|
||||
BarChartText Attribute
|
||||
BarChartNum Attribute
|
||||
}
|
||||
|
||||
// default color scheme depends on the user's terminal setting.
|
||||
var themeDefault = colorScheme{HasBorder: true}
|
||||
|
||||
var themeHelloWorld = colorScheme{
|
||||
BodyBg: ColorBlack,
|
||||
BlockBg: ColorBlack,
|
||||
HasBorder: true,
|
||||
BorderFg: ColorWhite,
|
||||
BorderBg: ColorBlack,
|
||||
BorderLabelTextBg: ColorBlack,
|
||||
BorderLabelTextFg: ColorGreen,
|
||||
ParTextBg: ColorBlack,
|
||||
ParTextFg: ColorWhite,
|
||||
SparklineLine: ColorMagenta,
|
||||
SparklineTitle: ColorWhite,
|
||||
GaugeBar: ColorRed,
|
||||
GaugePercent: ColorWhite,
|
||||
LineChartLine: ColorYellow | AttrBold,
|
||||
LineChartAxes: ColorWhite,
|
||||
ListItemBg: ColorBlack,
|
||||
ListItemFg: ColorYellow,
|
||||
BarChartBar: ColorRed,
|
||||
BarChartNum: ColorWhite,
|
||||
BarChartText: ColorCyan,
|
||||
}
|
||||
|
||||
var theme = themeDefault // global dep
|
||||
|
||||
func UseTheme(th string) {
|
||||
switch th {
|
||||
case "helloworld":
|
||||
theme = themeHelloWorld
|
||||
default:
|
||||
theme = themeDefault
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user