WIP use Buffer instead of []Point in Bufferer
Merge https://github.com/Matt3o12/termui.git colored-list Merge https://github.com/funkygao/termui.git master Add subdir widget Use image Rectangle represent buffer area
This commit is contained in:
parent
0a29dad7e7
commit
7aed750f64
124
block.go
124
block.go
@ -4,22 +4,22 @@
|
||||
|
||||
package termui
|
||||
|
||||
import "image"
|
||||
|
||||
// Block is a base struct for all other upper level widgets,
|
||||
// consider it as css: display:block.
|
||||
// Normally you do not need to create it manually.
|
||||
type Block struct {
|
||||
Area image.Rectangle
|
||||
innerArea image.Rectangle
|
||||
X int
|
||||
Y int
|
||||
Border labeledBorder
|
||||
Border LabeledBorder
|
||||
IsDisplay bool
|
||||
HasBorder bool
|
||||
BgColor Attribute
|
||||
Bg Attribute
|
||||
Width int
|
||||
Height int
|
||||
innerWidth int
|
||||
innerHeight int
|
||||
innerX int
|
||||
innerY int
|
||||
PaddingTop int
|
||||
PaddingBottom int
|
||||
PaddingLeft int
|
||||
@ -31,75 +31,81 @@ func NewBlock() *Block {
|
||||
d := Block{}
|
||||
d.IsDisplay = 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.Border.Left = true
|
||||
d.Border.Right = true
|
||||
d.Border.Top = true
|
||||
d.Border.Bottom = true
|
||||
d.Border.Bg = theme.BorderBg
|
||||
d.Border.Fg = theme.BorderFg
|
||||
d.Border.LabelBgClr = theme.BorderLabelTextBg
|
||||
d.Border.LabelFgClr = theme.BorderLabelTextFg
|
||||
d.Bg = theme.BlockBg
|
||||
d.Width = 2
|
||||
d.Height = 2
|
||||
return &d
|
||||
}
|
||||
|
||||
// compute box model
|
||||
func (d *Block) align() {
|
||||
d.innerWidth = d.Width - d.PaddingLeft - d.PaddingRight
|
||||
d.innerHeight = d.Height - d.PaddingTop - d.PaddingBottom
|
||||
d.innerX = d.X + d.PaddingLeft
|
||||
d.innerY = d.Y + d.PaddingTop
|
||||
// Align computes box model
|
||||
func (d *Block) Align() {
|
||||
d.Area.Min.X = d.X
|
||||
d.Area.Min.Y = d.Y
|
||||
d.Area.Max.X = d.X + d.Width - 1
|
||||
d.Area.Max.Y = d.Y + d.Height - 1
|
||||
|
||||
d.innerArea.Min.X = d.X + d.PaddingLeft
|
||||
d.innerArea.Min.Y = d.Y + d.PaddingTop
|
||||
d.innerArea.Max.X = d.Area.Max.X - d.PaddingRight
|
||||
d.innerArea.Max.Y = d.Area.Max.Y - d.PaddingBottom
|
||||
|
||||
d.Border.Area = d.Area
|
||||
|
||||
if d.HasBorder {
|
||||
d.innerHeight -= 2
|
||||
d.innerWidth -= 2
|
||||
d.Border.X = d.X
|
||||
d.Border.Y = d.Y
|
||||
d.Border.Width = d.Width
|
||||
d.Border.Height = d.Height
|
||||
d.innerX++
|
||||
d.innerY++
|
||||
switch {
|
||||
case d.Border.Left:
|
||||
d.innerArea.Min.X++
|
||||
fallthrough
|
||||
case d.Border.Right:
|
||||
d.innerArea.Max.X--
|
||||
fallthrough
|
||||
case d.Border.Top:
|
||||
d.innerArea.Min.Y++
|
||||
fallthrough
|
||||
case d.Border.Bottom:
|
||||
d.innerArea.Max.Y--
|
||||
}
|
||||
}
|
||||
|
||||
if d.innerHeight < 0 {
|
||||
d.innerHeight = 0
|
||||
}
|
||||
if d.innerWidth < 0 {
|
||||
d.innerWidth = 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// InnerBounds returns the internal bounds of the block after aligning and
|
||||
// calculating the padding and border, if any.
|
||||
func (d *Block) InnerBounds() (x, y, width, height int) {
|
||||
d.align()
|
||||
return d.innerX, d.innerY, d.innerWidth, d.innerHeight
|
||||
func (d *Block) InnerBounds() image.Rectangle {
|
||||
d.Align()
|
||||
return d.innerArea
|
||||
}
|
||||
|
||||
// Buffer implements Bufferer interface.
|
||||
// Draw background and border (if any).
|
||||
func (d *Block) Buffer() []Point {
|
||||
d.align()
|
||||
func (d *Block) Buffer() Buffer {
|
||||
d.Align()
|
||||
|
||||
ps := []Point{}
|
||||
buf := NewBuffer()
|
||||
buf.Area = d.Area
|
||||
if !d.IsDisplay {
|
||||
return ps
|
||||
return buf
|
||||
}
|
||||
|
||||
// render border
|
||||
if d.HasBorder {
|
||||
ps = d.Border.Buffer()
|
||||
buf.Union(d.Border.Buffer())
|
||||
}
|
||||
|
||||
for i := 0; i < d.innerWidth; i++ {
|
||||
for j := 0; j < d.innerHeight; j++ {
|
||||
p := Point{}
|
||||
p.X = d.X + 1 + i
|
||||
p.Y = d.Y + 1 + j
|
||||
p.Ch = ' '
|
||||
p.Bg = d.BgColor
|
||||
ps = append(ps, p)
|
||||
// render background
|
||||
for p := range buf.CellMap {
|
||||
if p.In(d.innerArea) {
|
||||
buf.CellMap[p] = Cell{' ', ColorDefault, d.Bg}
|
||||
}
|
||||
}
|
||||
return ps
|
||||
return buf
|
||||
}
|
||||
|
||||
// GetHeight implements GridBufferer.
|
||||
@ -122,21 +128,3 @@ func (d *Block) SetY(y int) {
|
||||
func (d *Block) SetWidth(w int) {
|
||||
d.Width = w
|
||||
}
|
||||
|
||||
// chop the overflow parts
|
||||
func (d *Block) chopOverflow(ps []Point) []Point {
|
||||
nps := make([]Point, 0, len(ps))
|
||||
x := d.X
|
||||
y := d.Y
|
||||
w := d.Width
|
||||
h := d.Height
|
||||
for _, v := range ps {
|
||||
if v.X >= x &&
|
||||
v.X < x+w &&
|
||||
v.Y >= y &&
|
||||
v.Y < y+h {
|
||||
nps = append(nps, v)
|
||||
}
|
||||
}
|
||||
return nps
|
||||
}
|
||||
|
198
box.go
198
box.go
@ -4,114 +4,120 @@
|
||||
|
||||
package termui
|
||||
|
||||
type border struct {
|
||||
X int
|
||||
Y int
|
||||
Width int
|
||||
Height int
|
||||
FgColor Attribute
|
||||
BgColor Attribute
|
||||
import "image"
|
||||
|
||||
type Border struct {
|
||||
Area image.Rectangle
|
||||
Left bool
|
||||
Top bool
|
||||
Right bool
|
||||
Bottom bool
|
||||
Fg Attribute
|
||||
Bg Attribute
|
||||
}
|
||||
|
||||
type hline struct {
|
||||
X int
|
||||
Y int
|
||||
Length int
|
||||
FgColor Attribute
|
||||
BgColor Attribute
|
||||
type Hline struct {
|
||||
X int
|
||||
Y int
|
||||
Len int
|
||||
Fg Attribute
|
||||
Bg Attribute
|
||||
}
|
||||
|
||||
type vline struct {
|
||||
X int
|
||||
Y int
|
||||
Length int
|
||||
FgColor Attribute
|
||||
BgColor Attribute
|
||||
type Vline struct {
|
||||
X int
|
||||
Y int
|
||||
Len int
|
||||
Fg Attribute
|
||||
Bg Attribute
|
||||
}
|
||||
|
||||
// Draw a horizontal line.
|
||||
func (l hline) Buffer() []Point {
|
||||
pts := make([]Point, l.Length)
|
||||
for i := 0; i < l.Length; i++ {
|
||||
pts[i].X = l.X + i
|
||||
pts[i].Y = l.Y
|
||||
pts[i].Ch = HORIZONTAL_LINE
|
||||
pts[i].Bg = l.BgColor
|
||||
pts[i].Fg = l.FgColor
|
||||
// Buffer draws a horizontal line.
|
||||
func (l Hline) Buffer() Buffer {
|
||||
buf := NewBuffer()
|
||||
for i := 0; i < l.Len; i++ {
|
||||
buf.Set(l.X+i, l.Y, Cell{HORIZONTAL_LINE, l.Fg, l.Bg})
|
||||
}
|
||||
return pts
|
||||
buf.Align()
|
||||
return buf
|
||||
}
|
||||
|
||||
// Draw a vertical line.
|
||||
func (l vline) Buffer() []Point {
|
||||
pts := make([]Point, l.Length)
|
||||
for i := 0; i < l.Length; i++ {
|
||||
pts[i].X = l.X
|
||||
pts[i].Y = l.Y + i
|
||||
pts[i].Ch = VERTICAL_LINE
|
||||
pts[i].Bg = l.BgColor
|
||||
pts[i].Fg = l.FgColor
|
||||
// Buffer draws a vertical line.
|
||||
func (l Vline) Buffer() Buffer {
|
||||
buf := NewBuffer()
|
||||
for i := 0; i < l.Len; i++ {
|
||||
buf.Set(l.X, l.Y+i, Cell{VERTICAL_LINE, l.Fg, l.Bg})
|
||||
}
|
||||
return pts
|
||||
buf.Align()
|
||||
return buf
|
||||
}
|
||||
|
||||
// Draw a box border.
|
||||
func (b border) Buffer() []Point {
|
||||
if b.Width < 2 || b.Height < 2 {
|
||||
return nil
|
||||
}
|
||||
pts := make([]Point, 2*b.Width+2*b.Height-4)
|
||||
|
||||
pts[0].X = b.X
|
||||
pts[0].Y = b.Y
|
||||
pts[0].Fg = b.FgColor
|
||||
pts[0].Bg = b.BgColor
|
||||
pts[0].Ch = TOP_LEFT
|
||||
|
||||
pts[1].X = b.X + b.Width - 1
|
||||
pts[1].Y = b.Y
|
||||
pts[1].Fg = b.FgColor
|
||||
pts[1].Bg = b.BgColor
|
||||
pts[1].Ch = TOP_RIGHT
|
||||
|
||||
pts[2].X = b.X
|
||||
pts[2].Y = b.Y + b.Height - 1
|
||||
pts[2].Fg = b.FgColor
|
||||
pts[2].Bg = b.BgColor
|
||||
pts[2].Ch = BOTTOM_LEFT
|
||||
|
||||
pts[3].X = b.X + b.Width - 1
|
||||
pts[3].Y = b.Y + b.Height - 1
|
||||
pts[3].Fg = b.FgColor
|
||||
pts[3].Bg = b.BgColor
|
||||
pts[3].Ch = BOTTOM_RIGHT
|
||||
|
||||
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+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())
|
||||
|
||||
return pts
|
||||
}
|
||||
|
||||
type labeledBorder struct {
|
||||
border
|
||||
Label string
|
||||
LabelFgColor Attribute
|
||||
LabelBgColor Attribute
|
||||
}
|
||||
|
||||
// Draw a box border with label.
|
||||
func (lb labeledBorder) Buffer() []Point {
|
||||
ps := lb.border.Buffer()
|
||||
maxTxtW := lb.Width - 2
|
||||
rs := trimStr2Runes(lb.Label, maxTxtW)
|
||||
|
||||
for i, j, w := 0, 0, 0; i < len(rs); i++ {
|
||||
w = charWidth(rs[i])
|
||||
ps = append(ps, newPointWithAttrs(rs[i], lb.X+1+j, lb.Y, lb.LabelFgColor, lb.LabelBgColor))
|
||||
j += w
|
||||
// Buffer draws a box border.
|
||||
func (b Border) Buffer() Buffer {
|
||||
buf := NewBuffer()
|
||||
if b.Area.Size().X < 2 || b.Area.Size().Y < 2 {
|
||||
return buf
|
||||
}
|
||||
|
||||
return ps
|
||||
min := b.Area.Min
|
||||
max := b.Area.Max
|
||||
|
||||
x0 := min.X
|
||||
y0 := min.Y
|
||||
x1 := max.X
|
||||
y1 := max.Y
|
||||
|
||||
// draw lines
|
||||
switch {
|
||||
case b.Top:
|
||||
buf.Union(Hline{x0, y0, x1 - x0, b.Fg, b.Bg}.Buffer())
|
||||
fallthrough
|
||||
case b.Bottom:
|
||||
buf.Union(Hline{x0, y1, x1 - x0, b.Fg, b.Bg}.Buffer())
|
||||
fallthrough
|
||||
case b.Left:
|
||||
buf.Union(Vline{x0, y0, y1 - y0, b.Fg, b.Bg}.Buffer())
|
||||
fallthrough
|
||||
case b.Right:
|
||||
buf.Union(Vline{x1, y0, y1 - y0, b.Fg, b.Bg}.Buffer())
|
||||
}
|
||||
|
||||
// draw corners
|
||||
switch {
|
||||
case b.Top && b.Left:
|
||||
buf.Set(x0, y0, Cell{TOP_LEFT, b.Fg, b.Bg})
|
||||
fallthrough
|
||||
case b.Top && b.Right:
|
||||
buf.Set(x1, y0, Cell{TOP_RIGHT, b.Fg, b.Bg})
|
||||
fallthrough
|
||||
case b.Bottom && b.Left:
|
||||
buf.Set(x0, y1, Cell{BOTTOM_LEFT, b.Fg, b.Bg})
|
||||
fallthrough
|
||||
case b.Bottom && b.Right:
|
||||
buf.Set(x1, y1, Cell{BOTTOM_RIGHT, b.Fg, b.Bg})
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
||||
|
||||
// LabeledBorder defined label upon Border
|
||||
type LabeledBorder struct {
|
||||
Border
|
||||
Label string
|
||||
LabelFgClr Attribute
|
||||
LabelBgClr Attribute
|
||||
}
|
||||
|
||||
// Buffer draw a box border with label.
|
||||
func (lb LabeledBorder) Buffer() Buffer {
|
||||
border := lb.Border.Buffer()
|
||||
maxTxtW := lb.Area.Dx() + 1 - 2
|
||||
tx := DTrimTxCls(TextCells(lb.Label, lb.LabelFgClr, lb.LabelBgClr), maxTxtW)
|
||||
|
||||
for i, w := 0, 0; i < len(tx); i++ {
|
||||
border.Set(border.Area.Min.X+1+w, border.Area.Min.Y, tx[i])
|
||||
w += tx[i].Width()
|
||||
}
|
||||
|
||||
return border
|
||||
}
|
||||
|
89
buffer.go
Normal file
89
buffer.go
Normal file
@ -0,0 +1,89 @@
|
||||
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can
|
||||
// be found in the LICENSE file.
|
||||
|
||||
package termui
|
||||
|
||||
import "image"
|
||||
|
||||
// Cell is a rune with assigned Fg and Bg
|
||||
type Cell struct {
|
||||
Ch rune
|
||||
Fg Attribute
|
||||
Bg Attribute
|
||||
}
|
||||
|
||||
// Buffer is a renderable rectangle cell data container.
|
||||
type Buffer struct {
|
||||
Area image.Rectangle // selected drawing area
|
||||
CellMap map[image.Point]Cell
|
||||
}
|
||||
|
||||
// At returns the cell at (x,y).
|
||||
func (b Buffer) At(x, y int) Cell {
|
||||
return b.CellMap[image.Pt(x, y)]
|
||||
}
|
||||
|
||||
// Set assigns a char to (x,y)
|
||||
func (b Buffer) Set(x, y int, c Cell) {
|
||||
b.CellMap[image.Pt(x, y)] = c
|
||||
}
|
||||
|
||||
// Bounds returns the domain for which At can return non-zero color.
|
||||
func (b Buffer) Bounds() image.Rectangle {
|
||||
x0, y0, x1, y1 := 0, 0, 0, 0
|
||||
for p := range b.CellMap {
|
||||
switch {
|
||||
case p.X > x1:
|
||||
x1 = p.X
|
||||
case p.X < x0:
|
||||
x0 = p.X
|
||||
case p.Y > y1:
|
||||
y1 = p.Y
|
||||
case p.Y < y0:
|
||||
y0 = p.Y
|
||||
}
|
||||
}
|
||||
return image.Rect(x0, y0, x1, y1)
|
||||
}
|
||||
|
||||
// Align sets drawing area to the buffer's bound
|
||||
func (b *Buffer) Align() {
|
||||
b.Area = b.Bounds()
|
||||
}
|
||||
|
||||
// NewCell returns a new cell
|
||||
func NewCell(ch rune, fg, bg Attribute) Cell {
|
||||
return Cell{ch, fg, bg}
|
||||
}
|
||||
|
||||
// Union squeezes buf into b
|
||||
func (b Buffer) Union(buf Buffer) {
|
||||
for p, c := range buf.CellMap {
|
||||
b.Set(p.X, p.Y, c)
|
||||
}
|
||||
}
|
||||
|
||||
// Union returns a new Buffer formed by squeezing bufs into one Buffer
|
||||
func Union(bufs ...Buffer) Buffer {
|
||||
buf := NewBuffer()
|
||||
for _, b := range bufs {
|
||||
buf.Union(b)
|
||||
}
|
||||
buf.Align()
|
||||
return buf
|
||||
}
|
||||
|
||||
// Point for adapting use, will be removed after resolving bridging.
|
||||
type Point struct {
|
||||
X int
|
||||
Y int
|
||||
Ch rune
|
||||
Fg Attribute
|
||||
Bg Attribute
|
||||
}
|
||||
|
||||
// NewBuffer returns a new Buffer
|
||||
func NewBuffer() Buffer {
|
||||
return Buffer{CellMap: make(map[image.Point]Cell)}
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
package main
|
||||
|
||||
import "github.com/gizak/termui"
|
||||
import "github.com/gizak/termui/widget"
|
||||
|
||||
func main() {
|
||||
err := termui.Init()
|
||||
@ -17,16 +18,23 @@ func main() {
|
||||
|
||||
termui.UseTheme("helloworld")
|
||||
|
||||
g0 := termui.NewGauge()
|
||||
g0 := widget.NewGauge()
|
||||
g0.Percent = 40
|
||||
g0.Width = 50
|
||||
g0.Height = 3
|
||||
g0.Border.Label = "Slim Gauge"
|
||||
g0.BarColor = termui.ColorRed
|
||||
g0.Border.FgColor = termui.ColorWhite
|
||||
g0.Border.LabelFgColor = termui.ColorCyan
|
||||
g0.Border.Fg = termui.ColorWhite
|
||||
g0.Border.LabelFgClr = termui.ColorCyan
|
||||
|
||||
g2 := termui.NewGauge()
|
||||
gg := termui.NewBlock()
|
||||
gg.Width = 50
|
||||
gg.Height = 5
|
||||
gg.Y = 12
|
||||
gg.Border.Label = "TEST"
|
||||
gg.Align()
|
||||
|
||||
g2 := widget.NewGauge()
|
||||
g2.Percent = 60
|
||||
g2.Width = 50
|
||||
g2.Height = 3
|
||||
@ -34,9 +42,9 @@ func main() {
|
||||
g2.Y = 3
|
||||
g2.Border.Label = "Slim Gauge"
|
||||
g2.BarColor = termui.ColorYellow
|
||||
g2.Border.FgColor = termui.ColorWhite
|
||||
g2.Border.Fg = termui.ColorWhite
|
||||
|
||||
g1 := termui.NewGauge()
|
||||
g1 := widget.NewGauge()
|
||||
g1.Percent = 30
|
||||
g1.Width = 50
|
||||
g1.Height = 5
|
||||
@ -44,10 +52,10 @@ func main() {
|
||||
g1.Border.Label = "Big Gauge"
|
||||
g1.PercentColor = termui.ColorYellow
|
||||
g1.BarColor = termui.ColorGreen
|
||||
g1.Border.FgColor = termui.ColorWhite
|
||||
g1.Border.LabelFgColor = termui.ColorMagenta
|
||||
g1.Border.Fg = termui.ColorWhite
|
||||
g1.Border.LabelFgClr = termui.ColorMagenta
|
||||
|
||||
termui.Render(g0, g1, g2)
|
||||
termui.Render(g0, g1, g2, gg)
|
||||
|
||||
<-termui.EventCh()
|
||||
}
|
||||
|
83
gauge.go
83
gauge.go
@ -1,83 +0,0 @@
|
||||
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can
|
||||
// be found in the LICENSE file.
|
||||
|
||||
package termui
|
||||
|
||||
import "strconv"
|
||||
|
||||
// Gauge is a progress bar like widget.
|
||||
// A simple example:
|
||||
/*
|
||||
g := termui.NewGauge()
|
||||
g.Percent = 40
|
||||
g.Width = 50
|
||||
g.Height = 3
|
||||
g.Border.Label = "Slim Gauge"
|
||||
g.BarColor = termui.ColorRed
|
||||
g.PercentColor = termui.ColorBlue
|
||||
*/
|
||||
type Gauge struct {
|
||||
Block
|
||||
Percent int
|
||||
BarColor Attribute
|
||||
PercentColor Attribute
|
||||
}
|
||||
|
||||
// NewGauge return a new gauge with current theme.
|
||||
func NewGauge() *Gauge {
|
||||
g := &Gauge{
|
||||
Block: *NewBlock(),
|
||||
PercentColor: theme.GaugePercent,
|
||||
BarColor: theme.GaugeBar}
|
||||
g.Width = 12
|
||||
g.Height = 5
|
||||
return g
|
||||
}
|
||||
|
||||
// Buffer implements Bufferer interface.
|
||||
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.Ch = ' '
|
||||
p.Bg = g.BarColor
|
||||
if p.Bg == ColorDefault {
|
||||
p.Bg |= AttrReverse
|
||||
}
|
||||
ps = append(ps, p)
|
||||
}
|
||||
}
|
||||
|
||||
// plot percentage
|
||||
for i, v := range rs {
|
||||
p := Point{}
|
||||
p.X = prx + i
|
||||
p.Y = pry
|
||||
p.Ch = v
|
||||
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
|
||||
}
|
||||
ps = append(ps, p)
|
||||
}
|
||||
return g.Block.chopOverflow(ps)
|
||||
}
|
17
grid.go
17
grid.go
@ -160,8 +160,8 @@ func (r *Row) SetWidth(w int) {
|
||||
|
||||
// Buffer implements Bufferer interface,
|
||||
// recursively merge all widgets buffer
|
||||
func (r *Row) Buffer() []Point {
|
||||
merged := []Point{}
|
||||
func (r *Row) Buffer() Buffer {
|
||||
merged := Buffer{}
|
||||
|
||||
if r.isRenderableLeaf() {
|
||||
return r.Widget.Buffer()
|
||||
@ -169,13 +169,13 @@ func (r *Row) Buffer() []Point {
|
||||
|
||||
// for those are not leaves but have a renderable widget
|
||||
if r.Widget != nil {
|
||||
merged = append(merged, r.Widget.Buffer()...)
|
||||
merged.Union(r.Widget.Buffer())
|
||||
}
|
||||
|
||||
// collect buffer from children
|
||||
if !r.isLeaf() {
|
||||
for _, c := range r.Cols {
|
||||
merged = append(merged, c.Buffer()...)
|
||||
merged.Union(c.Buffer())
|
||||
}
|
||||
}
|
||||
|
||||
@ -267,12 +267,13 @@ func (g *Grid) Align() {
|
||||
}
|
||||
|
||||
// Buffer implments Bufferer interface.
|
||||
func (g Grid) Buffer() []Point {
|
||||
ps := []Point{}
|
||||
func (g Grid) Buffer() Buffer {
|
||||
buf := Buffer{}
|
||||
|
||||
for _, r := range g.Rows {
|
||||
ps = append(ps, r.Buffer()...)
|
||||
buf.Union(r.Buffer())
|
||||
}
|
||||
return ps
|
||||
return buf
|
||||
}
|
||||
|
||||
// Body corresponds to the entire terminal display region.
|
||||
|
57
helper.go
57
helper.go
@ -148,3 +148,60 @@ func StringToAttribute(text string) Attribute {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// TextCells returns a coloured text cells []Cell
|
||||
func TextCells(s string, fg, bg Attribute) []Cell {
|
||||
cs := make([]Cell, 0, len(s))
|
||||
|
||||
// sequence := MarkdownTextRendererFactory{}.TextRenderer(s).Render(fg, bg)
|
||||
// runes := []rune(sequence.NormalizedText)
|
||||
runes := str2runes(s)
|
||||
|
||||
for n := range runes {
|
||||
// point, _ := sequence.PointAt(n, 0, 0)
|
||||
// cs = append(cs, Cell{point.Ch, point.Fg, point.Bg})
|
||||
cs = append(cs, Cell{runes[n], fg, bg})
|
||||
}
|
||||
return cs
|
||||
}
|
||||
|
||||
// Width returns the actual screen space the cell takes (usually 1 or 2).
|
||||
func (c Cell) Width() int {
|
||||
return charWidth(c.Ch)
|
||||
}
|
||||
|
||||
// Copy return a copy of c
|
||||
func (c Cell) Copy() Cell {
|
||||
return c
|
||||
}
|
||||
|
||||
// TrimTxCells trims the overflowed text cells sequence.
|
||||
func TrimTxCells(cs []Cell, w int) []Cell {
|
||||
if len(cs) <= w {
|
||||
return cs
|
||||
}
|
||||
return cs[:w]
|
||||
}
|
||||
|
||||
// DTrimTxCls trims the overflowed text cells sequence and append dots at the end.
|
||||
func DTrimTxCls(cs []Cell, w int) []Cell {
|
||||
l := len(cs)
|
||||
if l <= 0 {
|
||||
return []Cell{}
|
||||
}
|
||||
|
||||
rt := make([]Cell, 0, w)
|
||||
csw := 0
|
||||
for i := 0; i < l && csw <= w; i++ {
|
||||
c := cs[i]
|
||||
cw := c.Width()
|
||||
|
||||
if cw+csw <= w {
|
||||
rt = append(rt, c)
|
||||
} else {
|
||||
rt = append(rt, Cell{'…', c.Fg, c.Bg})
|
||||
}
|
||||
}
|
||||
|
||||
return rt
|
||||
}
|
||||
|
28
point.go
28
point.go
@ -1,28 +0,0 @@
|
||||
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can
|
||||
// be found in the LICENSE file.
|
||||
|
||||
package termui
|
||||
|
||||
// Point stands for a single cell in terminal.
|
||||
type Point struct {
|
||||
Ch rune
|
||||
Bg Attribute
|
||||
Fg Attribute
|
||||
X int
|
||||
Y int
|
||||
}
|
||||
|
||||
func newPoint(c rune, x, y int) (p Point) {
|
||||
p.Ch = c
|
||||
p.X = x
|
||||
p.Y = y
|
||||
return
|
||||
}
|
||||
|
||||
func newPointWithAttrs(c rune, x, y int, fg, bg Attribute) Point {
|
||||
p := newPoint(c, x, y)
|
||||
p.Bg = bg
|
||||
p.Fg = fg
|
||||
return p
|
||||
}
|
17
render.go
17
render.go
@ -8,7 +8,7 @@ import tm "github.com/nsf/termbox-go"
|
||||
|
||||
// Bufferer should be implemented by all renderable components.
|
||||
type Bufferer interface {
|
||||
Buffer() []Point
|
||||
Buffer() Buffer
|
||||
}
|
||||
|
||||
// Init initializes termui library. This function should be called before any others.
|
||||
@ -46,13 +46,18 @@ func TermHeight() int {
|
||||
|
||||
// Render renders all Bufferer in the given order from left to right,
|
||||
// right could overlap on left ones.
|
||||
func Render(rs ...Bufferer) {
|
||||
func Render(bs ...Bufferer) {
|
||||
// set tm bg
|
||||
tm.Clear(tm.ColorDefault, toTmAttr(theme.BodyBg))
|
||||
for _, r := range rs {
|
||||
buf := r.Buffer()
|
||||
for _, v := range buf {
|
||||
tm.SetCell(v.X, v.Y, v.Ch, toTmAttr(v.Fg), toTmAttr(v.Bg))
|
||||
for _, b := range bs {
|
||||
buf := b.Buffer()
|
||||
// set cels in buf
|
||||
for p, c := range buf.CellMap {
|
||||
if true { //}p.In(buf.Area) {
|
||||
tm.SetCell(p.X, p.Y, c.Ch, toTmAttr(c.Fg), toTmAttr(c.Bg))
|
||||
}
|
||||
}
|
||||
}
|
||||
// render
|
||||
tm.Flush()
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
// +build ignore
|
||||
|
||||
package termui
|
||||
|
||||
import (
|
||||
|
@ -1,3 +1,5 @@
|
||||
// +build ignore
|
||||
|
||||
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can
|
||||
// be found in the LICENSE file.
|
@ -1,3 +1,5 @@
|
||||
// +build ignore
|
||||
|
||||
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can
|
||||
// be found in the LICENSE file.
|
@ -1,3 +1,5 @@
|
||||
//+build ignore
|
||||
|
||||
package termui
|
||||
|
||||
import (
|
67
widget/gauge.go
Normal file
67
widget/gauge.go
Normal file
@ -0,0 +1,67 @@
|
||||
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can
|
||||
// be found in the LICENSE file.
|
||||
|
||||
package widget
|
||||
|
||||
import "github.com/gizak/termui"
|
||||
import "strconv"
|
||||
|
||||
// Gauge is a progress bar like widget.
|
||||
// A simple example:
|
||||
/*
|
||||
g := termui.NewGauge()
|
||||
g.Percent = 40
|
||||
g.Width = 50
|
||||
g.Height = 3
|
||||
g.Border.Label = "Slim Gauge"
|
||||
g.BarColor = termui.ColorRed
|
||||
g.PercentColor = termui.ColorBlue
|
||||
*/
|
||||
type Gauge struct {
|
||||
termui.Block
|
||||
Percent int
|
||||
BarColor termui.Attribute
|
||||
PercentColor termui.Attribute
|
||||
}
|
||||
|
||||
// NewGauge return a new gauge with current theme.
|
||||
func NewGauge() *Gauge {
|
||||
g := &Gauge{
|
||||
Block: *termui.NewBlock(),
|
||||
PercentColor: termui.Theme().GaugePercent,
|
||||
BarColor: termui.Theme().GaugeBar}
|
||||
g.Width = 12
|
||||
g.Height = 3
|
||||
return g
|
||||
}
|
||||
|
||||
// Buffer implements Bufferer interface.
|
||||
func (g *Gauge) Buffer() termui.Buffer {
|
||||
buf := g.Block.Buffer()
|
||||
|
||||
inner := g.InnerBounds()
|
||||
w := g.Percent * (inner.Dx() + 1) / 100
|
||||
s := strconv.Itoa(g.Percent) + "%"
|
||||
tx := termui.TextCells(s, g.PercentColor, g.Bg)
|
||||
|
||||
prx := inner.Min.X + (inner.Dx()+1)/2 - 1
|
||||
pry := inner.Min.Y + (inner.Dy()+1)/2
|
||||
|
||||
// plot bar
|
||||
for i := 0; i <= inner.Dy(); i++ {
|
||||
for j := 0; j < w; j++ {
|
||||
c := termui.Cell{' ', g.BarColor, g.BarColor}
|
||||
buf.Set(inner.Min.X+j, inner.Min.Y+i, c)
|
||||
}
|
||||
}
|
||||
|
||||
// plot percentage
|
||||
for i, v := range tx {
|
||||
if w > (inner.Dx()+1)/2-1+i {
|
||||
v.Bg = g.BarColor
|
||||
}
|
||||
buf.Set(prx+i, pry, v)
|
||||
}
|
||||
return buf
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
// +build ignore
|
||||
|
||||
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can
|
||||
// be found in the LICENSE file.
|
@ -1,3 +1,5 @@
|
||||
// +build ignore
|
||||
|
||||
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can
|
||||
// be found in the LICENSE file.
|
@ -1,3 +1,5 @@
|
||||
// +build ignore
|
||||
|
||||
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can
|
||||
// be found in the LICENSE file.
|
@ -1,3 +1,5 @@
|
||||
// +build ignore
|
||||
|
||||
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can
|
||||
// be found in the LICENSE file.
|
@ -1,3 +1,5 @@
|
||||
// +build ignore
|
||||
|
||||
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can
|
||||
// be found in the LICENSE file.
|
@ -1,3 +1,5 @@
|
||||
// +build ignore
|
||||
|
||||
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can
|
||||
// be found in the LICENSE file.
|
Loading…
Reference in New Issue
Block a user