diff options
Diffstat (limited to 'init.go')
| -rw-r--r-- | init.go | 392 |
1 files changed, 392 insertions, 0 deletions
@@ -0,0 +1,392 @@ +package gui + +import ( + "errors" + "fmt" + "os" + "runtime/debug" + + "go.wit.com/log" + "go.wit.com/widget" +) + +// 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) + + version, err := getGuiVersion() + fmt.Println("GO GUI version", version, showVersion()+"<Bromeliaceae>", err) + if version == "" { + log.Warn("Warning: compiled without version", err) + log.Sleep(1) + } + go watchCallback() +} + +// what genius figured this out? +// originally from github.com/dimasma0305/GoFetch +func showVersion() string { + // var runes rune + // color1 := "\x1b[0;29m \x1b[0m" + // runes = []rune(color1) + // view.WriteRunes(runes) + + color1 := "\x1b[0;29m \x1b[0m" + color2 := "\x1b[0;31m \x1b[0m" + color3 := "\x1b[0;32m \x1b[0m" + color4 := "\x1b[0;33m \x1b[0m" + color5 := "\x1b[0;34m \x1b[0m" + color6 := "\x1b[0;35m \x1b[0m" + color7 := "\x1b[0;36m \x1b[0m" + color8 := "\x1b[0;37m \x1b[0m" + + return color1 + " " + color2 + " " + color3 + " " + color4 + " " + color5 + " " + color6 + " " + color7 + " " + color8 +} + +var GUIVERSION string + +func getGuiVersion() (string, error) { + var found string + tmp, ok := debug.ReadBuildInfo() + if !ok { + return "", errors.New("debug.ReadBuildInfo() not ok") + } + if tmp == nil { + return "", errors.New("compiled without go module support") + } + // fmt.Println("mod.Path = ", tmp.Path) + // fmt.Println("mod.Main.Path = ", tmp.Main.Path) + // fmt.Println("mod.Main.Version = ", tmp.Main.Version) + // fmt.Println("mod.Main.Sum = ", tmp.Main.Sum) + for _, value := range tmp.Deps { + if value.Path == "go.wit.com/gui" { + found = value.Version + } + // fmt.Println("\tmod.Path = ", value.Path) + // fmt.Println("\tmod.Version = ", value.Version) + } + if found != "" { + // log.Println("GUI build version:", found) + return found, nil + } + if GUIVERSION != "" { + // log.Println("GUI build ldflag:", GUIVERSION) + return GUIVERSION, nil + } + if os.Getenv("GUIVERSION") != "" { + found = os.Getenv("GUIVERSION") + "-dirty" + // log.Println("GUI build $GUIVERSION", found) + return found, nil + } + found = "pre-v1-GO111" + // log.Println("GUI build version:", found) + return found, errors.New("GO111 developer build") +} + +// 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 pluginCounter(a *widget.Action) { + var found bool = false + for _, aplug := range allPlugins { + if a.ProgName == aplug.name { + aplug.count += 1 + found = true + } + } + if !found { + // TODO: fix this by making seperate channels for each plugin? + log.Log(WARN, "ListToolkits() got event from unidentified plugin") + } +} + +func toolkitPanic(pname string) { + log.Log(WARN, "toolkitPanic() in", pname) + log.Log(WARN, "toolkitPanic() unload toolkit plugin here", pname) + me.rootNode.ListToolkits() + for _, aplug := range allPlugins { + if aplug.name == pname { + log.Log(WARN, "toolkitPanic() FOUND PLUGIN =", aplug.name) + log.Log(WARN, "toolkitPanic() unload here aplug.dead =", aplug.dead) + log.Log(WARN, "toolkitPanic() TODO: stop talking to plugin:", pname) + aplug.dead = true + log.Log(WARN, "toolkitPanic() unload here aplug.dead =", aplug.dead) + // me.rootNode.CloseToolkit(aplug.name) + // panic("panic trapped!") + // log.Sleep(.5) + // me.rootNode.LoadToolkit("gocui") + } + } + // log.UnsetTmp() + // StandardExit() + log.Log(WARN, "toolkitPanic() attempt to load nocui") + me.rootNode.LoadToolkit("nocui") +} + +func watchCallback() { + log.Log(INFO, "guiChan() START") + for { + log.Log(CHANGE, "guiChan() select restarted") + select { + case a := <-me.guiChan: + pluginCounter(&a) + + if a.ActionType == widget.ToolkitPanic { + toolkitPanic(a.ProgName) + break + } + + // 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.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 { + /* + if argGui.GuiStdout { + log.Log(WARN, "--gui-stdout doesn't work yet") + // trapStdout() + } + */ + + return me.rootNode +} + +func NoGui() bool { + return argGui.NoGui +} + +// try to load andlabs, if that doesn't work, fall back to the console +func (n *Node) Default() *Node { + var err error + if argGui.NoGui { + log.Log(WARN, "--no-gui chill Winston. I don't need no gui") + return n + } + if argGui.GuiPlugin != "" { + log.Log(WARN, "New.Default() try toolkit =", argGui.GuiPlugin) + if n, err = n.LoadToolkit(argGui.GuiPlugin); err == nil { + return n + } + log.Log(WARN, "LoadToolkit() failed for =", argGui.GuiPlugin) + return nil + } + // 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, err = n.LoadToolkit("gocui"); err == nil { + return n + } + log.Log(WARN, "LoadToolkit() failed to load gocui") + } + if n, err = n.LoadToolkit("andlabs"); err == nil { + return n + } + log.Log(WARN, "LoadToolkit() failed to load andlabs") + + if n, err = n.LoadToolkit("gocui"); err == nil { + return n + } + log.Log(WARN, "LoadToolkit() failed to load gocui") + + log.Log(WARN, "") + log.Log(WARN, "### Error ####") + log.Log(WARN, "The GUI golang plugins did not load.") + log.Log(WARN, "You will have to rebuild them") + log.Log(WARN, "go-clone go.wit.com/toolkits/<pick one>/") + log.Log(WARN, "TODO: try to rebuild them here") + log.Log(WARN, "TODO: falling back to STDIN interface") + log.Log(WARN, "### Error ####") + log.Log(WARN, "") + log.Log(WARN, "sleep 2 seconds") + log.Sleep(2) + + if n, err = n.LoadToolkit("nocui"); err == nil { + return n + } + log.Log(WARN, "LoadToolkit() failed to load nocui") + 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) +} + +var origStdout *os.File +var origStderr *os.File +var guioutf *os.File +var guierrf *os.File + +// THIS DOES NOT WORK. +// this needs to work like screen. somehow make pseudo tty's or something +// to correctly isolate and trap STDOUT and STDERR so the gocui can work +func trapStdout() { + // attempts to control STDOUT + var err error + log.Log(WARN, "trapStdout() START") + + guioutf, err = os.OpenFile("/tmp/go-gui.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + log.Error(err, "error opening /tmp/go-gui.log") + os.Exit(0) + } + origStdout = os.Stdout + os.Stdout = guioutf + // defer guioutf.Close() + + // setOutput(outf) + // log("This is a test log entry") + + guierrf, err = os.OpenFile("/tmp/go-gui.err", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0664) + if err != nil { + log.Error(err, "error opening /tmp/go-gui.err") + os.Exit(0) + } + // defer guierrf.Close() + origStderr = os.Stderr + os.Stderr = guierrf + + println("TEST println") + println("TEST println") + println("TEST println") + fmt.Println("TEST fmt") + fmt.Println("TEST fmt") + fmt.Println("TEST fmt") + log.Info("TEST log") + log.Info("TEST log") + log.Info("TEST log") + + // defer guioutf.Close() +} |
