2016-12-22 16:15:22 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2016-12-27 02:24:02 +00:00
|
|
|
"fmt"
|
2016-12-22 16:15:22 +00:00
|
|
|
|
2017-02-07 03:33:09 +00:00
|
|
|
"github.com/bcicen/ctop/config"
|
2017-01-06 13:49:22 +00:00
|
|
|
"github.com/bcicen/ctop/widgets"
|
2016-12-22 16:15:22 +00:00
|
|
|
ui "github.com/gizak/termui"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Grid struct {
|
2017-01-09 15:02:34 +00:00
|
|
|
cursorID string // id of currently selected container
|
|
|
|
cmap *ContainerMap
|
|
|
|
containers []*Container // sorted slice of containers
|
|
|
|
header *widgets.CTopHeader
|
2016-12-22 16:15:22 +00:00
|
|
|
}
|
|
|
|
|
2016-12-30 21:14:07 +00:00
|
|
|
func NewGrid() *Grid {
|
2017-01-09 15:02:34 +00:00
|
|
|
cmap := NewContainerMap()
|
2017-01-25 19:57:22 +00:00
|
|
|
g := &Grid{
|
2017-01-09 15:02:34 +00:00
|
|
|
cmap: cmap,
|
2017-01-25 19:57:22 +00:00
|
|
|
containers: cmap.All(),
|
2017-01-09 15:02:34 +00:00
|
|
|
header: widgets.NewCTopHeader(),
|
2016-12-30 21:14:07 +00:00
|
|
|
}
|
2017-01-25 19:57:22 +00:00
|
|
|
// set initial cursor position
|
|
|
|
if len(g.containers) > 0 {
|
|
|
|
g.cursorID = g.containers[0].id
|
|
|
|
}
|
|
|
|
return g
|
2016-12-26 18:39:15 +00:00
|
|
|
}
|
|
|
|
|
2017-01-02 16:04:22 +00:00
|
|
|
// Return current cursor index
|
2017-01-02 20:14:35 +00:00
|
|
|
func (g *Grid) cursorIdx() int {
|
2017-01-02 16:04:22 +00:00
|
|
|
for n, c := range g.containers {
|
|
|
|
if c.id == g.cursorID {
|
|
|
|
return n
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2017-01-02 20:14:35 +00:00
|
|
|
func (g *Grid) cursorUp() {
|
|
|
|
idx := g.cursorIdx()
|
2017-01-02 16:04:22 +00:00
|
|
|
// decrement if possible
|
|
|
|
if idx > 0 {
|
|
|
|
g.cursorID = g.containers[idx-1].id
|
2017-01-02 20:14:35 +00:00
|
|
|
g.redrawCursor()
|
2017-01-02 16:04:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-02 20:14:35 +00:00
|
|
|
func (g *Grid) cursorDown() {
|
|
|
|
idx := g.cursorIdx()
|
2017-01-02 16:04:22 +00:00
|
|
|
// increment if possible
|
|
|
|
if idx < (len(g.containers) - 1) {
|
|
|
|
g.cursorID = g.containers[idx+1].id
|
2017-01-02 20:14:35 +00:00
|
|
|
g.redrawCursor()
|
2016-12-22 16:15:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-26 18:39:15 +00:00
|
|
|
// Redraw the cursor with the currently selected row
|
2017-01-02 20:14:35 +00:00
|
|
|
func (g *Grid) redrawCursor() {
|
2017-01-02 16:04:22 +00:00
|
|
|
for _, c := range g.containers {
|
|
|
|
if c.id == g.cursorID {
|
2017-01-06 12:59:45 +00:00
|
|
|
c.widgets.Highlight()
|
2016-12-26 18:39:15 +00:00
|
|
|
} else {
|
2017-01-06 12:59:45 +00:00
|
|
|
c.widgets.UnHighlight()
|
2016-12-26 18:39:15 +00:00
|
|
|
}
|
2017-01-02 16:04:22 +00:00
|
|
|
ui.Render(ui.Body)
|
2016-12-26 18:39:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-02 20:14:35 +00:00
|
|
|
func (g *Grid) redrawRows() {
|
2016-12-30 22:10:49 +00:00
|
|
|
// reinit body rows
|
|
|
|
ui.Body.Rows = []*ui.Row{}
|
2017-01-23 15:00:33 +00:00
|
|
|
ui.Clear()
|
2017-01-02 20:14:35 +00:00
|
|
|
|
2016-12-30 22:10:49 +00:00
|
|
|
// build layout
|
2017-02-16 04:06:05 +00:00
|
|
|
if config.GetSwitchVal("enableHeader") {
|
2017-01-06 13:49:22 +00:00
|
|
|
g.header.SetCount(len(g.containers))
|
2017-02-16 04:06:05 +00:00
|
|
|
g.header.SetFilter(config.GetVal("filterStr"))
|
2017-01-06 13:49:22 +00:00
|
|
|
ui.Body.AddRows(g.header.Row())
|
|
|
|
}
|
|
|
|
ui.Body.AddRows(fieldHeader())
|
2017-01-02 16:04:22 +00:00
|
|
|
for _, c := range g.containers {
|
2017-01-06 11:51:11 +00:00
|
|
|
ui.Body.AddRows(c.widgets.Row())
|
2016-12-22 16:15:22 +00:00
|
|
|
}
|
2016-12-30 22:10:49 +00:00
|
|
|
|
|
|
|
ui.Body.Align()
|
|
|
|
ui.Render(ui.Body)
|
2016-12-22 16:15:22 +00:00
|
|
|
}
|
|
|
|
|
2017-01-06 13:49:22 +00:00
|
|
|
func fieldHeader() *ui.Row {
|
2016-12-22 16:15:22 +00:00
|
|
|
return ui.NewRow(
|
2017-02-01 05:44:24 +00:00
|
|
|
ui.NewCol(1, 0, headerPar("STATUS")),
|
2016-12-28 03:01:44 +00:00
|
|
|
ui.NewCol(2, 0, headerPar("NAME")),
|
2017-01-01 22:42:13 +00:00
|
|
|
ui.NewCol(2, 0, headerPar("CID")),
|
2016-12-27 02:24:02 +00:00
|
|
|
ui.NewCol(2, 0, headerPar("CPU")),
|
|
|
|
ui.NewCol(2, 0, headerPar("MEM")),
|
|
|
|
ui.NewCol(2, 0, headerPar("NET RX/TX")),
|
2016-12-22 16:15:22 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2016-12-27 02:24:02 +00:00
|
|
|
func headerPar(s string) *ui.Par {
|
|
|
|
p := ui.NewPar(fmt.Sprintf(" %s", s))
|
|
|
|
p.Border = false
|
|
|
|
p.Height = 2
|
|
|
|
p.Width = 20
|
|
|
|
p.TextFgColor = ui.ColorWhite
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
2017-01-01 22:42:13 +00:00
|
|
|
func ResetView() {
|
|
|
|
ui.DefaultEvtStream.ResetHandlers()
|
|
|
|
ui.Clear()
|
|
|
|
}
|
|
|
|
|
2017-01-06 19:46:30 +00:00
|
|
|
func (g *Grid) ExpandView() {
|
|
|
|
ResetView()
|
|
|
|
defer ResetView()
|
2017-01-09 15:02:34 +00:00
|
|
|
container := g.cmap.Get(g.cursorID)
|
2017-01-06 19:46:30 +00:00
|
|
|
container.Expand()
|
|
|
|
container.widgets.Render()
|
|
|
|
container.Collapse()
|
|
|
|
}
|
|
|
|
|
2017-02-05 00:56:45 +00:00
|
|
|
func logEvent(e ui.Event) {
|
|
|
|
var s string
|
|
|
|
s += fmt.Sprintf("Type: %s\n", e.Type)
|
|
|
|
s += fmt.Sprintf("Path: %s\n", e.Path)
|
|
|
|
s += fmt.Sprintf("From: %s\n", e.From)
|
|
|
|
s += fmt.Sprintf("To: %s", e.To)
|
|
|
|
log.Debugf("new event:\n%s", s)
|
|
|
|
}
|
|
|
|
|
2017-01-01 22:42:13 +00:00
|
|
|
func Display(g *Grid) bool {
|
2017-01-08 23:07:58 +00:00
|
|
|
var menu func()
|
2017-01-06 19:46:30 +00:00
|
|
|
var expand bool
|
2017-01-26 00:53:03 +00:00
|
|
|
var loopIter int
|
2017-01-01 22:42:13 +00:00
|
|
|
|
2017-02-05 00:56:45 +00:00
|
|
|
ui.DefaultEvtStream.Hook(logEvent)
|
|
|
|
|
2016-12-22 16:15:22 +00:00
|
|
|
// calculate layout
|
|
|
|
ui.Body.Align()
|
2017-01-02 20:14:35 +00:00
|
|
|
g.redrawCursor()
|
2017-02-02 07:09:43 +00:00
|
|
|
g.redrawRows()
|
2016-12-22 16:15:22 +00:00
|
|
|
|
2016-12-26 18:39:15 +00:00
|
|
|
ui.Handle("/sys/kbd/<up>", func(ui.Event) {
|
2017-01-02 20:14:35 +00:00
|
|
|
g.cursorUp()
|
2016-12-26 18:39:15 +00:00
|
|
|
})
|
|
|
|
ui.Handle("/sys/kbd/<down>", func(ui.Event) {
|
2017-01-02 20:14:35 +00:00
|
|
|
g.cursorDown()
|
2016-12-26 18:39:15 +00:00
|
|
|
})
|
2017-01-06 19:46:30 +00:00
|
|
|
ui.Handle("/sys/kbd/<enter>", func(ui.Event) {
|
|
|
|
expand = true
|
|
|
|
ui.StopLoop()
|
|
|
|
})
|
2017-02-16 00:00:31 +00:00
|
|
|
ui.Handle("/sys/kbd/a", func(ui.Event) {
|
|
|
|
config.Toggle("allContainers")
|
|
|
|
g.redrawRows()
|
|
|
|
})
|
2017-01-21 18:15:29 +00:00
|
|
|
ui.Handle("/sys/kbd/f", func(ui.Event) {
|
|
|
|
menu = FilterMenu
|
|
|
|
ui.StopLoop()
|
|
|
|
})
|
2017-01-01 22:42:13 +00:00
|
|
|
ui.Handle("/sys/kbd/h", func(ui.Event) {
|
2017-01-08 23:07:58 +00:00
|
|
|
menu = HelpMenu
|
2017-01-02 23:40:55 +00:00
|
|
|
ui.StopLoop()
|
|
|
|
})
|
2017-02-13 03:37:17 +00:00
|
|
|
ui.Handle("/sys/kbd/H", func(ui.Event) {
|
|
|
|
config.Toggle("enableHeader")
|
|
|
|
g.redrawRows()
|
|
|
|
})
|
2017-01-12 19:48:29 +00:00
|
|
|
ui.Handle("/sys/kbd/q", func(ui.Event) {
|
2017-01-01 22:42:13 +00:00
|
|
|
ui.StopLoop()
|
|
|
|
})
|
2017-01-21 18:15:29 +00:00
|
|
|
ui.Handle("/sys/kbd/r", func(e ui.Event) {
|
2017-02-07 03:33:09 +00:00
|
|
|
config.Toggle("sortReversed")
|
2017-01-12 19:48:29 +00:00
|
|
|
})
|
|
|
|
ui.Handle("/sys/kbd/s", func(ui.Event) {
|
|
|
|
menu = SortMenu
|
2016-12-22 16:15:22 +00:00
|
|
|
ui.StopLoop()
|
|
|
|
})
|
|
|
|
ui.Handle("/timer/1s", func(e ui.Event) {
|
2017-01-26 00:53:03 +00:00
|
|
|
loopIter++
|
|
|
|
if loopIter%5 == 0 {
|
|
|
|
g.cmap.Refresh()
|
|
|
|
}
|
2017-01-09 15:02:34 +00:00
|
|
|
g.containers = g.cmap.All() // refresh containers for current sort order
|
2017-01-02 20:14:35 +00:00
|
|
|
g.redrawRows()
|
2016-12-22 16:15:22 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
ui.Handle("/sys/wnd/resize", func(e ui.Event) {
|
|
|
|
ui.Body.Width = ui.TermWidth()
|
|
|
|
ui.Body.Align()
|
|
|
|
ui.Clear()
|
|
|
|
ui.Render(ui.Body)
|
|
|
|
})
|
|
|
|
|
|
|
|
ui.Loop()
|
2017-01-08 23:07:58 +00:00
|
|
|
if menu != nil {
|
2017-02-13 03:22:32 +00:00
|
|
|
menu()
|
2017-01-01 22:42:13 +00:00
|
|
|
return false
|
|
|
|
}
|
2017-01-06 19:46:30 +00:00
|
|
|
if expand {
|
|
|
|
g.ExpandView()
|
|
|
|
return false
|
|
|
|
}
|
2017-01-01 22:42:13 +00:00
|
|
|
return true
|
2016-12-22 16:15:22 +00:00
|
|
|
}
|