Merge branch 'termui-port'
This commit is contained in:
commit
43d8b32230
10
README.md
10
README.md
|
@ -113,11 +113,11 @@ This will place the built packages into the `dist` folder.
|
||||||
|
|
||||||
## Built With
|
## Built With
|
||||||
|
|
||||||
- [cjbassi/termui](https://github.com/cjbassi/termui)
|
- [gizak/termui](https://github.com/gizak/termui)
|
||||||
- [drawille-go](https://github.com/exrook/drawille-go)
|
- [nsf/termbox](https://github.com/nsf/termbox-go)
|
||||||
- [termbox](https://github.com/nsf/termbox-go)
|
- [exrook/drawille-go](https://github.com/exrook/drawille-go)
|
||||||
- [gopsutil](https://github.com/shirou/gopsutil)
|
- [shirou/gopsutil](https://github.com/shirou/gopsutil)
|
||||||
- [goreleaser](https://github.com/goreleaser/goreleaser)
|
- [goreleaser/goreleaser](https://github.com/goreleaser/goreleaser)
|
||||||
|
|
||||||
## Stargazers over time
|
## Stargazers over time
|
||||||
|
|
||||||
|
|
7
go.mod
7
go.mod
|
@ -3,14 +3,11 @@ module github.com/cjbassi/gotop
|
||||||
require (
|
require (
|
||||||
github.com/ProtonMail/go-appdir v0.0.0-20180220133335-7c788d1b45c6
|
github.com/ProtonMail/go-appdir v0.0.0-20180220133335-7c788d1b45c6
|
||||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
|
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
|
||||||
github.com/cjbassi/drawille-go v0.0.0-20180329221028-ad535d0f92cd // indirect
|
github.com/cjbassi/drawille-go v0.0.0-20180329221028-ad535d0f92cd
|
||||||
github.com/cjbassi/termui v0.0.0-20181208033036-e8dd23f6146c
|
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
|
|
||||||
github.com/docopt/docopt.go v0.0.0-20180111231733-ee0de3bc6815
|
github.com/docopt/docopt.go v0.0.0-20180111231733-ee0de3bc6815
|
||||||
|
github.com/gizak/termui v0.0.0-20190101005313-46c77dca8480
|
||||||
github.com/go-ole/go-ole v1.2.1 // indirect
|
github.com/go-ole/go-ole v1.2.1 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.2 // indirect
|
|
||||||
github.com/nsf/termbox-go v0.0.0-20180407224525-3e24a7b6661e // indirect
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/shirou/gopsutil v2.18.11+incompatible
|
github.com/shirou/gopsutil v2.18.11+incompatible
|
||||||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect
|
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect
|
||||||
|
|
12
go.sum
12
go.sum
|
@ -4,20 +4,20 @@ github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIO
|
||||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||||
github.com/cjbassi/drawille-go v0.0.0-20180329221028-ad535d0f92cd h1:nSJpATLVvFa19BEHX4ys+VGNWfI4FUGMweEI6QXs8wg=
|
github.com/cjbassi/drawille-go v0.0.0-20180329221028-ad535d0f92cd h1:nSJpATLVvFa19BEHX4ys+VGNWfI4FUGMweEI6QXs8wg=
|
||||||
github.com/cjbassi/drawille-go v0.0.0-20180329221028-ad535d0f92cd/go.mod h1:vjcQJUZJYD3MeVGhtZXSMnCHfUNZxsyYzJt90eCYxK4=
|
github.com/cjbassi/drawille-go v0.0.0-20180329221028-ad535d0f92cd/go.mod h1:vjcQJUZJYD3MeVGhtZXSMnCHfUNZxsyYzJt90eCYxK4=
|
||||||
github.com/cjbassi/termui v0.0.0-20181208033036-e8dd23f6146c h1:vcaCtK8ObawtpQRW8GdbKZ+eJGEUn41xJ8Snagd/c6I=
|
|
||||||
github.com/cjbassi/termui v0.0.0-20181208033036-e8dd23f6146c/go.mod h1:rqXckrwz+i0fH/zNwU6AdBNULHwmZsgehnSlhKP5i2Q=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
|
|
||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
|
||||||
github.com/docopt/docopt.go v0.0.0-20180111231733-ee0de3bc6815 h1:HMAfwOa33y82IaQEKQDfUCiwNlxtM1iw7HLM9ru0RNc=
|
github.com/docopt/docopt.go v0.0.0-20180111231733-ee0de3bc6815 h1:HMAfwOa33y82IaQEKQDfUCiwNlxtM1iw7HLM9ru0RNc=
|
||||||
github.com/docopt/docopt.go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:l7JNRynTRuqe45tpIyItHNqZWTxywYjp87MWTOnU5cg=
|
github.com/docopt/docopt.go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:l7JNRynTRuqe45tpIyItHNqZWTxywYjp87MWTOnU5cg=
|
||||||
|
github.com/gizak/termui v0.0.0-20190101005313-46c77dca8480 h1:+NHS7QUnQqEwIuhrHaFT6R78LMGbja4fYTu6wny7Q4s=
|
||||||
|
github.com/gizak/termui v0.0.0-20190101005313-46c77dca8480/go.mod h1:S3xz8JHXNDPSNFsvXCdG7bHlEGrwvUG3a0joR/xYZ5M=
|
||||||
github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
|
github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
|
||||||
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
|
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
|
||||||
github.com/mattn/go-runewidth v0.0.2 h1:UnlwIPBGaTZfPQ6T1IGzPI0EkYAQmT9fAEJ/poFC63o=
|
github.com/mattn/go-runewidth v0.0.2 h1:UnlwIPBGaTZfPQ6T1IGzPI0EkYAQmT9fAEJ/poFC63o=
|
||||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/nsf/termbox-go v0.0.0-20180407224525-3e24a7b6661e h1:w2JDz0jtOlFFdvtUXISyYPFwmbZnwKL1mRDT0tKDvuk=
|
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
|
||||||
github.com/nsf/termbox-go v0.0.0-20180407224525-3e24a7b6661e/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
|
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||||
|
github.com/nsf/termbox-go v0.0.0-20180613055208-5c94acc5e6eb h1:YahEjAGkJtCrkqgVHhX6n8ZX+CZ3hDRL9fjLYugLfSs=
|
||||||
|
github.com/nsf/termbox-go v0.0.0-20180613055208-5c94acc5e6eb/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/shirou/gopsutil v2.18.11+incompatible h1:PMFTKnFTr/YTRW5rbLK4vWALV3a+IGXse5nvhSjztmg=
|
github.com/shirou/gopsutil v2.18.11+incompatible h1:PMFTKnFTr/YTRW5rbLK4vWALV3a+IGXse5nvhSjztmg=
|
||||||
|
|
102
main.go
102
main.go
|
@ -18,8 +18,8 @@ import (
|
||||||
"github.com/cjbassi/gotop/colorschemes"
|
"github.com/cjbassi/gotop/colorschemes"
|
||||||
"github.com/cjbassi/gotop/src/logging"
|
"github.com/cjbassi/gotop/src/logging"
|
||||||
w "github.com/cjbassi/gotop/src/widgets"
|
w "github.com/cjbassi/gotop/src/widgets"
|
||||||
ui "github.com/cjbassi/termui"
|
|
||||||
docopt "github.com/docopt/docopt.go"
|
docopt "github.com/docopt/docopt.go"
|
||||||
|
ui "github.com/gizak/termui"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version = "1.7.1"
|
var version = "1.7.1"
|
||||||
|
@ -38,6 +38,8 @@ var (
|
||||||
configDir = appdir.New("gotop").UserConfig()
|
configDir = appdir.New("gotop").UserConfig()
|
||||||
logPath = filepath.Join(configDir, "errors.log")
|
logPath = filepath.Join(configDir, "errors.log")
|
||||||
stderrLogger = log.New(os.Stderr, "", 0)
|
stderrLogger = log.New(os.Stderr, "", 0)
|
||||||
|
termWidth int
|
||||||
|
termHeight int
|
||||||
|
|
||||||
cpu *w.CPU
|
cpu *w.CPU
|
||||||
mem *w.Mem
|
mem *w.Mem
|
||||||
|
@ -46,6 +48,7 @@ var (
|
||||||
disk *w.Disk
|
disk *w.Disk
|
||||||
temp *w.Temp
|
temp *w.Temp
|
||||||
help *w.HelpMenu
|
help *w.HelpMenu
|
||||||
|
grid *ui.Grid
|
||||||
)
|
)
|
||||||
|
|
||||||
func cliArguments() error {
|
func cliArguments() error {
|
||||||
|
@ -137,41 +140,46 @@ func getCustomColorscheme(name string) (colorschemes.Colorscheme, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupGrid() {
|
func setupGrid() {
|
||||||
ui.Body.Cols = 12
|
grid = ui.NewGrid()
|
||||||
ui.Body.Rows = 12
|
grid.SetRect(0, 0, termWidth, termHeight)
|
||||||
|
|
||||||
if minimal {
|
if minimal {
|
||||||
ui.Body.Set(0, 0, 12, 6, cpu)
|
grid.Set(
|
||||||
ui.Body.Set(0, 6, 6, 12, mem)
|
ui.NewRow(1.0/2, cpu),
|
||||||
ui.Body.Set(6, 6, 12, 12, proc)
|
ui.NewRow(1.0/2,
|
||||||
|
ui.NewCol(1.0/2, mem),
|
||||||
|
ui.NewCol(1.0/2, proc),
|
||||||
|
),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
ui.Body.Set(0, 0, 12, 4, cpu)
|
grid.Set(
|
||||||
|
ui.NewRow(1.0/3, cpu),
|
||||||
ui.Body.Set(0, 4, 4, 6, disk)
|
ui.NewRow(1.0/3,
|
||||||
ui.Body.Set(0, 6, 4, 8, temp)
|
ui.NewCol(1.0/3,
|
||||||
ui.Body.Set(4, 4, 12, 8, mem)
|
ui.NewRow(1.0/2, disk),
|
||||||
|
ui.NewRow(1.0/2, temp),
|
||||||
ui.Body.Set(0, 8, 6, 12, net)
|
),
|
||||||
ui.Body.Set(6, 8, 12, 12, proc)
|
ui.NewCol(2.0/3, mem),
|
||||||
|
),
|
||||||
|
ui.NewRow(1.0/3,
|
||||||
|
ui.NewCol(1.0/2, net),
|
||||||
|
ui.NewCol(1.0/2, proc),
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func termuiColors() {
|
func termuiColors() {
|
||||||
ui.Theme.Fg = ui.Color(colorscheme.Fg)
|
ui.Theme.Default = ui.AttrPair{ui.Attribute(colorscheme.Fg), ui.Attribute(colorscheme.Bg)}
|
||||||
ui.Theme.Bg = ui.Color(colorscheme.Bg)
|
ui.Theme.Block.Title = ui.AttrPair{ui.Attribute(colorscheme.BorderLabel), ui.Attribute(colorscheme.Bg)}
|
||||||
ui.Theme.LabelFg = ui.Color(colorscheme.BorderLabel)
|
ui.Theme.Block.Border = ui.AttrPair{ui.Attribute(colorscheme.BorderLine), ui.Attribute(colorscheme.Bg)}
|
||||||
ui.Theme.LabelBg = ui.Color(colorscheme.Bg)
|
|
||||||
ui.Theme.BorderFg = ui.Color(colorscheme.BorderLine)
|
|
||||||
ui.Theme.BorderBg = ui.Color(colorscheme.Bg)
|
|
||||||
|
|
||||||
ui.Theme.TableCursor = ui.Color(colorscheme.ProcCursor)
|
|
||||||
ui.Theme.Sparkline = ui.Color(colorscheme.Sparkline)
|
|
||||||
ui.Theme.GaugeColor = ui.Color(colorscheme.DiskBar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func widgetColors() {
|
func widgetColors() {
|
||||||
mem.LineColor["Main"] = ui.Color(colorscheme.MainMem)
|
mem.LineColor["Main"] = ui.Attribute(colorscheme.MainMem)
|
||||||
mem.LineColor["Swap"] = ui.Color(colorscheme.SwapMem)
|
mem.LineColor["Swap"] = ui.Attribute(colorscheme.SwapMem)
|
||||||
|
|
||||||
|
proc.CursorColor = ui.Attribute(colorscheme.ProcCursor)
|
||||||
|
|
||||||
var keys []string
|
var keys []string
|
||||||
for key := range cpu.Data {
|
for key := range cpu.Data {
|
||||||
|
@ -185,13 +193,18 @@ func widgetColors() {
|
||||||
i = 0
|
i = 0
|
||||||
}
|
}
|
||||||
c := colorscheme.CPULines[i]
|
c := colorscheme.CPULines[i]
|
||||||
cpu.LineColor[v] = ui.Color(c)
|
cpu.LineColor[v] = ui.Attribute(c)
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
if !minimal {
|
if !minimal {
|
||||||
temp.TempLow = ui.Color(colorscheme.TempLow)
|
temp.TempLow = ui.Attribute(colorscheme.TempLow)
|
||||||
temp.TempHigh = ui.Color(colorscheme.TempHigh)
|
temp.TempHigh = ui.Attribute(colorscheme.TempHigh)
|
||||||
|
|
||||||
|
net.Lines[0].LineColor = ui.Attribute(colorscheme.Sparkline)
|
||||||
|
net.Lines[0].TitleColor = ui.Attribute(colorscheme.BorderLabel)
|
||||||
|
net.Lines[1].LineColor = ui.Attribute(colorscheme.Sparkline)
|
||||||
|
net.Lines[1].TitleColor = ui.Attribute(colorscheme.BorderLabel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,7 +259,7 @@ func eventLoop() {
|
||||||
return
|
return
|
||||||
case <-drawTicker:
|
case <-drawTicker:
|
||||||
if !helpVisible {
|
if !helpVisible {
|
||||||
ui.Render(ui.Body)
|
ui.Render(grid)
|
||||||
}
|
}
|
||||||
case e := <-uiEvents:
|
case e := <-uiEvents:
|
||||||
switch e.ID {
|
switch e.ID {
|
||||||
|
@ -258,7 +271,7 @@ func eventLoop() {
|
||||||
ui.Clear()
|
ui.Clear()
|
||||||
ui.Render(help)
|
ui.Render(help)
|
||||||
} else {
|
} else {
|
||||||
ui.Render(ui.Body)
|
ui.Render(grid)
|
||||||
}
|
}
|
||||||
case "h":
|
case "h":
|
||||||
if !helpVisible {
|
if !helpVisible {
|
||||||
|
@ -279,27 +292,27 @@ func eventLoop() {
|
||||||
case "<Escape>":
|
case "<Escape>":
|
||||||
if helpVisible {
|
if helpVisible {
|
||||||
helpVisible = false
|
helpVisible = false
|
||||||
ui.Render(ui.Body)
|
ui.Render(grid)
|
||||||
}
|
}
|
||||||
case "<Resize>":
|
case "<Resize>":
|
||||||
payload := e.Payload.(ui.Resize)
|
payload := e.Payload.(ui.Resize)
|
||||||
ui.Body.Width, ui.Body.Height = payload.Width, payload.Height
|
grid.SetRect(0, 0, payload.Width, payload.Height)
|
||||||
ui.Body.Resize()
|
help.Resize(payload.Width, payload.Height)
|
||||||
ui.Clear()
|
ui.Clear()
|
||||||
if helpVisible {
|
if helpVisible {
|
||||||
ui.Render(help)
|
ui.Render(help)
|
||||||
} else {
|
} else {
|
||||||
ui.Render(ui.Body)
|
ui.Render(grid)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "<MouseLeft>":
|
case "<MouseLeft>":
|
||||||
payload := e.Payload.(ui.Mouse)
|
payload := e.Payload.(ui.Mouse)
|
||||||
proc.Click(payload.X, payload.Y)
|
proc.Click(payload.X, payload.Y)
|
||||||
ui.Render(proc)
|
ui.Render(proc)
|
||||||
case "<MouseWheelUp>", "<Up>", "k":
|
case "k", "<Up>", "<MouseWheelUp>":
|
||||||
proc.Up()
|
proc.Up()
|
||||||
ui.Render(proc)
|
ui.Render(proc)
|
||||||
case "<MouseWheelDown>", "<Down>", "j":
|
case "j", "<Down>", "<MouseWheelDown>":
|
||||||
proc.Down()
|
proc.Down()
|
||||||
ui.Render(proc)
|
ui.Render(proc)
|
||||||
case "g", "<Home>":
|
case "g", "<Home>":
|
||||||
|
@ -373,11 +386,6 @@ func main() {
|
||||||
stderrLogger.Fatalf("failed to parse cli args: %v", err)
|
stderrLogger.Fatalf("failed to parse cli args: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
termuiColors() // need to do this before initializing widgets so that they can inherit the colors
|
|
||||||
initWidgets()
|
|
||||||
widgetColors()
|
|
||||||
help = w.NewHelpMenu()
|
|
||||||
|
|
||||||
if err := ui.Init(); err != nil {
|
if err := ui.Init(); err != nil {
|
||||||
stderrLogger.Fatalf("failed to initialize termui: %v", err)
|
stderrLogger.Fatalf("failed to initialize termui: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -385,8 +393,16 @@ func main() {
|
||||||
|
|
||||||
logging.StderrToLogfile(lf)
|
logging.StderrToLogfile(lf)
|
||||||
|
|
||||||
|
termWidth, termHeight = ui.TerminalSize()
|
||||||
|
|
||||||
|
termuiColors() // need to do this before initializing widgets so that they can inherit the colors
|
||||||
|
initWidgets()
|
||||||
|
widgetColors()
|
||||||
|
help = w.NewHelpMenu()
|
||||||
|
help.Resize(termWidth, termHeight)
|
||||||
|
|
||||||
setupGrid()
|
setupGrid()
|
||||||
ui.Render(ui.Body)
|
ui.Render(grid)
|
||||||
|
|
||||||
eventLoop()
|
eventLoop()
|
||||||
}
|
}
|
||||||
|
|
132
src/termui/linegraph.go
Normal file
132
src/termui/linegraph.go
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
package termui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
drawille "github.com/cjbassi/drawille-go"
|
||||||
|
. "github.com/gizak/termui"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LineGraph implements a line graph of data points.
|
||||||
|
type LineGraph struct {
|
||||||
|
*Block
|
||||||
|
Data map[string][]float64
|
||||||
|
LineColor map[string]Attribute
|
||||||
|
Zoom int
|
||||||
|
Labels map[string]string
|
||||||
|
|
||||||
|
DefaultLineColor Attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLineGraph returns a new LineGraph with current theme.
|
||||||
|
func NewLineGraph() *LineGraph {
|
||||||
|
return &LineGraph{
|
||||||
|
Block: NewBlock(),
|
||||||
|
Data: make(map[string][]float64),
|
||||||
|
LineColor: make(map[string]Attribute),
|
||||||
|
Labels: make(map[string]string),
|
||||||
|
Zoom: 5,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer implements Bufferer interface.
|
||||||
|
func (self *LineGraph) Draw(buf *Buffer) {
|
||||||
|
self.Block.Draw(buf)
|
||||||
|
// we render each data point on to the canvas then copy over the braille to the buffer at the end
|
||||||
|
// fyi braille characters have 2x4 dots for each character
|
||||||
|
c := drawille.NewCanvas()
|
||||||
|
// used to keep track of the braille colors until the end when we render the braille to the buffer
|
||||||
|
colors := make([][]Attribute, self.Inner.Dx()+2)
|
||||||
|
for i := range colors {
|
||||||
|
colors[i] = make([]Attribute, self.Inner.Dy()+2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort the series so that overlapping data will overlap the same way each time
|
||||||
|
seriesList := make([]string, len(self.Data))
|
||||||
|
i := 0
|
||||||
|
for seriesName := range self.Data {
|
||||||
|
seriesList[i] = seriesName
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
sort.Strings(seriesList)
|
||||||
|
|
||||||
|
// draw lines in reverse order so that the first color defined in the colorscheme is on top
|
||||||
|
for i := len(seriesList) - 1; i >= 0; i-- {
|
||||||
|
seriesName := seriesList[i]
|
||||||
|
seriesData := self.Data[seriesName]
|
||||||
|
seriesLineColor, ok := self.LineColor[seriesName]
|
||||||
|
if !ok {
|
||||||
|
seriesLineColor = self.DefaultLineColor
|
||||||
|
}
|
||||||
|
|
||||||
|
// coordinates of last point
|
||||||
|
lastY, lastX := -1, -1
|
||||||
|
// assign colors to `colors` and lines/points to the canvas
|
||||||
|
for i := len(seriesData) - 1; i >= 0; i-- {
|
||||||
|
x := ((self.Inner.Dx() + 1) * 2) - 1 - (((len(seriesData) - 1) - i) * self.Zoom)
|
||||||
|
y := ((self.Inner.Dy() + 1) * 4) - 1 - int((float64((self.Inner.Dy())*4)-1)*(seriesData[i]/100))
|
||||||
|
if x < 0 {
|
||||||
|
// render the line to the last point up to the wall
|
||||||
|
if x > 0-self.Zoom {
|
||||||
|
for _, p := range drawille.Line(lastX, lastY, x, y) {
|
||||||
|
if p.X > 0 {
|
||||||
|
c.Set(p.X, p.Y)
|
||||||
|
colors[p.X/2][p.Y/4] = seriesLineColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if lastY == -1 { // if this is the first point
|
||||||
|
c.Set(x, y)
|
||||||
|
colors[x/2][y/4] = seriesLineColor
|
||||||
|
} else {
|
||||||
|
c.DrawLine(lastX, lastY, x, y)
|
||||||
|
for _, p := range drawille.Line(lastX, lastY, x, y) {
|
||||||
|
colors[p.X/2][p.Y/4] = seriesLineColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastX, lastY = x, y
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy braille and colors to buffer
|
||||||
|
for y, line := range c.Rows(c.MinX(), c.MinY(), c.MaxX(), c.MaxY()) {
|
||||||
|
for x, char := range line {
|
||||||
|
x /= 3 // idk why but it works
|
||||||
|
if x == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if char != 10240 { // empty braille character
|
||||||
|
buf.SetCell(
|
||||||
|
Cell{char, AttrPair{colors[x][y], -1}},
|
||||||
|
image.Pt(self.Inner.Min.X+x-1, self.Inner.Min.Y+y-1),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// renders key/label ontop
|
||||||
|
for i, seriesName := range seriesList {
|
||||||
|
if i+2 > self.Inner.Dy() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seriesLineColor, ok := self.LineColor[seriesName]
|
||||||
|
if !ok {
|
||||||
|
seriesLineColor = self.DefaultLineColor
|
||||||
|
}
|
||||||
|
|
||||||
|
// render key ontop, but let braille be drawn over space characters
|
||||||
|
str := seriesName + " " + self.Labels[seriesName]
|
||||||
|
for k, char := range str {
|
||||||
|
if char != ' ' {
|
||||||
|
buf.SetCell(
|
||||||
|
Cell{char, AttrPair{seriesLineColor, -1}},
|
||||||
|
image.Pt(self.Inner.Min.X+2+k, self.Inner.Min.Y+i+1),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
96
src/termui/sparkline.go
Normal file
96
src/termui/sparkline.go
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
package termui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
|
||||||
|
. "github.com/gizak/termui"
|
||||||
|
)
|
||||||
|
|
||||||
|
var SPARKS = [8]rune{'▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'}
|
||||||
|
|
||||||
|
// Sparkline is like: ▅▆▂▂▅▇▂▂▃▆▆▆▅▃. The data points should be non-negative integers.
|
||||||
|
type Sparkline struct {
|
||||||
|
Data []int
|
||||||
|
Title1 string
|
||||||
|
Title2 string
|
||||||
|
TitleColor Attribute
|
||||||
|
LineColor Attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sparklines is a renderable widget which groups together the given sparklines.
|
||||||
|
type Sparklines struct {
|
||||||
|
*Block
|
||||||
|
Lines []*Sparkline
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add appends a given Sparkline to the *Sparklines.
|
||||||
|
func (self *Sparklines) Add(sl Sparkline) {
|
||||||
|
self.Lines = append(self.Lines, &sl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSparkline returns an unrenderable single sparkline that intended to be added into a Sparklines.
|
||||||
|
func NewSparkline() *Sparkline {
|
||||||
|
return &Sparkline{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSparklines return a new *Sparklines with given Sparklines, you can always add a new Sparkline later.
|
||||||
|
func NewSparklines(ss ...*Sparkline) *Sparklines {
|
||||||
|
return &Sparklines{
|
||||||
|
Block: NewBlock(),
|
||||||
|
Lines: ss,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer implements Bufferer interface.
|
||||||
|
func (self *Sparklines) Draw(buf *Buffer) {
|
||||||
|
self.Block.Draw(buf)
|
||||||
|
|
||||||
|
lc := len(self.Lines) // lineCount
|
||||||
|
|
||||||
|
// renders each sparkline and its titles
|
||||||
|
for i, line := range self.Lines {
|
||||||
|
|
||||||
|
// prints titles
|
||||||
|
title1Y := 2 + (self.Inner.Dy()/lc)*i
|
||||||
|
title2Y := (2 + (self.Inner.Dy()/lc)*i) + 1
|
||||||
|
title1 := TrimString(line.Title1, self.Inner.Dx())
|
||||||
|
title2 := TrimString(line.Title2, self.Inner.Dx())
|
||||||
|
buf.SetString(
|
||||||
|
title1,
|
||||||
|
image.Pt(self.Inner.Min.X, self.Inner.Min.Y+title1Y-1),
|
||||||
|
AttrPair{line.TitleColor | AttrBold, -1},
|
||||||
|
)
|
||||||
|
buf.SetString(
|
||||||
|
title2,
|
||||||
|
image.Pt(self.Inner.Min.X, self.Inner.Min.Y+title2Y-1),
|
||||||
|
AttrPair{line.TitleColor | AttrBold, -1},
|
||||||
|
)
|
||||||
|
|
||||||
|
sparkY := (self.Inner.Dy() / lc) * (i + 1)
|
||||||
|
// finds max data in current view used for relative heights
|
||||||
|
max := 1
|
||||||
|
for i := len(line.Data) - 1; i >= 0 && self.Inner.Dx()-((len(line.Data)-1)-i) >= 1; i-- {
|
||||||
|
if line.Data[i] > max {
|
||||||
|
max = line.Data[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// prints sparkline
|
||||||
|
for x := self.Inner.Dx(); x >= 1; x-- {
|
||||||
|
char := SPARKS[0]
|
||||||
|
if (self.Inner.Dx() - x) < len(line.Data) {
|
||||||
|
offset := self.Inner.Dx() - x
|
||||||
|
cur_item := line.Data[(len(line.Data)-1)-offset]
|
||||||
|
percent := float64(cur_item) / float64(max)
|
||||||
|
index := int(percent * 7)
|
||||||
|
if index < 0 || index >= len(SPARKS) {
|
||||||
|
panic("TODO")
|
||||||
|
}
|
||||||
|
char = SPARKS[index]
|
||||||
|
}
|
||||||
|
buf.SetCell(
|
||||||
|
Cell{char, AttrPair{line.LineColor, -1}},
|
||||||
|
image.Pt(self.Inner.Min.X+x-1, self.Inner.Min.Y+sparkY-1),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
201
src/termui/table.go
Normal file
201
src/termui/table.go
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
package termui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
. "github.com/gizak/termui"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table tracks all the attributes of a Table instance
|
||||||
|
type Table struct {
|
||||||
|
*Block
|
||||||
|
|
||||||
|
Header []string
|
||||||
|
Rows [][]string
|
||||||
|
|
||||||
|
ColWidths []int
|
||||||
|
CellXPos []int // column position
|
||||||
|
ColResizer func() // for widgets that inherit a Table and want to overload the ColResize method
|
||||||
|
Gap int // gap between columns
|
||||||
|
PadLeft int
|
||||||
|
|
||||||
|
Cursor bool
|
||||||
|
CursorColor Attribute
|
||||||
|
|
||||||
|
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
|
||||||
|
TopRow int // used to indicate where in the table we are scrolled at
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTable returns a new Table instance
|
||||||
|
func NewTable() *Table {
|
||||||
|
self := &Table{
|
||||||
|
Block: NewBlock(),
|
||||||
|
// CursorColor: Theme.TableCursor,
|
||||||
|
SelectedRow: 0,
|
||||||
|
TopRow: 0,
|
||||||
|
UniqueCol: 0,
|
||||||
|
}
|
||||||
|
self.ColResizer = self.ColResize
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
// ColResize is the default column resizer, but can be overriden.
|
||||||
|
// ColResize calculates the width of each column.
|
||||||
|
func (self *Table) ColResize() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer implements the Bufferer interface.
|
||||||
|
func (self *Table) Draw(buf *Buffer) {
|
||||||
|
self.Block.Draw(buf)
|
||||||
|
|
||||||
|
self.ColResizer()
|
||||||
|
|
||||||
|
// finds exact column starting position
|
||||||
|
self.CellXPos = []int{}
|
||||||
|
cur := 1 + self.PadLeft
|
||||||
|
for _, w := range self.ColWidths {
|
||||||
|
self.CellXPos = append(self.CellXPos, cur)
|
||||||
|
cur += w
|
||||||
|
cur += self.Gap
|
||||||
|
}
|
||||||
|
|
||||||
|
// prints header
|
||||||
|
for i, h := range self.Header {
|
||||||
|
width := self.ColWidths[i]
|
||||||
|
if width == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// don't render column if it doesn't fit in widget
|
||||||
|
if width > (self.Inner.Dx()-self.CellXPos[i])+1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
buf.SetString(
|
||||||
|
h,
|
||||||
|
image.Pt(self.Inner.Min.X+self.CellXPos[i]-1, self.Inner.Min.Y),
|
||||||
|
AttrPair{Theme.Default.Fg | AttrBold, -1},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// prints each row
|
||||||
|
for rowNum := self.TopRow; rowNum < self.TopRow+self.Inner.Dy()-1 && rowNum < len(self.Rows); rowNum++ {
|
||||||
|
if rowNum < 0 || rowNum >= len(self.Rows) {
|
||||||
|
panic("TODO")
|
||||||
|
}
|
||||||
|
row := self.Rows[rowNum]
|
||||||
|
y := (rowNum + 2) - self.TopRow
|
||||||
|
|
||||||
|
// prints cursor
|
||||||
|
fg := Theme.Default.Fg
|
||||||
|
if self.Cursor {
|
||||||
|
if (self.SelectedItem == "" && rowNum == self.SelectedRow) || (self.SelectedItem != "" && self.SelectedItem == row[self.UniqueCol]) {
|
||||||
|
fg = self.CursorColor | AttrReverse
|
||||||
|
for _, width := range self.ColWidths {
|
||||||
|
if width == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
buf.SetString(
|
||||||
|
strings.Repeat(" ", self.Inner.Dx()),
|
||||||
|
image.Pt(self.Inner.Min.X, self.Inner.Min.Y+y-1),
|
||||||
|
AttrPair{fg, -1},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
self.SelectedItem = row[self.UniqueCol]
|
||||||
|
self.SelectedRow = rowNum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prints each col of the row
|
||||||
|
for i, width := range self.ColWidths {
|
||||||
|
if width == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// don't render column if width is greater than distance to end of widget
|
||||||
|
if width > (self.Inner.Dx()-self.CellXPos[i])+1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r := TrimString(row[i], width)
|
||||||
|
buf.SetString(
|
||||||
|
r,
|
||||||
|
image.Pt(self.Inner.Min.X+self.CellXPos[i]-1, self.Inner.Min.Y+y-1),
|
||||||
|
AttrPair{fg, -1},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Cursor Movement //
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// calcPos is used to calculate the cursor position and the current view.
|
||||||
|
func (self *Table) calcPos() {
|
||||||
|
self.SelectedItem = ""
|
||||||
|
|
||||||
|
if self.SelectedRow < 0 {
|
||||||
|
self.SelectedRow = 0
|
||||||
|
}
|
||||||
|
if self.SelectedRow < self.TopRow {
|
||||||
|
self.TopRow = self.SelectedRow
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.SelectedRow > len(self.Rows)-1 {
|
||||||
|
self.SelectedRow = len(self.Rows) - 1
|
||||||
|
}
|
||||||
|
if self.SelectedRow > self.TopRow+(self.Inner.Dy()-2) {
|
||||||
|
self.TopRow = self.SelectedRow - (self.Inner.Dy() - 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Table) Up() {
|
||||||
|
self.SelectedRow -= 1
|
||||||
|
self.calcPos()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Table) Down() {
|
||||||
|
self.SelectedRow += 1
|
||||||
|
self.calcPos()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Table) Top() {
|
||||||
|
self.SelectedRow = 0
|
||||||
|
self.calcPos()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Table) Bottom() {
|
||||||
|
self.SelectedRow = len(self.Rows) - 1
|
||||||
|
self.calcPos()
|
||||||
|
}
|
||||||
|
|
||||||
|
// The number of lines in a page is equal to the height of the widgeself.
|
||||||
|
|
||||||
|
func (self *Table) HalfPageUp() {
|
||||||
|
self.SelectedRow = self.SelectedRow - (self.Inner.Dy()-2)/2
|
||||||
|
self.calcPos()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Table) HalfPageDown() {
|
||||||
|
self.SelectedRow = self.SelectedRow + (self.Inner.Dy()-2)/2
|
||||||
|
self.calcPos()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Table) PageUp() {
|
||||||
|
self.SelectedRow -= (self.Inner.Dy() - 2)
|
||||||
|
self.calcPos()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Table) PageDown() {
|
||||||
|
self.SelectedRow += (self.Inner.Dy() - 2)
|
||||||
|
self.calcPos()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Table) Click(x, y int) {
|
||||||
|
x = x - self.Min.X
|
||||||
|
y = y - self.Min.Y
|
||||||
|
if (x > 0 && x <= self.Inner.Dx()) && (y > 0 && y <= self.Inner.Dy()) {
|
||||||
|
self.SelectedRow = (self.TopRow + y) - 2
|
||||||
|
self.calcPos()
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
ui "github.com/cjbassi/termui"
|
ui "github.com/cjbassi/gotop/src/termui"
|
||||||
psCPU "github.com/shirou/gopsutil/cpu"
|
psCPU "github.com/shirou/gopsutil/cpu"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ func NewCPU(interval time.Duration, zoom int, average bool, percpu bool) *CPU {
|
||||||
PerCPU: percpu,
|
PerCPU: percpu,
|
||||||
formatString: formatString,
|
formatString: formatString,
|
||||||
}
|
}
|
||||||
self.Label = "CPU Usage"
|
self.Title = " CPU Usage "
|
||||||
self.Zoom = zoom
|
self.Zoom = zoom
|
||||||
|
|
||||||
if !(self.Average || self.PerCPU) {
|
if !(self.Average || self.PerCPU) {
|
||||||
|
|
|
@ -7,8 +7,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
ui "github.com/cjbassi/gotop/src/termui"
|
||||||
"github.com/cjbassi/gotop/src/utils"
|
"github.com/cjbassi/gotop/src/utils"
|
||||||
ui "github.com/cjbassi/termui"
|
|
||||||
psDisk "github.com/shirou/gopsutil/disk"
|
psDisk "github.com/shirou/gopsutil/disk"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ func NewDisk() *Disk {
|
||||||
interval: time.Second,
|
interval: time.Second,
|
||||||
Partitions: make(map[string]*Partition),
|
Partitions: make(map[string]*Partition),
|
||||||
}
|
}
|
||||||
self.Label = "Disk Usage"
|
self.Title = " Disk Usage "
|
||||||
self.Header = []string{"Disk", "Mount", "Used", "Free", "R/s", "W/s"}
|
self.Header = []string{"Disk", "Mount", "Used", "Free", "R/s", "W/s"}
|
||||||
self.Gap = 2
|
self.Gap = 2
|
||||||
self.ColResizer = self.ColResize
|
self.ColResizer = self.ColResize
|
||||||
|
@ -154,8 +154,8 @@ func (self *Disk) update() {
|
||||||
// ColResize overrides the default ColResize in the termui table.
|
// ColResize overrides the default ColResize in the termui table.
|
||||||
func (self *Disk) ColResize() {
|
func (self *Disk) ColResize() {
|
||||||
self.ColWidths = []int{
|
self.ColWidths = []int{
|
||||||
utils.Max(4, (self.X-29)/2),
|
utils.Max(4, (self.Inner.Dx()-29)/2),
|
||||||
utils.Max(5, (self.X-29)/2),
|
utils.Max(5, (self.Inner.Dx()-29)/2),
|
||||||
4, 5, 5, 5,
|
4, 5, 5, 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package widgets
|
package widgets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"image"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
ui "github.com/cjbassi/termui"
|
ui "github.com/gizak/termui"
|
||||||
)
|
)
|
||||||
|
|
||||||
const KEYBINDS = `
|
const KEYBINDS = `
|
||||||
|
@ -34,27 +35,33 @@ CPU and Mem graph scaling:
|
||||||
`
|
`
|
||||||
|
|
||||||
type HelpMenu struct {
|
type HelpMenu struct {
|
||||||
*ui.Block
|
ui.Block
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHelpMenu() *HelpMenu {
|
func NewHelpMenu() *HelpMenu {
|
||||||
block := ui.NewBlock()
|
return &HelpMenu{
|
||||||
block.X = 51 // width - 1
|
Block: *ui.NewBlock(),
|
||||||
block.Y = 24 // height - 1
|
}
|
||||||
return &HelpMenu{block}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *HelpMenu) Buffer() *ui.Buffer {
|
func (self *HelpMenu) Resize(termWidth, termHeight int) {
|
||||||
buf := self.Block.Buffer()
|
textWidth := 53
|
||||||
|
textHeight := 22
|
||||||
|
x := (termWidth - textWidth) / 2
|
||||||
|
y := (termHeight - textHeight) / 2
|
||||||
|
|
||||||
self.Block.XOffset = (ui.Body.Width - self.Block.X) / 2 // X coordinate
|
self.Block.SetRect(x, y, textWidth+x, textHeight+y)
|
||||||
self.Block.YOffset = (ui.Body.Height - self.Block.Y) / 2 // Y coordinate
|
}
|
||||||
|
|
||||||
|
func (self *HelpMenu) Draw(buf *ui.Buffer) {
|
||||||
|
self.Block.Draw(buf)
|
||||||
|
|
||||||
for y, line := range strings.Split(KEYBINDS, "\n") {
|
for y, line := range strings.Split(KEYBINDS, "\n") {
|
||||||
for x, char := range line {
|
for x, char := range line {
|
||||||
buf.SetCell(x+1, y, ui.NewCell(char, ui.Color(7), self.Bg))
|
buf.SetCell(
|
||||||
|
ui.Cell{char, ui.AttrPair{ui.Attribute(7), -1}},
|
||||||
|
image.Pt(self.Inner.Min.X+x, self.Inner.Min.Y+y-1),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
ui "github.com/cjbassi/gotop/src/termui"
|
||||||
"github.com/cjbassi/gotop/src/utils"
|
"github.com/cjbassi/gotop/src/utils"
|
||||||
ui "github.com/cjbassi/termui"
|
|
||||||
psMem "github.com/shirou/gopsutil/mem"
|
psMem "github.com/shirou/gopsutil/mem"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ func NewMem(interval time.Duration, zoom int) *Mem {
|
||||||
LineGraph: ui.NewLineGraph(),
|
LineGraph: ui.NewLineGraph(),
|
||||||
interval: interval,
|
interval: interval,
|
||||||
}
|
}
|
||||||
self.Label = "Memory Usage"
|
self.Title = " Memory Usage "
|
||||||
self.Zoom = zoom
|
self.Zoom = zoom
|
||||||
self.Data["Main"] = []float64{0}
|
self.Data["Main"] = []float64{0}
|
||||||
self.Data["Swap"] = []float64{0}
|
self.Data["Swap"] = []float64{0}
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
ui "github.com/cjbassi/gotop/src/termui"
|
||||||
"github.com/cjbassi/gotop/src/utils"
|
"github.com/cjbassi/gotop/src/utils"
|
||||||
ui "github.com/cjbassi/termui"
|
|
||||||
psNet "github.com/shirou/gopsutil/net"
|
psNet "github.com/shirou/gopsutil/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ func NewNet() *Net {
|
||||||
Sparklines: spark,
|
Sparklines: spark,
|
||||||
interval: time.Second,
|
interval: time.Second,
|
||||||
}
|
}
|
||||||
self.Label = "Network Usage"
|
self.Title = " Network Usage "
|
||||||
|
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,9 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
ui "github.com/cjbassi/gotop/src/termui"
|
||||||
"github.com/cjbassi/gotop/src/utils"
|
"github.com/cjbassi/gotop/src/utils"
|
||||||
ui "github.com/cjbassi/termui"
|
"github.com/gizak/termui"
|
||||||
psCPU "github.com/shirou/gopsutil/cpu"
|
psCPU "github.com/shirou/gopsutil/cpu"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -49,7 +50,7 @@ func NewProc() *Proc {
|
||||||
sortMethod: "c",
|
sortMethod: "c",
|
||||||
group: true,
|
group: true,
|
||||||
}
|
}
|
||||||
self.Label = "Processes"
|
self.Title = " Processes "
|
||||||
self.ColResizer = self.ColResize
|
self.ColResizer = self.ColResize
|
||||||
self.Cursor = true
|
self.Cursor = true
|
||||||
self.Gap = 3
|
self.Gap = 3
|
||||||
|
@ -108,11 +109,11 @@ func (self *Proc) Sort() {
|
||||||
// ColResize overrides the default ColResize in the termui table.
|
// ColResize overrides the default ColResize in the termui table.
|
||||||
func (self *Proc) ColResize() {
|
func (self *Proc) ColResize() {
|
||||||
self.ColWidths = []int{
|
self.ColWidths = []int{
|
||||||
5, utils.Max(self.X-26, 10), 4, 4,
|
5, utils.Max(self.Inner.Dx()-26, 10), 4, 4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Proc) ChangeSort(e ui.Event) {
|
func (self *Proc) ChangeSort(e termui.Event) {
|
||||||
if self.sortMethod != e.ID {
|
if self.sortMethod != e.ID {
|
||||||
self.sortMethod = e.ID
|
self.sortMethod = e.ID
|
||||||
self.Top()
|
self.Top()
|
||||||
|
|
|
@ -5,10 +5,11 @@ package widgets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
ui "github.com/cjbassi/termui"
|
ui "github.com/gizak/termui"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Temp struct {
|
type Temp struct {
|
||||||
|
@ -16,8 +17,8 @@ type Temp struct {
|
||||||
interval time.Duration
|
interval time.Duration
|
||||||
Data map[string]int
|
Data map[string]int
|
||||||
Threshold int
|
Threshold int
|
||||||
TempLow ui.Color
|
TempLow ui.Attribute
|
||||||
TempHigh ui.Color
|
TempHigh ui.Attribute
|
||||||
Fahrenheit bool
|
Fahrenheit bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ func NewTemp(fahrenheit bool) *Temp {
|
||||||
Data: make(map[string]int),
|
Data: make(map[string]int),
|
||||||
Threshold: 80, // temp at which color should change
|
Threshold: 80, // temp at which color should change
|
||||||
}
|
}
|
||||||
self.Label = "Temperatures"
|
self.Title = " Temperatures "
|
||||||
|
|
||||||
if fahrenheit {
|
if fahrenheit {
|
||||||
self.Fahrenheit = true
|
self.Fahrenheit = true
|
||||||
|
@ -48,8 +49,8 @@ func NewTemp(fahrenheit bool) *Temp {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buffer implements ui.Bufferer interface and renders the widget.
|
// Buffer implements ui.Bufferer interface and renders the widget.
|
||||||
func (self *Temp) Buffer() *ui.Buffer {
|
func (self *Temp) Draw(buf *ui.Buffer) {
|
||||||
buf := self.Block.Buffer()
|
self.Block.Draw(buf)
|
||||||
|
|
||||||
var keys []string
|
var keys []string
|
||||||
for key := range self.Data {
|
for key := range self.Data {
|
||||||
|
@ -58,7 +59,7 @@ func (self *Temp) Buffer() *ui.Buffer {
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
|
|
||||||
for y, key := range keys {
|
for y, key := range keys {
|
||||||
if y+1 > self.Y {
|
if y+1 > self.Inner.Dy() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,14 +68,23 @@ func (self *Temp) Buffer() *ui.Buffer {
|
||||||
fg = self.TempHigh
|
fg = self.TempHigh
|
||||||
}
|
}
|
||||||
|
|
||||||
s := ui.MaxString(key, (self.X - 4))
|
s := ui.TrimString(key, (self.Inner.Dx() - 4))
|
||||||
buf.SetString(1, y+1, s, self.Fg, self.Bg)
|
buf.SetString(s,
|
||||||
|
image.Pt(self.Inner.Min.X, self.Inner.Min.Y+y),
|
||||||
|
ui.Theme.Default,
|
||||||
|
)
|
||||||
if self.Fahrenheit {
|
if self.Fahrenheit {
|
||||||
buf.SetString(self.X-3, y+1, fmt.Sprintf("%3dF", self.Data[key]), fg, self.Bg)
|
buf.SetString(
|
||||||
|
fmt.Sprintf("%3dF", self.Data[key]),
|
||||||
|
image.Pt(self.Inner.Dx()-3, y+1),
|
||||||
|
ui.AttrPair{fg, -1},
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
buf.SetString(self.X-3, y+1, fmt.Sprintf("%3dC", self.Data[key]), fg, self.Bg)
|
buf.SetString(
|
||||||
|
fmt.Sprintf("%3dC", self.Data[key]),
|
||||||
|
image.Pt(self.Inner.Max.X-4, self.Inner.Min.Y+y),
|
||||||
|
ui.AttrPair{fg, -1},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user