diff options
| author | Jeff Carr <[email protected]> | 2024-01-17 21:21:29 -0600 |
|---|---|---|
| committer | Jeff Carr <[email protected]> | 2024-01-17 21:21:29 -0600 |
| commit | a6a3e1193fa7c77165f3ed2eb0031f319b4abdd0 (patch) | |
| tree | 2c5a9fbf4dbc5f7bd5cb235542082da5eba342c6 | |
| parent | 8ef3fc7a73a004385d36561c6c8acc4be7e3e24b (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.go | 52 | ||||
| -rw-r--r-- | addText.go | 50 | ||||
| -rw-r--r-- | button.go | 2 | ||||
| -rw-r--r-- | checkbox.go | 2 | ||||
| -rw-r--r-- | common.go | 50 | ||||
| -rw-r--r-- | debug.go | 19 | ||||
| -rw-r--r-- | dropdown.go | 13 | ||||
| -rw-r--r-- | go.mod | 4 | ||||
| -rw-r--r-- | go.sum | 8 | ||||
| -rw-r--r-- | group.go | 2 | ||||
| -rw-r--r-- | label.go | 2 | ||||
| -rw-r--r-- | main.go | 56 | ||||
| -rw-r--r-- | node.go | 2 | ||||
| -rw-r--r-- | plugin.go | 6 | ||||
| -rw-r--r-- | setText.go | 4 | ||||
| -rw-r--r-- | structs.go | 9 | ||||
| -rw-r--r-- | window.go | 4 |
17 files changed, 232 insertions, 53 deletions
@@ -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 +} @@ -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 @@ -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 { @@ -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) @@ -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 ( @@ -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= @@ -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) @@ -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 @@ -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) +} @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 { |
