diff options
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | addNode.go | 47 | ||||
| -rw-r--r-- | common.go | 35 | ||||
| -rw-r--r-- | debug.go | 44 | ||||
| -rw-r--r-- | event.go | 88 | ||||
| -rw-r--r-- | go.mod | 10 | ||||
| -rw-r--r-- | go.sum | 6 | ||||
| -rw-r--r-- | init.go | 58 | ||||
| -rw-r--r-- | json.go | 60 | ||||
| -rw-r--r-- | plugin.go | 50 | ||||
| -rw-r--r-- | structs.go | 51 |
11 files changed, 453 insertions, 0 deletions
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 +} @@ -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 @@ -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= @@ -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 +} @@ -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 +} |
