work on hiding widgets
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 <jcarr@wit.com>
This commit is contained in:
parent
1e2fa2dce9
commit
732edc3faf
|
@ -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
|
||||
}
|
||||
}
|
48
box.go
48
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
|
||||
}
|
||||
|
|
25
button.go
25
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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
360
common.go
360
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)
|
||||
}
|
||||
if ! n.Ready() { return n }
|
||||
// if n.enabled { return n }
|
||||
|
||||
n.enabled = true
|
||||
n.changed = true
|
||||
|
||||
// inform the toolkits
|
||||
sendAction(n, widget.Enable)
|
||||
return n
|
||||
}
|
||||
|
||||
// disables a widget so the user can see it, but can not
|
||||
// interact or change it.
|
||||
func (n *Node) Disable() *Node {
|
||||
if ! n.hidden {
|
||||
a := newAction(n, widget.Disable)
|
||||
sendAction(a)
|
||||
}
|
||||
if ! n.Ready() { return n }
|
||||
// if ! n.enabled { return n }
|
||||
|
||||
n.enabled = false
|
||||
n.changed = true
|
||||
|
||||
// inform the toolkits
|
||||
sendAction(n, widget.Disable)
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Node) Add(str string) {
|
||||
log.Log(GUI, "gui.Add() value =", str)
|
||||
|
||||
n.value = str
|
||||
|
||||
if ! n.hidden {
|
||||
a := newAction(n, widget.Add)
|
||||
sendAction(a)
|
||||
}
|
||||
}
|
||||
|
||||
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,14 +116,177 @@ 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 {
|
||||
func (n *Node) SetProgName(s string) {
|
||||
if ! n.Ready() { return }
|
||||
|
||||
if n.progname == s {
|
||||
// don't do anything since nothing changed
|
||||
return
|
||||
}
|
||||
|
||||
n.changed = true
|
||||
n.progname = s
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
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 (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)
|
||||
if (n.Custom == nil) {
|
||||
log.Log(CHANGE, "Not Running n.Custom(n) == nil")
|
||||
} else {
|
||||
log.Log(CHANGE, "Running n.Custom(n)")
|
||||
n.Custom()
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
func (n *Node) Margin() *Node {
|
||||
if ! n.Ready() { return n }
|
||||
if n.margin { return n }
|
||||
|
||||
n.margin = true
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
n.changed = true
|
||||
|
||||
// inform the toolkits
|
||||
sendAction(n, widget.SetExpand)
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Node) SetExpand(b bool) *Node {
|
||||
if ! n.Ready() { return n }
|
||||
if n.expand == b { return n } // nothing changed
|
||||
|
||||
n.expand = b
|
||||
n.changed = true
|
||||
|
||||
// inform the toolkits
|
||||
sendAction(n, widget.SetExpand)
|
||||
return n
|
||||
}
|
||||
|
||||
// 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
|
||||
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
|
||||
/*
|
||||
func (n *Node) Standard() *Node {
|
||||
log.Warn("Standard() not implemented yet")
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Node) SetMargin() *Node {
|
||||
log.Warn("DoMargin() not implemented yet")
|
||||
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
|
||||
|
@ -145,100 +320,3 @@ func normalizeInt(s string) string {
|
|||
log.Log(GUI, "normalizeInt() s =", clean)
|
||||
return clean
|
||||
}
|
||||
|
||||
func commonCallback(n *Node) {
|
||||
// TODO: make all of this common code to all the widgets
|
||||
// This might be common everywhere finally (2023/03/01)
|
||||
if (n.Custom == nil) {
|
||||
log.Log(CHANGE, "Not Running n.Custom(n) == nil")
|
||||
} else {
|
||||
log.Log(CHANGE, "Running n.Custom(n)")
|
||||
n.Custom()
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Node) Margin() *Node {
|
||||
n.margin = true
|
||||
if ! n.hidden {
|
||||
a := newAction(n, widget.Margin)
|
||||
sendAction(a)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Node) Unmargin() *Node {
|
||||
n.margin = false
|
||||
if ! n.hidden {
|
||||
a := newAction(n, widget.Unmargin)
|
||||
sendAction(a)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Node) Pad() *Node {
|
||||
n.pad = true
|
||||
if ! n.hidden {
|
||||
a := newAction(n, widget.Pad)
|
||||
sendAction(a)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Node) Unpad() *Node {
|
||||
n.pad = false
|
||||
if ! n.hidden {
|
||||
a := newAction(n, widget.Unpad)
|
||||
sendAction(a)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Node) Expand() *Node {
|
||||
n.expand = true
|
||||
if ! n.hidden {
|
||||
a := newAction(n, widget.Pad)
|
||||
a.Expand = true
|
||||
sendAction(a)
|
||||
}
|
||||
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) Window(title string) *Node {
|
||||
log.Warn("Window()", n)
|
||||
return n.NewWindow(title)
|
||||
}
|
||||
*/
|
||||
|
||||
func (n *Node) ProgName() string {
|
||||
if ! n.Ready() { return "" }
|
||||
return n.progname
|
||||
}
|
||||
|
||||
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
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// This should not really do anything. as per the docs, the "Standard()" way
|
||||
// should be the default way
|
||||
/*
|
||||
func (n *Node) Standard() *Node {
|
||||
log.Warn("Standard() not implemented yet")
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Node) SetMargin() *Node {
|
||||
log.Warn("DoMargin() not implemented yet")
|
||||
return n
|
||||
}
|
||||
*/
|
||||
|
|
6
debug.go
6
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{}) {
|
||||
|
|
33
dropdown.go
33
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
|
||||
}
|
||||
|
|
15
grid.go
15
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
|
||||
}
|
||||
|
||||
|
|
11
group.go
11
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
|
||||
}
|
||||
|
|
9
image.go
9
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
|
||||
}
|
||||
|
|
6
label.go
6
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
|
||||
}
|
||||
|
|
38
main.go
38
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?
|
||||
|
|
17
node.go
17
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) {
|
||||
|
|
42
plugin.go
42
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
|
||||
|
|
69
setText.go
69
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 }
|
||||
|
||||
if n.GetText() == text {
|
||||
// nothing changed
|
||||
return n
|
||||
}
|
||||
n.value = text
|
||||
n.changed = true
|
||||
log.Log(CHANGE, "SetText() value =", text)
|
||||
|
||||
n.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 {
|
||||
func (n *Node) Set(val any) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
func (n *Node) Set(val any) {
|
||||
n.value = val
|
||||
n.changed = true
|
||||
log.Log(CHANGE, "Set() value =", val)
|
||||
|
||||
n.value = val
|
||||
/*
|
||||
n.value = val
|
||||
|
||||
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)
|
||||
}
|
||||
*/
|
||||
|
||||
if ! n.hidden {
|
||||
a := newAction(n, widget.Set)
|
||||
a.Value = n.value
|
||||
sendAction(a)
|
||||
}
|
||||
// inform the toolkits
|
||||
sendAction(n, widget.Set)
|
||||
}
|
||||
|
|
15
slider.go
15
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
|
||||
}
|
||||
|
|
13
spinner.go
13
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
|
||||
}
|
||||
|
|
71
structs.go
71
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
|
||||
}
|
||||
|
|
16
textbox.go
16
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
|
||||
}
|
||||
|
|
43
window.go
43
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 {
|
||||
n.hidden = false
|
||||
if ! n.Ready() { return n }
|
||||
|
||||
a := newAction(n, widget.Add)
|
||||
sendAction(a)
|
||||
n.hidden = false
|
||||
n.changed= true
|
||||
|
||||
// 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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue