prevent recursive/nested running menus, handle all within main Display() loop

This commit is contained in:
Bradley Cicenas 2018-01-11 14:23:28 +00:00
parent 734d4bfc0c
commit eb49e51ffb
2 changed files with 86 additions and 77 deletions

25
grid.go
View File

@ -2,7 +2,6 @@ package main
import ( import (
"github.com/bcicen/ctop/config" "github.com/bcicen/ctop/config"
"github.com/bcicen/ctop/container"
"github.com/bcicen/ctop/cwidgets/single" "github.com/bcicen/ctop/cwidgets/single"
ui "github.com/gizak/termui" ui "github.com/gizak/termui"
) )
@ -35,7 +34,12 @@ func RedrawRows(clr bool) {
ui.Render(cGrid) ui.Render(cGrid)
} }
func SingleView(c *container.Container) { func SingleView() MenuFn {
c := cursor.Selected()
if c == nil {
return nil
}
ui.Clear() ui.Clear()
ui.DefaultEvtStream.ResetHandlers() ui.DefaultEvtStream.ResetHandlers()
defer ui.DefaultEvtStream.ResetHandlers() defer ui.DefaultEvtStream.ResetHandlers()
@ -59,6 +63,7 @@ func SingleView(c *container.Container) {
ui.Loop() ui.Loop()
c.SetUpdater(c.Widgets) c.SetUpdater(c.Widgets)
return nil
} }
func RefreshDisplay() { func RefreshDisplay() {
@ -70,8 +75,7 @@ func RefreshDisplay() {
} }
func Display() bool { func Display() bool {
var menu func() var menu MenuFn
var single bool
cGrid.SetWidth(ui.TermWidth()) cGrid.SetWidth(ui.TermWidth())
ui.DefaultEvtStream.Hook(logEvent) ui.DefaultEvtStream.Hook(logEvent)
@ -102,7 +106,7 @@ func Display() bool {
ui.StopLoop() ui.StopLoop()
}) })
ui.Handle("/sys/kbd/o", func(ui.Event) { ui.Handle("/sys/kbd/o", func(ui.Event) {
single = true menu = SingleView
ui.StopLoop() ui.StopLoop()
}) })
ui.Handle("/sys/kbd/a", func(ui.Event) { ui.Handle("/sys/kbd/a", func(ui.Event) {
@ -141,16 +145,13 @@ func Display() bool {
}) })
ui.Loop() ui.Loop()
if menu != nil { if menu != nil {
menu() for menu != nil {
return false menu = menu()
}
if single {
c := cursor.Selected()
if c != nil {
SingleView(c)
} }
return false return false
} }
return true return true
} }

138
menus.go
View File

@ -11,6 +11,9 @@ import (
ui "github.com/gizak/termui" ui "github.com/gizak/termui"
) )
// MenuFn executes a menu window, returning the next menu or nil
type MenuFn func() MenuFn
var helpDialog = []menu.Item{ var helpDialog = []menu.Item{
{"<enter> - open container menu", ""}, {"<enter> - open container menu", ""},
{"", ""}, {"", ""},
@ -25,7 +28,7 @@ var helpDialog = []menu.Item{
{"[q] - exit ctop", ""}, {"[q] - exit ctop", ""},
} }
func HelpMenu() { func HelpMenu() MenuFn {
ui.Clear() ui.Clear()
ui.DefaultEvtStream.ResetHandlers() ui.DefaultEvtStream.ResetHandlers()
defer ui.DefaultEvtStream.ResetHandlers() defer ui.DefaultEvtStream.ResetHandlers()
@ -38,9 +41,10 @@ func HelpMenu() {
ui.StopLoop() ui.StopLoop()
}) })
ui.Loop() ui.Loop()
return nil
} }
func FilterMenu() { func FilterMenu() MenuFn {
ui.DefaultEvtStream.ResetHandlers() ui.DefaultEvtStream.ResetHandlers()
defer ui.DefaultEvtStream.ResetHandlers() defer ui.DefaultEvtStream.ResetHandlers()
@ -70,9 +74,10 @@ func FilterMenu() {
ui.StopLoop() ui.StopLoop()
}) })
ui.Loop() ui.Loop()
return nil
} }
func SortMenu() { func SortMenu() MenuFn {
ui.Clear() ui.Clear()
ui.DefaultEvtStream.ResetHandlers() ui.DefaultEvtStream.ResetHandlers()
defer ui.DefaultEvtStream.ResetHandlers() defer ui.DefaultEvtStream.ResetHandlers()
@ -100,13 +105,13 @@ func SortMenu() {
ui.Render(m) ui.Render(m)
ui.Loop() ui.Loop()
return nil
} }
func ContainerMenu() { func ContainerMenu() MenuFn {
c := cursor.Selected() c := cursor.Selected()
if c == nil { if c == nil {
return return nil
} }
ui.DefaultEvtStream.ResetHandlers() ui.DefaultEvtStream.ResetHandlers()
@ -133,42 +138,36 @@ func ContainerMenu() {
m.AddItems(items...) m.AddItems(items...)
ui.Render(m) ui.Render(m)
confirmTxt := func(a, n string) string { return fmt.Sprintf("%s container %s?", a, n) } var nextMenu MenuFn
HandleKeys("up", m.Up) HandleKeys("up", m.Up)
HandleKeys("down", m.Down) HandleKeys("down", m.Down)
ui.Handle("/sys/kbd/<enter>", func(ui.Event) { ui.Handle("/sys/kbd/<enter>", func(ui.Event) {
switch m.SelectedItem().Val { switch m.SelectedItem().Val {
case "single": case "single":
SingleView(c) nextMenu = SingleView
ui.StopLoop()
case "logs": case "logs":
LogMenu() nextMenu = LogMenu
ui.StopLoop()
case "start": case "start":
Confirm(confirmTxt("start", c.GetMeta("name")), c.Start) nextMenu = Confirm(confirmTxt("start", c.GetMeta("name")), c.Start)
ui.StopLoop()
case "stop": case "stop":
Confirm(confirmTxt("stop", c.GetMeta("name")), c.Stop) nextMenu = Confirm(confirmTxt("stop", c.GetMeta("name")), c.Stop)
ui.StopLoop()
case "remove": case "remove":
Confirm(confirmTxt("remove", c.GetMeta("name")), c.Remove) nextMenu = Confirm(confirmTxt("remove", c.GetMeta("name")), c.Remove)
ui.StopLoop()
case "cancel":
ui.StopLoop()
} }
ui.StopLoop()
}) })
ui.Handle("/sys/kbd/", func(ui.Event) { ui.Handle("/sys/kbd/", func(ui.Event) {
ui.StopLoop() ui.StopLoop()
}) })
ui.Loop() ui.Loop()
return nextMenu
} }
func LogMenu() { func LogMenu() MenuFn {
c := cursor.Selected() c := cursor.Selected()
if c == nil { if c == nil {
return return nil
} }
ui.DefaultEvtStream.ResetHandlers() ui.DefaultEvtStream.ResetHandlers()
@ -190,56 +189,63 @@ func LogMenu() {
ui.StopLoop() ui.StopLoop()
}) })
ui.Loop() ui.Loop()
return nil
} }
func Confirm(txt string, fn func()) { // Create a confirmation dialog with a given description string and
ui.DefaultEvtStream.ResetHandlers() // func to perform if confirmed
defer ui.DefaultEvtStream.ResetHandlers() func Confirm(txt string, fn func()) MenuFn {
menu := func() MenuFn {
ui.DefaultEvtStream.ResetHandlers()
defer ui.DefaultEvtStream.ResetHandlers()
m := menu.NewMenu() m := menu.NewMenu()
m.Selectable = true m.Selectable = true
m.BorderLabel = "Confirm" m.BorderLabel = "Confirm"
m.SubText = txt m.SubText = txt
items := []menu.Item{ items := []menu.Item{
menu.Item{Val: "cancel", Label: "[c]ancel"}, menu.Item{Val: "cancel", Label: "[c]ancel"},
menu.Item{Val: "yes", Label: "[y]es"}, menu.Item{Val: "yes", Label: "[y]es"},
}
var response bool
m.AddItems(items...)
ui.Render(m)
yes := func() {
response = true
ui.StopLoop()
}
no := func() {
response = false
ui.StopLoop()
}
HandleKeys("up", m.Up)
HandleKeys("down", m.Down)
HandleKeys("exit", no)
ui.Handle("/sys/kbd/c", func(ui.Event) { no() })
ui.Handle("/sys/kbd/y", func(ui.Event) { yes() })
ui.Handle("/sys/kbd/<enter>", func(ui.Event) {
switch m.SelectedItem().Val {
case "cancel":
no()
case "yes":
yes()
} }
})
ui.Loop() var response bool
if response {
fn() m.AddItems(items...)
ui.Render(m)
yes := func() {
response = true
ui.StopLoop()
}
no := func() {
response = false
ui.StopLoop()
}
HandleKeys("up", m.Up)
HandleKeys("down", m.Down)
HandleKeys("exit", no)
ui.Handle("/sys/kbd/c", func(ui.Event) { no() })
ui.Handle("/sys/kbd/y", func(ui.Event) { yes() })
ui.Handle("/sys/kbd/<enter>", func(ui.Event) {
switch m.SelectedItem().Val {
case "cancel":
no()
case "yes":
yes()
}
})
ui.Loop()
if response {
fn()
}
return nil
} }
return menu
} }
type toggleLog struct { type toggleLog struct {
@ -275,3 +281,5 @@ func logReader(container *container.Container) (logs chan widgets.ToggleText, qu
}() }()
return return
} }
func confirmTxt(a, n string) string { return fmt.Sprintf("%s container %s?", a, n) }