summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
+}