Add gauge and list component
This commit is contained in:
parent
ddc86587d8
commit
cc6b38d600
@ -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
74
box.go
@ -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
56
gauge.go
Normal 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
|
||||||
|
}
|
25
helper.go
25
helper.go
@ -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
71
list.go
Normal 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
22
p.go
@ -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++
|
||||||
|
4
point.go
4
point.go
@ -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
|
||||||
}
|
}
|
||||||
|
12
render.go
12
render.go
@ -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()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user