summaryrefslogtreecommitdiff
path: root/init.go
diff options
context:
space:
mode:
authorJeff Carr <[email protected]>2024-12-24 02:30:04 -0600
committerJeff Carr <[email protected]>2024-12-24 02:30:04 -0600
commit985218e1c0a8cc0bbf6f82f3d00074b8bcea71a0 (patch)
tree014bbd5e55bfe217778beb75f9eef2f69fde80b2 /init.go
parent47dd3242102228c977101f6a207f7fe00d7d8643 (diff)
should have been called this beforev0.22.15
Diffstat (limited to 'init.go')
-rw-r--r--init.go392
1 files changed, 392 insertions, 0 deletions
diff --git a/init.go b/init.go
new file mode 100644
index 0000000..c8b4df5
--- /dev/null
+++ b/init.go
@@ -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()
+}