termui/table.go

186 lines
5.3 KiB
Go
Raw Normal View History

2017-01-13 23:07:43 -07:00
// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
2016-11-10 03:55:42 -07:00
package termui
2016-11-25 01:35:00 -07:00
import "strings"
2016-11-10 03:55:42 -07:00
/* Table is like:
Awesome Table
Col0 | Col1 | Col2 | Col3 | Col4 | Col5 | Col6 |
Some Item #1 | AAA | 123 | CCCCC | EEEEE | GGGGG | IIIII |
Some Item #2 | BBB | 456 | DDDDD | FFFFF | HHHHH | JJJJJ |
Datapoints are a two dimensional array of strings: [][]string
Example:
data := [][]string{
{"Col0", "Col1", "Col3", "Col4", "Col5", "Col6"},
{"Some Item #1", "AAA", "123", "CCCCC", "EEEEE", "GGGGG", "IIIII"},
{"Some Item #2", "BBB", "456", "DDDDD", "FFFFF", "HHHHH", "JJJJJ"},
}
2016-11-10 03:55:42 -07:00
table := termui.NewTable()
table.Rows = data // type [][]string
2016-11-10 03:55:42 -07:00
table.FgColor = termui.ColorWhite
table.BgColor = termui.ColorDefault
table.Height = 7
table.Width = 62
table.Y = 0
table.X = 0
table.Border = true
*/
// Table tracks all the attributes of a Table instance
2016-11-10 03:55:42 -07:00
type Table struct {
Block
Rows [][]string
2016-11-25 01:35:00 -07:00
CellWidth []int
2016-11-10 03:55:42 -07:00
FgColor Attribute
BgColor Attribute
FgColors []Attribute
BgColors []Attribute
Separator bool
TextAlign Align
2016-11-10 03:55:42 -07:00
}
// NewTable returns a new Table instance
2016-11-10 03:55:42 -07:00
func NewTable() *Table {
table := &Table{Block: *NewBlock()}
table.FgColor = ColorWhite
table.BgColor = ColorDefault
table.Separator = true
2016-11-10 03:55:42 -07:00
return table
}
// CellsWidth calculates the width of a cell array and returns an int
func cellsWidth(cells []Cell) int {
width := 0
for _, c := range cells {
width += c.Width()
}
return width
}
// Analysis generates and returns an array of []Cell that represent all columns in the Table
func (table *Table) Analysis() [][]Cell {
var rowCells [][]Cell
2016-11-10 03:55:42 -07:00
length := len(table.Rows)
if length < 1 {
return rowCells
2016-11-10 03:55:42 -07:00
}
if len(table.FgColors) == 0 {
table.FgColors = make([]Attribute, len(table.Rows))
}
if len(table.BgColors) == 0 {
table.BgColors = make([]Attribute, len(table.Rows))
}
cellWidths := make([]int, len(table.Rows[0]))
2016-11-10 03:55:42 -07:00
for y, row := range table.Rows {
if table.FgColors[y] == 0 {
table.FgColors[y] = table.FgColor
2016-11-10 03:55:42 -07:00
}
if table.BgColors[y] == 0 {
table.BgColors[y] = table.BgColor
}
for x, str := range row {
cells := DefaultTxBuilder.Build(str, table.FgColors[y], table.BgColors[y])
cw := cellsWidth(cells)
if cellWidths[x] < cw {
cellWidths[x] = cw
}
rowCells = append(rowCells, cells)
}
2016-11-10 03:55:42 -07:00
}
table.CellWidth = cellWidths
return rowCells
2016-11-10 03:55:42 -07:00
}
// SetSize calculates the table size and sets the internal value
2016-11-10 03:55:42 -07:00
func (table *Table) SetSize() {
length := len(table.Rows)
if table.Separator {
table.Height = length*2 + 1
} else {
table.Height = length + 2
}
2016-11-10 03:55:42 -07:00
table.Width = 2
if length != 0 {
for _, cellWidth := range table.CellWidth {
table.Width += cellWidth + 3
2016-11-10 03:55:42 -07:00
}
}
}
// CalculatePosition ...
func (table *Table) CalculatePosition(x int, y int, coordinateX *int, coordinateY *int, cellStart *int) {
if table.Separator {
*coordinateY = table.innerArea.Min.Y + y*2
2016-11-25 01:35:00 -07:00
} else {
*coordinateY = table.innerArea.Min.Y + y
2016-11-25 01:35:00 -07:00
}
if x == 0 {
*cellStart = table.innerArea.Min.X
2016-11-25 01:35:00 -07:00
} else {
*cellStart += table.CellWidth[x-1] + 3
2016-11-25 01:35:00 -07:00
}
switch table.TextAlign {
case AlignRight:
*coordinateX = *cellStart + (table.CellWidth[x] - len(table.Rows[y][x])) + 2
case AlignCenter:
*coordinateX = *cellStart + (table.CellWidth[x]-len(table.Rows[y][x]))/2 + 2
default:
*coordinateX = *cellStart + 2
2016-11-25 01:35:00 -07:00
}
}
// Buffer ...
2016-11-10 03:55:42 -07:00
func (table *Table) Buffer() Buffer {
buffer := table.Block.Buffer()
rowCells := table.Analysis()
pointerX := table.innerArea.Min.X + 2
pointerY := table.innerArea.Min.Y
borderPointerX := table.innerArea.Min.X
2016-11-25 01:35:00 -07:00
for y, row := range table.Rows {
for x := range row {
table.CalculatePosition(x, y, &pointerX, &pointerY, &borderPointerX)
background := DefaultTxBuilder.Build(strings.Repeat(" ", table.CellWidth[x]+3), table.BgColors[y], table.BgColors[y])
cells := rowCells[y*len(row)+x]
for i, back := range background {
buffer.Set(borderPointerX+i, pointerY, back)
}
2016-11-10 03:55:42 -07:00
coordinateX := pointerX
2016-11-25 01:35:00 -07:00
for _, printer := range cells {
buffer.Set(coordinateX, pointerY, printer)
coordinateX += printer.Width()
}
2016-11-25 01:35:00 -07:00
if x != 0 {
dividors := DefaultTxBuilder.Build("|", table.FgColors[y], table.BgColors[y])
for _, dividor := range dividors {
buffer.Set(borderPointerX, pointerY, dividor)
2016-11-25 01:35:00 -07:00
}
}
}
if table.Separator {
2016-11-25 01:35:00 -07:00
border := DefaultTxBuilder.Build(strings.Repeat("─", table.Width-2), table.FgColor, table.BgColor)
for i, cell := range border {
buffer.Set(i+1, pointerY+1, cell)
}
2016-11-10 03:55:42 -07:00
}
}
2016-11-25 01:35:00 -07:00
2016-11-10 03:55:42 -07:00
return buffer
}