diff --git a/README-goreadme.md b/README-goreadme.md index 96323d8..156c030 100644 --- a/README-goreadme.md +++ b/README-goreadme.md @@ -127,13 +127,16 @@ Creates a window helpful for debugging this package `func Indent(b bool, a ...interface{})` -### func [InitPlugins](/main.go#L58) +### func [InitPlugins](/main.go#L61) -`func InitPlugins(names []string)` +`func InitPlugins(names []string) []string` + +TODO: add logic to just load the 1st 'most common' gui toolkit +and allow the 'go-arg' command line args to override the defaults ### func [LoadToolkit](/plugin.go#L50) -`func LoadToolkit(name string) bool` +`func LoadToolkit(name string) *aplug` loads and initializes a toolkit (andlabs/ui, gocui, etc) @@ -159,7 +162,7 @@ This should not pass a function `func ShowDebugValues()` -### func [StandardExit](/main.go#L255) +### func [StandardExit](/main.go#L262) `func StandardExit()` @@ -248,11 +251,11 @@ func main() { You get a window ``` -#### func [Start](/main.go#L98) +#### func [Start](/main.go#L97) `func Start() *Node` -#### func [StartS](/main.go#L180) +#### func [StartS](/main.go#L178) `func StartS(name string) *Node` diff --git a/cmds/buttonplugin/main.go b/cmds/buttonplugin/main.go index 5636a87..f09afd3 100644 --- a/cmds/buttonplugin/main.go +++ b/cmds/buttonplugin/main.go @@ -11,6 +11,7 @@ import ( var title string = "Demo Plugin Window" var outfile string = "/tmp/guilogfile" +var myGui *gui.Node var buttonCounter int = 5 @@ -27,25 +28,13 @@ func main() { // gui.Init() // buttonWindow() - go gui.Main(func () { - log.Println("START Main f()") - buttonWindow() - /* - log.Println("END NewWindow()") - log.Println("START NewGroup()") - g := w.NewGroup("new Group 22") - log.Println("END NewGroup()") - g.NewButton("asdjkl", func () { - log.Println("world") - }) - */ - log.Println("END Main f()") - // gui.StandardExit(nil) - }) + myGui = gui.Start() + time.Sleep(1 * time.Second) + buttonWindow() log.Println("Main() END") time.Sleep(1 * time.Second) - gui.StartS("gocui") - gui.Redraw("gocui") + // gui.StartS("gocui") + // gui.Redraw("gocui") gui.Watchdog() gui.StandardExit() } @@ -84,6 +73,10 @@ func buttonWindow() { gui.Redraw("gocui") }) + g.NewButton("Load 'andlabs'", func () { + gui.StartS("andlabs") + }) + g.NewButton("NewButton(more)", func () { log.Println("new foobar 2. Adding button 'foobar 3'") name := "foobar " + strconv.Itoa(buttonCounter) diff --git a/main.go b/main.go index 07cd420..e489e25 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package gui import ( + "os" // "embed" "git.wit.org/wit/gui/toolkit" ) @@ -55,44 +56,42 @@ func doGuiChan() { } } -func InitPlugins(names []string) { +// TODO: add logic to just load the 1st 'most common' gui toolkit +// and allow the 'go-arg' command line args to override the defaults +func InitPlugins(names []string) []string { log(debugGui, "Starting gui.Init()") for _, aplug := range allPlugins { log(debugGui, "LoadToolkit() already loaded toolkit plugin =", aplug.name) for _, name := range names { if (name == aplug.name) { - return + return []string{name} } } } // try to load each plugin in the order passed to this function for _, name := range names { - if (LoadToolkit(name)) { - // aplug.InitOk = true - // aplug.Init() - return + aPlug := LoadToolkit(name) + if (aPlug != nil) { + // exit because it worked! + return []string{name} } } // the program didn't specify a plugin. Try to load one // TODO: detect the OS & user preferences to load the best one // TODO: commented out Init() on 02/26/2023 because I'm not sure how to run it correctly - if (LoadToolkit("andlabs")) { - // aplug.InitOk = true - // aplug.Init() - return + andlabsPlug := LoadToolkit("andlabs") + if (andlabsPlug != nil) { + return []string{} } - if (LoadToolkit("gocui")) { - // aplug.InitOk = true - // aplug.Init() - return + gocuiPlug := LoadToolkit("andlabs") + if (gocuiPlug != nil) { + return []string{} } - - // Should die here? TODO: need a Node to call StandardExit - // StandardExit("golang wit/gui could not load a plugin TODO: do something to STDOUT (?)") + return []string{} } func Start() *Node { @@ -173,13 +172,13 @@ func (n *Node) doUserEvent(a toolkit.Action) { func (n *Node) LoadPlugin(name string) bool { StartS(name) - Redraw(name) return true } func StartS(name string) *Node { log(logInfo, "Start() Main(f) for name =", name) - if (LoadToolkit(name) == false) { + aplug := LoadToolkit(name) + if (aplug == nil) { return Config.rootNode } // will this really work on mswindows & macos? @@ -187,6 +186,7 @@ func StartS(name string) *Node { } go Main(f) sleep(1) // temp hack until chan communication is setup + Config.rootNode.Redraw(aplug) return Config.rootNode } @@ -194,7 +194,14 @@ func StartS(name string) *Node { func Main(f func()) { log(debugGui, "Starting gui.Main() (using gtk via andlabs/ui)") - InitPlugins([]string{"andlabs", "gocui"}) + // TODO: this is linux only + // TODO: detect if this was run from the command line (parent == bash?) + // if DISPLAY is not set, don't even bother with loading andlabs + if (os.Getenv("DISPLAY") == "") { + InitPlugins([]string{"gocui"}) + } else { + InitPlugins([]string{"andlabs", "gocui"}) + } if (Config.guiChan == nil) { Config.guiChan = make(chan toolkit.Action) diff --git a/plugin.go b/plugin.go index 26667cf..051f9c7 100644 --- a/plugin.go +++ b/plugin.go @@ -47,8 +47,9 @@ type aplug struct { var allPlugins []*aplug // loads and initializes a toolkit (andlabs/ui, gocui, etc) -func LoadToolkit(name string) bool { - var newPlug aplug +func LoadToolkit(name string) *aplug { + var newPlug *aplug + newPlug = new(aplug) log(debugGui, "gui.LoadToolkit() START") newPlug.LoadOk = false @@ -57,44 +58,45 @@ func LoadToolkit(name string) bool { log(debugGui, "gui.LoadToolkit() already loaded toolkit plugin =", aplug.name) if (aplug.name == name) { log(debugGui, "gui.LoadToolkit() SKIPPING") - return true + return aplug } } // locate the shared library file filename := name + ".so" - loadPlugin(&newPlug, filename) + loadPlugin(newPlug, filename) if (newPlug.plug == nil) { log(true, "attempt to find plugin", filename, "failed") - return false + return nil } // newPlug.Ok = true newPlug.name = name // deprecate Init(?) - newPlug.Init = loadFuncE(&newPlug, "Init") + newPlug.Init = loadFuncE(newPlug, "Init") // should make a goroutine that never exits - newPlug.Main = loadFuncF(&newPlug, "Main") + newPlug.Main = loadFuncF(newPlug, "Main") // should send things to the goroutine above // newPlug.Queue = loadFuncF(&newPlug, "Queue") // unload the plugin and restore state - newPlug.Quit = loadFuncE(&newPlug, "Quit") + newPlug.Quit = loadFuncE(newPlug, "Quit") // Sends instructions like "Add", "Delete", "Disable", etc // Sends a widget (button, checkbox, etc) and it's parent widget - newPlug.Action = loadFuncA(&newPlug, "Action") + newPlug.Action = loadFuncA(newPlug, "Action") - newPlug.Callback = loadCallback(&newPlug, "Callback") + newPlug.Callback = loadCallback(newPlug, "Callback") - allPlugins = append(allPlugins, &newPlug) + allPlugins = append(allPlugins, newPlug) log(debugPlugin, "gui.LoadToolkit() END", newPlug.name, filename) newPlug.Init() + Config.rootNode.Redraw(newPlug) newPlug.LoadOk = true - return true + return newPlug } // TODO: All these functions need to be done a smarter way diff --git a/toolkit/gocui/help.go b/toolkit/gocui/help.go index d1206e7..cf4e84d 100644 --- a/toolkit/gocui/help.go +++ b/toolkit/gocui/help.go @@ -38,9 +38,10 @@ func helplayout(g *gocui.Gui) error { fmt.Fprintln(help, "d: show/hide debugging") fmt.Fprintln(help, "h: hide widgets") fmt.Fprintln(help, "s: show all widgets") + fmt.Fprintln(help, "q: quit()") fmt.Fprintln(help, "p: panic()") fmt.Fprintln(help, "STDOUT: /tmp/witgui.log") - fmt.Fprintln(help, "Ctrl-C or Q: Exit") + // fmt.Fprintln(help, "Ctrl-C: Exit") // TODO: fix ctrl-c handling if _, err := g.SetCurrentView("help"); err != nil { return err } diff --git a/toolkit/gocui/keybindings.go b/toolkit/gocui/keybindings.go index 8e8a8dc..23db0eb 100644 --- a/toolkit/gocui/keybindings.go +++ b/toolkit/gocui/keybindings.go @@ -70,9 +70,24 @@ func addDebugKeys(g *gocui.Gui) { return nil }) + // exit + g.SetKeybinding("", 'q', gocui.ModNone, + func(g *gocui.Gui, v *gocui.View) error { + me.baseGui.Close() + exit("forced exit() from within gocui") + return nil + }) + g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, + func(g *gocui.Gui, v *gocui.View) error { + me.baseGui.Close() + exit("forced exit() from within gocui") + return nil + }) + // panic g.SetKeybinding("", 'p', gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { + me.baseGui.Close() panic("forced panic in gocui") return nil }) diff --git a/toolkit/gocui/main.go b/toolkit/gocui/main.go index 6821a82..b115786 100644 --- a/toolkit/gocui/main.go +++ b/toolkit/gocui/main.go @@ -34,7 +34,7 @@ func Callback(guiCallback chan toolkit.Action) { } func Exit() { - // TODO: exit correctly + // TODO: send exit to the plugin me.baseGui.Close() } @@ -51,4 +51,5 @@ func Main(f func()) { log("This is a test log entry") MouseMain() + me.baseGui.Close() } diff --git a/toolkit/gocui/plugin.go b/toolkit/gocui/plugin.go index eb3f2af..1758690 100644 --- a/toolkit/gocui/plugin.go +++ b/toolkit/gocui/plugin.go @@ -15,8 +15,15 @@ func Action(a *toolkit.Action) { w := findWidget(a.WidgetId, me.rootNode) switch a.ActionType { case toolkit.Add: - w = makeWidget(a) - w.addWidget() + if (w == nil) { + w = makeWidget(a) + w.addWidget() + } else { + // this is done to protect the plugin being 'refreshed' with the + // widget binary tree. TODO: find a way to keep them in sync + log(logError, "Action() Add ignored for already defined widget", + a.WidgetId, a.ActionType, a.WidgetType, a.Name) + } case toolkit.Show: if (a.B) { w.drawView() diff --git a/watchdog.go b/watchdog.go index 0f649cb..a9e0880 100644 --- a/watchdog.go +++ b/watchdog.go @@ -15,7 +15,14 @@ var watchtime time.Duration = 100 // in tenths of seconds func Watchdog() { var i = 1 for { - log(logInfo, "watchdog timer is alive. give me something to do.", i) + log(logNow, "watchdog timer is alive. give me something to do.", i) + if (Config.rootNode == nil) { + log(logInfo, "Config.rootNode == nil", i) + } else { + if (logVerbose) { + Config.rootNode.ListChildren(true) + } + } i += 1 time.Sleep(watchtime * time.Second / 10) }