From 66f87e34481df249b238d2b1490b6a0c1a3402e0 Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Thu, 18 Jan 2024 00:11:03 -0600 Subject: [PATCH] just a "gui" from Signed-off-by: Jeff Carr --- Makefile | 16 ++++++++++ README.md | 5 +++ action.go | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ args.go | 30 ++++++++++++++++++ event.go | 51 +++++++++++++++++++++++++++++++ go.mod | 3 ++ main.go | 24 +++++++++++++++ stdin.go | 74 +++++++++++++++++++++++++++++++++++++++++++++ structs.go | 22 ++++++++++++++ tree.go | 24 +++++++++++++++ 10 files changed, 338 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100644 action.go create mode 100644 args.go create mode 100644 event.go create mode 100644 go.mod create mode 100644 main.go create mode 100644 stdin.go create mode 100644 structs.go create mode 100644 tree.go diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..15c7487 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +all: plugin + ldd ../nocui.so + +plugin: + GO111MODULE="off" go build -v -x -buildmode=plugin -o ../nocui.so + +cleanbuild: + go build -v -x -buildmode=plugin -o ../nocui.so + +check-git-clean: + @git diff-index --quiet HEAD -- || (echo "Git repository is dirty, please commit your changes first"; exit 1) + +redomod: + rm -f go.* + GO111MODULE= go mod init + GO111MODULE= go mod tidy diff --git a/README.md b/README.md new file mode 100644 index 0000000..018b9ce --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# nogui + +Package gui implements a abstraction layer for Go visual elements. + +This is a sample plugin. It's a skeleton intended to be used when making a new toolkit plugin. diff --git a/action.go b/action.go new file mode 100644 index 0000000..ea1a6fa --- /dev/null +++ b/action.go @@ -0,0 +1,89 @@ +package main + +/* + a simple function to handle widget actions + + You can tie this into your toolkit here. +*/ + +import ( + "go.wit.com/log" + "go.wit.com/lib/widget" + // "go.wit.com/gui/toolkits/tree" +) + +func doAction(a widget.Action) { + log.Log(INFO, "doAction() START a.ActionType =", a.ActionType) + log.Log(INFO, "doAction() START a.ProgName =", a.ProgName) + + if (a.ActionType == widget.ToolkitInit) { + return + } + + log.Log(INFO, "doAction() START a.WidgetId =", a.WidgetId, "a.ParentId =", a.ParentId) + switch a.WidgetType { + case widget.Root: + me.treeRoot = me.myTree.AddNode(&a) + log.Log(INFO, "doAction() found treeRoot") + return + } + + switch a.ActionType { + case widget.Add: + me.myTree.AddNode(&a) + return + } + + n := me.treeRoot.FindWidgetId(a.WidgetId) + if n == nil { + log.Warn("FindId() n == nil", a.WidgetId, a.ActionType) + log.Warn("FindId() n == nil", a.WidgetId, a.ActionType) + log.Warn("FindId() n == nil", a.WidgetId, a.ActionType) + log.Warn("Aaaaa!, return") + return + } + + switch a.ActionType { + case widget.Show: + n.State.Visable = true + case widget.Hide: + n.State.Visable = false + case widget.Enable: + n.State.Visable = true + case widget.Disable: + n.State.Visable = false + case widget.Get: + log.Warn("value =", n.State.Value) + case widget.GetText: + log.Warn("value =", n.String()) + case widget.Set: + n.State.Value = a.State.Value + case widget.SetText: + log.Warn("GOT TO SetText()", a.WidgetId) + log.Warn("GOT TO SetText()", a.WidgetId) + log.Warn("GOT TO SetText()", a.WidgetId) + log.Warn("GOT TO SetText()", a.WidgetId) + if n == nil { + log.Warn("HOT DIGGITY. n == nil") + } + n.State.Value = a.State.Value + case widget.AddText: + n.State.Strings = append(a.State.Strings, widget.GetString(a.State.Value)) + case widget.Margin: + n.State.Pad = true + case widget.Unmargin: + n.State.Pad = false + case widget.Pad: + n.State.Pad = true + case widget.Unpad: + n.State.Pad = false + case widget.Delete: + log.Warn("doAction() TODO: Delete()") + // n.Delete() + case widget.Move: + log.Warn("doAction() TODO: Move()") + default: + log.Log(ERROR, "doAction() Unknown =", a.ActionType, a.WidgetType) + } + log.Log(INFO, "doAction() END =", a.ActionType, a.WidgetType) +} diff --git a/args.go b/args.go new file mode 100644 index 0000000..4b6b38e --- /dev/null +++ b/args.go @@ -0,0 +1,30 @@ +package main + +/* + this enables command line options from other packages like 'gui' and 'log' +*/ + +import ( + log "go.wit.com/log" +) + +var NOW *log.LogFlag +var INFO *log.LogFlag + +var SPEW *log.LogFlag +var WARN *log.LogFlag + +var ERROR *log.LogFlag + +func init() { + full := "toolkit/nocui" + short := "nocui" + + NOW = log.NewFlag( "NOW", true, full, short, "temp debugging stuff") + INFO = log.NewFlag("INFO", false, full, short, "normal debugging stuff") + + WARN = log.NewFlag("WARN", true, full, short, "bad things") + SPEW = log.NewFlag("SPEW", false, full, short, "spew stuff") + + ERROR = log.NewFlag("ERROR", false, full, short, "toolkit errors") +} diff --git a/event.go b/event.go new file mode 100644 index 0000000..9bbafdb --- /dev/null +++ b/event.go @@ -0,0 +1,51 @@ +package main + +/* +import ( + "go.wit.com/log" + "go.wit.com/gui/widget" + "go.wit.com/gui/toolkits/tree" +) + +func doWidgetClick(n *tree.Node) { + switch n.WidgetType { + case widget.Root: + // THIS IS THE BEGINING OF THE LAYOUT + // rootNode.nextW = 0 + // rootNode.nextH = 0 + // rootNode.redoTabs(true) + case widget.Flag: + // me.rootNode.redoColor(true) + // rootNode.dumpTree(true) + case widget.Window: + // setCurrentWindow(w) + // n.doUserEvent() + case widget.Tab: + // setCurrentTab(w) + case widget.Group: + // n.placeWidgets() + // n.toggleTree() + case widget.Checkbox: + if n.Bool() { + // n.setCheckbox(false) + } else { + // n.setCheckbox(true) + } + // n.doUserEvent() + case widget.Grid: + // rootNode.hideWidgets() + // n.placeGrid() + // n.showWidgets() + case widget.Box: + // n.showWidgetPlacement(logNow, "drawTree()") + if n.Bool() { + log.Log(NOW, "BOX IS HORIZONTAL", n.GetProgName()) + } else { + log.Log(NOW, "BOX IS VERTICAL", n.GetProgName()) + } + case widget.Button: + // n.doUserEvent() + default: + } +} +*/ diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..e802e10 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module go.wit.com/gui/toolkits/nocui + +go 1.21.4 diff --git a/main.go b/main.go new file mode 100644 index 0000000..4b2b53b --- /dev/null +++ b/main.go @@ -0,0 +1,24 @@ +package main + +/* + This is reference code for toolkit developers + + The 'nocui' is a bare minimum toolkit. It's all you need + to interact with the GUI +*/ + +import ( + "go.wit.com/log" + "go.wit.com/toolkits/tree" +) + +func init() { + log.Log(INFO, "Init()") + + me.myTree = tree.New() + me.myTree.PluginName = "nocui" + me.myTree.ActionFromChannel = doAction + + go simpleStdin() + log.Log(INFO, "Init() END") +} diff --git a/stdin.go b/stdin.go new file mode 100644 index 0000000..9b9f794 --- /dev/null +++ b/stdin.go @@ -0,0 +1,74 @@ +package main + +import ( + "os" + "fmt" + "bufio" + "runtime/debug" + "strings" + "strconv" + + "go.wit.com/log" + "go.wit.com/lib/widget" +) + +func simpleStdin() { + defer func() { + if r := recover(); r != nil { + log.Warn("nocui YAHOOOO Recovered in simpleStdin()", r) + log.Println("Recovered from panic:", r) + log.Println("Stack trace:") + debug.PrintStack() + me.myTree.DoToolkitPanic() + } + }() + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + s := scanner.Text() + s = strings.TrimSuffix(s, "\n") + switch s { + case "l": + log.Log(NOW, "list widgets") + me.treeRoot.ListWidgets() + case "b": + log.Log(NOW, "show buttons") + me.treeRoot.ShowButtons() + case "g": + me.myTree.DoToolkitLoad("gocui") + case "a": + me.myTree.DoToolkitLoad("andlabs") + case "d": + me.myTree.DoEnableDebugger() + case "": + fmt.Println("") + fmt.Println("Enter:") + fmt.Println("'l': list all widgets") + fmt.Println("'b': for buttons") + fmt.Println("'g': load gocui plugin") + fmt.Println("'a': load andlabs plugin") + fmt.Println("'d': enable debugging") + default: + i, _ := strconv.Atoi(s) + log.Log(NOW, "got input:", i) + n := me.treeRoot.FindWidgetId(i) + if (n != nil) { + n.DumpWidget("found node") + for i, s := range n.State.Strings { + log.Warn("n.State.Strings =", i, s) + } + switch n.WidgetType { + case widget.Root: + log.Warn("this is the root widget") + case widget.Dropdown: + log.Warn("print out dropdown values here") + case widget.Button: + me.myTree.DoUserEvent(n) + case widget.Checkbox: + me.myTree.DoUserEvent(n) + default: + log.Warn("you haven't defined an event for", n.WidgetType) + } + } + } + } +} diff --git a/structs.go b/structs.go new file mode 100644 index 0000000..8d01ef0 --- /dev/null +++ b/structs.go @@ -0,0 +1,22 @@ +package main + +import ( + "go.wit.com/toolkits/tree" +) + +// stores the raw toolkit internals +type guiWidget struct { + Width int + Height int + + c int + val map[string]int +} + +// It's probably a terrible idea to call this 'me' +var me config + +type config struct { + treeRoot *tree.Node // the base of the binary tree. it should have id == 0 + myTree *tree.TreeInfo +} diff --git a/tree.go b/tree.go new file mode 100644 index 0000000..6ba353e --- /dev/null +++ b/tree.go @@ -0,0 +1,24 @@ +package main + +/* + This is reference code for toolkit developers +*/ + +import ( + "go.wit.com/lib/widget" +) + +// Other goroutines must use this to access the GUI +// +// You can not acess / process the GUI thread directly from +// other goroutines. This is due to the nature of how +// Linux, MacOS and Windows work (they all work differently. suprise. surprise.) +// +// this sets the channel to send user events back from the plugin +func Callback(guiCallback chan widget.Action) { + me.myTree.Callback(guiCallback) +} + +func PluginChannel() chan widget.Action { + return me.myTree.PluginChannel() +}