ctop/cursor.go

198 lines
3.7 KiB
Go

package main
import (
"math"
"github.com/bcicen/ctop/connector"
"github.com/bcicen/ctop/container"
ui "github.com/gizak/termui"
)
type GridCursor struct {
selectedID string // id of currently selected container
filtered container.Containers
cSuper *connector.ConnectorSuper
isScrolling bool // toggled when actively scrolling
}
func (gc *GridCursor) Len() int { return len(gc.filtered) }
func (gc *GridCursor) Selected() *container.Container {
idx := gc.Idx()
if idx < gc.Len() {
return gc.filtered[idx]
}
return nil
}
// Refresh containers from source, returning whether the quantity of
// containers has changed and any error
func (gc *GridCursor) RefreshContainers() (bool, error) {
oldLen := gc.Len()
gc.filtered = container.Containers{}
cSource, err := gc.cSuper.Get()
if err != nil {
return true, err
}
// filter Containers by display bool
var cursorVisible bool
for _, c := range cSource.All() {
if c.Display {
if c.Id == gc.selectedID {
cursorVisible = true
}
gc.filtered = append(gc.filtered, c)
}
}
if !cursorVisible || gc.selectedID == "" {
gc.Reset()
}
return oldLen != gc.Len(), nil
}
// Set an initial cursor position, if possible
func (gc *GridCursor) Reset() {
cSource, err := gc.cSuper.Get()
if err != nil {
return
}
for _, c := range cSource.All() {
c.Widgets.UnHighlight()
}
if gc.Len() > 0 {
gc.selectedID = gc.filtered[0].Id
gc.filtered[0].Widgets.Highlight()
}
}
// Idx returns current cursor index
func (gc *GridCursor) Idx() int {
for n, c := range gc.filtered {
if c.Id == gc.selectedID {
return n
}
}
gc.Reset()
return 0
}
func (gc *GridCursor) ScrollPage() {
// skip scroll if no need to page
if gc.Len() < cGrid.MaxRows() {
cGrid.Offset = 0
return
}
idx := gc.Idx()
// page down
if idx >= cGrid.Offset+cGrid.MaxRows() {
cGrid.Offset++
cGrid.Align()
}
// page up
if idx < cGrid.Offset {
cGrid.Offset--
cGrid.Align()
}
}
func (gc *GridCursor) Up() {
gc.isScrolling = true
defer func() { gc.isScrolling = false }()
idx := gc.Idx()
if idx <= 0 { // already at top
return
}
active := gc.filtered[idx]
next := gc.filtered[idx-1]
active.Widgets.UnHighlight()
gc.selectedID = next.Id
next.Widgets.Highlight()
gc.ScrollPage()
ui.Render(cGrid)
}
func (gc *GridCursor) Down() {
gc.isScrolling = true
defer func() { gc.isScrolling = false }()
idx := gc.Idx()
if idx >= gc.Len()-1 { // already at bottom
return
}
active := gc.filtered[idx]
next := gc.filtered[idx+1]
active.Widgets.UnHighlight()
gc.selectedID = next.Id
next.Widgets.Highlight()
gc.ScrollPage()
ui.Render(cGrid)
}
func (gc *GridCursor) PgUp() {
idx := gc.Idx()
if idx <= 0 { // already at top
return
}
nextidx := int(math.Max(0.0, float64(idx-cGrid.MaxRows())))
if gc.pgCount() > 0 {
cGrid.Offset = int(math.Max(float64(cGrid.Offset-cGrid.MaxRows()),
float64(0)))
}
active := gc.filtered[idx]
next := gc.filtered[nextidx]
active.Widgets.UnHighlight()
gc.selectedID = next.Id
next.Widgets.Highlight()
cGrid.Align()
ui.Render(cGrid)
}
func (gc *GridCursor) PgDown() {
idx := gc.Idx()
if idx >= gc.Len()-1 { // already at bottom
return
}
nextidx := int(math.Min(float64(gc.Len()-1), float64(idx+cGrid.MaxRows())))
if gc.pgCount() > 0 {
cGrid.Offset = int(math.Min(float64(cGrid.Offset+cGrid.MaxRows()),
float64(gc.Len()-cGrid.MaxRows())))
}
active := gc.filtered[idx]
next := gc.filtered[nextidx]
active.Widgets.UnHighlight()
gc.selectedID = next.Id
next.Widgets.Highlight()
cGrid.Align()
ui.Render(cGrid)
}
// number of pages at current row count and term height
func (gc *GridCursor) pgCount() int {
pages := gc.Len() / cGrid.MaxRows()
if gc.Len()%cGrid.MaxRows() > 0 {
pages++
}
return pages
}