package gui import ( "os" "go.wit.com/log" "go.wit.com/widget" ) // TODO: make a fake 'plugin' channel of communication to andlabs for mswindows // Windows doesn't support plugins. How can I keep andlabs and only compile it on windows? // https://forum.heroiclabs.com/t/setting-up-goland-to-compile-plugins-on-windows/594/5 // import toolkit "go.wit.com/gui/toolkit/andlabs" const Xaxis = 0 // stack things horizontally const Yaxis = 1 // stack things vertically func init() { log.Log(INFO, "init() has been run") me.counter = 0 // me.prefix = "wit" // Populates the top of the binary tree me.rootNode = addNode() me.rootNode.progname = "guiBinaryTree" me.rootNode.WidgetType = widget.Root me.rootNode.hidden = false // always send the rootNode to the toolkits // used to pass debugging flags to the toolkit plugins me.flag = me.rootNode.newNode("flag", 0) me.flag.WidgetType = widget.Flag me.flag = me.rootNode.newNode("stdout", 0) me.flag.WidgetType = widget.Stdout me.guiChan = make(chan widget.Action, 1) go watchCallback() } // lookup the widget by the id sent from the toolkit func (n *Node) findId(i int) *Node { if n == nil { return nil } if n.id == i { return n } for _, child := range n.children { newN := child.findId(i) if newN != nil { return newN } } return nil } func watchCallback() { log.Log(INFO, "guiChan() START") for { log.Log(CHANGE, "guiChan() select restarted") select { case a := <-me.guiChan: // 99.9% of events are just widget changes n := me.rootNode.findId(a.WidgetId) if n != nil { log.Log(INFO, "guiChan() FOUND widget id =", n.id, n.progname) n.gotUserEvent(a) break } // if not a widget change, something more bizare if a.ActionType == widget.UserQuit { log.Log(WARN, "guiChan() User sent Quit()") log.Exit("wit/gui toolkit.UserQuit") break } if a.ActionType == widget.ToolkitPanic { log.Log(WARN, "guiChan() Toolkit panic() in", a.ProgName) log.Log(WARN, "guiChan() unload toolkit plugin here", a.ProgName) me.rootNode.ListToolkits() for _, aplug := range allPlugins { log.Log(WARN, "ListToolkits() already loaded toolkit plugin =", aplug.name) if aplug.name == a.ProgName { log.Log(WARN, "FOUND PLUGIN =", aplug.name) log.Log(WARN, "unload here") log.Log(WARN, "panic on purpose") me.rootNode.CloseToolkit(aplug.name) // panic("panic trapped!") // log.Sleep(.5) // me.rootNode.LoadToolkit("gocui") break } } log.UnsetTmp() // StandardExit() me.rootNode.LoadToolkit("nocui") break } if a.ActionType == widget.ToolkitLoad { newPlug := widget.GetString(a.Value) log.Log(WARN, "Attempt to load a new toolkit", newPlug, "here") me.rootNode.LoadToolkit(newPlug) } if a.ActionType == widget.EnableDebug { log.Log(WARN, "guiChan() Enable Debugging Window") log.Log(WARN, "guiChan() TODO: not implemented") log.Log(WARN, "guiChan() Listing Toolkits:") PLUG.SetBool(true) me.rootNode.ListToolkits() me.rootNode.ListChildren(true) /* for i, aplug := range allPlugins { log.Log("plug =", i, aplug.name) if aplug.name == "andlabs" { log.Log("Found plug =", i, aplug.name) //closePlugin(aplug) allPlugins = allPlugins[1:] } } */ break } log.Log(WARN, "guiChan() Action could not be found or handled", a.ActionType, a) } } } // stores the value returned then // spawns the user defined custom routine // hopefully everything is designed smart enough // that it doesn't matter what happens outside of here // TODO: implement throttling someday func (n *Node) gotUserEvent(a widget.Action) { log.Log(CHANGE, "gotUserEvent() received event node =", n.id, n.progname, a.Value) switch n.WidgetType { case widget.Dropdown: // n.checked = a.State.Checked // TODO: do this and/or time to switch to protobuf n.currentS = a.State.CurrentS case widget.Combobox: // n.checked = a.State.Checked // TODO: do this and/or time to switch to protobuf n.currentS = a.State.CurrentS case widget.Checkbox: // n.checked = a.State.Checked // TODO: do this and/or time to switch to protobuf n.checked = a.State.Checked default: } n.currentS = a.State.CurrentS log.Log(CHANGE, "gotUserEvent() n.Bool() =", n.Bool(), "n.String() =", n.String()) if n.Custom == nil { log.Log(CHANGE, "a Custom() function was not set for this widget") return } go n.Custom() } // There should only be one of these per application // This is due to restrictions by being cross platform // some toolkit's on some operating systems don't support more than one // Keep things simple. Do the default expected thing whenever possible func New() *Node { return me.rootNode } // try to load andlabs, if that doesn't work, fall back to the console func (n *Node) Default() *Node { if argGui.GuiPlugin != "" { log.Log(WARN, "New.Default() try toolkit =", argGui.GuiPlugin) return n.LoadToolkit(argGui.GuiPlugin) } // if DISPLAY isn't set, return since gtk can't load // TODO: figure out how to check what to do in macos and mswindows if os.Getenv("DISPLAY") == "" { if n.LoadToolkit("gocui") == nil { log.Log(WARN, "New() failed to load gocui") } return n } if n.LoadToolkit("andlabs") != nil { return n } n.LoadToolkit("gocui") return n } // The window is destroyed but the application does not quit func (n *Node) StandardClose() { log.Log(INFO, "wit/gui Standard Window Close. name =", n.progname) log.Log(INFO, "wit/gui Standard Window Close. n.Custom exit =", n.Custom) } // The window is destroyed and the application exits // TODO: properly exit the plugin since Quit() doesn't do it func StandardExit() { log.Log(INFO, "wit/gui Standard Window Exit. running os.Exit()") log.Log(INFO, "StandardExit() attempt to exit each toolkit plugin") for i, plug := range allPlugins { log.Log(INFO, "NewButton()", i, plug) } log.Exit(0) } // The window is destroyed and the application exits // TODO: properly exit the plugin since Quit() doesn't do it func (n *Node) StandardExit() { log.Log(INFO, "wit/gui Standard Window Exit. running os.Exit()") log.Log(INFO, "StandardExit() attempt to exit each toolkit plugin") for i, plug := range allPlugins { log.Log(INFO, "NewButton()", i, plug) } log.Exit(0) }