xmtop/termui/table.go

183 lines
3.3 KiB
Go
Raw Normal View History

2018-02-19 15:25:02 +08:00
package termui
import (
"os/exec"
"strings"
)
// Table tracks all the attributes of a Table instance
type Table struct {
*Block
Header []string
Rows [][]string
Fg Attribute
Bg Attribute
Cursor Attribute
UniqueCol int
pid string
selected int
topRow int
}
// NewTable returns a new Table instance
func NewTable() *Table {
return &Table{
Block: NewBlock(),
Fg: Theme.Fg,
Bg: Theme.Bg,
Cursor: Theme.TableCursor,
selected: 0,
topRow: 0,
UniqueCol: 0,
}
}
// Buffer ...
func (t *Table) Buffer() *Buffer {
buf := t.Block.Buffer()
if t.topRow > len(t.Rows)-(t.Y-1) {
t.topRow = len(t.Rows) - (t.Y - 1)
}
// calculate gap size based on total width
gap := 3
if t.X < 50 {
gap = 1
} else if t.X < 75 {
gap = 2
}
cw := []int{5, 10, 4, 4} // cellWidth
cp := []int{ // cellPosition
gap,
gap + cw[0] + gap,
t.X - gap - cw[3] - gap - cw[2],
t.X - gap - cw[3],
}
// total width requires by all 4 columns
contentWidth := gap + cw[0] + gap + cw[1] + gap + cw[2] + gap + cw[3] + gap
render := 4 // number of columns to iterate through
// removes CPU and MEM if there isn't enough room
if t.X < (contentWidth - gap - cw[3]) {
render = 2
} else if t.X < contentWidth {
cp[2] = cp[3]
render = 3
}
// print header
for i := 0; i < render; i++ {
r := MaxString(t.Header[i], t.X-6)
buf.SetString(cp[i], 1, r, t.Fg|AttrBold, t.Bg)
}
// prints each row
// for y, row := range t.Rows {
// for y := t.topRow; y <= t.topRow+t.Y; y++ {
for rowNum := t.topRow; rowNum < t.topRow+t.Y-1 && rowNum < len(t.Rows); rowNum++ {
row := t.Rows[rowNum]
y := (rowNum + 2) - t.topRow
// cursor
bg := t.Bg
if (t.pid == "" && rowNum == t.selected) || (t.pid != "" && t.pid == row[t.UniqueCol]) {
bg = t.Cursor
for i := 0; i < render; i++ {
buf.SetString(1, y, strings.Repeat(" ", t.X), t.Fg, bg)
}
t.pid = row[t.UniqueCol]
t.selected = rowNum
}
// prints each string
for i := 0; i < render; i++ {
r := MaxString(row[i], t.X-6)
buf.SetString(cp[i], y, r, t.Fg, bg)
}
}
return buf
}
////////////////////////////////////////////////////////////////////////////////
func (t *Table) calcPos() {
t.pid = ""
if t.selected < 0 {
t.selected = 0
}
if t.selected < t.topRow {
t.topRow = t.selected
}
if t.selected > len(t.Rows)-1 {
t.selected = len(t.Rows) - 1
}
if t.selected > t.topRow+(t.Y-2) {
t.topRow = t.selected - (t.Y - 2)
}
}
func (t *Table) Up() {
t.selected -= 1
t.calcPos()
}
func (t *Table) Down() {
t.selected += 1
t.calcPos()
}
func (t *Table) Top() {
t.selected = 0
t.calcPos()
}
func (t *Table) Bottom() {
t.selected = len(t.Rows) - 1
t.calcPos()
}
func (t *Table) HalfPageUp() {
t.selected = t.selected - (t.Y-2)/2
t.calcPos()
}
func (t *Table) HalfPageDown() {
t.selected = t.selected + (t.Y-2)/2
t.calcPos()
}
func (t *Table) PageUp() {
t.selected -= (t.Y - 2)
t.calcPos()
}
func (t *Table) PageDown() {
t.selected += (t.Y - 2)
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.selected = (t.topRow + y) - 2
t.calcPos()
}
}
func (t *Table) Kill() {
t.pid = ""
command := "kill"
if t.UniqueCol == 1 {
command = "pkill"
}
cmd := exec.Command(command, t.Rows[t.selected][t.UniqueCol])
cmd.Start()
}