common tree package for toolkits

This update provides *lots* of toolkit updates. This will allow
        the next step of debugging the gocui toolkit to make it work
        again. There are new common routines for handling the plugin
        channel communication

Signed-off-by: Jeff Carr <jcarr@wit.com>
This commit is contained in:
Jeff Carr 2024-01-17 21:31:49 -06:00
parent ba95c13799
commit 841e6252c9
46 changed files with 1201 additions and 879 deletions

View File

@ -1,47 +1,99 @@
package main
import (
"strconv"
"go.wit.com/dev/andlabs/ui"
"errors"
"go.wit.com/log"
"go.wit.com/gui/widget"
"go.wit.com/gui/toolkits/tree"
)
// this will check to make sure that the node
// is valid for making a New TK andlabs widget
// Basically, it makes sure there is a parent ID
// and that there already a widget created
func notNew(n *tree.Node) bool {
if n == nil {
log.Warn("ready() n = nil")
return true
}
if n.TK != nil {
log.Warn("ready() n.TK = nil", n.WidgetId, n.GetProgName())
return true
}
if n.Parent == nil {
log.Warn("ready() n.Parent = nil", n.WidgetId, n.GetProgName())
return true
}
if n.Parent.TK == nil {
log.Warn("ready() n.Parent.TK = nil", n.WidgetId, n.GetProgName())
log.Warn("ready() n.Parent.TK = nil", n.Parent.WidgetId, n.Parent.GetProgName())
return true
}
// this means you can add a new widgets
return false
}
func ready(n *tree.Node) bool {
if n == nil {
log.Warn("ready() n = nil")
return false
}
if n.TK == nil {
log.Warn("ready() n.TK = nil", n.WidgetId, n.GetProgName())
return false
}
if n.Parent == nil {
log.Warn("ready() n.Parent = nil", n.WidgetId, n.GetProgName())
return false
}
if n.Parent.TK == nil {
log.Warn("ready() n.Parent.TK = nil", n.WidgetId, n.GetProgName())
log.Warn("ready() n.Parent.TK = nil", n.Parent.WidgetId, n.Parent.GetProgName())
return false
}
return true
}
func (n *node) ready() bool {
if n == nil { return false }
if n.tk == nil { return false }
return true
}
func (n *node) show(b bool) {
if n.tk == nil {
func show(n *tree.Node, b bool) {
var tk *guiWidget
tk = n.TK.(*guiWidget)
// tk = getTK(n)
if tk == nil {
return
}
if n.tk.uiControl == nil {
if tk.uiControl == nil {
return
}
if (b) {
n.tk.uiControl.Show()
tk.uiControl.Show()
} else {
n.tk.uiControl.Hide()
tk.uiControl.Hide()
}
}
func (n *node) enable(b bool) {
func enable(n *tree.Node, b bool) {
var tk *guiWidget
tk = n.TK.(*guiWidget)
if n == nil {
panic("WHAT? enable was passed nil. How does this even happen?")
}
if n.tk == nil {
if tk == nil {
return
}
if n.tk.uiControl == nil {
if tk.uiControl == nil {
return
}
if (b) {
n.tk.uiControl.Enable()
tk.uiControl.Enable()
} else {
n.tk.uiControl.Disable()
tk.uiControl.Disable()
}
}
@ -152,73 +204,88 @@ func (n *node) Delete() {
func rawAction(a *widget.Action) {
log.Log(INFO, "rawAction() START a.ActionType =", a.ActionType, "a.Value", a.Value)
if (a.ActionType == widget.InitToolkit) {
// TODO: make sure to only do this once
// go uiMain.Do(func() {
// ui.Main(demoUI)
// go catchActionChannel()
// })
// try doing this on toolkit load in init()
if (a.ActionType == widget.ToolkitInit) {
Init()
return
}
switch a.WidgetType {
case widget.Root:
me.treeRoot = me.myTree.AddNode(a)
log.Log(INFO, "doAction() found treeRoot")
return
}
log.Log(INFO, "rawAction() START a.WidgetId =", a.WidgetId, "a.ParentId =", a.ParentId)
log.Warn("andlabs rawAction() START a.WidgetId =", a.WidgetId, "a.ParentId =", a.ParentId, a.ActionType)
switch a.WidgetType {
case widget.Flag:
log.Log(ERROR, "rawAction() RE-IMPLEMENT LOG FLAGS")
return
}
n := me.rootNode.findWidgetId(a.WidgetId)
if me.treeRoot == nil {
panic("me.treeRoot == nil")
}
n := me.treeRoot.FindWidgetId(a.WidgetId)
if (a.ActionType == widget.Add) {
ui.QueueMain(func() {
me.treeRoot.ListWidgets()
// ui.QueueMain(func() {
add(a)
})
// })
// TODO: remove this artificial delay
// sleep(.001)
return
}
if (a.ActionType == widget.Dump) {
log.Log(NOW, "rawAction() Dump =", a.ActionType, a.WidgetType, n.progname)
me.rootNode.listChildren(true)
log.Log(NOW, "rawAction() Dump =", a.ActionType, a.WidgetType, n.State.ProgName)
// me.rootNode.listChildren(true)
return
}
if (n == nil) {
me.rootNode.listChildren(true)
log.Log(NOW, "rawAction() ERROR findWidgetId found nil", a.ActionType, a.WidgetType)
log.Error(errors.New("andlabs rawAction() ERROR findWidgetId found nil"), a.ActionType, a.WidgetType)
log.Log(NOW, "rawAction() ERROR findWidgetId found nil for id =", a.WidgetId)
log.Log(NOW, "rawAction() ERROR findWidgetId found nil", a.ActionType, a.WidgetType)
log.Log(NOW, "rawAction() ERROR findWidgetId found nil for id =", a.WidgetId)
me.treeRoot.ListWidgets()
return
panic("findWidgetId found nil for id = " + strconv.Itoa(a.WidgetId))
panic("findWidgetId found nil for id = " + string(a.WidgetId))
}
switch a.ActionType {
case widget.Show:
n.show(true)
show(n, true)
// n.show(true)
case widget.Hide:
n.show(false)
show(n, false)
//n.show(false)
case widget.Enable:
n.enable(true)
enable(n, true)
// n.enable(true)
case widget.Disable:
log.Warn("andlabs got disable for", n.WidgetId, n.progname)
n.enable(false)
log.Warn("andlabs got disable for", n.WidgetId, n.State.ProgName)
enable(n, false)
// n.enable(false)
case widget.Get:
n.setText(a)
// n.setText(a)
setText(n, a)
case widget.GetText:
switch a.WidgetType {
case widget.Textbox:
a.Value = n.value
a.Value = n.State.Value
}
case widget.Set:
n.setText(a)
setText(n, a)
// n.setText(a)
case widget.SetText:
n.setText(a)
setText(n, a)
// n.setText(a)
case widget.AddText:
n.addText(a)
addText(n, a)
// n.addText(a)
/*
case widget.Margin:
n.pad(true)
case widget.Unmargin:
@ -231,8 +298,7 @@ func rawAction(a *widget.Action) {
n.Delete()
case widget.Move:
log.Log(NOW, "rawAction() attempt to move() =", a.ActionType, a.WidgetType)
newParent := me.rootNode.findWidgetId(a.ParentId)
n.move(newParent)
*/
default:
log.Log(ERROR, "rawAction() Unknown =", a.ActionType, a.WidgetType)
}

View File

@ -6,57 +6,67 @@ import (
)
func add(a *widget.Action) {
log.Warn("andlabs add()", a.WidgetId, a.State.ProgName)
if (a.WidgetType == widget.Root) {
me.rootNode = addNode(a)
if me.treeRoot == nil {
me.treeRoot = me.myTree.AddNode(a)
}
return
}
n := addNode(a)
// n := addNode(a)
n := me.myTree.AddNode(a)
p := n.parent
p := n.Parent
switch n.WidgetType {
case widget.Window:
newWindow(n)
return
case widget.Tab:
p.newTab(n)
return
case widget.Label:
p.newLabel(n)
return
case widget.Button:
p.newButton(n)
return
case widget.Grid:
p.newGrid(n)
return
case widget.Checkbox:
p.newCheckbox(n)
return
case widget.Spinner:
p.newSpinner(n)
return
case widget.Slider:
p.newSlider(n)
return
case widget.Dropdown:
p.newDropdown(n)
return
case widget.Combobox:
p.newCombobox(n)
return
case widget.Textbox:
p.newTextbox(n)
log.Warn("SPEEDY Add window", n.WidgetId, n.GetProgName())
newWindow(p, n)
return
case widget.Group:
p.newGroup(n)
log.Warn("SPEEDY Add Group", n.WidgetId, n.GetProgName())
newGroup(p, n)
return
case widget.Grid:
newGrid(n)
return
case widget.Box:
p.newBox(n)
newBox(n)
return
/*
case widget.Tab:
newTab(n)
return
*/
case widget.Label:
newLabel(p, n)
return
case widget.Button:
newButton(p, n)
return
case widget.Checkbox:
newCheckbox(p, n)
return
case widget.Spinner:
newSpinner(p, n)
return
case widget.Slider:
newSlider(p, n)
return
case widget.Dropdown:
newDropdown(p, n)
return
case widget.Combobox:
newCombobox(p, n)
return
case widget.Textbox:
newTextbox(p, n)
return
/*
case widget.Image:
p.newImage(n)
newImage(p, n)
return
*/
default:
log.Log(ERROR, "add() error TODO: ", n.WidgetType, n.progname)
log.Log(ERROR, "add() error TODO: ", n.WidgetType, n.State.ProgName)
}
}

View File

@ -3,22 +3,40 @@ package main
import (
"go.wit.com/log"
"go.wit.com/gui/widget"
"go.wit.com/gui/toolkits/tree"
)
func (n *node) addText(a *widget.Action) {
log.Log(CHANGE, "addText() START with a.Value =", a.Value)
t := n.tk
if (t == nil) {
log.Log(ERROR, "addText error. tk == nil", n.progname, n.WidgetId)
func compareStrings(n *tree.Node, ss []string) {
}
// func (n *node) addText(a *widget.Action) {
func addText(n *tree.Node, a *widget.Action) {
var tk *guiWidget
tk = n.TK.(*guiWidget)
log.Warn("andlabs addText() START with a.Value =", a.Value)
if (tk == nil) {
log.Log(ERROR, "addText error. tk == nil", n.State.ProgName, n.WidgetId)
return
}
log.Log(CHANGE, "addText() Attempt on", n.WidgetType, "with", a.Value)
log.Warn("andlabs addText() Attempt on", n.WidgetType, "with", a.Value)
switch n.WidgetType {
case widget.Dropdown:
n.addDropdownName(widget.GetString(a.Value))
for i, s := range a.State.Strings {
log.Warn("andlabs a.State.Strings =", i, s)
_, ok := n.Strings[s]
// If the key exists
if ok {
log.Warn("andlabs a.State.Strings is here", i, s)
} else {
log.Warn("andlabs is not here", i, s)
addDropdownName(n, s)
// TODO: make numbers
n.Strings[s] = 21
}
}
case widget.Combobox:
n.addComboboxName(widget.GetString(a.Value))
addComboboxName(n, widget.GetString(a.Value))
default:
log.Log(ERROR, "plugin Send() Don't know how to addText on", n.WidgetType, "yet", a.ActionType)
}

View File

@ -2,17 +2,19 @@ package main
import (
"go.wit.com/gui/widget"
"go.wit.com/gui/toolkits/tree"
"go.wit.com/dev/andlabs/ui"
_ "go.wit.com/dev/andlabs/ui/winmanifest"
)
// make new Box here
func (p *node) newBox(n *node) {
func newBox(n *tree.Node) {
if notNew(n) { return }
newt := new(guiWidget)
var box *ui.Box
if n.direction == widget.Horizontal {
if n.State.Direction == widget.Horizontal {
box = ui.NewHorizontalBox()
} else {
box = ui.NewVerticalBox()
@ -22,8 +24,8 @@ func (p *node) newBox(n *node) {
newt.uiBox = box
newt.uiControl = box
newt.boxC = 0
n.tk = newt
p.place(n)
n.TK = newt
place(n.Parent, n)
}
/*
@ -46,10 +48,11 @@ func (p *node) newBox(n *node) {
TODO: handle user killing/closing a window using the OS
*/
func (n *node) rawBox() *ui.Box {
// func (n *node) rawBox() *ui.Box {
func rawBox(n *tree.Node) *ui.Box {
var box *ui.Box
if n.direction == widget.Horizontal {
if n.State.Direction == widget.Horizontal {
box = ui.NewHorizontalBox()
} else {
box = ui.NewVerticalBox()

View File

@ -1,25 +1,28 @@
package main
import (
"go.wit.com/gui/widget"
"go.wit.com/gui/toolkits/tree"
"go.wit.com/dev/andlabs/ui"
_ "go.wit.com/dev/andlabs/ui/winmanifest"
)
func (p *node) newButton(n *node) {
t := p.tk
// func (p *node) newButton(n *node) {
func newButton(p *tree.Node, n *tree.Node) {
if notNew(n) { return }
var ptk *guiWidget
ptk = p.TK.(*guiWidget)
newt := new(guiWidget)
b := ui.NewButton(widget.GetString(n.value))
b := ui.NewButton(n.GetLabel())
newt.uiButton = b
newt.uiControl = b
newt.parent = t
newt.parent = ptk
b.OnClicked(func(*ui.Button) {
n.doUserEvent()
me.myTree.DoUserEvent(n)
})
n.tk = newt
p.place(n)
n.TK = newt
place(p, n)
}

View File

@ -1,23 +1,26 @@
package main
import (
"go.wit.com/gui/toolkits/tree"
"go.wit.com/dev/andlabs/ui"
_ "go.wit.com/dev/andlabs/ui/winmanifest"
)
func (p *node) newCheckbox(n *node) {
func newCheckbox(p *tree.Node, n *tree.Node) {
if notNew(n) { return }
newt := new(guiWidget)
newt.uiCheckbox = ui.NewCheckbox(n.label)
newt.uiCheckbox = ui.NewCheckbox(n.GetLabel())
newt.uiControl = newt.uiCheckbox
newt.uiCheckbox.OnToggled(func(spin *ui.Checkbox) {
n.value = newt.checked()
n.doUserEvent()
n.SetValue(newt.checked())
me.myTree.DoUserEvent(n)
})
n.tk = newt
p.place(n)
n.TK = newt
place(p, n)
}
func (t *guiWidget) checked() bool {

View File

@ -5,10 +5,11 @@ import (
_ "go.wit.com/dev/andlabs/ui/winmanifest"
"go.wit.com/log"
"go.wit.com/gui/widget"
"go.wit.com/gui/toolkits/tree"
)
func (p *node) newCombobox(n *node) {
func newCombobox(p, n *tree.Node) {
if notNew(n) { return }
newt := new(guiWidget)
cb := ui.NewEditableCombobox()
@ -20,46 +21,53 @@ func (p *node) newCombobox(n *node) {
newt.val = make(map[int]string)
cb.OnChanged(func(spin *ui.EditableCombobox) {
n.value = spin.Text()
n.SetValue(spin.Text())
log.Warn("combobox changed =" + spin.Text() + ".")
n.doUserEvent()
me.myTree.DoUserEvent(n)
})
n.tk = newt
p.place(n)
n.TK = newt
place(p, n)
log.Warn("add combobox entries on create:", n.State.Strings)
log.Warn("add combobox entries on create:", n.State.Strings)
log.Warn("add combobox entries on create:", n.State.Strings)
// add the initial combobox entries
for i, s := range n.strings {
log.Warn("add combobox entries on create", n.progname, i, s)
n.addComboboxName(s)
for i, s := range n.State.Strings {
log.Warn("add combobox entries on create", n.GetProgName(), i, s)
addComboboxName(n, s)
}
cur := widget.GetString(n.value)
log.Warn("add combobox: TODO: set default value on create", n.progname, cur)
n.setComboboxName(cur)
cur := n.String()
log.Warn("add combobox: TODO: set default value on create", n.GetProgName(), cur)
setComboboxName(n, cur)
}
func (n *node) addComboboxName(s string) {
if ! n.ready() { return }
func addComboboxName(n *tree.Node, s string) {
if ! ready(n) { return }
var tk *guiWidget
tk = n.TK.(*guiWidget)
log.Log(INFO, "addComboboxName()", n.WidgetId, "add:", s)
n.tk.uiEditableCombobox.Append(s)
if (n.tk.val == nil) {
tk.uiEditableCombobox.Append(s)
if (tk.val == nil) {
log.Log(INFO, "make map didn't work")
return
}
n.tk.val[n.tk.c] = s
tk.val[tk.c] = s
// If this is the first menu added, set the dropdown to it
if (n.tk.c == 0) {
if (tk.c == 0) {
log.Log(INFO, "THIS IS THE FIRST combobox", s)
n.tk.uiEditableCombobox.SetText(s)
tk.uiEditableCombobox.SetText(s)
}
n.tk.c = n.tk.c + 1
tk.c = tk.c + 1
}
func (n *node) setComboboxName(s string) bool {
if ! n.ready() { return false}
func setComboboxName(n *tree.Node, s string) bool {
if ! ready(n) { return false}
var tk *guiWidget
tk = n.TK.(*guiWidget)
log.Log(INFO, "SetComboboxName()", n.WidgetId, ",", s)
n.tk.uiEditableCombobox.SetText(s)
tk.uiEditableCombobox.SetText(s)
return false
}

View File

@ -1 +0,0 @@
../nocui/common.go

61
andlabs/common.go Normal file
View File

@ -0,0 +1,61 @@
package main
import (
"go.wit.com/gui/widget"
)
type node struct {
parent *node
children []*node
WidgetId int // widget ID
WidgetType widget.WidgetType
ParentId int // parent ID
state widget.State
// a reference name for programming and debuggign. Must be unique
progname string
// the text used for button labesl, window titles, checkbox names, etc
label string
// horizontal means layout widgets like books on a bookshelf
// vertical means layout widgets like books in a stack
// direction widget.Orientation
direction widget.Orientation
// This is how the values are passed back and forth
// values from things like checkboxes & dropdown's
value any
strings []string
// This is used for things like a slider(0,100)
X int
Y int
// This is for the grid size & widget position
W int
H int
AtW int
AtH int
vals []string // dropdown menu items
// horizontal bool `default:false`
hasTabs bool // does the window have tabs?
currentTab bool // the visible tab
// the internal plugin toolkit structure
// in the gtk plugin, it has gtk things like margin & border settings
// in the text console one, it has text console things like colors for menus & buttons
tk *guiWidget
}
/*
func (n *node) doUserEvent() {
log.Log(ERROR, "doUserEvent() ERROR")
}
*/

View File

@ -1,8 +1,6 @@
package main
import (
"strconv"
"go.wit.com/log"
// "go.wit.com/gui/widget"
)
@ -94,7 +92,7 @@ func (n *node) dumpWidget(b bool) {
}
info = n.WidgetType.String()
d = strconv.Itoa(n.WidgetId) + " " + info + " " + n.progname
d = string(n.WidgetId) + " " + info + " " + n.progname
var tabs string
for i := 0; i < listChildrenDepth; i++ {

View File

@ -5,12 +5,13 @@ import (
_ "go.wit.com/dev/andlabs/ui/winmanifest"
"go.wit.com/log"
"go.wit.com/gui/widget"
"go.wit.com/gui/toolkits/tree"
)
func (p *node) newDropdown(n *node) {
func newDropdown(p, n *tree.Node) {
if notNew(n) { return }
newt := new(guiWidget)
log.Log(INFO, "gui.Toolbox.newDropdown() START", n.progname)
log.Log(INFO, "gui.Toolbox.newDropdown() START", n.GetProgName())
cb := ui.NewCombobox()
newt.uiCombobox = cb
@ -24,60 +25,69 @@ func (p *node) newDropdown(n *node) {
i := spin.Selected()
if (newt.val == nil) {
log.Log(ERROR, "make map didn't work")
n.value = "map did not work. ui.Combobox error"
n.SetValue("map did not work. ui.Combobox error")
} else {
n.value = newt.val[i]
n.SetValue(newt.val[i])
}
n.doUserEvent()
me.myTree.DoUserEvent(n)
})
n.tk = newt
p.place(n)
n.TK = newt
place(p, n)
if n.strings == nil {return}
log.Warn("add dropdown entries on create:", n.State.Strings)
log.Warn("add dropdown entries on create:", n.State.Strings)
log.Warn("add dropdown entries on create:", n.State.Strings)
if n.State.Strings == nil {return}
// add the initial dropdown entries
for i, s := range n.strings {
log.Warn("add dropdown: add entries on create", n.progname, i, s)
n.addDropdownName(s)
for i, s := range n.State.Strings {
log.Warn("add dropdown: add entries on create", n.GetProgName(), i, s)
addDropdownName(n, s)
}
cur := widget.GetString(n.value)
log.Warn("add dropdown: set default value on create", n.progname, cur)
n.setDropdownName(cur)
cur := n.String()
log.Warn("add dropdown: set default value on create", n.GetProgName(), cur)
setDropdownName(n, cur)
}
func (n *node) SetDropdownInt(i int) {
if ! n.ready() { return }
n.tk.uiCombobox.SetSelected(i)
func setDropdownInt(n *tree.Node, i int) {
if ! ready(n) { return }
var tk *guiWidget
tk = n.TK.(*guiWidget)
tk.uiCombobox.SetSelected(i)
}
func (n *node) addDropdownName(s string) {
if ! n.ready() { return }
func addDropdownName(n *tree.Node, s string) {
if ! ready(n) { return }
var tk *guiWidget
tk = n.TK.(*guiWidget)
log.Log(INFO, "addDropdownName()", n.WidgetId, "add:", s)
n.tk.uiCombobox.Append(s)
if (n.tk.val == nil) {
tk.uiCombobox.Append(s)
if (tk.val == nil) {
log.Log(INFO, "make map didn't work")
return
}
n.tk.val[n.tk.c] = s
tk.val[tk.c] = s
// If this is the first menu added, set the dropdown to it
if (n.tk.c == 0) {
if (tk.c == 0) {
log.Log(INFO, "THIS IS THE FIRST Dropdown", s)
n.tk.uiCombobox.SetSelected(0)
tk.uiCombobox.SetSelected(0)
}
n.tk.c = n.tk.c + 1
tk.c = tk.c + 1
}
func (n *node) setDropdownName(s string) bool {
if ! n.ready() { return false}
func setDropdownName(n *tree.Node, s string) bool {
if ! ready(n) { return false}
var tk *guiWidget
tk = n.TK.(*guiWidget)
log.Log(INFO, "SetDropdownName()", n.WidgetId, ",", s)
for i, tmp := range n.tk.val {
for i, tmp := range tk.val {
if s == tmp {
n.value = s
n.SetDropdownInt(i)
n.SetValue(s)
setDropdownInt(n, i)
log.Warn("SetDropdownInt() worked", tmp, i)
return true
}

View File

@ -1,6 +1,8 @@
package main
import (
"go.wit.com/gui/toolkits/tree"
"go.wit.com/dev/andlabs/ui"
_ "go.wit.com/dev/andlabs/ui/winmanifest"
)
@ -10,9 +12,9 @@ import (
// -- (1,1) -- (2,1) -- (3,1) --
// -- (1,2) -- (2,1) -- (3,1) --
// -----------------------------
func (p *node) newGrid(n *node) {
func newGrid(n *tree.Node) {
if notNew(n) { return }
var newt *guiWidget
newt = new(guiWidget)
c := ui.NewGrid()
@ -20,6 +22,6 @@ func (p *node) newGrid(n *node) {
newt.uiControl = c
c.SetPadded(true)
n.tk = newt
p.place(n)
n.TK = newt
place(n.Parent, n)
}

View File

@ -1,20 +1,22 @@
package main
import (
"go.wit.com/gui/widget"
// "go.wit.com/gui/widget"
"go.wit.com/gui/toolkits/tree"
"go.wit.com/dev/andlabs/ui"
_ "go.wit.com/dev/andlabs/ui/winmanifest"
)
func (p *node) newGroup(n *node) {
func newGroup(p, n *tree.Node) {
if notNew(n) { return }
newt := new(guiWidget)
g := ui.NewGroup(widget.GetString(n.value))
g := ui.NewGroup(n.GetLabel())
g.SetMargined(true)
newt.uiGroup = g
newt.uiControl = g
n.tk = newt
p.place(n)
n.TK = newt
place(p, n)
}

View File

@ -16,7 +16,7 @@ func (p *node) newImage(n *node) {
// newt.uiControl = img
n.tk = newt
p.place(n)
// p.place(n)
}
/*
if (a.Name == "image") {

View File

@ -1,18 +1,19 @@
package main
import (
"go.wit.com/gui/widget"
"go.wit.com/gui/toolkits/tree"
"go.wit.com/dev/andlabs/ui"
_ "go.wit.com/dev/andlabs/ui/winmanifest"
)
func (p *node) newLabel(n *node) {
func newLabel(p, n *tree.Node) {
if notNew(n) { return }
newt := new(guiWidget)
c := ui.NewLabel(widget.GetString(n.value))
c := ui.NewLabel(n.GetLabel())
newt.uiLabel = c
newt.uiControl = c
n.tk = newt
p.place(n)
n.TK = newt
place(p, n)
}

View File

@ -2,8 +2,11 @@ package main
import (
"sync"
"runtime/debug"
"go.wit.com/log"
"go.wit.com/gui/widget"
"go.wit.com/gui/toolkits/tree"
"go.wit.com/dev/andlabs/ui"
// the _ means we only need this for the init()
@ -17,7 +20,11 @@ var muAction sync.Mutex
func queueMain(currentA widget.Action) {
defer func() {
if r := recover(); r != nil {
log.Warn("YAHOOOO Recovered in main application:", r)
log.Warn("YAHOOOO Recovered in queueMain() application:", r)
log.Println("Recovered from panic:", r)
log.Println("Stack trace:")
debug.PrintStack()
me.myTree.DoToolkitPanic()
}
}()
ui.QueueMain( func() {
@ -25,29 +32,14 @@ func queueMain(currentA widget.Action) {
})
}
func catchActionChannel() {
log.Log(INFO, "catchActionChannel() START")
for {
log.Log(INFO, "catchActionChannel() for loop")
select {
case a := <-pluginChan:
log.Log(INFO, "catchActionChannel() SELECT widget id =", a.WidgetId, a.ProgName)
log.Log(INFO, "catchActionChannel() STUFF", a.WidgetId, a.ActionType, a.WidgetType)
muAction.Lock()
// TODO ui.QueueMain(f)
// TODO ui.QueueMain( func() {rawAction(a)} )
// rawAction(a)
queueMain(a)
muAction.Unlock()
log.Log(INFO, "catchActionChannel() STUFF END", a.WidgetId, a.ActionType, a.WidgetType)
}
}
}
func guiMain() {
defer func() {
if r := recover(); r != nil {
log.Warn("YAHOOOO Recovered in main application:", r)
log.Warn("YAHOOOO Recovered in guiMain application:", r)
log.Println("Recovered from panic:", r)
log.Println("Stack trace:")
debug.PrintStack()
me.myTree.DoToolkitPanic()
}
}()
ui.Main(func() {
@ -55,6 +47,10 @@ func guiMain() {
})
}
func Init() {
log.Warn("Init() TODO: move init() to here")
}
// This is important. This sets the defaults for the gui. Without this, there isn't correct padding, etc
func init() {
log.Log(INFO, "Init() START")
@ -63,15 +59,12 @@ func init() {
// log.Log(INFO, "init() Setting defaultBehavior = true")
setDefaultBehavior(true)
me.myTree = tree.New()
me.myTree.PluginName = "andlabs"
me.myTree.ActionFromChannel = queueMain
// TODO: this is messed up. run ui.Main() from the first add? Initialize it with an empty thing first?
// fake out the OS toolkit by making a fake window. This is probably needed for macos & windows
// actually, this probably breaks the macos build
go guiMain()
// andlabs = make(map[int]*andlabsT)
pluginChan = make(chan widget.Action, 1)
log.Log(INFO, "Init() start channel reciever")
go catchActionChannel()
log.Log(INFO, "Init() END")
}

View File

@ -1,12 +1,15 @@
package main
import (
// "os"
"go.wit.com/dev/andlabs/ui"
_ "go.wit.com/dev/andlabs/ui/winmanifest"
"go.wit.com/log"
"go.wit.com/gui/widget"
"go.wit.com/gui/toolkits/tree"
)
// This routine is very specific to this toolkit
@ -33,62 +36,78 @@ import (
// -- (0,0) -- (1,0) -- (1,0) --
// -- (0,1) -- (1,1) -- (1,1) --
// -----------------------------
func (p *node) place(n *node) bool {
log.Log(INFO, "place() START", n.WidgetType, n.progname)
if (p.tk == nil) {
log.Log(ERROR, "p.tk == nil", p.progname, p.ParentId, p.WidgetType, p.tk)
log.Log(ERROR, "n = ", n.progname, n.ParentId, n.WidgetType, n.tk)
panic("p.tk == nil")
func place(p *tree.Node, n *tree.Node) bool {
log.Warn("SPEEDY newplace() 1 START", n.WidgetId, n.GetProgName(), n.GetLabel(), n.String())
log.Warn("SPEEDY newplace() n.State.Strings =", n.State.Strings)
log.Log(INFO, "place() 1 START", n.WidgetType, n.GetProgName(), n.GetLabel())
if ! ready(n) {
log.Warn("place() 1 START not ready()")
return false
}
log.Log(INFO, "place() 1 START ready()")
var tk, ptk *guiWidget
tk = n.TK.(*guiWidget)
ptk = p.TK.(*guiWidget)
log.Warn("SPEEDY newplace() 2 START", n.WidgetId, n.GetProgName(), n.GetLabel())
if (ptk == nil) {
log.Log(ERROR, "ptk == nil", p.GetProgName(), p.ParentId, p.WidgetType, ptk)
log.Log(ERROR, "n = ", n.GetProgName(), n.ParentId, n.WidgetType, tk)
log.Warn("SPEEDY ptk == nil", n.WidgetId, n.GetProgName())
log.Sleep(1)
panic("ptk == nil")
}
log.Log(INFO, "place() switch", p.WidgetType)
log.Warn("SPEEDY newplace() before switch", n.WidgetId, n.GetProgName())
switch p.WidgetType {
case widget.Grid:
log.Log(INFO, "place() Grid try at Parent X,Y =", n.X, n.Y)
n.tk.gridX = n.AtW - 1
n.tk.gridY = n.AtH - 1
log.Log(INFO, "place() Grid try at gridX,gridY", n.tk.gridX, n.tk.gridY)
// at the very end, subtract 1 from X & Y since andlabs/ui starts counting at zero
p.tk.uiGrid.Append(n.tk.uiControl,
n.tk.gridX, n.tk.gridY, 1, 1,
tk.gridX = n.State.GridOffset.X - 1
tk.gridY = n.State.GridOffset.Y - 1
log.Warn("place() on Grid at gridX,gridY", tk.gridX, tk.gridY)
ptk.uiGrid.Append(tk.uiControl,
tk.gridX, tk.gridY, 1, 1,
false, ui.AlignFill, false, ui.AlignFill)
return true
case widget.Group:
if (p.tk.uiBox == nil) {
log.Log(WARN, "place() andlabs hack group to use add a box", n.progname, n.WidgetType)
p.tk.uiBox = n.rawBox()
p.tk.uiGroup.SetChild(p.tk.uiBox)
if (ptk.uiBox == nil) {
log.Log(WARN, "place() andlabs hack group to use add a box", n.GetProgName(), n.WidgetType)
ptk.uiBox = rawBox(n)
ptk.uiGroup.SetChild(ptk.uiBox)
}
p.tk.uiBox.Append(n.tk.uiControl, stretchy)
ptk.uiBox.Append(tk.uiControl, stretchy)
return true
case widget.Tab:
if (p.tk.uiTab == nil) {
log.Log(ERROR, "p.tk.uiTab == nil for n.WidgetId =", n.WidgetId, "p.tk =", p.tk)
panic("p.tk.uiTab == nil")
if (ptk.uiTab == nil) {
log.Log(ERROR, "ptk.uiTab == nil for n.WidgetId =", n.WidgetId, "ptk =", ptk)
panic("ptk.uiTab == nil")
}
if (n.tk.uiControl == nil) {
log.Log(ERROR, "n.tk.uiControl == nil for n.WidgetId =", n.WidgetId, "n.tk =", n.tk)
panic("n.tk.uiControl == nil")
if (tk.uiControl == nil) {
log.Log(ERROR, "tk.uiControl == nil for n.WidgetId =", n.WidgetId, "tk =", tk)
panic("tk.uiControl == nil")
}
log.Log(ERROR, "CHECK LOGIC ON THIS. APPENDING directly into a window without a tab")
// log.Log(ERROR, "THIS SHOULD NEVER HAPPEN ??????? trying to place() node=", n.WidgetId, n.progname, n.Text, n.WidgetType)
// log.Log(ERROR, "THIS SHOULD NEVER HAPPEN ??????? trying to place() on parent=", p.WidgetId, p.progname, p.Text, p.WidgetType)
// panic("n.tk.uiControl == nil")
p.tk.uiTab.Append(widget.GetString(n.value), n.tk.uiControl)
p.tk.boxC += 1
// log.Log(ERROR, "THIS SHOULD NEVER HAPPEN ??????? trying to place() node=", n.WidgetId, n.GetProgName(), n.Text, n.WidgetType)
// log.Log(ERROR, "THIS SHOULD NEVER HAPPEN ??????? trying to place() on parent=", p.WidgetId, p.GetProgName(), p.Text, p.WidgetType)
// panic("tk.uiControl == nil")
ptk.uiTab.Append(widget.GetString(n.State.Value), tk.uiControl)
ptk.boxC += 1
return true
case widget.Box:
log.Log(INFO, "place() uiBox =", p.tk.uiBox)
log.Log(INFO, "place() uiControl =", n.tk.uiControl)
p.tk.uiBox.Append(n.tk.uiControl, stretchy)
p.tk.boxC += 1
log.Warn("SPEEDY Add Something to Box", n.WidgetId, n.GetProgName())
log.Log(INFO, "place() uiBox =", ptk.uiBox)
log.Log(INFO, "place() uiControl =", tk.uiControl)
ptk.uiBox.Append(tk.uiControl, stretchy)
ptk.boxC += 1
return true
case widget.Window:
p.tk.uiWindow.SetChild(n.tk.uiControl)
log.Warn("SPEEDY Add Something to Window", n.WidgetId, n.GetProgName())
ptk.uiWindow.SetChild(tk.uiControl)
return true
default:
log.Log(ERROR, "place() how? Parent =", p.WidgetId, p.WidgetType)
}
log.Warn("SPEEDY newplace() return", n.WidgetId, n.GetProgName())
return false
}

View File

@ -3,15 +3,18 @@ package main
import (
"go.wit.com/log"
"go.wit.com/gui/widget"
"go.wit.com/gui/toolkits/tree"
)
func (n *node) setText(a *widget.Action) {
// func (n *node) setText(a *widget.Action) {
func setText(n *tree.Node, a *widget.Action) {
name := widget.GetString(a.Value)
var tk *guiWidget
tk = n.TK.(*guiWidget)
log.Log(CHANGE, "setText() START with text =", name)
t := n.tk
if (t == nil) {
log.Log(ERROR, "setText error. tk == nil", n.progname, n.WidgetId)
if (tk == nil) {
log.Log(ERROR, "setText error. tk == nil", n.GetProgName(), n.WidgetId)
return
}
log.Log(CHANGE, "setText() Attempt on", n.WidgetType, "with", name)
@ -19,38 +22,38 @@ func (n *node) setText(a *widget.Action) {
switch n.WidgetType {
case widget.Window:
log.Warn("setText() Attempt to set the title to", name)
t.uiWindow.SetTitle(name)
tk.uiWindow.SetTitle(name)
case widget.Tab:
case widget.Group:
t.uiGroup.SetTitle(name)
tk.uiGroup.SetTitle(name)
case widget.Checkbox:
t.uiCheckbox.SetText(name)
tk.uiCheckbox.SetText(name)
case widget.Textbox:
if (t.uiEntry != nil) {
t.uiEntry.SetText(name)
if (tk.uiEntry != nil) {
tk.uiEntry.SetText(name)
}
if (t.uiMultilineEntry != nil) {
t.uiMultilineEntry.SetText(name)
if (tk.uiMultilineEntry != nil) {
tk.uiMultilineEntry.SetText(name)
}
case widget.Label:
t.uiLabel.SetText(name)
tk.uiLabel.SetText(name)
case widget.Button:
t.uiButton.SetText(name)
tk.uiButton.SetText(name)
case widget.Slider:
log.Log(ERROR, "setText() on slider unknown", a.ActionType, "on checkbox", n.progname)
log.Log(ERROR, "setText() on slider unknown", a.ActionType, "on checkbox", n.GetProgName())
case widget.Spinner:
log.Log(ERROR, "setText() on spinner unknown", a.ActionType, "on checkbox", n.progname)
log.Log(ERROR, "setText() on spinner unknown", a.ActionType, "on checkbox", n.GetProgName())
case widget.Dropdown:
var orig int
var i int = -1
var s string
orig = t.uiCombobox.Selected()
orig = tk.uiCombobox.Selected()
log.Log(CHANGE, "try to set the Dropdown to", name, "from", orig)
// try to find the string
for i, s = range t.val {
for i, s = range tk.val {
log.Log(CHANGE, "i, s", i, s)
if (name == s) {
t.uiCombobox.SetSelected(i)
tk.uiCombobox.SetSelected(i)
log.Log(CHANGE, "setText() Dropdown worked.", name)
return
}
@ -62,10 +65,10 @@ func (n *node) setText(a *widget.Action) {
}
// if the string was never set, then set the dropdown to the last thing added to the menu
if (orig == -1) {
t.uiCombobox.SetSelected(i)
tk.uiCombobox.SetSelected(i)
}
case widget.Combobox:
t.uiEditableCombobox.SetText(name)
tk.uiEditableCombobox.SetText(name)
default:
log.Log(ERROR, "plugin Send() Don't know how to setText on", n.WidgetType, "yet", a.ActionType)
}

View File

@ -1,22 +1,29 @@
package main
import (
"go.wit.com/gui/toolkits/tree"
"go.wit.com/dev/andlabs/ui"
_ "go.wit.com/dev/andlabs/ui/winmanifest"
)
func (p *node) newSlider(n *node) {
func newSlider(p, n *tree.Node) {
if notNew(n) { return }
newt := new(guiWidget)
s := ui.NewSlider(n.X, n.Y)
var x, y int
x = n.State.Range.Low
y = n.State.Range.High
s := ui.NewSlider(x, y)
newt.uiSlider = s
newt.uiControl = s
s.OnChanged(func(spin *ui.Slider) {
n.value = newt.uiSlider.Value()
n.doUserEvent()
n.SetValue(newt.uiSlider.Value())
me.myTree.DoUserEvent(n)
})
n.tk = newt
p.place(n)
n.TK = newt
place(p, n)
}

View File

@ -1,22 +1,25 @@
package main
import (
"go.wit.com/gui/toolkits/tree"
"go.wit.com/dev/andlabs/ui"
_ "go.wit.com/dev/andlabs/ui/winmanifest"
)
func (p *node) newSpinner(n *node) {
func newSpinner(p, n *tree.Node) {
if notNew(n) { return }
newt := new(guiWidget)
s := ui.NewSpinbox(n.X, n.Y)
s := ui.NewSpinbox(n.State.Range.Low,n.State.Range.High)
newt.uiSpinbox = s
newt.uiControl = s
s.OnChanged(func(s *ui.Spinbox) {
n.value = newt.uiSpinbox.Value()
n.doUserEvent()
n.SetValue(newt.uiSpinbox.Value())
me.myTree.DoUserEvent(n)
})
n.tk = newt
p.place(n)
n.TK = newt
place(p, n)
}

View File

@ -1,7 +1,11 @@
package main
import "go.wit.com/dev/andlabs/ui"
import _ "go.wit.com/dev/andlabs/ui/winmanifest"
import (
"go.wit.com/gui/toolkits/tree"
"go.wit.com/dev/andlabs/ui"
_ "go.wit.com/dev/andlabs/ui/winmanifest"
)
// var andlabs map[int]*andlabsT
// var callback func(int) bool
@ -11,7 +15,9 @@ import _ "go.wit.com/dev/andlabs/ui/winmanifest"
var me config
type config struct {
rootNode *node // the base of the binary tree. it should have id == 0
rootNode *tree.Node // the base of the binary tree. it should have id == 0
treeRoot *tree.Node // the base of the binary tree. it should have id == 0
myTree *tree.TreeInfo
}
// stores the raw toolkit internals

View File

@ -1,21 +1,24 @@
package main
import (
"go.wit.com/gui/toolkits/tree"
"go.wit.com/dev/andlabs/ui"
_ "go.wit.com/dev/andlabs/ui/winmanifest"
)
func (p *node) newTextbox(n *node) {
func newTextbox(p, n *tree.Node) {
if notNew(n) { return }
newt := new(guiWidget)
if (n.X == 1) {
if (n.State.Range.Low == 1) {
e := ui.NewEntry()
newt.uiEntry = e
newt.uiControl = e
e.OnChanged(func(spin *ui.Entry) {
n.value = spin.Text()
n.doUserEvent()
n.SetValue(spin.Text())
me.myTree.DoUserEvent(n)
})
} else {
e := ui.NewNonWrappingMultilineEntry()
@ -23,10 +26,10 @@ func (p *node) newTextbox(n *node) {
newt.uiControl = e
e.OnChanged(func(spin *ui.MultilineEntry) {
n.value = spin.Text()
n.doUserEvent()
n.SetValue(spin.Text())
me.myTree.DoUserEvent(n)
})
}
n.tk = newt
p.place(n)
n.TK = newt
place(p, n)
}

31
andlabs/tree.go Normal file
View File

@ -0,0 +1,31 @@
package main
/*
This code should be common to all gui plugins
There are some helper functions that are probably going to be
the same everywhere. Mostly due to handling the binary tree structure
and the channel communication
For now, it's just a symlink to the 'master' version in
./toolkit/nocui/common.go
*/
import (
"go.wit.com/gui/widget"
)
// Other goroutines must use this to access the GUI
//
// You can not acess / process the GUI thread directly from
// other goroutines. This is due to the nature of how
// Linux, MacOS and Windows work (they all work differently. suprise. surprise.)
//
// this sets the channel to send user events back from the plugin
func Callback(guiCallback chan widget.Action) {
me.myTree.Callback(guiCallback)
}
func PluginChannel() chan widget.Action {
return me.myTree.PluginChannel()
}

View File

@ -2,16 +2,16 @@ package main
import (
"go.wit.com/gui/widget"
"go.wit.com/gui/toolkits/tree"
)
// this is specific to the nocui toolkit
func initWidget(n *node) *guiWidget {
func initWidget(n *tree.Node) *guiWidget {
var w *guiWidget
w = new(guiWidget)
if n.WidgetType == widget.Root {
n.WidgetId = 0
me.rootNode = n
me.treeRoot = n
return w
}
return w

View File

@ -6,6 +6,7 @@ import (
"go.wit.com/log"
"go.wit.com/gui/widget"
"go.wit.com/gui/toolkits/tree"
)
func (t *guiWidget) MessageWindow(msg1 string, msg2 string) {
@ -16,23 +17,24 @@ func (t *guiWidget) ErrorWindow(msg1 string, msg2 string) {
ui.MsgBoxError(t.uiWindow, msg1, msg2)
}
func newWindow(n *node) {
func newWindow(p, n *tree.Node) {
var newt *guiWidget
newt = new(guiWidget)
// menubar bool is if the OS defined border on the window should be used
win := ui.NewWindow(n.progname, n.X, n.Y, menubar)
win := ui.NewWindow(n.GetProgName(), 640, 480, menubar)
win.SetBorderless(canvas)
win.SetMargined(margin)
win.OnClosing(func(*ui.Window) bool {
n.show(false)
n.doUserEvent()
// show(n, false)
me.myTree.DoWindowCloseEvent(n)
return false
})
newt.uiWindow = win
newt.uiControl = win
n.tk = newt
n.TK = newt
place(p, n)
win.Show()
return
}

View File

@ -1,68 +0,0 @@
package main
/*
These code should be common to all gui plugins
There are some helper functions that are probably going to be
the same everywhere. Mostly due to handling the binary tree structure
and the channel communication
For now, it's just a symlink to the 'master' version in
./toolkit/nocui/common.go
*/
import (
"reflect"
"strconv"
"go.wit.com/log"
"go.wit.com/gui/widget"
)
// this is in common.go, do not move it
func addNode(a *widget.Action) *node {
n := new(node)
n.WidgetType = a.WidgetType
n.WidgetId = a.WidgetId
n.ParentId = a.ParentId
n.state = a.State
// copy the data from the action message
n.progname = a.ProgName
n.value = a.Value
n.direction = a.Direction
n.strings = a.Strings
// TODO: these need to be rethought
n.X = a.X
n.Y = a.Y
n.W = a.W
n.H = a.H
n.AtW = a.AtW
n.AtH = a.AtH
// store the internal toolkit information
n.tk = initWidget(n)
// n.tk = new(guiWidget)
if (a.WidgetType == widget.Root) {
log.Log(INFO, "addNode() Root")
return n
}
if (me.rootNode.findWidgetId(a.WidgetId) != nil) {
log.Log(ERROR, "addNode() WidgetId already exists", a.WidgetId)
return me.rootNode.findWidgetId(a.WidgetId)
}
// add this new widget on the binary tree
n.parent = me.rootNode.findWidgetId(a.ParentId)
if n.parent != nil {
n.parent.children = append(n.parent.children, n)
//w := n.tk
//w.parent = n.parent.tk
//w.parent.children = append(w.parent.children, w)
}
return n
}

View File

@ -1 +0,0 @@
../nocui/common.go

218
gocui/common.go Normal file
View File

@ -0,0 +1,218 @@
package main
/*
These code should be common to all gui plugins
There are some helper functions that are probably going to be
the same everywhere. Mostly due to handling the binary tree structure
and the channel communication
For now, it's just a symlink to the 'master' version in
./toolkit/nocui/common.go
*/
import (
"go.wit.com/log"
"go.wit.com/gui/widget"
)
// this is the channel we send user events like
// mouse clicks or keyboard events back to the program
var callback chan widget.Action
// this is the channel we get requests to make widgets
var pluginChan chan widget.Action
type node struct {
parent *node
children []*node
WidgetId int // widget ID
WidgetType widget.WidgetType
ParentId int // parent ID
state widget.State
// a reference name for programming and debuggign. Must be unique
progname string
// the text used for button labesl, window titles, checkbox names, etc
label string
// horizontal means layout widgets like books on a bookshelf
// vertical means layout widgets like books in a stack
// direction widget.Orientation
direction widget.Orientation
// This is how the values are passed back and forth
// values from things like checkboxes & dropdown's
value any
strings []string
// This is used for things like a slider(0,100)
X int
Y int
// This is for the grid size & widget position
W int
H int
AtW int
AtH int
vals []string // dropdown menu items
// horizontal bool `default:false`
hasTabs bool // does the window have tabs?
currentTab bool // the visible tab
// the internal plugin toolkit structure
// in the gtk plugin, it has gtk things like margin & border settings
// in the text console one, it has text console things like colors for menus & buttons
tk *guiWidget
}
// searches the binary tree for a WidgetId
func (n *node) findWidgetId(id int) *node {
if (n == nil) {
return nil
}
if n.WidgetId == id {
return n
}
for _, child := range n.children {
newN := child.findWidgetId(id)
if (newN != nil) {
return newN
}
}
return nil
}
func (n *node) doUserEvent() {
if (callback == nil) {
log.Log(ERROR, "doUserEvent() callback == nil", n.WidgetId)
return
}
var a widget.Action
a.WidgetId = n.WidgetId
a.Value = n.value
a.ActionType = widget.User
log.Log(INFO, "doUserEvent() START: send a user event to the callback channel")
callback <- a
log.Log(INFO, "doUserEvent() END: sent a user event to the callback channel")
return
}
// Other goroutines must use this to access the GUI
//
// You can not acess / process the GUI thread directly from
// other goroutines. This is due to the nature of how
// Linux, MacOS and Windows work (they all work differently. suprise. surprise.)
//
// this sets the channel to send user events back from the plugin
func Callback(guiCallback chan widget.Action) {
callback = guiCallback
}
func PluginChannel() chan widget.Action {
return pluginChan
}
/*
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)
}
}
*/
/*
// this is in common.go, do not move it
func getString(A any) string {
if A == nil {
log.Warn("getString() got nil")
return ""
}
var k reflect.Kind
k = reflect.TypeOf(A).Kind()
switch k {
case reflect.Int:
var i int
i = A.(int)
return string(i)
case reflect.String:
return A.(string)
case reflect.Bool:
if A.(bool) == true {
return "true"
} else {
return "false"
}
default:
log.Warn("getString uknown kind", k, "value =", A)
return ""
}
return ""
}
*/
// this is in common.go, do not move it
func addNode(a *widget.Action) *node {
n := new(node)
n.WidgetType = a.WidgetType
n.WidgetId = a.WidgetId
n.ParentId = a.ParentId
n.state = a.State
// copy the data from the action message
n.progname = a.ProgName
n.value = a.Value
n.direction = a.Direction
n.strings = a.Strings
// TODO: these need to be rethought
n.X = a.X
n.Y = a.Y
n.W = a.W
n.H = a.H
n.AtW = a.AtW
n.AtH = a.AtH
// store the internal toolkit information
n.tk = initWidget(n)
// n.tk = new(guiWidget)
if (a.WidgetType == widget.Root) {
log.Log(INFO, "addNode() Root")
return n
}
if (me.rootNode.findWidgetId(a.WidgetId) != nil) {
log.Log(ERROR, "addNode() WidgetId already exists", a.WidgetId)
return me.rootNode.findWidgetId(a.WidgetId)
}
// add this new widget on the binary tree
n.parent = me.rootNode.findWidgetId(a.ParentId)
if n.parent != nil {
n.parent.children = append(n.parent.children, n)
//w := n.tk
//w.parent = n.parent.tk
//w.parent.children = append(w.parent.children, w)
}
return n
}

View File

@ -50,7 +50,7 @@ func action(a *widget.Action) {
n.AddText(widget.GetString(a.Value))
case widget.Move:
log.Log(NOW, "attempt to move() =", a.ActionType, a.WidgetType, a.ProgName)
case widget.CloseToolkit:
case widget.ToolkitClose:
log.Log(NOW, "attempting to close the plugin and release stdout and stderr")
standardExit()
case widget.Enable:

View File

@ -3,7 +3,6 @@ package main
import (
"fmt"
"errors"
"strconv"
"bufio"
"strings"
@ -60,7 +59,7 @@ func (n *node) showView() {
if (w.cuiName == "") {
log.Log(ERROR, "showView() w.cuiName was not set for widget", w)
w.cuiName = strconv.Itoa(n.WidgetId)
w.cuiName = string(n.WidgetId)
}
// if the gocui element doesn't exist, create it

View File

@ -1,8 +1,6 @@
package main
import (
"strconv"
"go.wit.com/log"
"go.wit.com/gui/widget"
)
@ -15,7 +13,7 @@ func initWidget(n *node) *guiWidget {
w.frame = true
// set the name used by gocui to the id
w.cuiName = strconv.Itoa(n.WidgetId)
w.cuiName = string(n.WidgetId)
if n.WidgetType == widget.Root {
log.Log(INFO, "setupWidget() FOUND ROOT w.id =", n.WidgetId)

View File

@ -1,152 +1,87 @@
package main
/*
a simple function to handle widget actions
You can tie this into your toolkit here.
*/
import (
"go.wit.com/log"
"go.wit.com/gui/widget"
// "go.wit.com/gui/toolkits/tree"
)
func (n *node) show(b bool) {
}
func (n *node) enable(b bool) {
}
func (n *node) pad(at widget.ActionType) {
switch n.WidgetType {
case widget.Group:
switch at {
case widget.Margin:
// SetMargined(true)
case widget.Unmargin:
// SetMargined(false)
case widget.Pad:
// SetMargined(true)
case widget.Unpad:
// SetMargined(false)
}
case widget.Tab:
case widget.Window:
case widget.Grid:
case widget.Box:
case widget.Textbox:
log.Log(ERROR, "TODO: implement ActionType =", at)
default:
log.Log(ERROR, "TODO: implement pad() for", at)
}
}
func (n *node) move(newParent *node) {
p := n.parent
switch p.WidgetType {
case widget.Group:
case widget.Tab:
// tabSetMargined(tParent.uiTab, true)
case widget.Window:
// t.uiWindow.SetBorderless(false)
case widget.Grid:
// t.uiGrid.SetPadded(true)
case widget.Box:
log.Log(INFO, "TODO: move() where =", p.ParentId)
log.Log(INFO, "TODO: move() for widget =", n.WidgetId)
default:
log.Log(ERROR, "TODO: need to implement move() for type =", n.WidgetType)
log.Log(ERROR, "TODO: need to implement move() for where =", p.ParentId)
log.Log(ERROR, "TODO: need to implement move() for widget =", n.WidgetId)
}
}
func (n *node) Delete() {
p := n.parent
log.Log(NOW, "uiDelete()", n.WidgetId, "to", p.WidgetId)
switch p.WidgetType {
case widget.Group:
// tParent.uiGroup.SetMargined(true)
case widget.Tab:
// tabSetMargined(tParent.uiTab, true)
case widget.Window:
// t.uiWindow.SetBorderless(false)
case widget.Grid:
// t.uiGrid.SetPadded(true)
case widget.Box:
log.Log(NOW, "tWidget.boxC =", p.progname)
log.Log(NOW, "is there a tParent parent? =", p.parent)
// this didn't work:
// tWidget.uiControl.Disable()
// sleep(.8)
// tParent.uiBox.Append(tWidget.uiControl, stretchy)
default:
log.Log(ERROR, "TODO: need to implement uiDelete() for widget =", n.WidgetId, n.WidgetType)
log.Log(ERROR, "TODO: need to implement uiDelete() for parent =", p.WidgetId, p.WidgetType)
}
}
func doAction(a *widget.Action) {
func doAction(a widget.Action) {
log.Log(INFO, "doAction() START a.ActionType =", a.ActionType)
log.Log(INFO, "doAction() START a.ProgName =", a.ProgName)
if (a.ActionType == widget.InitToolkit) {
// TODO: make sure to only do this once
// go uiMain.Do(func() {
// ui.Main(demoUI)
// go catchActionChannel()
// })
// try doing this on toolkit load in init()
if (a.ActionType == widget.ToolkitInit) {
return
}
log.Log(INFO, "doAction() START a.WidgetId =", a.WidgetId, "a.ParentId =", a.ParentId)
switch a.WidgetType {
case widget.Root:
me.rootNode = addNode(a)
log.Log(INFO, "doAction() found rootNode")
return
case widget.Flag:
// flag(&a)
me.treeRoot = me.myTree.AddNode(&a)
log.Log(INFO, "doAction() found treeRoot")
return
}
n := me.rootNode.findWidgetId(a.WidgetId)
switch a.ActionType {
case widget.Add:
addNode(a)
case widget.Show:
n.show(true)
case widget.Hide:
n.show(false)
case widget.Enable:
n.enable(true)
case widget.Disable:
n.enable(false)
case widget.Get:
// n.setText(a.S)
case widget.GetText:
switch a.WidgetType {
case widget.Textbox:
a.Value = n.value
me.myTree.AddNode(&a)
return
}
n := me.treeRoot.FindWidgetId(a.WidgetId)
if n == nil {
log.Warn("FindId() n == nil", a.WidgetId, a.ActionType)
log.Warn("FindId() n == nil", a.WidgetId, a.ActionType)
log.Warn("FindId() n == nil", a.WidgetId, a.ActionType)
log.Warn("Aaaaa!, return")
return
}
switch a.ActionType {
case widget.Show:
n.State.Visable = true
case widget.Hide:
n.State.Visable = false
case widget.Enable:
n.State.Visable = true
case widget.Disable:
n.State.Visable = false
case widget.Get:
log.Warn("value =", n.State.Value)
case widget.GetText:
log.Warn("value =", n.String())
case widget.Set:
// n.setText(a.S)
n.State.Value = a.State.Value
case widget.SetText:
// n.setText(a.S)
log.Warn("GOT TO SetText()", a.WidgetId)
log.Warn("GOT TO SetText()", a.WidgetId)
log.Warn("GOT TO SetText()", a.WidgetId)
log.Warn("GOT TO SetText()", a.WidgetId)
if n == nil {
log.Warn("HOT DIGGITY. n == nil")
}
n.State.Value = a.State.Value
case widget.AddText:
// n.setText(a.S)
n.State.Strings = append(a.State.Strings, widget.GetString(a.State.Value))
case widget.Margin:
n.pad(widget.Unmargin)
n.State.Pad = true
case widget.Unmargin:
n.pad(widget.Margin)
n.State.Pad = false
case widget.Pad:
n.pad(widget.Pad)
n.State.Pad = true
case widget.Unpad:
n.pad(widget.Unpad)
n.State.Pad = false
case widget.Delete:
n.Delete()
log.Warn("doAction() TODO: Delete()")
// n.Delete()
case widget.Move:
log.Log(INFO, "doAction() attempt to move() =", a.ActionType, a.WidgetType)
newParent := me.rootNode.findWidgetId(a.ParentId)
n.move(newParent)
log.Warn("doAction() TODO: Move()")
default:
log.Log(ERROR, "doAction() Unknown =", a.ActionType, a.WidgetType)
}

View File

@ -1,218 +0,0 @@
package main
/*
These code should be common to all gui plugins
There are some helper functions that are probably going to be
the same everywhere. Mostly due to handling the binary tree structure
and the channel communication
For now, it's just a symlink to the 'master' version in
./toolkit/nocui/common.go
*/
import (
"go.wit.com/log"
"go.wit.com/gui/widget"
)
// this is the channel we send user events like
// mouse clicks or keyboard events back to the program
var callback chan widget.Action
// this is the channel we get requests to make widgets
var pluginChan chan widget.Action
type node struct {
parent *node
children []*node
WidgetId int // widget ID
WidgetType widget.WidgetType
ParentId int // parent ID
state widget.State
// a reference name for programming and debuggign. Must be unique
progname string
// the text used for button labesl, window titles, checkbox names, etc
label string
// horizontal means layout widgets like books on a bookshelf
// vertical means layout widgets like books in a stack
// direction widget.Orientation
direction widget.Orientation
// This is how the values are passed back and forth
// values from things like checkboxes & dropdown's
value any
strings []string
// This is used for things like a slider(0,100)
X int
Y int
// This is for the grid size & widget position
W int
H int
AtW int
AtH int
vals []string // dropdown menu items
// horizontal bool `default:false`
hasTabs bool // does the window have tabs?
currentTab bool // the visible tab
// the internal plugin toolkit structure
// in the gtk plugin, it has gtk things like margin & border settings
// in the text console one, it has text console things like colors for menus & buttons
tk *guiWidget
}
// searches the binary tree for a WidgetId
func (n *node) findWidgetId(id int) *node {
if (n == nil) {
return nil
}
if n.WidgetId == id {
return n
}
for _, child := range n.children {
newN := child.findWidgetId(id)
if (newN != nil) {
return newN
}
}
return nil
}
func (n *node) doUserEvent() {
if (callback == nil) {
log.Log(ERROR, "doUserEvent() callback == nil", n.WidgetId)
return
}
var a widget.Action
a.WidgetId = n.WidgetId
a.Value = n.value
a.ActionType = widget.User
log.Log(INFO, "doUserEvent() START: send a user event to the callback channel")
callback <- a
log.Log(INFO, "doUserEvent() END: sent a user event to the callback channel")
return
}
// Other goroutines must use this to access the GUI
//
// You can not acess / process the GUI thread directly from
// other goroutines. This is due to the nature of how
// Linux, MacOS and Windows work (they all work differently. suprise. surprise.)
//
// this sets the channel to send user events back from the plugin
func Callback(guiCallback chan widget.Action) {
callback = guiCallback
}
func PluginChannel() chan widget.Action {
return pluginChan
}
/*
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)
}
}
*/
/*
// this is in common.go, do not move it
func getString(A any) string {
if A == nil {
log.Warn("getString() got nil")
return ""
}
var k reflect.Kind
k = reflect.TypeOf(A).Kind()
switch k {
case reflect.Int:
var i int
i = A.(int)
return strconv.Itoa(i)
case reflect.String:
return A.(string)
case reflect.Bool:
if A.(bool) == true {
return "true"
} else {
return "false"
}
default:
log.Warn("getString uknown kind", k, "value =", A)
return ""
}
return ""
}
*/
// this is in common.go, do not move it
func addNode(a *widget.Action) *node {
n := new(node)
n.WidgetType = a.WidgetType
n.WidgetId = a.WidgetId
n.ParentId = a.ParentId
n.state = a.State
// copy the data from the action message
n.progname = a.ProgName
n.value = a.Value
n.direction = a.Direction
n.strings = a.Strings
// TODO: these need to be rethought
n.X = a.X
n.Y = a.Y
n.W = a.W
n.H = a.H
n.AtW = a.AtW
n.AtH = a.AtH
// store the internal toolkit information
n.tk = initWidget(n)
// n.tk = new(guiWidget)
if (a.WidgetType == widget.Root) {
log.Log(INFO, "addNode() Root")
return n
}
if (me.rootNode.findWidgetId(a.WidgetId) != nil) {
log.Log(ERROR, "addNode() WidgetId already exists", a.WidgetId)
return me.rootNode.findWidgetId(a.WidgetId)
}
// add this new widget on the binary tree
n.parent = me.rootNode.findWidgetId(a.ParentId)
if n.parent != nil {
n.parent.children = append(n.parent.children, n)
//w := n.tk
//w.parent = n.parent.tk
//w.parent.children = append(w.parent.children, w)
}
return n
}

View File

@ -1,11 +1,13 @@
package main
/*
import (
"go.wit.com/log"
"go.wit.com/gui/widget"
"go.wit.com/gui/toolkits/tree"
)
func (n *node) doWidgetClick() {
func doWidgetClick(n *tree.Node) {
switch n.WidgetType {
case widget.Root:
// THIS IS THE BEGINING OF THE LAYOUT
@ -17,32 +19,33 @@ func (n *node) doWidgetClick() {
// rootNode.dumpTree(true)
case widget.Window:
// setCurrentWindow(w)
n.doUserEvent()
// n.doUserEvent()
case widget.Tab:
// setCurrentTab(w)
case widget.Group:
// n.placeWidgets()
// n.toggleTree()
case widget.Checkbox:
if widget.GetBool(n.value) {
if n.Bool() {
// n.setCheckbox(false)
} else {
// n.setCheckbox(true)
}
n.doUserEvent()
// n.doUserEvent()
case widget.Grid:
// rootNode.hideWidgets()
// n.placeGrid()
// n.showWidgets()
case widget.Box:
// n.showWidgetPlacement(logNow, "drawTree()")
if widget.GetBool(n.value) {
log.Log(NOW, "BOX IS HORIZONTAL", n.progname)
if n.Bool() {
log.Log(NOW, "BOX IS HORIZONTAL", n.GetProgName())
} else {
log.Log(NOW, "BOX IS VERTICAL", n.progname)
log.Log(NOW, "BOX IS VERTICAL", n.GetProgName())
}
case widget.Button:
n.doUserEvent()
// n.doUserEvent()
default:
}
}
*/

View File

@ -1,10 +1,3 @@
module go.wit.com/gui/toolkits/nocui
go 1.21.4
require (
go.wit.com/gui/widget v1.1.3
go.wit.com/log v0.5.4
)
require go.wit.com/dev/davecgh/spew v1.1.4 // indirect

View File

@ -1,10 +0,0 @@
go.wit.com/dev/davecgh/spew v1.1.3 h1:hqnB5qsPgC2cLZaJXqQJspQ5n/Ugry9kyL3tLk0hVzQ=
go.wit.com/dev/davecgh/spew v1.1.3/go.mod h1:sihvWmnQ/09FWplnEmozt90CCVqBtGuPXM811tgfhFA=
go.wit.com/dev/davecgh/spew v1.1.4 h1:C9hj/rjlUpdK+E6aroyLjCbS5MFcyNUOuP1ICLWdNek=
go.wit.com/dev/davecgh/spew v1.1.4/go.mod h1:sihvWmnQ/09FWplnEmozt90CCVqBtGuPXM811tgfhFA=
go.wit.com/gui/widget v1.1.3 h1:GvLzGSOF9tfmoh6HNbFdN+NSlBo2qeS/Ba2TnQQ1A1U=
go.wit.com/gui/widget v1.1.3/go.mod h1:A6/FaiFQtAHTjgo7c4FrokXe6bXX1Cowo35b2Lgi31E=
go.wit.com/log v0.5.3 h1:/zHkniOPusPEuX1R401rMny9uwSO/nSU/QOMx6qoEnE=
go.wit.com/log v0.5.3/go.mod h1:LzIzVxc2xJQxWQBtV9VbV605P4TOxmYDCl+BZF38yGE=
go.wit.com/log v0.5.4 h1:vijLRPTUgChb8J5tx/7Uma/lGTUxeSXosFbheAmL914=
go.wit.com/log v0.5.4/go.mod h1:BaJBfHFqcJSJLXGQ9RHi3XVhPgsStxSMZRlaRxW4kAo=

View File

@ -1,55 +1,24 @@
package main
import (
"sync"
"go.wit.com/log"
"go.wit.com/gui/widget"
)
var muAction sync.Mutex
func catchActionChannel() {
log.Log(NOW, "catchActionChannel() START")
for {
log.Log(NOW, "catchActionChannel() for loop")
select {
case a := <-pluginChan:
log.Log(NOW, "catchActionChannel() SELECT widget id =", a.WidgetId, a.ProgName)
log.Log(NOW, "catchActionChannel() STUFF", a.WidgetId, a.ActionType, a.WidgetType)
muAction.Lock()
doAction(&a)
muAction.Unlock()
log.Log(NOW, "catchActionChannel() STUFF END", a.WidgetId, a.ActionType, a.WidgetType)
}
}
}
/*
// Other goroutines must use this to access the GUI
//
// You can not acess / process the GUI thread directly from
// other goroutines. This is due to the nature of how
// Linux, MacOS and Windows work (they all work differently. suprise. surprise.)
//
// this sets the channel to send user events back from the plugin
func Callback(guiCallback chan widget.Action) {
callback = guiCallback
}
This is reference code for toolkit developers
func PluginChannel() chan widget.Action {
return pluginChan
}
The 'nocui' is a bare minimum toolkit. It's all you need
to interact with the GUI
*/
// This is important. This sets the defaults for the gui. Without this, there isn't correct padding, etc
import (
"go.wit.com/log"
"go.wit.com/gui/toolkits/tree"
)
func init() {
log.Log(INFO, "Init()")
// andlabs = make(map[int]*andlabsT)
pluginChan = make(chan widget.Action, 1)
me.myTree = tree.New()
me.myTree.PluginName = "nocui"
me.myTree.ActionFromChannel = doAction
log.Log(NOW, "Init() start channel reciever")
go catchActionChannel()
go simpleStdin()
log.Log(NOW, "Init() END")
log.Log(INFO, "Init() END")
}

View File

@ -4,6 +4,7 @@ import (
"os"
"fmt"
"bufio"
"runtime/debug"
"strings"
"strconv"
@ -12,6 +13,15 @@ import (
)
func simpleStdin() {
defer func() {
if r := recover(); r != nil {
log.Warn("nocui YAHOOOO Recovered in simpleStdin()", r)
log.Println("Recovered from panic:", r)
log.Println("Stack trace:")
debug.PrintStack()
me.myTree.DoToolkitPanic()
}
}()
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
s := scanner.Text()
@ -19,63 +29,46 @@ func simpleStdin() {
switch s {
case "l":
log.Log(NOW, "list widgets")
me.rootNode.listWidgets()
me.treeRoot.ListWidgets()
case "b":
log.Log(NOW, "show buttons")
me.rootNode.showButtons()
me.treeRoot.ShowButtons()
case "g":
me.myTree.DoToolkitLoad("gocui")
case "a":
me.myTree.DoToolkitLoad("andlabs")
case "d":
var a widget.Action
a.ActionType = widget.EnableDebug
callback <- a
me.myTree.DoEnableDebugger()
case "":
fmt.Println("")
fmt.Println("Enter:")
fmt.Println("'l': list all widgets")
fmt.Println("'b': for buttons")
fmt.Println("'g': load gocui plugin")
fmt.Println("'a': load andlabs plugin")
fmt.Println("'d': enable debugging")
default:
i, _ := strconv.Atoi(s)
log.Log(NOW, "got input:", i)
n := me.rootNode.findWidgetId(i)
n := me.treeRoot.FindWidgetId(i)
if (n != nil) {
n.dumpWidget("found node")
n.doUserEvent()
n.DumpWidget("found node")
for i, s := range n.State.Strings {
log.Warn("n.State.Strings =", i, s)
}
switch n.WidgetType {
case widget.Root:
log.Warn("this is the root widget")
case widget.Dropdown:
log.Warn("print out dropdown values here")
case widget.Button:
me.myTree.DoUserEvent(n)
case widget.Checkbox:
me.myTree.DoUserEvent(n)
default:
log.Warn("you haven't defined an event for", n.WidgetType)
}
}
}
}
func (n *node) showButtons() {
if n.WidgetType == widget.Button {
n.dumpWidget("Button:")
}
for _, child := range n.children {
child.showButtons()
}
}
func (n *node) dumpWidget(pad string) {
log.Log(NOW, "node:", pad, n.WidgetId, ",", n.WidgetType, ",", n.progname)
}
var depth int = 0
func (n *node) listWidgets() {
if (n == nil) {
return
}
var pad string
for i := 0; i < depth; i++ {
pad = pad + " "
}
n.dumpWidget(pad)
for _, child := range n.children {
depth += 1
child.listWidgets()
depth -= 1
}
return
}

View File

@ -1,17 +1,22 @@
package main
import (
"go.wit.com/gui/toolkits/tree"
)
// stores the raw toolkit internals
type guiWidget struct {
Width int
Height int
c int
val map[int]string
val map[string]int
}
// It's probably a terrible idea to call this 'me'
var me config
type config struct {
rootNode *node // the base of the binary tree. it should have id == 0
treeRoot *tree.Node // the base of the binary tree. it should have id == 0
myTree *tree.TreeInfo
}

24
nocui/tree.go Normal file
View File

@ -0,0 +1,24 @@
package main
/*
This is reference code for toolkit developers
*/
import (
"go.wit.com/gui/widget"
)
// Other goroutines must use this to access the GUI
//
// You can not acess / process the GUI thread directly from
// other goroutines. This is due to the nature of how
// Linux, MacOS and Windows work (they all work differently. suprise. surprise.)
//
// this sets the channel to send user events back from the plugin
func Callback(guiCallback chan widget.Action) {
me.myTree.Callback(guiCallback)
}
func PluginChannel() chan widget.Action {
return me.myTree.PluginChannel()
}

View File

@ -1,30 +0,0 @@
package main
import (
"go.wit.com/log"
"go.wit.com/gui/widget"
)
// this is specific to the nocui toolkit
func initWidget(n *node) *guiWidget {
var w *guiWidget
w = new(guiWidget)
// Set(w, "default")
if n.WidgetType == widget.Root {
log.Log(INFO, "setupWidget() FOUND ROOT w.id =", n.WidgetId)
n.WidgetId = 0
me.rootNode = n
return w
}
if (n.WidgetType == widget.Box) {
if (n.direction == widget.Horizontal) {
// n.horizontal = true
} else {
// n.horizontal = false
}
}
return w
}

47
tree/addNode.go Normal file
View File

@ -0,0 +1,47 @@
package tree
import (
"errors"
"go.wit.com/log"
"go.wit.com/gui/widget"
)
// this is in common.go, do not move it
func (me *TreeInfo) AddNode(a *widget.Action) *Node {
n := new(Node)
n.WidgetType = a.WidgetType
n.WidgetId = a.WidgetId
n.ParentId = a.ParentId
n.State = a.State
n.Strings = make(map[string]int)
if (a.WidgetType == widget.Root) {
log.Info("AddNode() Root")
n.Parent = n
me.treeRoot = n
return n
}
if (me.treeRoot.FindWidgetId(a.WidgetId) != nil) {
log.Warn("AddNode() WidgetId already exists", a.WidgetId)
log.Warn("probably this is a Show() / Hide() issue")
log.Warn("TODO: figure out what to do here")
return me.treeRoot.FindWidgetId(a.WidgetId)
}
// add this new widget on the binary tree
p := me.treeRoot.FindWidgetId(a.ParentId)
n.Parent = p
if n.Parent == nil {
log.Error(errors.New("tree.AddNode() ERROR n.Parent == nil"), a.WidgetId, a.ParentId, a.ActionType)
log.Warn("AddNode() ERROR n.Parent == nil", a.WidgetId, a.ParentId, a.ActionType)
log.Warn("AddNode() ERROR n.Parent == nil", a.WidgetId, a.ParentId, a.WidgetType)
return n
}
log.Warn("AddNode() Adding to parent =", p.ParentId, p.WidgetType, p.GetProgName())
log.Warn("AddNode() Adding child =", n.ParentId, n.WidgetType, n.GetProgName())
p.children = append(p.children, n)
return n
}

35
tree/common.go Normal file
View File

@ -0,0 +1,35 @@
package tree
import (
"go.wit.com/gui/widget"
)
func (n *Node) GetProgName() string {
return n.State.ProgName
}
func (n *Node) GetValue() any {
return n.State.Value
}
func (n *Node) Bool() bool {
return widget.GetBool(n.State.Value)
}
func (n *Node) String() string {
return widget.GetString(n.State.Value)
}
/* avoid this function name as confusing
func (n *Node) GetText() string {
return widget.GetString(n.State.Value)
}
*/
func (n *Node) SetValue(a any) {
n.State.Value = a
}
func (n *Node) GetLabel() string {
return n.State.Label
}

44
tree/debug.go Normal file
View File

@ -0,0 +1,44 @@
package tree
import (
"go.wit.com/log"
"go.wit.com/gui/widget"
)
func (n *Node) ShowButtons() {
if n.WidgetType == widget.Button {
n.DumpWidget("Button:")
}
for _, child := range n.children {
child.ShowButtons()
}
}
func (n *Node) DumpWidget(pad string) {
log.Warn("node:", pad, n.WidgetId, ",", n.WidgetType, ",", n.GetProgName())
}
var depth int = 0
func (n *Node) ListWidgets() {
if (n == nil) {
log.Warn("ERRRORRRR: n == nil in ListWidgets()")
log.Warn("ERRRORRRR: n == nil in ListWidgets()")
log.Warn("ERRRORRRR: n == nil in ListWidgets()")
return
}
var pad string
for i := 0; i < depth; i++ {
pad = pad + " "
}
n.DumpWidget(pad)
for _, child := range n.children {
depth += 1
child.ListWidgets()
depth -= 1
}
return
}

88
tree/event.go Normal file
View File

@ -0,0 +1,88 @@
package tree
/*
These code should be common to all gui plugins
There are some helper functions that are probably going to be
the same everywhere. Mostly due to handling the binary tree structure
and the channel communication
For now, it's just a symlink to the 'master' version in
./toolkit/nocui/common.go
*/
import (
"go.wit.com/log"
"go.wit.com/gui/widget"
)
func (me *TreeInfo) DoEnableDebugger() {
if (me.callback == nil) {
log.Warn("DoUserEvent() toolkit panic() callback == nil")
return
}
var a widget.Action
a.ActionType = widget.EnableDebug
a.ProgName = me.PluginName
me.callback <- a
return
}
func (me *TreeInfo) DoToolkitLoad(s string) {
if (me.callback == nil) {
log.Warn("DoUserEvent() toolkit load callback == nil")
return
}
var a widget.Action
a.ActionType = widget.ToolkitLoad
a.ProgName = me.PluginName
a.Value = s
log.Warn("DoUserEvent() START: toolkit load", s)
me.callback <- a
log.Warn("DoUserEvent() END: toolkit load", s)
return
}
func (me *TreeInfo) DoToolkitPanic() {
if (me.callback == nil) {
log.Warn("DoUserEvent() toolkit panic() callback == nil")
return
}
var a widget.Action
a.ActionType = widget.ToolkitPanic
a.ProgName = me.PluginName
log.Info("DoUserEvent() START: toolkit panic()")
me.callback <- a
log.Info("DoUserEvent() END: toolkit panic()")
return
}
func (me *TreeInfo) DoWindowCloseEvent(n *Node) {
if (me.callback == nil) {
log.Warn("DoUserEvent() callback == nil", n.WidgetId)
return
}
var a widget.Action
a.WidgetId = n.WidgetId
a.ActionType = widget.CloseWindow
log.Info("DoUserEvent() START: user closed the window", n.GetProgName())
me.callback <- a
log.Info("DoUserEvent() END: user closed the window", n.GetProgName())
return
}
// Other goroutines must use this to access the GUI
func (me *TreeInfo) DoUserEvent(n *Node) {
if (me.callback == nil) {
log.Warn("DoUserEvent() callback == nil", n.WidgetId)
return
}
var a widget.Action
a.WidgetId = n.WidgetId
a.Value = n.State.Value
a.ActionType = widget.User
log.Info("DoUserEvent() START: send a user event to the callback channel")
me.callback <- a
log.Info("DoUserEvent() END: sent a user event to the callback channel")
return
}

58
tree/init.go Normal file
View File

@ -0,0 +1,58 @@
package tree
import (
"sync"
"errors"
"go.wit.com/log"
"go.wit.com/gui/widget"
)
var muAction sync.Mutex
func (me *TreeInfo) toolkit(a widget.Action) {
if me.ActionFromChannel == nil {
log.Error(errors.New("toolkit ActionFromChannel == nil"), a.WidgetId, a.ActionType, a.WidgetType)
return
}
me.ActionFromChannel(a)
}
func (me *TreeInfo) catchActionChannel() {
defer func() {
if r := recover(); r != nil {
log.Warn("nocui YAHOOOO Recovered in simpleStdin()", r)
me.DoToolkitPanic()
panic(-1)
}
}()
log.Info("catchActionChannel() START")
for {
log.Info("catchActionChannel() for loop")
select {
case a := <-me.pluginChan:
log.Info("catchActionChannel() SELECT widget id =", a.WidgetId, a.ProgName)
log.Warn("catchActionChannel() STUFF", a.WidgetId, a.ActionType, a.WidgetType)
if a.WidgetType == widget.Dropdown {
log.Warn("Found dropdown", a.WidgetId, a.ActionType, a.WidgetType)
for i, s := range a.State.Strings {
log.Warn("a.State.Strings =", i, s)
}
}
muAction.Lock()
me.toolkit(a)
muAction.Unlock()
log.Info("catchActionChannel() STUFF END", a.WidgetId, a.ActionType, a.WidgetType)
}
}
}
func New() *TreeInfo {
me := new(TreeInfo)
me.pluginChan = make(chan widget.Action, 1)
log.Info("Init() start channel reciever")
go me.catchActionChannel()
log.Info("Init() END")
return me
}

View File

@ -1,4 +1,4 @@
package main
package tree
/*
These code should be common to all gui plugins
@ -12,15 +12,11 @@ package main
*/
import (
"reflect"
"strconv"
"go.wit.com/log"
"go.wit.com/gui/widget"
)
// searches the binary tree for a WidgetId
func (n *node) findWidgetId(id int) *node {
func (n *Node) FindWidgetId(id int) *Node {
if (n == nil) {
return nil
}
@ -30,7 +26,7 @@ func (n *node) findWidgetId(id int) *node {
}
for _, child := range n.children {
newN := child.findWidgetId(id)
newN := child.FindWidgetId(id)
if (newN != nil) {
return newN
}
@ -38,21 +34,6 @@ func (n *node) findWidgetId(id int) *node {
return nil
}
func (n *node) doUserEvent() {
if (callback == nil) {
log.Log(ERROR, "doUserEvent() callback == nil", n.WidgetId)
return
}
var a widget.Action
a.WidgetId = n.WidgetId
a.Value = n.value
a.ActionType = widget.User
log.Log(INFO, "doUserEvent() START: send a user event to the callback channel")
callback <- a
log.Log(INFO, "doUserEvent() END: sent a user event to the callback channel")
return
}
// Other goroutines must use this to access the GUI
//
// You can not acess / process the GUI thread directly from
@ -60,10 +41,10 @@ func (n *node) doUserEvent() {
// Linux, MacOS and Windows work (they all work differently. suprise. surprise.)
//
// this sets the channel to send user events back from the plugin
func Callback(guiCallback chan widget.Action) {
callback = guiCallback
func (me *TreeInfo) Callback(guiCallback chan widget.Action) {
me.callback = guiCallback
}
func PluginChannel() chan widget.Action {
return pluginChan
func (me *TreeInfo) PluginChannel() chan widget.Action {
return me.pluginChan
}

View File

@ -1,4 +1,4 @@
package main
package tree
/*
These code should be common to all gui plugins
@ -12,23 +12,29 @@ package main
*/
import (
"reflect"
"strconv"
"go.wit.com/log"
// "go.wit.com/log"
"go.wit.com/gui/widget"
)
// var me *TreeInfo
type TreeInfo struct {
// this is the channel we send user events like
// mouse clicks or keyboard events back to the program
var callback chan widget.Action
callback chan widget.Action
// this is the channel we get requests to make widgets
var pluginChan chan widget.Action
pluginChan chan widget.Action
treeRoot *Node
NodeI interface {}
ActionFromChannel func (widget.Action) ()
PluginName string
}
type Node struct {
parent *node
children []*node
Parent *Node
children []*Node
WidgetId int // widget ID
WidgetType widget.WidgetType
@ -36,6 +42,8 @@ type Node struct {
State widget.State
Strings map[string]int
// the internal plugin toolkit structure
// in the gtk plugin, it has gtk things like margin & border settings
// in the text console one, it has text console things like colors for menus & buttons