summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Carr <[email protected]>2024-01-13 22:02:12 -0600
committerJeff Carr <[email protected]>2024-01-13 22:02:12 -0600
commit47b15946de10a75cda026a7317a90d4857b453c8 (patch)
treeab6a8c085226263982d3b19f2913e540707af2a1
parent4ef8409eeadcd4a359b7593b5ea35f9f523bfb64 (diff)
work on hiding widgetsv0.12.5
When widgets are hidden, their state works exactly the same as normal, but updates are not sent to the toolkits Signed-off-by: Jeff Carr <[email protected]>
-rw-r--r--action.go68
-rw-r--r--box.go48
-rw-r--r--button.go25
-rw-r--r--checkbox.go6
-rw-r--r--common.go296
-rw-r--r--debug.go6
-rw-r--r--dropdown.go33
-rw-r--r--grid.go15
-rw-r--r--group.go11
-rw-r--r--image.go9
-rw-r--r--label.go6
-rw-r--r--main.go38
-rw-r--r--node.go17
-rw-r--r--plugin.go42
-rw-r--r--setText.go67
-rw-r--r--slider.go15
-rw-r--r--spinner.go13
-rw-r--r--structs.go71
-rw-r--r--textbox.go16
-rw-r--r--window.go41
20 files changed, 495 insertions, 348 deletions
diff --git a/action.go b/action.go
new file mode 100644
index 0000000..516cf15
--- /dev/null
+++ b/action.go
@@ -0,0 +1,68 @@
+package gui
+
+/*
+ This is where the communication to the toolkit plugin happens.
+
+ We copy the current values from the widget node of the binary tree
+ and send an "action" to the toolkit over a channel.
+
+ TODO: use protobuf
+*/
+
+import (
+ "go.wit.com/log"
+ "go.wit.com/gui/widget"
+)
+
+// 2024/01/11 finally moving to type any. simplify to just 'value'
+// 2023/05/09 pretty clean
+// 2023/04/06 Queue() is also being used and channels are being used.
+func sendAction(n *Node, atype widget.ActionType) {
+ if n == nil {
+ return
+ }
+ if n.hidden {
+ return
+ }
+
+ var a widget.Action
+ a.ActionType = atype
+
+ // These should be "stable" at this point (2024/01/13)
+ a.WidgetId = n.id
+ 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.Expand = n.expand
+
+ a.X = n.X
+ a.Y = n.Y
+
+ a.AtW = n.AtW
+ a.AtH = n.AtH
+
+ if (n.parent != nil) {
+ a.ParentId = n.parent.id
+ }
+ a.WidgetType = n.WidgetType
+ sendActionToPlugin(&a)
+}
+
+// sends the action/event to each toolkit via a golang plugin channel
+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)
+ aplug.pluginChan = aplug.PluginChannel()
+ log.Info("Action() retrieved", aplug.pluginChan)
+ }
+ log.Info("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
+ }
+}
diff --git a/box.go b/box.go
index 4a16469..03b843f 100644
--- a/box.go
+++ b/box.go
@@ -4,39 +4,39 @@ import (
"go.wit.com/gui/widget"
)
-func (parent *Node) NewBox(name string, b bool) *Node {
- newNode := parent.newNode(name, widget.Box)
+func (parent *Node) NewBox(progname string, b bool) *Node {
+ newNode := parent.newNode(progname, widget.Box)
+ newNode.progname = progname
- if ! newNode.hidden {
- a := newAction(newNode, widget.Add)
- if b {
- a.Direction = widget.Horizontal
- } else {
- a.Direction = widget.Vertical
- }
- sendAction(a)
+ if b {
+ newNode.direction = widget.Horizontal
+ } else {
+ newNode.direction = widget.Vertical
}
+
+ // inform the toolkits
+ sendAction(newNode, widget.Add)
return newNode
}
-func (parent *Node) NewHorizontalBox(name string) *Node {
- newNode := parent.newNode(name, widget.Box)
+func (parent *Node) NewHorizontalBox(progname string) *Node {
+ newNode := parent.newNode(progname, widget.Box)
+ newNode.progname = progname
- if ! newNode.hidden {
- a := newAction(newNode, widget.Add)
- a.Direction = widget.Horizontal
- sendAction(a)
- }
+ newNode.direction = widget.Horizontal
+
+ // inform the toolkits
+ sendAction(newNode, widget.Add)
return newNode
}
-func (parent *Node) NewVerticalBox(name string) *Node {
- newNode := parent.newNode(name, widget.Box)
+func (parent *Node) NewVerticalBox(progname string) *Node {
+ newNode := parent.newNode(progname, widget.Box)
+ newNode.progname = progname
- if ! newNode.hidden {
- a := newAction(newNode, widget.Add)
- a.Direction = widget.Vertical
- sendAction(a)
- }
+ newNode.direction = widget.Vertical
+
+ // inform the toolkits
+ sendAction(newNode, widget.Add)
return newNode
}
diff --git a/button.go b/button.go
index 463a776..9ccff89 100644
--- a/button.go
+++ b/button.go
@@ -8,28 +8,7 @@ func (parent *Node) NewButton(name string, custom func()) *Node {
newNode.value = name
newNode.progname = name
- if ! newNode.hidden {
- a := newAction(newNode, widget.Add)
- sendAction(a)
- }
+ // inform the toolkits
+ sendAction(newNode, widget.Add)
return newNode
}
-
-// find widget by number
-func (n *Node) FindId(i int) (*Node) {
- if (n == nil) {
- return nil
- }
-
- if (n.id == i) {
- return n
- }
-
- for _, child := range n.children {
- newN := child.FindId(i)
- if (newN != nil) {
- return newN
- }
- }
- return nil
-}
diff --git a/checkbox.go b/checkbox.go
index 9075bbd..ed28185 100644
--- a/checkbox.go
+++ b/checkbox.go
@@ -11,9 +11,7 @@ func (n *Node) NewCheckbox(name string) *Node {
newNode.value = name
newNode.progname = name
- if ! newNode.hidden {
- a := newAction(newNode, widget.Add)
- sendAction(a)
- }
+ // inform the toolkits
+ sendAction(newNode, widget.Add)
return newNode
}
diff --git a/common.go b/common.go
index 1d17d48..6c31758 100644
--- a/common.go
+++ b/common.go
@@ -11,79 +11,91 @@ import (
// functions for handling text related GUI elements
func (n *Node) Show() *Node {
- if ! n.hidden {
- a := newAction(n, widget.Show)
- sendAction(a)
- }
+ if ! n.Ready() { return n }
+ if ! n.Hidden() { return n }
+
+ n.hidden = false
+ n.changed = true
+
+ // inform the toolkits
+ sendAction(n, widget.Show)
return n
}
func (n *Node) Hide() *Node {
- if ! n.hidden {
- a := newAction(n, widget.Hide)
- sendAction(a)
- }
+ if ! n.Ready() { return n }
+ if n.Hidden() { return n }
+
+ n.hidden = true
+ n.changed = true
+ // inform the toolkits
+ sendAction(n, widget.Hide)
return n
}
+// enables a widget so the user can see it and work/click/etc on it
+// by default, widgets are enabled when they are created
func (n *Node) Enable() *Node {
- if ! n.hidden {
- a := newAction(n, widget.Enable)
- sendAction(a)
- }
- return n
-}
+ if ! n.Ready() { return n }
+ // if n.enabled { return n }
-func (n *Node) Disable() *Node {
- if ! n.hidden {
- a := newAction(n, widget.Disable)
- sendAction(a)
- }
+ n.enabled = true
+ n.changed = true
+
+ // inform the toolkits
+ sendAction(n, widget.Enable)
return n
}
-func (n *Node) Add(str string) {
- log.Log(GUI, "gui.Add() value =", str)
+// disables a widget so the user can see it, but can not
+// interact or change it.
+func (n *Node) Disable() *Node {
+ if ! n.Ready() { return n }
+ // if ! n.enabled { return n }
- n.value = str
+ n.enabled = false
+ n.changed = true
- if ! n.hidden {
- a := newAction(n, widget.Add)
- sendAction(a)
- }
+ // inform the toolkits
+ sendAction(n, widget.Disable)
+ return n
}
-func (n *Node) AddText(str string) {
+
+// 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)
- if ! n.hidden {
- a := newAction(n, widget.AddText)
- sendAction(a)
- }
+ // inform the toolkits
+ sendAction(n, widget.AddText)
+ return true
}
-func (n *Node) SetNext(w int, h int) {
- n.NextW = w
- n.NextH = h
- log.Info("SetNext() w,h =", n.NextW, n.NextH)
-}
+// appends text to the existing text
+// TODO: this is an experiement
func (n *Node) AppendText(str string) {
+ if ! n.Ready() { return }
tmp := widget.GetString(n.value) + str
n.value = tmp
+ n.changed = true
- if ! n.hidden {
- a := newAction(n, widget.SetText)
- sendAction(a)
- }
+ // inform the toolkits
+ sendAction(n, widget.SetText)
}
// THESE TWO FUNCTIONS ARE TERRIBLY NAMED AND NEED TO BE FIXED
// 5 seconds worth of ideas:
// Value() ?
// 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 {
@@ -104,48 +116,31 @@ func (n *Node) GetBool() bool {
}
// should get the reference name used for programming and debugging
-// myButton = myGroup.NewButton("hit ball", nil).SetName("HIT")
-// myButton.GetName() should return "HIT"
-// n = Find("HIT") should return myButton
-func (n *Node) GetName() string {
- if ! n.Ready() { return "" }
- return n.progname
-}
+func (n *Node) SetProgName(s string) {
+ if ! n.Ready() { return }
-/*
-// string handling examples that might be helpful for normalizeInt()
-isAlpha := regexp.MustCompile(`^[A-Za-z]+$`).MatchString
+ if n.progname == s {
+ // don't do anything since nothing changed
+ return
+ }
-for _, username := range []string{"userone", "user2", "user-three"} {
- if !isAlpha(username) {
- log.Log(GUI, "%q is not valid\n", username)
- }
+ n.changed = true
+ n.progname = s
+ return
}
-const alpha = "abcdefghijklmnopqrstuvwxyz"
-
-func alphaOnly(s string) bool {
- for _, char := range s {
- if !strings.Contains(alpha, strings.ToLower(string(char))) {
- return false
- }
- }
- return true
-}
+/*
+ TODO: ensure these are unique and make a way to look them up
+ myButton = myGroup.NewButton("hit ball", nil).SetName("HIT")
+ myButton.GetName() should return "HIT"
+ n = Find("HIT") should return myButton
*/
-
-func normalizeInt(s string) string {
- // reg, err := regexp.Compile("[^a-zA-Z0-9]+")
- reg, err := regexp.Compile("[^0-9]+")
- if err != nil {
- log.Log(GUI, "normalizeInt() regexp.Compile() ERROR =", err)
- return s
- }
- clean := reg.ReplaceAllString(s, "")
- log.Log(GUI, "normalizeInt() s =", clean)
- return clean
+func (n *Node) GetProgName() string {
+ if ! n.Ready() { return "" }
+ return n.progname
}
+/*
func commonCallback(n *Node) {
// TODO: make all of this common code to all the widgets
// This might be common everywhere finally (2023/03/01)
@@ -156,79 +151,102 @@ func commonCallback(n *Node) {
n.Custom()
}
}
+*/
func (n *Node) Margin() *Node {
+ if ! n.Ready() { return n }
+ if n.margin { return n }
+
n.margin = true
- if ! n.hidden {
- a := newAction(n, widget.Margin)
- sendAction(a)
- }
+ n.changed = true
+
+ // inform the toolkits
+ sendAction(n, widget.Margin)
return n
}
func (n *Node) Unmargin() *Node {
+ if ! n.Ready() { return n }
+ if ! n.margin { return n }
+
n.margin = false
- if ! n.hidden {
- a := newAction(n, widget.Unmargin)
- sendAction(a)
- }
+ n.changed = true
+
+ // inform the toolkits
+ sendAction(n, widget.Unmargin)
return n
}
func (n *Node) Pad() *Node {
+ if ! n.Ready() { return n }
+ if n.pad == true { return n } // nothing changed
+
n.pad = true
- if ! n.hidden {
- a := newAction(n, widget.Pad)
- sendAction(a)
- }
+ n.changed = true
+
+ // inform the toolkits
+ sendAction(n, widget.Pad)
return n
}
func (n *Node) Unpad() *Node {
+ if ! n.Ready() { return n }
+ if n.pad == false { return n } // nothing changed
+
n.pad = false
- if ! n.hidden {
- a := newAction(n, widget.Unpad)
- sendAction(a)
- }
+ n.changed = true
+
+ // inform the toolkits
+ sendAction(n, widget.Unpad)
return n
}
func (n *Node) Expand() *Node {
+ if ! n.Ready() { return n }
+ if n.expand == true { return n } // nothing changed
+
n.expand = true
- if ! n.hidden {
- a := newAction(n, widget.Pad)
- a.Expand = true
- sendAction(a)
- }
+ n.changed = true
+
+ // inform the toolkits
+ sendAction(n, widget.SetExpand)
return n
}
-// is this better?
-// yes, this is better. it allows Internationalization very easily
-// me.window = myGui.New2().Window("DNS and IPv6 Control Panel").Standard()
-// myFunnyWindow = myGui.NewWindow("Hello").Standard().SetText("Hola")
+func (n *Node) SetExpand(b bool) *Node {
+ if ! n.Ready() { return n }
+ if n.expand == b { return n } // nothing changed
-/*
-func (n *Node) Window(title string) *Node {
- log.Warn("Window()", n)
- return n.NewWindow(title)
+ n.expand = b
+ n.changed = true
+
+ // inform the toolkits
+ sendAction(n, widget.SetExpand)
+ return n
}
-*/
-func (n *Node) ProgName() string {
- if ! n.Ready() { return "" }
- return n.progname
+// is the widget currently viewable?
+func (n *Node) Hidden() bool {
+ if ! n.Ready() { return false }
+ return n.hidden
}
func (n *Node) Ready() bool {
if n == nil {
log.Warn("Ready() got node == nil")
- // TODO: figure out if you can identify the code trace to help find the root cause
+ // TODO: figure out if you can identify the code trace
+ // to help find the root cause
return false
}
return true
}
+//
+//
+// DEPRECATE / REDO / SORT OUT THIS STUFF
+//
+//
+
// This should not really do anything. as per the docs, the "Standard()" way
// should be the default way
/*
@@ -242,3 +260,63 @@ func (n *Node) SetMargin() *Node {
return n
}
*/
+
+/*
+func (n *Node) Window(title string) *Node {
+ log.Warn("Window()", n)
+ return n.NewWindow(title)
+}
+*/
+
+/*
+func (n *Node) Add(str string) {
+ log.Log(GUI, "gui.Add() value =", str)
+
+ n.value = str
+
+ // inform the toolkits
+ sendAction(n, widget.Add)
+}
+*/
+
+/*
+func (n *Node) SetNext(w int, h int) {
+ n.NextW = w
+ n.NextH = h
+ log.Info("SetNext() w,h =", n.NextW, n.NextH)
+}
+*/
+
+/*
+// string handling examples that might be helpful for normalizeInt()
+isAlpha := regexp.MustCompile(`^[A-Za-z]+$`).MatchString
+
+for _, username := range []string{"userone", "user2", "user-three"} {
+ if !isAlpha(username) {
+ log.Log(GUI, "%q is not valid\n", username)
+ }
+}
+
+const alpha = "abcdefghijklmnopqrstuvwxyz"
+
+func alphaOnly(s string) bool {
+ for _, char := range s {
+ if !strings.Contains(alpha, strings.ToLower(string(char))) {
+ return false
+ }
+ }
+ return true
+}
+*/
+
+func normalizeInt(s string) string {
+ // reg, err := regexp.Compile("[^a-zA-Z0-9]+")
+ reg, err := regexp.Compile("[^0-9]+")
+ if err != nil {
+ log.Log(GUI, "normalizeInt() regexp.Compile() ERROR =", err)
+ return s
+ }
+ clean := reg.ReplaceAllString(s, "")
+ log.Log(GUI, "normalizeInt() s =", clean)
+ return clean
+}
diff --git a/debug.go b/debug.go
index 35b73b7..496fa72 100644
--- a/debug.go
+++ b/debug.go
@@ -38,10 +38,8 @@ func (n *Node) Dump() {
}
Indent(b, "NODE DUMP END")
- a := new(widget.Action)
- a.ActionType = widget.Dump
- a.WidgetId = n.id
- sendAction(a)
+ n.changed = true
+ sendAction(n, widget.Dump)
}
func Indent(b bool, a ...interface{}) {
diff --git a/dropdown.go b/dropdown.go
index 03479bb3..9b65154 100644
--- a/dropdown.go
+++ b/dropdown.go
@@ -6,41 +6,38 @@ 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 }
+ log.Warn("AddDropdownName() deprecated")
n.AddText(name)
}
// Set the dropdown menu to 'name'
func (n *Node) SetDropdownName(name string) {
+ if ! n.Ready() { return }
+ log.Warn("SetDropdownName() deprecated")
n.SetText(name)
}
-func (n *Node) NewDropdown(name string) *Node {
- newNode := n.newNode(name, widget.Dropdown)
- newNode.progname = name
- newNode.value = name
-
- if ! newNode.hidden {
- a := newAction(newNode, widget.Add)
- sendAction(a)
- }
+func (n *Node) NewDropdown(progname string) *Node {
+ newNode := n.newNode(progname, widget.Dropdown)
+ newNode.progname = progname
+ // inform the toolkits
+ sendAction(newNode, widget.Add)
return newNode
}
-func (n *Node) NewCombobox(name string) *Node {
- newNode := n.newNode(name, widget.Combobox)
- newNode.progname = name
- newNode.value = name
-
- if ! newNode.hidden {
- a := newAction(newNode, widget.Add)
- sendAction(a)
- }
+func (n *Node) NewCombobox(progname string) *Node {
+ newNode := n.newNode(progname, widget.Combobox)
+ newNode.progname = progname
+ // inform the toolkits
+ sendAction(newNode, widget.Add)
return newNode
}
diff --git a/grid.go b/grid.go
index d48edcd..7f8747d 100644
--- a/grid.go
+++ b/grid.go
@@ -33,21 +33,20 @@ type GridOffset struct {
Y int
}
-func (n *Node) NewGrid(name string, w int, h int) *Node {
- newNode := n.newNode(name, widget.Grid)
+func (n *Node) NewGrid(progname string, w int, h int) *Node {
+ newNode := n.newNode(progname, widget.Grid)
+ newNode.progname = progname
newNode.W = w
newNode.H = h
newNode.NextW = 1
newNode.NextH = 1
- if ! newNode.hidden {
- a := newAction(newNode, widget.Add)
- sendAction(a)
- }
-
// by default, always pad grids
- newNode.Pad()
+ newNode.pad = true
+
+ // inform the toolkits
+ sendAction(newNode, widget.Add)
return newNode
}
diff --git a/group.go b/group.go
index ceab839..ada0e4a 100644
--- a/group.go
+++ b/group.go
@@ -13,14 +13,7 @@ func (parent *Node) NewGroup(name string) *Node {
newNode.progname = name
newNode.value = name
- if ! newNode.hidden {
- a := newAction(newNode, widget.Add)
- sendAction(a)
- }
-
- // by default, always pad groups
- newNode.Pad()
-
- // newBox := newNode.NewBox("defaultGroupBox", false)
+ // inform the toolkits
+ sendAction(newNode, widget.Add)
return newNode
}
diff --git a/image.go b/image.go
index bd6b972..aa7435e 100644
--- a/image.go
+++ b/image.go
@@ -1,6 +1,7 @@
package gui
import (
+ "go.wit.com/log"
"go.wit.com/gui/widget"
)
@@ -8,9 +9,9 @@ func (parent *Node) NewImage(name string) *Node {
var newNode *Node
newNode = parent.newNode(name, widget.Image)
- if ! newNode.hidden {
- a := newAction(newNode, widget.Add)
- sendAction(a)
- }
+ log.Warn("NewImage() not implemented. fix this")
+
+ // inform the toolkits
+ sendAction(newNode, widget.Add)
return newNode
}
diff --git a/label.go b/label.go
index 24d1ad9..39dfc57 100644
--- a/label.go
+++ b/label.go
@@ -9,9 +9,7 @@ func (parent *Node) NewLabel(text string) *Node {
newNode.value = text
newNode.progname = text
- if ! newNode.hidden {
- a := newAction(newNode, widget.Add)
- sendAction(a)
- }
+ // inform the toolkits
+ sendAction(newNode, widget.Add)
return newNode
}
diff --git a/main.go b/main.go
index bffbee9..4955ac9 100644
--- a/main.go
+++ b/main.go
@@ -19,7 +19,7 @@ func init() {
log.Log(NOW, "init() has been run")
me.counter = 0
- me.prefix = "wit"
+ // me.prefix = "wit"
// Populates the top of the binary tree
me.rootNode = addNode()
@@ -38,30 +38,50 @@ func init() {
go watchCallback()
}
+// lookup the widget by the id sent from the toolkit
+func (n *Node) findId(i int) (*Node) {
+ if (n == nil) {
+ return nil
+ }
+
+ if (n.id == i) {
+ return n
+ }
+
+ for _, child := range n.children {
+ newN := child.findId(i)
+ if (newN != nil) {
+ return newN
+ }
+ }
+ return nil
+}
+
func watchCallback() {
- log.Info("watchCallback() START")
+ log.Info("guiChan() START")
for {
- log.Info("watchCallback() restarted select for toolkit user events")
+ log.Info("guiChan() restarted")
select {
case a := <-me.guiChan:
if (a.ActionType == widget.UserQuit) {
- log.Info("doUserEvent() User sent Quit()")
+ log.Warn("guiChan() User sent Quit()")
me.rootNode.doCustom()
log.Exit("wit/gui toolkit.UserQuit")
break
}
if (a.ActionType == widget.EnableDebug) {
- log.Warn("doUserEvent() Enable Debugging Window")
- log.Warn("doUserEvent() TODO: not implemented")
+ log.Warn("guiChan() Enable Debugging Window")
+ log.Warn("guiChan() TODO: not implemented")
// DebugWindow()
break
}
- n := me.rootNode.FindId(a.WidgetId)
+ n := me.rootNode.findId(a.WidgetId)
if (n == nil) {
- log.Warn("watchCallback() UNKNOWN widget id =", a.WidgetId, a.ProgName)
+ log.Warn("guiChan() UNKNOWN widget id")
+ log.Warn("id =", a.WidgetId, a.ProgName)
} else {
- log.Info("watchCallback() FOUND widget id =", n.id, n.progname)
+ log.Verbose("guiChan() FOUND widget id =", n.id, n.progname)
n.doUserEvent(a)
}
// this maybe a good idea?
diff --git a/node.go b/node.go
index 5ce28a2..1fd8470 100644
--- a/node.go
+++ b/node.go
@@ -7,14 +7,26 @@ import (
/*
generic function to create a new node on the binary tree
+
+ this is called each time you want a new widget
+ and it initializes basic default values
+
+ there isn't much to see here.
*/
func (n *Node) newNode(title string, t widget.WidgetType) *Node {
var newN *Node
newN = addNode()
+ newN.progname = title
newN.value = title
newN.WidgetType = t
+ // set these defaults
+ newN.expand = true
+ newN.pad = true
+ newN.enabled = true
+ newN.changed = true
+
if n.WidgetType == widget.Grid {
n.gridIncrement()
}
@@ -28,7 +40,7 @@ func (n *Node) newNode(title string, t widget.WidgetType) *Node {
}
/*
- raw create function for a new node struct
+ raw create function for a new node struct and increments the counter
*/
func addNode() *Node {
n := new(Node)
@@ -40,10 +52,13 @@ func addNode() *Node {
}
func (n *Node) Parent() *Node {
+ if ! n.Ready() { return n }
return n.parent
}
func (n *Node) Delete(d *Node) {
+ if ! n.Ready() { return }
+
for i, child := range n.children {
log.Log(NODE, "\t", i, child.id, child.progname)
if (child.id == d.id) {
diff --git a/plugin.go b/plugin.go
index 6623fd4..ff4d512 100644
--- a/plugin.go
+++ b/plugin.go
@@ -214,48 +214,6 @@ func initToolkit(name string, filename string) *aplug {
return newPlug
}
-// 2024/01/11 finally moving to type any. simplify to just 'value'
-// 2023/05/09 pretty clean
-// 2023/04/06 Queue() is also being used and channels are being used.
-func newAction(n *Node, atype widget.ActionType) *widget.Action {
- var a widget.Action
- a.ActionType = atype
- if (n == nil) {
- return &a
- }
- a.WidgetId = n.id
- a.ProgName = n.progname
- a.Value = n.value
-
- a.X = n.X
- a.Y = n.Y
-
- a.AtW = n.AtW
- a.AtH = n.AtH
-
- if (n.parent != nil) {
- a.ParentId = n.parent.id
- }
- a.WidgetType = n.WidgetType
- return &a
-}
-
-// sends the action/event to each toolkit via a golang plugin channel
-func sendAction(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)
- aplug.pluginChan = aplug.PluginChannel()
- log.Info("Action() retrieved", aplug.pluginChan)
- }
- log.Info("Action() SEND to pluginChan", aplug.name)
- 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
- }
-}
-
func (n *Node) InitEmbed(resFS embed.FS) *Node {
me.resFS = resFS
return n
diff --git a/setText.go b/setText.go
index 8b90425..3cd21fb 100644
--- a/setText.go
+++ b/setText.go
@@ -3,64 +3,55 @@ package gui
// Common actions for widgets like 'Enable' or 'Hide'
import (
+ "errors"
+
"go.wit.com/log"
"go.wit.com/gui/widget"
)
func (n *Node) SetText(text string) *Node {
if ! n.Ready() { return n }
- log.Log(CHANGE, "SetText() value =", text)
+ if n.GetText() == text {
+ // nothing changed
+ return n
+ }
n.value = text
+ n.changed = true
+ log.Log(CHANGE, "SetText() value =", text)
- if ! n.hidden {
- a := newAction(n, widget.SetText)
- a.Value = n.value
- sendAction(a)
- }
+ // inform the toolkits
+ sendAction(n, widget.SetText)
return n
}
-/*
-func convertString(val any) string {
- switch v := val.(type) {
- case bool:
- n.B = val.(bool)
- case string:
- n.label = val.(string)
- n.S = val.(string)
- case int:
- n.I = val.(int)
- default:
- log.Error(errors.New("Set() unknown type"), "v =", v)
- }
-}
-*/
-
-
func (n *Node) Set(val any) {
- log.Log(CHANGE, "Set() value =", val)
-
- n.value = val
- /*
- n.value = val
+ if ! n.Ready() { return }
switch v := val.(type) {
case bool:
- n.B = val.(bool)
+ if widget.GetBool(n.value) == val.(bool) {
+ // nothing changed
+ return
+ }
case string:
- n.label = val.(string)
- n.S = val.(string)
+ if widget.GetString(n.value) == val.(string) {
+ // nothing changed
+ return
+ }
case int:
- n.I = val.(int)
+ if widget.GetInt(n.value) == val.(int) {
+ // nothing changed
+ return
+ }
default:
log.Error(errors.New("Set() unknown type"), "v =", v)
}
- */
- if ! n.hidden {
- a := newAction(n, widget.Set)
- a.Value = n.value
- sendAction(a)
- }
+ n.value = val
+ n.changed = true
+ log.Log(CHANGE, "Set() value =", val)
+
+ // inform the toolkits
+ sendAction(n, widget.Set)
}
diff --git a/slider.go b/slider.go
index fd2b207..e5314d5 100644
--- a/slider.go
+++ b/slider.go
@@ -5,21 +5,18 @@ import (
"go.wit.com/gui/widget"
)
-func (parent *Node) NewSlider(name string, x int, y int) *Node {
- newNode := parent.newNode(name, widget.Slider)
+func (parent *Node) NewSlider(progname string, x int, y int) *Node {
+ newNode := parent.newNode(progname, widget.Slider)
+ newNode.progname = progname
newNode.Custom = func() {
- log.Log(GUI, "even newer clicker() name in NewSlider name =", name)
+ log.Log(GUI, "even newer clicker() name in NewSlider name =", progname)
}
newNode.X = x
newNode.Y = y
- if ! newNode.hidden {
- a := newAction(newNode, widget.Add)
- a.X = x
- a.Y = y
- sendAction(a)
- }
+ // inform the toolkits
+ sendAction(newNode, widget.Add)
return newNode
}
diff --git a/spinner.go b/spinner.go
index 301ed61..cba9d52 100644
--- a/spinner.go
+++ b/spinner.go
@@ -5,19 +5,18 @@ import (
"go.wit.com/gui/widget"
)
-func (parent *Node) NewSpinner(name string, x int, y int) *Node {
- newNode := parent.newNode(name, widget.Spinner)
+func (parent *Node) NewSpinner(progname string, x int, y int) *Node {
+ newNode := parent.newNode(progname, widget.Spinner)
+ newNode.progname = progname
newNode.Custom = func() {
- log.Info("default NewSpinner() change", name)
+ log.Info("default NewSpinner() change", progname)
}
newNode.X = x
newNode.Y = y
- if ! newNode.hidden {
- a := newAction(newNode, widget.Add)
- sendAction(a)
- }
+ // inform the toolkits
+ sendAction(newNode, widget.Add)
return newNode
}
diff --git a/structs.go b/structs.go
index 079cb6f..7139cea 100644
--- a/structs.go
+++ b/structs.go
@@ -27,14 +27,15 @@ var me guiConfig
// almost all toolkits use integers so there doesn't
// seem to be a good idea to use 'type any' here as it
// just makes things more complicated for no good reason
-type Range struct {
+type RangeMovedToWidget struct {
Low int
High int
}
-type List []string
+// type List []string
type guiConfig struct {
+ // a toolkit requirement. never allow more than one per program
initOnce sync.Once
// This is the master node. The Binary Tree starts here
@@ -52,28 +53,69 @@ type guiConfig struct {
resFS embed.FS
// used to beautify logging to Stdout
- depth int
- prefix string
+// depth int
+// prefix string
}
-// The Node is a binary tree. This is how all GUI elements are stored
-// simply the name and the size of whatever GUI element exists
+/*
+ The Node is a binary tree. This is how all GUI elements are stored
+ simply the name and the size of whatever GUI element exists
+
+ value : most widgets need 1 value. this is it.
+ For a window -- the title. For a button -- the name
+
+ hidden : this means the widget is not displayed yet. In that
+ case, don't waste time trying to pass information to
+ the toolkits. This makes things efficient and fast if
+ the GUI does not have to display anything
+
+ Custom() : if the user does something like click on a button,
+ this function will be called. (this should probably
+ be renamed Callback()
+
+ progname : a short name to reference the widgets in the debugger
+ n.NewButton("click here to send it").SetProgName("SENT")
+
+ parent, children : the binary tree
+
+ pad, margin, expand : re-think these names and clarify
+
+*/
+
type Node struct {
id int // should be unique
- hidden bool // Sierpinski Carpet mode. It's there, but you can't see it.
- pad bool // the toolkit may use this. it's up to the toolkit
- margin bool // the toolkit may use this. it's up to the toolkit
- expand bool // the toolkit may use this. it's up to the toolkit
+ 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
WidgetType widget.WidgetType
- // the current widget value.
+ // most widgets need one value, this is current alue
value any
// 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
+
+ // how to arrange widgets
+ direction widget.Orientation
+
+ // this function is run when there are mouse or keyboard events
+ Custom func()
+
+ parent *Node
+ children []*Node
+
+
+ // RETHINK EVERYTHING BELOW HERE
+ pad bool // the toolkit may use this. it's up to the toolkit
+ margin bool // the toolkit may use this. it's up to the toolkit
+ expand bool // the toolkit may use this. it's up to the toolkit
+
+
// used for Windows in toolkits measured in pixels
width int
height int
@@ -95,11 +137,4 @@ type Node struct {
// if this widget is in a grid, this is the position of a widget
AtW int
AtH int
-
-
- // this function is run when there are mouse or keyboard events
- Custom func()
-
- parent *Node
- children []*Node
}
diff --git a/textbox.go b/textbox.go
index 16837c0..d6ae8a4 100644
--- a/textbox.go
+++ b/textbox.go
@@ -8,20 +8,22 @@ import (
func (parent *Node) NewTextbox(name string) *Node {
newNode := parent.newNode(name, widget.Textbox)
+ newNode.value = name
+ newNode.progname = name
newNode.Custom = func() {
log.Log(GUI, "NewTextbox changed =", name)
}
- if ! newNode.hidden {
- a := newAction(newNode, widget.Add)
- sendAction(a)
- }
+ // inform the toolkits
+ sendAction(newNode, widget.Add)
return newNode
}
func (parent *Node) NewEntryLine(name string) *Node {
newNode := parent.newNode(name, widget.Textbox)
+ newNode.value = name
+ newNode.progname = name
newNode.X = 1
@@ -29,9 +31,7 @@ func (parent *Node) NewEntryLine(name string) *Node {
log.Log(GUI, "NewTextbox changed =", name)
}
- if ! newNode.hidden {
- a := newAction(newNode, widget.Add)
- sendAction(a)
- }
+ // inform the toolkits
+ sendAction(newNode, widget.Add)
return newNode
}
diff --git a/window.go b/window.go
index c2e2b38..4bda74e 100644
--- a/window.go
+++ b/window.go
@@ -18,10 +18,8 @@ func (parent *Node) NewWindow(title string) *Node {
newNode.progname = title
newNode.value = title
- if ! newNode.hidden {
- a := newAction(newNode, widget.Add)
- sendAction(a)
- }
+ // inform the toolkits
+ sendAction(newNode, widget.Add)
return newNode
}
@@ -40,26 +38,51 @@ func (parent *Node) RawWindow(title string) *Node {
// TODO: should do this recursively
func (n *Node) UnDraw() *Node {
- if ! n.hidden {
- n.Hide()
- }
+ if ! n.Ready() { return n }
+
n.hidden = true
+ n.changed = true
+
+ // inform the toolkits
+ sendAction(n, widget.Delete)
return n
}
// TODO: should do this recursively
func (n *Node) Draw() *Node {
+ if ! n.Ready() { return n }
+
n.hidden = false
+ n.changed= true
- a := newAction(n, widget.Add)
- sendAction(a)
+ // inform the toolkits
+ sendAction(n, widget.Add)
return n
}
// if the toolkit supports a gui with pixels, it might honor this. no promises
// consider this a 'recommendation' or developer 'preference' to the toolkit
+/*
func (n *Node) PixelSize(w, h int) *Node {
n.width = w
n.height = w
return n
}
+*/
+
+func (n *Node) TestDraw() {
+ if (n == nil) {
+ return
+ }
+
+ // enable and
+ n.hidden = false
+ n.changed = true
+ log.Warn("TestDraw() sending widget.Add", n.id, n.WidgetType, n.progname)
+ sendAction(n, widget.Add)
+
+ for _, child := range n.children {
+ child.TestDraw()
+ }
+ return
+}