summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Carr <[email protected]>2024-01-17 21:21:29 -0600
committerJeff Carr <[email protected]>2024-01-17 21:21:29 -0600
commita6a3e1193fa7c77165f3ed2eb0031f319b4abdd0 (patch)
tree2c5a9fbf4dbc5f7bd5cb235542082da5eba342c6
parent8ef3fc7a73a004385d36561c6c8acc4be7e3e24b (diff)
work around a toolkit panic()v0.12.11
things should work when GUI is not really there Int() and Bool() helloworld works compiles and runs RawWindow shouldn't auto exit add StandardExit() Signed-off-by: Jeff Carr <[email protected]> Signed-off-by: Jeff Carr <[email protected]>
-rw-r--r--action.go52
-rw-r--r--addText.go50
-rw-r--r--button.go2
-rw-r--r--checkbox.go2
-rw-r--r--common.go50
-rw-r--r--debug.go19
-rw-r--r--dropdown.go13
-rw-r--r--go.mod4
-rw-r--r--go.sum8
-rw-r--r--group.go2
-rw-r--r--label.go2
-rw-r--r--main.go56
-rw-r--r--node.go2
-rw-r--r--plugin.go6
-rw-r--r--setText.go4
-rw-r--r--structs.go9
-rw-r--r--window.go4
17 files changed, 232 insertions, 53 deletions
diff --git a/action.go b/action.go
index e0d2690..f5fdb33 100644
--- a/action.go
+++ b/action.go
@@ -10,6 +10,8 @@ package gui
*/
import (
+ "errors"
+
"go.wit.com/log"
"go.wit.com/gui/widget"
)
@@ -19,10 +21,22 @@ import (
// 2023/04/06 Queue() is also being used and channels are being used.
func sendAction(n *Node, atype widget.ActionType) {
if n == nil {
+ log.Error(errors.New("Sending Action on n = nil"))
+ log.Warn("Sending Action on n = nil")
return
}
+ n.mu.Lock()
+ defer n.mu.Unlock()
+ log.Warn("SENDING ACTION STRINGS n.Strings", n.strings)
+
+ // if the widget is hidden, don't send actions to the plugin
if n.hidden {
- return
+ if atype == widget.Hide {
+ // well, unless this is a Hide action, then inform the toolkit
+ } else {
+ log.Warn("NOT SENDING HIDDEN ACTION", n.GetProgName(), atype)
+ // return
+ }
}
var a widget.Action
@@ -30,17 +44,29 @@ func sendAction(n *Node, atype widget.ActionType) {
// These should be "stable" at this point (2024/01/13)
a.WidgetId = n.id
+
+ // set state
+ a.State.ProgName = n.progname
+ a.State.Label = n.label
+ a.State.Value = n.value
+ a.State.Direction = n.direction
+ for s, _ := range n.strings {
+ a.State.Strings = append(a.State.Strings, s)
+ }
+ log.Warn("SENDING ACTION STRINGS a.Strings", a.Strings)
+ a.State.Range.Low = n.X
+ a.State.Range.High = n.Y
+
a.ProgName = n.progname
a.Value = n.value
a.Direction = n.direction
- a.Strings = n.strings
// These should be improved/deprecated based on the gui/widget docs
a.X = n.X
a.Y = n.Y
- a.AtW = n.AtW
- a.AtH = n.AtH
+ a.State.GridOffset.X = n.AtW
+ a.State.GridOffset.Y = n.AtH
if (n.parent != nil) {
a.ParentId = n.parent.id
@@ -54,13 +80,23 @@ func sendActionToPlugin(a *widget.Action) {
for _, aplug := range allPlugins {
log.Log(PLUG, "Action() aplug =", aplug.name, "Action type=", a.ActionType)
if (aplug.pluginChan == nil) {
- log.Info("Action() retrieving the aplug.PluginChannel()", aplug.name)
+ log.Warn("Action() retrieving the aplug.PluginChannel()", aplug.name)
aplug.pluginChan = aplug.PluginChannel()
- log.Info("Action() retrieved", aplug.pluginChan)
+ log.Warn("Action() retrieved", aplug.pluginChan)
}
- log.Info("Action() SEND to pluginChan", aplug.name, a.ActionType, a.WidgetType, a.WidgetId, a.ProgName)
+ log.Verbose("Action() SEND to pluginChan", aplug.name, a.ActionType, a.WidgetType, a.WidgetId, a.ProgName)
aplug.pluginChan <- *a
// added during debugging. might be a good idea in general for a tactile experience
- log.Sleep(.02) // this delay makes it so SetText() works on initial widget creation
+ // start playing with this
+ if a.ActionType == widget.Hide {
+ // log.Sleep(.001) // this delay makes it so SetText() works on initial widget creation
+ } else {
+ // 2024/12/16 still leaving this as I'm not sure binary tree access is actually
+ // safe (thread safe, correct locking, etc). I think it is. Things seem stable
+ // sync.Mutex() locks don't appear to work somehow in a way I don't understand
+ // it's probably due to []string use. use map[] instead
+ // log.Sleep(.000001) // this delay makes it so SetText() works on initial widget creation
+ log.Sleep(.002) // this delay makes it so SetText() works on initial widget creation
+ }
}
}
diff --git a/addText.go b/addText.go
new file mode 100644
index 0000000..7f98c63
--- /dev/null
+++ b/addText.go
@@ -0,0 +1,50 @@
+package gui
+
+import (
+ "go.wit.com/log"
+ "go.wit.com/gui/widget"
+)
+
+// tracks dropdown and combobox entries. Makes sure they are unique
+func (n *Node) addText(newS string) {
+ var highest int
+ for s, i := range n.strings {
+ if i > highest { highest = i }
+ if s == newS {
+ return
+ }
+ }
+ n.strings[newS] = highest + 1 // TODO: use the int's for the order
+ n.value = newS
+ /*
+ // time.Sleep(time.Duration(1000 * time.Nanosecond)) // doesn't work
+ // maybe this stupid chipset is defective. TODO: try on different hardware
+ // tried with go 1.21.4 debian sid
+ mylock.Lock()
+ n.mu.Lock()
+ // time.Sleep(time.Duration(10 * time.Microsecond)) // doesn't work
+ time.Sleep(time.Duration(100 * time.Microsecond)) // does work
+ n.strings = append(n.strings, newS)
+ n.mu.Unlock()
+ mylock.Unlock()
+ log.Warn("addText() has strings:", n.strings)
+ */
+
+ // inform the toolkits
+ sendAction(n, widget.AddText)
+}
+
+// add a new text string to widgets that support
+// multiple string values
+// These must be unique. return false if the string already exists
+func (n *Node) AddText(str string) bool {
+ if ! n.Ready() { return false }
+ log.Warn("AddText() value =", str)
+ log.Warn("AddText() value =", str)
+ log.Warn("AddText() value =", str)
+
+ // for some reason, the n.mu.Lock() doesn't seem to protect the append() function on strings
+ // switched to a map. I suspect that is what maps are for because they are safer
+ n.addText(str)
+ return true
+}
diff --git a/button.go b/button.go
index 9ccff89..7e8ab65 100644
--- a/button.go
+++ b/button.go
@@ -5,7 +5,7 @@ import "go.wit.com/gui/widget"
func (parent *Node) NewButton(name string, custom func()) *Node {
newNode := parent.newNode(name, widget.Button)
newNode.Custom = custom
- newNode.value = name
+ newNode.label = name
newNode.progname = name
// inform the toolkits
diff --git a/checkbox.go b/checkbox.go
index ed28185..012c30c 100644
--- a/checkbox.go
+++ b/checkbox.go
@@ -8,7 +8,7 @@ func (n *Node) Checked() bool {
func (n *Node) NewCheckbox(name string) *Node {
newNode := n.newNode(name, widget.Checkbox)
- newNode.value = name
+ newNode.label = name
newNode.progname = name
// inform the toolkits
diff --git a/common.go b/common.go
index c6397fa..585e7dc 100644
--- a/common.go
+++ b/common.go
@@ -30,6 +30,7 @@ func (n *Node) Show() *Node {
}
func (n *Node) Hide() *Node {
+ return n
if ! n.Ready() { return n }
if n.Hidden() { return n }
@@ -79,6 +80,35 @@ func (n *Node) Disable() *Node {
return n
}
+func (n *Node) Bool() bool {
+ if ! n.Ready() { return false}
+
+ return widget.GetBool(n.value)
+}
+
+func (n *Node) Int() int {
+ if ! n.Ready() { return -1}
+
+ return widget.GetInt(n.value)
+}
+
+func (n *Node) String() string {
+ if ! n.Ready() { return ""}
+
+ return widget.GetString(n.value)
+}
+
+func (n *Node) Strings() []string {
+ if ! n.Ready() { return nil}
+ var tmp []string
+
+ for s, _ := range n.strings {
+ tmp = append(tmp, s)
+ }
+
+ return tmp
+}
+
func (n *Node) Destroy() {
if ! n.Ready() { return }
// if ! n.enabled { return }
@@ -91,24 +121,6 @@ func (n *Node) Destroy() {
return
}
-
-// add a new text string to widgets that support
-// multiple string values
-// These must be unique. return false if the string already exists
-func (n *Node) AddText(str string) bool {
- if ! n.Ready() { return false }
- log.Log(CHANGE, "AddText() value =", str)
-
- n.value = str
- // TODO: make sure these are unique
- n.strings = append(n.strings, str)
-
- // inform the toolkits
- sendAction(n, widget.AddText)
- return true
-}
-
-
// appends text to the existing text
// TODO: this is an experiement
func (n *Node) AppendText(str string) {
@@ -127,6 +139,7 @@ func (n *Node) AppendText(str string) {
// Progname() Reference() ?
// 2024/01/13 the names are starting to grow on me and make it clearer to code against
+/*
// get a string from the widget
func (n *Node) GetText() string {
if ! n.Ready() { return "" }
@@ -144,6 +157,7 @@ func (n *Node) GetBool() bool {
if ! n.Ready() { return false}
return widget.GetBool(n.value)
}
+*/
// should get the reference name used for programming and debugging
func (n *Node) SetProgName(s string) *Node {
diff --git a/debug.go b/debug.go
index 496fa72..9d70bb5 100644
--- a/debug.go
+++ b/debug.go
@@ -7,6 +7,7 @@ package gui
import (
"errors"
"strconv"
+ "strings"
"go.wit.com/log"
"go.wit.com/gui/widget"
@@ -55,13 +56,29 @@ func (n *Node) dumpWidget(b bool) string {
}
info = n.WidgetType.String()
- d = strconv.Itoa(n.id) + " " + info + " " + n.progname
var tabs string
for i := 0; i < listChildrenDepth; i++ {
tabs = tabs + defaultPadding
}
+ d = strconv.Itoa(n.id) + " " + info + " " + n.GetProgName() + strings.Join(n.Json(), " ")
logindent(b, listChildrenDepth, defaultPadding, d)
+ if b {
+ switch n.WidgetType {
+ case widget.Combobox:
+ logindent(b, listChildrenDepth, defaultPadding, " Dropdown", n.value)
+ logindent(b, listChildrenDepth, defaultPadding, " Dropdown", n.strings)
+ case widget.Dropdown:
+ logindent(b, listChildrenDepth, defaultPadding, " Dropdown", n.value)
+ logindent(b, listChildrenDepth, defaultPadding, " Dropdown", n.strings)
+ case widget.Grid:
+ logindent(b, listChildrenDepth, defaultPadding, " GridSize =", n.X, n.Y)
+ case widget.Box:
+ logindent(b, listChildrenDepth, defaultPadding, " Direction =", n.direction)
+ default:
+ }
+ }
+
return tabs + d
}
diff --git a/dropdown.go b/dropdown.go
index 9b65154..f5882a9 100644
--- a/dropdown.go
+++ b/dropdown.go
@@ -6,10 +6,10 @@ package gui
// since it is the same. confusing names? maybe...
import (
- "go.wit.com/log"
"go.wit.com/gui/widget"
)
+/*
// add a new entry to the dropdown name
func (n *Node) AddDropdownName(name string) {
if ! n.Ready() { return }
@@ -23,19 +23,18 @@ func (n *Node) SetDropdownName(name string) {
log.Warn("SetDropdownName() deprecated")
n.SetText(name)
}
+*/
-func (n *Node) NewDropdown(progname string) *Node {
- newNode := n.newNode(progname, widget.Dropdown)
- newNode.progname = progname
+func (n *Node) NewDropdown() *Node {
+ newNode := n.newNode("dropdown", widget.Dropdown)
// inform the toolkits
sendAction(newNode, widget.Add)
return newNode
}
-func (n *Node) NewCombobox(progname string) *Node {
- newNode := n.newNode(progname, widget.Combobox)
- newNode.progname = progname
+func (n *Node) NewCombobox() *Node {
+ newNode := n.newNode("combobox", widget.Combobox)
// inform the toolkits
sendAction(newNode, widget.Add)
diff --git a/go.mod b/go.mod
index e41e5dc..4aa2794 100644
--- a/go.mod
+++ b/go.mod
@@ -4,8 +4,8 @@ go 1.21.4
require (
go.wit.com/dev/alexflint/arg v1.4.5
- go.wit.com/gui/widget v1.1.3
- go.wit.com/log v0.5.4
+ go.wit.com/gui/widget v1.1.4
+ go.wit.com/log v0.5.5
)
require (
diff --git a/go.sum b/go.sum
index 99987ba..eff5e76 100644
--- a/go.sum
+++ b/go.sum
@@ -4,7 +4,7 @@ go.wit.com/dev/alexflint/scalar v1.2.1 h1:loXOcbVnd+8YeJRLey+XXidecBiedMDO00zQ26
go.wit.com/dev/alexflint/scalar v1.2.1/go.mod h1:+rYsfxqdI2cwA8kJ7GCMwWbNJvfvWUurOCXLiwdTtSs=
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.3 h1:GvLzGSOF9tfmoh6HNbFdN+NSlBo2qeS/Ba2TnQQ1A1U=
-go.wit.com/gui/widget v1.1.3/go.mod h1:A6/FaiFQtAHTjgo7c4FrokXe6bXX1Cowo35b2Lgi31E=
-go.wit.com/log v0.5.4 h1:vijLRPTUgChb8J5tx/7Uma/lGTUxeSXosFbheAmL914=
-go.wit.com/log v0.5.4/go.mod h1:BaJBfHFqcJSJLXGQ9RHi3XVhPgsStxSMZRlaRxW4kAo=
+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/group.go b/group.go
index ada0e4a..e7eb31b 100644
--- a/group.go
+++ b/group.go
@@ -11,7 +11,7 @@ func (parent *Node) NewGroup(name string) *Node {
var newNode *Node
newNode = parent.newNode(name, widget.Group)
newNode.progname = name
- newNode.value = name
+ newNode.label = name
// inform the toolkits
sendAction(newNode, widget.Add)
diff --git a/label.go b/label.go
index 39dfc57..45eee62 100644
--- a/label.go
+++ b/label.go
@@ -6,7 +6,7 @@ import (
func (parent *Node) NewLabel(text string) *Node {
newNode := parent.newNode(text, widget.Label)
- newNode.value = text
+ newNode.label = text
newNode.progname = text
// inform the toolkits
diff --git a/main.go b/main.go
index 4955ac9..29eedc7 100644
--- a/main.go
+++ b/main.go
@@ -60,7 +60,7 @@ func (n *Node) findId(i int) (*Node) {
func watchCallback() {
log.Info("guiChan() START")
for {
- log.Info("guiChan() restarted")
+ log.Info("guiChan() select restarted")
select {
case a := <-me.guiChan:
if (a.ActionType == widget.UserQuit) {
@@ -69,9 +69,52 @@ func watchCallback() {
log.Exit("wit/gui toolkit.UserQuit")
break
}
+ if (a.ActionType == widget.CloseWindow) {
+ log.Warn("guiChan() Close Window")
+ StandardExit()
+ break
+ }
+ if (a.ActionType == widget.ToolkitPanic) {
+ log.Warn("guiChan() Toolkit panic() in", a.ProgName)
+ log.Warn("guiChan() unload toolkit plugin here", a.ProgName)
+ me.rootNode.ListToolkits()
+ for _, aplug := range allPlugins {
+ log.Warn("ListToolkits() already loaded toolkit plugin =", aplug.name)
+ if aplug.name == a.ProgName {
+ log.Warn("FOUND PLUGIN =", aplug.name)
+ log.Warn("unload here")
+ log.Warn("panic on purpose")
+ me.rootNode.CloseToolkit(aplug.name)
+ // panic("panic trapped!")
+ // log.Sleep(.5)
+ // me.rootNode.LoadToolkit("gocui")
+ break
+ }
+ }
+ // StandardExit()
+ me.rootNode.LoadToolkit("nocui")
+ break
+ }
+ if (a.ActionType == widget.ToolkitLoad) {
+ newPlug := widget.GetString(a.Value)
+ log.Warn("Attempt to load a new toolkit", newPlug, "here")
+ me.rootNode.LoadToolkit(newPlug)
+ }
if (a.ActionType == widget.EnableDebug) {
log.Warn("guiChan() Enable Debugging Window")
log.Warn("guiChan() TODO: not implemented")
+ log.Warn("guiChan() Listing Toolkits:")
+ PLUG.Set(true)
+ me.rootNode.ListToolkits()
+ me.rootNode.ListChildren(true)
+ for i, aplug := range allPlugins {
+ log.Warn("plug =", i, aplug.name)
+ if aplug.name == "andlabs" {
+ log.Warn("Found plug =", i, aplug.name)
+ //closePlugin(aplug)
+ allPlugins = allPlugins[1:]
+ }
+ }
// DebugWindow()
break
}
@@ -191,3 +234,14 @@ func StandardExit() {
}
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(NOW, "wit/gui Standard Window Exit. running os.Exit()")
+ log.Log(NOW, "StandardExit() attempt to exit each toolkit plugin")
+ for i, plug := range allPlugins {
+ log.Log(NOW, "NewButton()", i, plug)
+ }
+ log.Exit(0)
+}
diff --git a/node.go b/node.go
index 1fd8470..ae1cd55 100644
--- a/node.go
+++ b/node.go
@@ -21,6 +21,8 @@ func (n *Node) newNode(title string, t widget.WidgetType) *Node {
newN.value = title
newN.WidgetType = t
+ newN.strings = make(map[string]int)
+
// set these defaults
newN.expand = true
newN.pad = true
diff --git a/plugin.go b/plugin.go
index 42baead..d1b4b2c 100644
--- a/plugin.go
+++ b/plugin.go
@@ -255,9 +255,9 @@ func (n *Node) LoadToolkit(name string) *Node {
return n
}
- log.Log(PLUG, "LoadToolkit() sending InitToolkit action to the plugin channel")
+ log.Log(PLUG, "LoadToolkit() sending Toolkit Init action to the plugin channel")
var a widget.Action
- a.ActionType = widget.InitToolkit
+ a.ActionType = widget.ToolkitInit
plug.pluginChan <- a
// sleep(.5) // temp hack until chan communication is setup
@@ -274,7 +274,7 @@ func (n *Node) CloseToolkit(name string) bool {
if (plug.name == name) {
log.Log(PLUG, "CloseToolkit() sending close", name)
var a widget.Action
- a.ActionType = widget.CloseToolkit
+ a.ActionType = widget.ToolkitClose
plug.pluginChan <- a
// sleep(.5) // is this needed? TODO: properly close channel
return true
diff --git a/setText.go b/setText.go
index 3cd21fb..a4ba556 100644
--- a/setText.go
+++ b/setText.go
@@ -12,9 +12,9 @@ import (
func (n *Node) SetText(text string) *Node {
if ! n.Ready() { return n }
- if n.GetText() == text {
+ if n.String() == text {
// nothing changed
- return n
+ // return n
}
n.value = text
n.changed = true
diff --git a/structs.go b/structs.go
index 7139cea..f9bfed5 100644
--- a/structs.go
+++ b/structs.go
@@ -38,6 +38,9 @@ type guiConfig struct {
// a toolkit requirement. never allow more than one per program
initOnce sync.Once
+ // locking for the binary tree
+ muTree sync.Mutex
+
// This is the master node. The Binary Tree starts here
rootNode *Node
@@ -87,18 +90,22 @@ type Node struct {
hidden bool // don't update the toolkits when it's hidden
changed bool // do we need to inform the toolkit something changed?
enabled bool // if false, then the the user can't click on it
+ mu sync.Mutex
WidgetType widget.WidgetType
// most widgets need one value, this is current alue
value any
+ //
+ label string
+
// this can programatically identify the widget
// The name must be unique
progname string // a name useful for debugging
// for widgets that a user select from a list of strings
- strings []string
+ strings map[string]int
// how to arrange widgets
direction widget.Orientation
diff --git a/window.go b/window.go
index 4bda74e..a66ee7d 100644
--- a/window.go
+++ b/window.go
@@ -16,6 +16,7 @@ func (parent *Node) NewWindow(title string) *Node {
log.Info("NewWindow()", title)
newNode.progname = title
+ newNode.label = title
newNode.value = title
// inform the toolkits
@@ -29,7 +30,6 @@ func (parent *Node) RawWindow(title string) *Node {
// Windows are created off of the master node of the Binary Tree
newNode = parent.newNode(title, widget.Window)
- newNode.Custom = StandardExit
newNode.hidden = true
log.Info("RawWindow()", title)
@@ -78,7 +78,7 @@ func (n *Node) TestDraw() {
// enable and
n.hidden = false
n.changed = true
- log.Warn("TestDraw() sending widget.Add", n.id, n.WidgetType, n.progname)
+ log.Verbose("TestDraw() sending widget.Add", n.id, n.WidgetType, n.progname)
sendAction(n, widget.Add)
for _, child := range n.children {