2016-12-22 17:15:22 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2016-12-27 03:24:02 +01:00
|
|
|
"fmt"
|
2016-12-22 17:15:22 +01:00
|
|
|
|
2017-02-07 04:33:09 +01:00
|
|
|
"github.com/bcicen/ctop/config"
|
2017-02-26 23:04:24 +01:00
|
|
|
"github.com/bcicen/ctop/cwidgets/compact"
|
2017-01-06 14:49:22 +01:00
|
|
|
"github.com/bcicen/ctop/widgets"
|
2016-12-22 17:15:22 +01:00
|
|
|
ui "github.com/gizak/termui"
|
|
|
|
)
|
|
|
|
|
2017-03-06 03:00:30 +01:00
|
|
|
var (
|
|
|
|
cGrid = compact.NewCompactGrid()
|
|
|
|
header = widgets.NewCTopHeader()
|
|
|
|
)
|
2017-02-26 07:22:50 +01:00
|
|
|
|
2017-02-25 08:16:00 +01:00
|
|
|
func maxRows() int {
|
2017-02-26 07:22:50 +01:00
|
|
|
return ui.TermHeight() - 2 - cGrid.Y
|
2017-02-25 08:16:00 +01:00
|
|
|
}
|
|
|
|
|
2016-12-22 17:15:22 +01:00
|
|
|
type Grid struct {
|
2017-02-26 08:31:23 +01:00
|
|
|
cursorID string // id of currently selected container
|
2017-02-26 22:12:28 +01:00
|
|
|
cSource ContainerSource
|
2017-02-26 08:31:23 +01:00
|
|
|
containers Containers // sorted slice of containers
|
2016-12-22 17:15:22 +01:00
|
|
|
}
|
|
|
|
|
2016-12-30 22:14:07 +01:00
|
|
|
func NewGrid() *Grid {
|
2017-01-25 20:57:22 +01:00
|
|
|
g := &Grid{
|
2017-03-06 03:00:30 +01:00
|
|
|
//cSource: NewDockerContainerSource(),
|
|
|
|
cSource: NewMockContainerSource(),
|
2016-12-30 22:14:07 +01:00
|
|
|
}
|
2017-01-25 20:57:22 +01:00
|
|
|
return g
|
2016-12-26 19:39:15 +01:00
|
|
|
}
|
|
|
|
|
2017-02-24 10:10:14 +01:00
|
|
|
// Set an initial cursor position, if possible
|
|
|
|
func (g *Grid) cursorReset() {
|
|
|
|
if len(g.containers) > 0 {
|
2017-03-03 08:57:26 +01:00
|
|
|
g.cursorID = g.containers[0].Id
|
2017-03-03 09:02:08 +01:00
|
|
|
g.containers[0].Widgets.Name.Highlight()
|
2017-02-24 10:10:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-02 17:04:22 +01:00
|
|
|
// Return current cursor index
|
2017-01-02 21:14:35 +01:00
|
|
|
func (g *Grid) cursorIdx() int {
|
2017-01-02 17:04:22 +01:00
|
|
|
for n, c := range g.containers {
|
2017-03-03 08:57:26 +01:00
|
|
|
if c.Id == g.cursorID {
|
2017-01-02 17:04:22 +01:00
|
|
|
return n
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2017-01-02 21:14:35 +01:00
|
|
|
func (g *Grid) cursorUp() {
|
|
|
|
idx := g.cursorIdx()
|
2017-01-02 17:04:22 +01:00
|
|
|
// decrement if possible
|
2017-02-20 00:23:59 +01:00
|
|
|
if idx <= 0 {
|
|
|
|
return
|
2017-01-02 17:04:22 +01:00
|
|
|
}
|
2017-02-20 00:23:59 +01:00
|
|
|
active := g.containers[idx]
|
|
|
|
next := g.containers[idx-1]
|
|
|
|
|
2017-03-03 09:02:08 +01:00
|
|
|
active.Widgets.Name.UnHighlight()
|
2017-03-03 08:57:26 +01:00
|
|
|
g.cursorID = next.Id
|
2017-03-03 09:02:08 +01:00
|
|
|
next.Widgets.Name.Highlight()
|
2017-02-20 00:23:59 +01:00
|
|
|
|
2017-02-26 07:22:50 +01:00
|
|
|
ui.Render(cGrid)
|
2017-01-02 17:04:22 +01:00
|
|
|
}
|
|
|
|
|
2017-01-02 21:14:35 +01:00
|
|
|
func (g *Grid) cursorDown() {
|
|
|
|
idx := g.cursorIdx()
|
2017-01-02 17:04:22 +01:00
|
|
|
// increment if possible
|
2017-02-22 06:20:37 +01:00
|
|
|
if idx >= (len(g.containers) - 1) {
|
2017-02-20 00:23:59 +01:00
|
|
|
return
|
2016-12-22 17:15:22 +01:00
|
|
|
}
|
2017-02-25 08:16:00 +01:00
|
|
|
if idx >= maxRows()-1 {
|
2017-02-20 00:23:59 +01:00
|
|
|
return
|
2016-12-26 19:39:15 +01:00
|
|
|
}
|
2017-02-20 00:23:59 +01:00
|
|
|
active := g.containers[idx]
|
|
|
|
next := g.containers[idx+1]
|
|
|
|
|
2017-03-03 09:02:08 +01:00
|
|
|
active.Widgets.Name.UnHighlight()
|
2017-03-03 08:57:26 +01:00
|
|
|
g.cursorID = next.Id
|
2017-03-03 09:02:08 +01:00
|
|
|
next.Widgets.Name.Highlight()
|
2017-02-26 07:22:50 +01:00
|
|
|
ui.Render(cGrid)
|
2016-12-26 19:39:15 +01:00
|
|
|
}
|
|
|
|
|
2017-01-02 21:14:35 +01:00
|
|
|
func (g *Grid) redrawRows() {
|
2016-12-30 23:10:49 +01:00
|
|
|
// reinit body rows
|
2017-02-26 23:04:24 +01:00
|
|
|
cGrid.Clear()
|
2017-01-02 21:14:35 +01:00
|
|
|
|
2016-12-30 23:10:49 +01:00
|
|
|
// build layout
|
2017-02-26 07:22:50 +01:00
|
|
|
y := 1
|
2017-02-16 05:06:05 +01:00
|
|
|
if config.GetSwitchVal("enableHeader") {
|
2017-03-06 03:00:30 +01:00
|
|
|
header.SetCount(len(g.containers))
|
|
|
|
header.SetFilter(config.GetVal("filterStr"))
|
|
|
|
y += header.Height()
|
2017-01-06 14:49:22 +01:00
|
|
|
}
|
2017-02-26 08:31:23 +01:00
|
|
|
cGrid.SetY(y)
|
2017-02-24 10:10:14 +01:00
|
|
|
|
|
|
|
var cursorVisible bool
|
2017-02-25 08:16:00 +01:00
|
|
|
max := maxRows()
|
2017-03-06 03:00:30 +01:00
|
|
|
for n, c := range g.containers {
|
2017-02-25 08:16:00 +01:00
|
|
|
if n >= max {
|
2017-02-20 00:23:59 +01:00
|
|
|
break
|
|
|
|
}
|
2017-03-03 08:57:26 +01:00
|
|
|
cGrid.AddRows(c.Widgets)
|
|
|
|
if c.Id == g.cursorID {
|
2017-02-24 10:10:14 +01:00
|
|
|
cursorVisible = true
|
|
|
|
}
|
2016-12-22 17:15:22 +01:00
|
|
|
}
|
2016-12-30 23:10:49 +01:00
|
|
|
|
2017-02-24 10:10:14 +01:00
|
|
|
if !cursorVisible {
|
|
|
|
g.cursorReset()
|
|
|
|
}
|
|
|
|
|
2017-02-26 08:31:23 +01:00
|
|
|
ui.Clear()
|
|
|
|
if config.GetSwitchVal("enableHeader") {
|
2017-03-06 03:00:30 +01:00
|
|
|
header.Render()
|
2017-02-26 08:31:23 +01:00
|
|
|
}
|
|
|
|
cGrid.Align()
|
2017-02-26 07:22:50 +01:00
|
|
|
ui.Render(cGrid)
|
2016-12-22 17:15:22 +01:00
|
|
|
}
|
|
|
|
|
2017-03-06 03:00:30 +01:00
|
|
|
func (g *Grid) refreshContainers() {
|
|
|
|
g.containers = g.cSource.All().Filter()
|
|
|
|
}
|
|
|
|
|
2017-03-01 02:10:33 +01:00
|
|
|
// Log current container and widget state
|
|
|
|
func (g *Grid) dumpContainer() {
|
|
|
|
c, _ := g.cSource.Get(g.cursorID)
|
2017-03-03 08:57:26 +01:00
|
|
|
msg := fmt.Sprintf("logging state for container: %s\n", c.Id)
|
|
|
|
msg += fmt.Sprintf("Id = %s\nname = %s\nstate = %s\n", c.Id, c.Name, c.State)
|
|
|
|
msg += inspect(&c.Metrics)
|
2017-03-01 02:10:33 +01:00
|
|
|
log.Infof(msg)
|
|
|
|
}
|
|
|
|
|
2017-03-01 06:10:28 +01:00
|
|
|
//func (g *Grid) ExpandView() {
|
|
|
|
//ui.Clear()
|
|
|
|
//ui.DefaultEvtStream.ResetHandlers()
|
|
|
|
//defer ui.DefaultEvtStream.ResetHandlers()
|
|
|
|
|
|
|
|
//container, _ := g.cSource.Get(g.cursorID)
|
|
|
|
//// copy current widgets to restore on exit view
|
|
|
|
//curWidgets := container.widgets
|
|
|
|
//container.Expand()
|
|
|
|
|
|
|
|
//ui.Render(container.widgets)
|
|
|
|
//ui.Handle("/timer/1s", func(ui.Event) {
|
|
|
|
//ui.Render(container.widgets)
|
|
|
|
//})
|
|
|
|
//ui.Handle("/sys/kbd/", func(ui.Event) {
|
|
|
|
//ui.StopLoop()
|
|
|
|
//})
|
|
|
|
//ui.Loop()
|
|
|
|
|
|
|
|
//container.widgets = curWidgets
|
|
|
|
//container.widgets.Reset()
|
|
|
|
//}
|
2017-01-06 20:46:30 +01:00
|
|
|
|
2017-01-01 23:42:13 +01:00
|
|
|
func Display(g *Grid) bool {
|
2017-01-09 00:07:58 +01:00
|
|
|
var menu func()
|
2017-01-01 23:42:13 +01:00
|
|
|
|
2017-02-26 07:22:50 +01:00
|
|
|
cGrid.SetWidth(ui.TermWidth())
|
2017-02-05 01:56:45 +01:00
|
|
|
ui.DefaultEvtStream.Hook(logEvent)
|
|
|
|
|
2017-02-18 04:31:50 +01:00
|
|
|
// initial draw
|
2017-03-06 03:00:30 +01:00
|
|
|
header.Align()
|
|
|
|
g.refreshContainers()
|
2017-02-02 08:09:43 +01:00
|
|
|
g.redrawRows()
|
2016-12-22 17:15:22 +01:00
|
|
|
|
2016-12-26 19:39:15 +01:00
|
|
|
ui.Handle("/sys/kbd/<up>", func(ui.Event) {
|
2017-01-02 21:14:35 +01:00
|
|
|
g.cursorUp()
|
2016-12-26 19:39:15 +01:00
|
|
|
})
|
|
|
|
ui.Handle("/sys/kbd/<down>", func(ui.Event) {
|
2017-01-02 21:14:35 +01:00
|
|
|
g.cursorDown()
|
2016-12-26 19:39:15 +01:00
|
|
|
})
|
2017-01-06 20:46:30 +01:00
|
|
|
ui.Handle("/sys/kbd/<enter>", func(ui.Event) {
|
2017-03-05 07:46:41 +01:00
|
|
|
//c := g.containers[g.cursorIdx()]
|
|
|
|
//c.Widgets.ToggleExpand()
|
|
|
|
g.redrawRows()
|
2017-01-06 20:46:30 +01:00
|
|
|
})
|
2017-02-23 23:00:05 +01:00
|
|
|
|
2017-02-16 01:00:31 +01:00
|
|
|
ui.Handle("/sys/kbd/a", func(ui.Event) {
|
|
|
|
config.Toggle("allContainers")
|
2017-03-06 03:00:30 +01:00
|
|
|
g.refreshContainers()
|
2017-02-16 01:00:31 +01:00
|
|
|
g.redrawRows()
|
|
|
|
})
|
2017-03-01 02:10:33 +01:00
|
|
|
ui.Handle("/sys/kbd/D", func(ui.Event) {
|
|
|
|
g.dumpContainer()
|
|
|
|
})
|
2017-01-21 19:15:29 +01:00
|
|
|
ui.Handle("/sys/kbd/f", func(ui.Event) {
|
|
|
|
menu = FilterMenu
|
|
|
|
ui.StopLoop()
|
|
|
|
})
|
2017-01-01 23:42:13 +01:00
|
|
|
ui.Handle("/sys/kbd/h", func(ui.Event) {
|
2017-01-09 00:07:58 +01:00
|
|
|
menu = HelpMenu
|
2017-01-03 00:40:55 +01:00
|
|
|
ui.StopLoop()
|
|
|
|
})
|
2017-02-13 04:37:17 +01:00
|
|
|
ui.Handle("/sys/kbd/H", func(ui.Event) {
|
|
|
|
config.Toggle("enableHeader")
|
|
|
|
g.redrawRows()
|
|
|
|
})
|
2017-01-12 20:48:29 +01:00
|
|
|
ui.Handle("/sys/kbd/q", func(ui.Event) {
|
2017-01-01 23:42:13 +01:00
|
|
|
ui.StopLoop()
|
|
|
|
})
|
2017-01-21 19:15:29 +01:00
|
|
|
ui.Handle("/sys/kbd/r", func(e ui.Event) {
|
2017-02-07 04:33:09 +01:00
|
|
|
config.Toggle("sortReversed")
|
2017-01-12 20:48:29 +01:00
|
|
|
})
|
|
|
|
ui.Handle("/sys/kbd/s", func(ui.Event) {
|
|
|
|
menu = SortMenu
|
2016-12-22 17:15:22 +01:00
|
|
|
ui.StopLoop()
|
|
|
|
})
|
2017-02-23 23:00:05 +01:00
|
|
|
|
2016-12-22 17:15:22 +01:00
|
|
|
ui.Handle("/timer/1s", func(e ui.Event) {
|
2017-03-06 03:00:30 +01:00
|
|
|
g.refreshContainers()
|
2017-01-02 21:14:35 +01:00
|
|
|
g.redrawRows()
|
2016-12-22 17:15:22 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
ui.Handle("/sys/wnd/resize", func(e ui.Event) {
|
2017-03-06 03:00:30 +01:00
|
|
|
header.Align()
|
2017-02-26 07:22:50 +01:00
|
|
|
cGrid.SetWidth(ui.TermWidth())
|
|
|
|
log.Infof("resize: width=%v max-rows=%v", cGrid.Width, maxRows())
|
2017-02-18 01:59:13 +01:00
|
|
|
g.redrawRows()
|
2016-12-22 17:15:22 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
ui.Loop()
|
2017-01-09 00:07:58 +01:00
|
|
|
if menu != nil {
|
2017-03-06 03:00:30 +01:00
|
|
|
ui.Clear()
|
2017-02-13 04:22:32 +01:00
|
|
|
menu()
|
2017-01-01 23:42:13 +01:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
2016-12-22 17:15:22 +01:00
|
|
|
}
|