xmtop/termui/table.go

180 lines
3.8 KiB
Go
Raw Normal View History

2018-02-18 23:25:02 -08:00
package termui
import (
"strings"
)
// Table tracks all the attributes of a Table instance
type Table struct {
*Block
Header []string
Rows [][]string
ColWidths []int
2018-03-03 17:05:52 -08:00
CellXPos []int // column position
Gap int // gap between columns
Cursor Color
UniqueCol int // the column used to identify the selected item
SelectedItem string // used to keep the cursor on the correct item if the data changes
SelectedRow int
2018-02-25 22:51:51 -08:00
TopRow int // used to indicate where in the table we are scrolled at
ColResizer func() // for widgets that inherit a Table and want to overload the ColResize method
2018-02-18 23:25:02 -08:00
}
// NewTable returns a new Table instance
func NewTable() *Table {
t := &Table{
Block: NewBlock(),
Cursor: Theme.TableCursor,
SelectedRow: 0,
TopRow: 0,
UniqueCol: 0,
2018-02-18 23:25:02 -08:00
}
t.ColResizer = t.ColResize
return t
2018-02-18 23:25:02 -08:00
}
// ColResize is the default column resizer, but can be overriden.
2018-03-03 17:05:52 -08:00
// ColResize calculates the width of each column.
func (t *Table) ColResize() {
2018-02-18 23:25:02 -08:00
// calculate gap size based on total width
t.Gap = 3
2018-02-18 23:25:02 -08:00
if t.X < 50 {
t.Gap = 1
2018-02-18 23:25:02 -08:00
} else if t.X < 75 {
t.Gap = 2
2018-02-18 23:25:02 -08:00
}
cur := 0
for _, w := range t.ColWidths {
cur += t.Gap
2018-03-03 17:05:52 -08:00
t.CellXPos = append(t.CellXPos, cur)
cur += w
2018-02-18 23:25:02 -08:00
}
}
2018-02-18 23:25:02 -08:00
// Buffer implements the Bufferer interface.
func (t *Table) Buffer() *Buffer {
buf := t.Block.Buffer()
2018-02-18 23:25:02 -08:00
2018-03-03 17:05:52 -08:00
// removes gap at the bottom of the current view if there is one
if t.TopRow > len(t.Rows)-(t.Y-1) {
t.TopRow = len(t.Rows) - (t.Y - 1)
2018-02-18 23:25:02 -08:00
}
t.ColResizer()
2018-03-03 17:05:52 -08:00
// prints header
for i, width := range t.ColWidths {
if width == 0 {
break
}
2018-02-18 23:25:02 -08:00
r := MaxString(t.Header[i], t.X-6)
2018-03-03 17:05:52 -08:00
buf.SetString(t.CellXPos[i], 1, r, t.Fg|AttrBold, t.Bg)
2018-02-18 23:25:02 -08:00
}
// prints each row
for rowNum := t.TopRow; rowNum < t.TopRow+t.Y-1 && rowNum < len(t.Rows); rowNum++ {
2018-02-18 23:25:02 -08:00
row := t.Rows[rowNum]
y := (rowNum + 2) - t.TopRow
2018-02-18 23:25:02 -08:00
2018-03-03 17:05:52 -08:00
// prints cursor
2018-02-18 23:25:02 -08:00
bg := t.Bg
if (t.SelectedItem == "" && rowNum == t.SelectedRow) || (t.SelectedItem != "" && t.SelectedItem == row[t.UniqueCol]) {
2018-02-18 23:25:02 -08:00
bg = t.Cursor
for _, width := range t.ColWidths {
if width == 0 {
break
}
2018-02-18 23:25:02 -08:00
buf.SetString(1, y, strings.Repeat(" ", t.X), t.Fg, bg)
}
t.SelectedItem = row[t.UniqueCol]
t.SelectedRow = rowNum
2018-02-18 23:25:02 -08:00
}
2018-02-23 21:15:38 -08:00
// prints each col of the row
for i, width := range t.ColWidths {
if width == 0 {
break
}
2018-02-18 23:25:02 -08:00
r := MaxString(row[i], t.X-6)
2018-03-03 17:05:52 -08:00
buf.SetString(t.CellXPos[i], y, r, t.Fg, bg)
2018-02-18 23:25:02 -08:00
}
}
return buf
}
2018-02-25 22:51:51 -08:00
/////////////////////////////////////////////////////////////////////////////////
// Cursor Movement //
/////////////////////////////////////////////////////////////////////////////////
2018-02-18 23:25:02 -08:00
2018-03-03 17:05:52 -08:00
// calcPos is used to calculate the cursor position and the current view.
2018-02-18 23:25:02 -08:00
func (t *Table) calcPos() {
t.SelectedItem = ""
2018-02-18 23:25:02 -08:00
if t.SelectedRow < 0 {
t.SelectedRow = 0
2018-02-18 23:25:02 -08:00
}
if t.SelectedRow < t.TopRow {
t.TopRow = t.SelectedRow
2018-02-18 23:25:02 -08:00
}
if t.SelectedRow > len(t.Rows)-1 {
t.SelectedRow = len(t.Rows) - 1
2018-02-18 23:25:02 -08:00
}
if t.SelectedRow > t.TopRow+(t.Y-2) {
t.TopRow = t.SelectedRow - (t.Y - 2)
2018-02-18 23:25:02 -08:00
}
}
func (t *Table) Up() {
t.SelectedRow -= 1
2018-02-18 23:25:02 -08:00
t.calcPos()
}
func (t *Table) Down() {
t.SelectedRow += 1
2018-02-18 23:25:02 -08:00
t.calcPos()
}
func (t *Table) Top() {
t.SelectedRow = 0
2018-02-18 23:25:02 -08:00
t.calcPos()
}
func (t *Table) Bottom() {
t.SelectedRow = len(t.Rows) - 1
2018-02-18 23:25:02 -08:00
t.calcPos()
}
2018-03-03 17:05:52 -08:00
// The number of lines in a page is equal to the height of the widget.
2018-02-18 23:25:02 -08:00
func (t *Table) HalfPageUp() {
t.SelectedRow = t.SelectedRow - (t.Y-2)/2
2018-02-18 23:25:02 -08:00
t.calcPos()
}
func (t *Table) HalfPageDown() {
t.SelectedRow = t.SelectedRow + (t.Y-2)/2
2018-02-18 23:25:02 -08:00
t.calcPos()
}
func (t *Table) PageUp() {
t.SelectedRow -= (t.Y - 2)
2018-02-18 23:25:02 -08:00
t.calcPos()
}
func (t *Table) PageDown() {
t.SelectedRow += (t.Y - 2)
2018-02-18 23:25:02 -08:00
t.calcPos()
}
func (t *Table) Click(x, y int) {
x = x - t.XOffset
y = y - t.YOffset
if (x > 0 && x <= t.X) && (y > 0 && y <= t.Y) {
t.SelectedRow = (t.TopRow + y) - 2
2018-02-18 23:25:02 -08:00
t.calcPos()
}
}