From 3ea3dd10db0e728240fc659bdd33c622d33e46b4 Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Thu, 18 Jan 2024 00:05:54 -0600 Subject: initial commit Signed-off-by: Jeff Carr --- Makefile | 4 +++ addNode.go | 47 +++++++++++++++++++++++++++++++++ common.go | 35 +++++++++++++++++++++++++ debug.go | 44 +++++++++++++++++++++++++++++++ event.go | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 10 +++++++ go.sum | 6 +++++ init.go | 58 +++++++++++++++++++++++++++++++++++++++++ json.go | 60 ++++++++++++++++++++++++++++++++++++++++++ plugin.go | 50 +++++++++++++++++++++++++++++++++++ structs.go | 51 ++++++++++++++++++++++++++++++++++++ 11 files changed, 453 insertions(+) create mode 100644 Makefile create mode 100644 addNode.go create mode 100644 common.go create mode 100644 debug.go create mode 100644 event.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 init.go create mode 100644 json.go create mode 100644 plugin.go create mode 100644 structs.go diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..186078d --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +redomod: + rm -f go.* + GO111MODULE= go mod init + GO111MODULE= go mod tidy diff --git a/addNode.go b/addNode.go new file mode 100644 index 0000000..36c5a06 --- /dev/null +++ b/addNode.go @@ -0,0 +1,47 @@ +package tree + +import ( + "errors" + + "go.wit.com/log" + "go.wit.com/lib/widget" +) + +// this is in common.go, do not move it +func (me *TreeInfo) AddNode(a *widget.Action) *Node { + n := new(Node) + n.WidgetType = a.WidgetType + n.WidgetId = a.WidgetId + n.ParentId = a.ParentId + + n.State = a.State + n.Strings = make(map[string]int) + + if (a.WidgetType == widget.Root) { + log.Info("AddNode() Root") + n.Parent = n + me.treeRoot = n + return n + } + + if (me.treeRoot.FindWidgetId(a.WidgetId) != nil) { + log.Warn("AddNode() WidgetId already exists", a.WidgetId) + log.Warn("probably this is a Show() / Hide() issue") + log.Warn("TODO: figure out what to do here") + return me.treeRoot.FindWidgetId(a.WidgetId) + } + + // add this new widget on the binary tree + p := me.treeRoot.FindWidgetId(a.ParentId) + n.Parent = p + if n.Parent == nil { + log.Error(errors.New("tree.AddNode() ERROR n.Parent == nil"), a.WidgetId, a.ParentId, a.ActionType) + log.Warn("AddNode() ERROR n.Parent == nil", a.WidgetId, a.ParentId, a.ActionType) + log.Warn("AddNode() ERROR n.Parent == nil", a.WidgetId, a.ParentId, a.WidgetType) + return n + } + log.Warn("AddNode() Adding to parent =", p.ParentId, p.WidgetType, p.GetProgName()) + log.Warn("AddNode() Adding child =", n.ParentId, n.WidgetType, n.GetProgName()) + p.children = append(p.children, n) + return n +} diff --git a/common.go b/common.go new file mode 100644 index 0000000..2ae4f9e --- /dev/null +++ b/common.go @@ -0,0 +1,35 @@ +package tree + +import ( + "go.wit.com/lib/widget" +) + +func (n *Node) GetProgName() string { + return n.State.ProgName +} + +func (n *Node) GetValue() any { + return n.State.Value +} + +func (n *Node) Bool() bool { + return widget.GetBool(n.State.Value) +} + +func (n *Node) String() string { + return widget.GetString(n.State.Value) +} + +/* avoid this function name as confusing +func (n *Node) GetText() string { + return widget.GetString(n.State.Value) +} +*/ + +func (n *Node) SetValue(a any) { + n.State.Value = a +} + +func (n *Node) GetLabel() string { + return n.State.Label +} diff --git a/debug.go b/debug.go new file mode 100644 index 0000000..64883ee --- /dev/null +++ b/debug.go @@ -0,0 +1,44 @@ +package tree + +import ( + "go.wit.com/log" + "go.wit.com/lib/widget" +) + +func (n *Node) ShowButtons() { + if n.WidgetType == widget.Button { + n.DumpWidget("Button:") + } + + for _, child := range n.children { + child.ShowButtons() + } +} + +func (n *Node) DumpWidget(pad string) { + log.Warn("node:", pad, n.WidgetId, ",", n.WidgetType, ",", n.GetProgName()) +} + +var depth int = 0 + +func (n *Node) ListWidgets() { + if (n == nil) { + log.Warn("ERRRORRRR: n == nil in ListWidgets()") + log.Warn("ERRRORRRR: n == nil in ListWidgets()") + log.Warn("ERRRORRRR: n == nil in ListWidgets()") + return + } + + var pad string + for i := 0; i < depth; i++ { + pad = pad + " " + } + n.DumpWidget(pad) + + for _, child := range n.children { + depth += 1 + child.ListWidgets() + depth -= 1 + } + return +} diff --git a/event.go b/event.go new file mode 100644 index 0000000..845b47b --- /dev/null +++ b/event.go @@ -0,0 +1,88 @@ +package tree + +/* + These code should be common to all gui plugins + + There are some helper functions that are probably going to be + the same everywhere. Mostly due to handling the binary tree structure + and the channel communication + + For now, it's just a symlink to the 'master' version in + ./toolkit/nocui/common.go +*/ + +import ( + "go.wit.com/log" + "go.wit.com/lib/widget" +) + +func (me *TreeInfo) DoEnableDebugger() { + if (me.callback == nil) { + log.Warn("DoUserEvent() toolkit panic() callback == nil") + return + } + var a widget.Action + a.ActionType = widget.EnableDebug + a.ProgName = me.PluginName + me.callback <- a + return +} + +func (me *TreeInfo) DoToolkitLoad(s string) { + if (me.callback == nil) { + log.Warn("DoUserEvent() toolkit load callback == nil") + return + } + var a widget.Action + a.ActionType = widget.ToolkitLoad + a.ProgName = me.PluginName + a.Value = s + log.Warn("DoUserEvent() START: toolkit load", s) + me.callback <- a + log.Warn("DoUserEvent() END: toolkit load", s) + return +} + +func (me *TreeInfo) DoToolkitPanic() { + if (me.callback == nil) { + log.Warn("DoUserEvent() toolkit panic() callback == nil") + return + } + var a widget.Action + a.ActionType = widget.ToolkitPanic + a.ProgName = me.PluginName + log.Info("DoUserEvent() START: toolkit panic()") + me.callback <- a + log.Info("DoUserEvent() END: toolkit panic()") + return +} + +func (me *TreeInfo) DoWindowCloseEvent(n *Node) { + if (me.callback == nil) { + log.Warn("DoUserEvent() callback == nil", n.WidgetId) + return + } + var a widget.Action + a.WidgetId = n.WidgetId + a.ActionType = widget.CloseWindow + log.Info("DoUserEvent() START: user closed the window", n.GetProgName()) + me.callback <- a + log.Info("DoUserEvent() END: user closed the window", n.GetProgName()) + return +} + +// Other goroutines must use this to access the GUI +func (me *TreeInfo) DoUserEvent(n *Node) { + if (me.callback == nil) { + log.Warn("DoUserEvent() callback == nil", n.WidgetId) + return + } + var a widget.Action + a.WidgetId = n.WidgetId + a.Value = n.State.Value + a.ActionType = widget.User + log.Info("DoUserEvent() START: send a user event to the callback channel") + me.callback <- a + log.Info("DoUserEvent() END: sent a user event to the callback channel") + return +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..6f2cb79 --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module go.wit.com/toolkits/tree + +go 1.21.4 + +require ( + go.wit.com/gui/widget v1.1.4 + go.wit.com/log v0.5.5 +) + +require go.wit.com/dev/davecgh/spew v1.1.4 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..4704880 --- /dev/null +++ b/go.sum @@ -0,0 +1,6 @@ +go.wit.com/dev/davecgh/spew v1.1.4 h1:C9hj/rjlUpdK+E6aroyLjCbS5MFcyNUOuP1ICLWdNek= +go.wit.com/dev/davecgh/spew v1.1.4/go.mod h1:sihvWmnQ/09FWplnEmozt90CCVqBtGuPXM811tgfhFA= +go.wit.com/gui/widget v1.1.4 h1:dCztWNSuTSSP+/M8h8F3cT7vWtoKdCL3DUQql0qLKdk= +go.wit.com/gui/widget v1.1.4/go.mod h1:A6/FaiFQtAHTjgo7c4FrokXe6bXX1Cowo35b2Lgi31E= +go.wit.com/log v0.5.5 h1:bK3b94uVKgev4jB5wg06FnvCFBEapQICTSH2YW+CWr4= +go.wit.com/log v0.5.5/go.mod h1:BaJBfHFqcJSJLXGQ9RHi3XVhPgsStxSMZRlaRxW4kAo= diff --git a/init.go b/init.go new file mode 100644 index 0000000..55e434d --- /dev/null +++ b/init.go @@ -0,0 +1,58 @@ +package tree + +import ( + "sync" + "errors" + + "go.wit.com/log" + "go.wit.com/lib/widget" +) + +var muAction sync.Mutex + +func (me *TreeInfo) toolkit(a widget.Action) { + if me.ActionFromChannel == nil { + log.Error(errors.New("toolkit ActionFromChannel == nil"), a.WidgetId, a.ActionType, a.WidgetType) + return + } + me.ActionFromChannel(a) +} + +func (me *TreeInfo) catchActionChannel() { + defer func() { + if r := recover(); r != nil { + log.Warn("nocui YAHOOOO Recovered in simpleStdin()", r) + me.DoToolkitPanic() + panic(-1) + } + }() + log.Info("catchActionChannel() START") + for { + log.Info("catchActionChannel() for loop") + select { + case a := <-me.pluginChan: + log.Info("catchActionChannel() SELECT widget id =", a.WidgetId, a.ProgName) + log.Warn("catchActionChannel() STUFF", a.WidgetId, a.ActionType, a.WidgetType) + if a.WidgetType == widget.Dropdown { + log.Warn("Found dropdown", a.WidgetId, a.ActionType, a.WidgetType) + for i, s := range a.State.Strings { + log.Warn("a.State.Strings =", i, s) + } + } + muAction.Lock() + me.toolkit(a) + muAction.Unlock() + log.Info("catchActionChannel() STUFF END", a.WidgetId, a.ActionType, a.WidgetType) + } + } +} + +func New() *TreeInfo { + me := new(TreeInfo) + me.pluginChan = make(chan widget.Action, 1) + + log.Info("Init() start channel reciever") + go me.catchActionChannel() + log.Info("Init() END") + return me +} diff --git a/json.go b/json.go new file mode 100644 index 0000000..68fe398 --- /dev/null +++ b/json.go @@ -0,0 +1,60 @@ +package tree + +import ( + "fmt" + + "go.wit.com/log" + "go.wit.com/lib/widget" +) + +// makes a JSON version to pass to the toolkits ? +// probably this should be in gui/toolkits/tree +/* +{"widget": { + "debug": "on", + "window": { + "title": "Sample Konfabulator Widget", + "name": "main_window", + "width": 500, + "height": 500 + }, + "image": { + "src": "Images/Sun.png", + "name": "sun1", + "hOffset": 250, + "vOffset": 250, + "alignment": "center" + }, + "text": { + "data": "Click Here", + "size": 36, + "style": "bold", + "name": "text1", + "hOffset": 250, + "vOffset": 100, + "alignment": "center", + "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" + } +}} +*/ + +func (n *Node) Json() []string { + var all []string + switch n.WidgetType { + case widget.Checkbox: + case widget.Button: + case widget.Combobox: + case widget.Dropdown: + case widget.Textbox: + case widget.Spinner: + case widget.Slider: + case widget.Window: + tmp := fmt.Sprint("{ WidgetType :", n.WidgetType, "}") + all = append(all, tmp) + log.Warn(tmp) + return all + default: + log.Info("doUserEvent() type =", n.WidgetType) + } + return all +} diff --git a/plugin.go b/plugin.go new file mode 100644 index 0000000..e8c61da --- /dev/null +++ b/plugin.go @@ -0,0 +1,50 @@ +package tree + +/* + These code should be common to all gui plugins + + There are some helper functions that are probably going to be + the same everywhere. Mostly due to handling the binary tree structure + and the channel communication + + For now, it's just a symlink to the 'master' version in + ./toolkit/nocui/common.go +*/ + +import ( + "go.wit.com/lib/widget" +) + +// searches the binary tree for a WidgetId +func (n *Node) FindWidgetId(id int) *Node { + if (n == nil) { + return nil + } + + if n.WidgetId == id { + return n + } + + for _, child := range n.children { + newN := child.FindWidgetId(id) + if (newN != nil) { + return newN + } + } + return nil +} + +// 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 (me *TreeInfo) Callback(guiCallback chan widget.Action) { + me.callback = guiCallback +} + +func (me *TreeInfo) PluginChannel() chan widget.Action { + return me.pluginChan +} diff --git a/structs.go b/structs.go new file mode 100644 index 0000000..e4d7418 --- /dev/null +++ b/structs.go @@ -0,0 +1,51 @@ +package tree + +/* + These code should be common to all gui plugins + + There are some helper functions that are probably going to be + the same everywhere. Mostly due to handling the binary tree structure + and the channel communication + + For now, it's just a symlink to the 'master' version in + ./toolkit/nocui/common.go +*/ + +import ( + // "go.wit.com/log" + "go.wit.com/lib/widget" +) + +// var me *TreeInfo + +type TreeInfo struct { + // this is the channel we send user events like + // mouse clicks or keyboard events back to the program + callback chan widget.Action + + // this is the channel we get requests to make widgets + pluginChan chan widget.Action + + treeRoot *Node + NodeI interface {} + ActionFromChannel func (widget.Action) () + PluginName string +} + +type Node struct { + Parent *Node + children []*Node + + WidgetId int // widget ID + WidgetType widget.WidgetType + ParentId int // parent ID + + State widget.State + + Strings map[string]int + + // the internal plugin toolkit structure + // in the gtk plugin, it has gtk things like margin & border settings + // in the text console one, it has text console things like colors for menus & buttons + TK any +} -- cgit v1.2.3