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:
Jeff Carr 2024-01-13 22:02:12 -06:00
parent 1e2fa2dce9
commit 732edc3faf
20 changed files with 529 additions and 382 deletions

68
action.go Normal file
View File

@ -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
}
}

44
box.go
View File

@ -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
newNode.direction = widget.Horizontal
} else {
a.Direction = widget.Vertical
}
sendAction(a)
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
}

View File

@ -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
}

View File

@ -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
View File

@ -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
}
*/

View File

@ -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{}) {

View File

@ -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
View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
View File

@ -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
View File

@ -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) {

View File

@ -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

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}