Add gauge and list component

This commit is contained in:
gizak 2015-02-03 20:56:49 -05:00
parent ddc86587d8
commit cc6b38d600
8 changed files with 216 additions and 75 deletions

View File

@ -1,14 +1,12 @@
package termui package termui
import tm "github.com/nsf/termbox-go" type Block struct {
type Div struct {
X int X int
Y int Y int
Border LabeledBox Border labeledBorder
IsDisplay bool IsDisplay bool
HasBorder bool HasBorder bool
BgColor tm.Attribute BgColor Attribute
Width int Width int
Height int Height int
innerWidth int innerWidth int
@ -17,21 +15,16 @@ type Div struct {
innerY int innerY int
} }
func NewDiv() Div { func NewBlock() *Block {
d := Div{} d := Block{}
d.Border.BgColor = tm.ColorDefault
d.Border.FgColor = tm.ColorDefault
d.Border.LabelFgColor = tm.ColorDefault
d.Border.LabelBgColor = tm.ColorDefault
d.IsDisplay = true d.IsDisplay = true
d.HasBorder = true d.HasBorder = true
d.Width = 2 d.Width = 2
d.Height = 2 d.Height = 2
d.BgColor = tm.ColorDefault return &d
return d
} }
func (d *Div) sync() { func (d *Block) align() {
d.innerWidth = d.Width d.innerWidth = d.Width
d.innerHeight = d.Height d.innerHeight = d.Height
d.innerX = d.X d.innerX = d.X
@ -49,8 +42,8 @@ func (d *Div) sync() {
} }
} }
func (d Div) Buffer() []Point { func (d *Block) Buffer() []Point {
(&d).sync() d.align()
ps := []Point{} ps := []Point{}
if !d.IsDisplay { if !d.IsDisplay {
@ -67,7 +60,7 @@ func (d Div) Buffer() []Point {
p.X = d.X + 1 + i p.X = d.X + 1 + i
p.Y = d.Y + 1 + j p.Y = d.Y + 1 + j
p.Code.Ch = ' ' p.Code.Ch = ' '
p.Code.Bg = d.BgColor p.Code.Bg = toTmAttr(d.BgColor)
ps = append(ps, p) ps = append(ps, p)
} }
} }

74
box.go
View File

@ -1,7 +1,5 @@
package termui package termui
import tm "github.com/nsf/termbox-go"
const TOP_RIGHT = '┐' const TOP_RIGHT = '┐'
const VERTICAL_LINE = '│' const VERTICAL_LINE = '│'
const HORIZONTAL_LINE = '─' const HORIZONTAL_LINE = '─'
@ -9,56 +7,56 @@ const TOP_LEFT = '┌'
const BOTTOM_RIGHT = '┘' const BOTTOM_RIGHT = '┘'
const BOTTOM_LEFT = '└' const BOTTOM_LEFT = '└'
type Box struct { type border struct {
X int X int
Y int Y int
Width int Width int
Height int Height int
FgColor tm.Attribute FgColor Attribute
BgColor tm.Attribute BgColor Attribute
} }
type HLine struct { type hline struct {
X int X int
Y int Y int
Length int Length int
FgColor tm.Attribute FgColor Attribute
BgColor tm.Attribute BgColor Attribute
} }
type VLine struct { type vline struct {
X int X int
Y int Y int
Length int Length int
FgColor tm.Attribute FgColor Attribute
BgColor tm.Attribute BgColor Attribute
} }
func (l HLine) Buffer() []Point { func (l hline) Buffer() []Point {
pts := make([]Point, l.Length) pts := make([]Point, l.Length)
for i := 0; i < l.Length; i++ { for i := 0; i < l.Length; i++ {
pts[i].X = l.X + i pts[i].X = l.X + i
pts[i].Y = l.Y pts[i].Y = l.Y
pts[i].Code.Ch = HORIZONTAL_LINE pts[i].Code.Ch = HORIZONTAL_LINE
pts[i].Code.Bg = l.BgColor pts[i].Code.Bg = toTmAttr(l.BgColor)
pts[i].Code.Fg = l.FgColor pts[i].Code.Fg = toTmAttr(l.FgColor)
} }
return pts return pts
} }
func (l VLine) Buffer() []Point { func (l vline) Buffer() []Point {
pts := make([]Point, l.Length) pts := make([]Point, l.Length)
for i := 0; i < l.Length; i++ { for i := 0; i < l.Length; i++ {
pts[i].X = l.X pts[i].X = l.X
pts[i].Y = l.Y + i pts[i].Y = l.Y + i
pts[i].Code.Ch = VERTICAL_LINE pts[i].Code.Ch = VERTICAL_LINE
pts[i].Code.Bg = l.BgColor pts[i].Code.Bg = toTmAttr(l.BgColor)
pts[i].Code.Fg = l.FgColor pts[i].Code.Fg = toTmAttr(l.FgColor)
} }
return pts return pts
} }
func (b Box) Buffer() []Point { func (b border) Buffer() []Point {
if b.Width < 2 || b.Height < 2 { if b.Width < 2 || b.Height < 2 {
return nil return nil
} }
@ -66,45 +64,45 @@ func (b Box) Buffer() []Point {
pts[0].X = b.X pts[0].X = b.X
pts[0].Y = b.Y pts[0].Y = b.Y
pts[0].Code.Fg = b.FgColor pts[0].Code.Fg = toTmAttr(b.FgColor)
pts[0].Code.Bg = b.BgColor pts[0].Code.Bg = toTmAttr(b.BgColor)
pts[0].Code.Ch = TOP_LEFT pts[0].Code.Ch = TOP_LEFT
pts[1].X = b.X + b.Width - 1 pts[1].X = b.X + b.Width - 1
pts[1].Y = b.Y pts[1].Y = b.Y
pts[1].Code.Fg = b.FgColor pts[1].Code.Fg = toTmAttr(b.FgColor)
pts[1].Code.Bg = b.BgColor pts[1].Code.Bg = toTmAttr(b.BgColor)
pts[1].Code.Ch = TOP_RIGHT pts[1].Code.Ch = TOP_RIGHT
pts[2].X = b.X pts[2].X = b.X
pts[2].Y = b.Y + b.Height - 1 pts[2].Y = b.Y + b.Height - 1
pts[2].Code.Fg = b.FgColor pts[2].Code.Fg = toTmAttr(b.FgColor)
pts[2].Code.Bg = b.BgColor pts[2].Code.Bg = toTmAttr(b.BgColor)
pts[2].Code.Ch = BOTTOM_LEFT pts[2].Code.Ch = BOTTOM_LEFT
pts[3].X = b.X + b.Width - 1 pts[3].X = b.X + b.Width - 1
pts[3].Y = b.Y + b.Height - 1 pts[3].Y = b.Y + b.Height - 1
pts[3].Code.Fg = b.FgColor pts[3].Code.Fg = toTmAttr(b.FgColor)
pts[3].Code.Bg = b.BgColor pts[3].Code.Bg = toTmAttr(b.BgColor)
pts[3].Code.Ch = BOTTOM_RIGHT pts[3].Code.Ch = BOTTOM_RIGHT
copy(pts[4:], (HLine{b.X + 1, b.Y, b.Width - 2, b.FgColor, b.BgColor}).Buffer()) copy(pts[4:], (hline{b.X + 1, b.Y, b.Width - 2, b.FgColor, b.BgColor}).Buffer())
copy(pts[4+b.Width-2:], (HLine{b.X + 1, b.Y + b.Height - 1, b.Width - 2, b.FgColor, b.BgColor}).Buffer()) copy(pts[4+b.Width-2:], (hline{b.X + 1, b.Y + b.Height - 1, b.Width - 2, b.FgColor, b.BgColor}).Buffer())
copy(pts[4+2*b.Width-4:], (VLine{b.X, b.Y + 1, b.Height - 2, b.FgColor, b.BgColor}).Buffer()) copy(pts[4+2*b.Width-4:], (vline{b.X, b.Y + 1, b.Height - 2, b.FgColor, b.BgColor}).Buffer())
copy(pts[4+2*b.Width-4+b.Height-2:], (VLine{b.X + b.Width - 1, b.Y + 1, b.Height - 2, b.FgColor, b.BgColor}).Buffer()) copy(pts[4+2*b.Width-4+b.Height-2:], (vline{b.X + b.Width - 1, b.Y + 1, b.Height - 2, b.FgColor, b.BgColor}).Buffer())
return pts return pts
} }
type LabeledBox struct { type labeledBorder struct {
Box border
Label string Label string
LabelFgColor tm.Attribute LabelFgColor Attribute
LabelBgColor tm.Attribute LabelBgColor Attribute
} }
func (lb LabeledBox) Buffer() []Point { func (lb labeledBorder) Buffer() []Point {
ps := lb.Box.Buffer() ps := lb.border.Buffer()
maxTxtW := lb.Width - 2 maxTxtW := lb.Width - 2
rs := trimStr2Runes(lb.Label, maxTxtW) rs := trimStr2Runes(lb.Label, maxTxtW)
@ -113,8 +111,8 @@ func (lb LabeledBox) Buffer() []Point {
p.X = lb.X + 1 + i p.X = lb.X + 1 + i
p.Y = lb.Y p.Y = lb.Y
p.Code.Ch = rs[i] p.Code.Ch = rs[i]
p.Code.Fg = lb.LabelFgColor p.Code.Fg = toTmAttr(lb.LabelFgColor)
p.Code.Bg = lb.LabelBgColor p.Code.Bg = toTmAttr(lb.LabelBgColor)
ps = append(ps, p) ps = append(ps, p)
} }

56
gauge.go Normal file
View File

@ -0,0 +1,56 @@
package termui
import "strconv"
type Gauge struct {
Block
Percent int
BarColor Attribute
PercentColor Attribute
}
func NewGauge() *Gauge {
g := &Gauge{Block: *NewBlock(), PercentColor: ColorWhite, BarColor: ColorGreen}
g.Width = 12
g.Height = 5
return g
}
func (g *Gauge) Buffer() []Point {
ps := g.Block.Buffer()
w := g.Percent * g.innerWidth / 100
s := strconv.Itoa(g.Percent) + "%"
rs := str2runes(s)
prx := g.innerX + g.innerWidth/2 - 1
pry := g.innerY + g.innerHeight/2
// plot bar
for i := 0; i < g.innerHeight; i++ {
for j := 0; j < w; j++ {
p := Point{}
p.X = g.innerX + j
p.Y = g.innerY + i
p.Code.Ch = ' '
p.Code.Bg = toTmAttr(g.BarColor)
ps = append(ps, p)
}
}
// plot percentage
for i, v := range rs {
p := Point{}
p.X = prx + i
p.Y = pry
p.Code.Ch = v
p.Code.Fg = toTmAttr(g.PercentColor)
if w > g.innerWidth/2-1+i {
p.Code.Bg = toTmAttr(g.BarColor)
} else {
p.Code.Bg = toTmAttr(g.Block.BgColor)
}
ps = append(ps, p)
}
return ps
}

View File

@ -2,6 +2,31 @@ package termui
import "unicode/utf8" import "unicode/utf8"
import "strings" import "strings"
import tm "github.com/nsf/termbox-go"
type Attribute uint16
const (
ColorDefault Attribute = iota
ColorBlack
ColorRed
ColorGreen
ColorYellow
ColorBlue
ColorMagenta
ColorCyan
ColorWhite
)
const (
AttrBold Attribute = 1 << (iota + 9)
AttrUnderline
AttrReverse
)
func toTmAttr(x Attribute) tm.Attribute {
return tm.Attribute(x)
}
func str2runes(s string) []rune { func str2runes(s string) []rune {
n := utf8.RuneCountInString(s) n := utf8.RuneCountInString(s)

71
list.go Normal file
View File

@ -0,0 +1,71 @@
package termui
import "strings"
type List struct {
Block
Items []string
Overflow string
ItemFgColor Attribute
ItemBgColor Attribute
}
func NewList() *List {
l := &List{Block: *NewBlock()}
l.Overflow = "hidden"
return l
}
func (l *List) Buffer() []Point {
ps := l.Block.Buffer()
switch l.Overflow {
case "wrap":
rs := str2runes(strings.Join(l.Items, "\n"))
i, j, k := 0, 0, 0
for i < l.innerHeight && k < len(rs) {
if rs[k] == '\n' || j == l.innerWidth {
i++
j = 0
if rs[k] == '\n' {
k++
}
continue
}
pi := Point{}
pi.X = l.innerX + j
pi.Y = l.innerY + i
pi.Code.Ch = rs[k]
pi.Code.Bg = toTmAttr(l.ItemBgColor)
pi.Code.Fg = toTmAttr(l.ItemFgColor)
ps = append(ps, pi)
k++
j++
}
case "hidden":
trimItems := l.Items
if len(trimItems) > l.innerHeight {
trimItems = trimItems[:l.innerHeight]
}
for i, v := range trimItems {
rs := trimStr2Runes(v, l.innerWidth)
j := 0
for _, vv := range rs {
p := Point{}
p.X = l.innerX + j
p.Y = l.innerY + i
p.Code.Ch = vv
p.Code.Bg = toTmAttr(l.ItemBgColor)
p.Code.Fg = toTmAttr(l.ItemFgColor)
ps = append(ps, p)
j++
}
}
}
return ps
}

22
p.go
View File

@ -1,22 +1,18 @@
package termui package termui
import tm "github.com/nsf/termbox-go"
type P struct { type P struct {
Div Block
Text string Text string
TextFgColor tm.Attribute TextFgColor Attribute
TextBgColor tm.Attribute TextBgColor Attribute
} }
func NewP(s string) P { func NewP(s string) *P {
return P{Div: NewDiv(), Text: s} return &P{Block: *NewBlock(), Text: s}
} }
func (p P) Buffer() []Point { func (p *P) Buffer() []Point {
ps := p.Div.Buffer() ps := p.Block.Buffer()
(&p).sync()
rs := str2runes(p.Text) rs := str2runes(p.Text)
i, j, k := 0, 0, 0 i, j, k := 0, 0, 0
@ -34,8 +30,8 @@ func (p P) Buffer() []Point {
pi.Y = p.innerY + i pi.Y = p.innerY + i
pi.Code.Ch = rs[k] pi.Code.Ch = rs[k]
pi.Code.Bg = p.TextBgColor pi.Code.Bg = toTmAttr(p.TextBgColor)
pi.Code.Fg = p.TextFgColor pi.Code.Fg = toTmAttr(p.TextFgColor)
ps = append(ps, pi) ps = append(ps, pi)
k++ k++

View File

@ -4,6 +4,6 @@ import tm "github.com/nsf/termbox-go"
type Point struct { type Point struct {
Code tm.Cell Code tm.Cell
X int X int
Y int Y int
} }

View File

@ -10,14 +10,16 @@ func Init() error {
return tm.Init() return tm.Init()
} }
func Close(){ func Close() {
tm.Close() tm.Close()
} }
func Render(r Renderer) { func Render(rs ...Renderer) {
buf := r.Buffer() for _, r := range rs {
for _,v := range buf { buf := r.Buffer()
tm.SetCell(v.X,v.Y,v.Code.Ch,v.Code.Fg,v.Code.Bg) for _, v := range buf {
tm.SetCell(v.X, v.Y, v.Code.Ch, v.Code.Fg, v.Code.Bg)
}
} }
tm.Flush() tm.Flush()
} }