Squashed commit of the following:

all non binary tree structs are gone (almost all)
    Use names from https://en.wikipedia.org/wiki/Graphical_widget
    toolkit andlabs/ui is isolated from being accessable
        all direct references to andlabs are removed
    working dropdown widgets
    add debugging more buttons and windows
This commit is contained in:
Jeff Carr 2022-10-20 06:55:42 -05:00
parent 6286635049
commit d28f0eb8c1
41 changed files with 1033 additions and 1889 deletions

105
box.go
View File

@ -1,105 +0,0 @@
package gui
import "log"
import "os"
import "github.com/andlabs/ui"
import _ "github.com/andlabs/ui/winmanifest"
func (n *Node) AddBox(axis int, name string) *Node {
newBox := new(GuiBox)
newBox.Window = n.window
newBox.Name = name
if (n.box == nil) {
n.box = newBox
}
// make a new box & a new node
newNode := n.New(name)
newNode.box = newBox
Config.counter += 1
var uiBox *ui.Box
if (axis == Xaxis) {
uiBox = ui.NewHorizontalBox()
} else {
uiBox = ui.NewVerticalBox()
}
uiBox.SetPadded(true)
newBox.UiBox = uiBox
newNode.uiBox = uiBox
n.Append(newNode)
// add(n.box, newBox)
return newNode
}
func HorizontalBreak(box *GuiBox) {
log.Println("VerticalSeparator added to box =", box.Name)
tmp := ui.NewHorizontalSeparator()
if (box == nil) {
return
}
if (box.UiBox == nil) {
return
}
box.UiBox.Append(tmp, false)
}
func VerticalBreak(box *GuiBox) {
log.Println("VerticalSeparator added to box =", box.Name)
tmp := ui.NewVerticalSeparator()
box.UiBox.Append(tmp, false)
}
func (n *Node) AddComboBox(title string, s ...string) *Node {
if (n.Toolkit == nil) {
log.Println("AddComboBox.Toolkit is nil", title, s)
n.Dump()
os.Exit(0)
}
if (n.uiBox == nil) {
log.Println("AddComboBox.uiBox is nil", title, s)
n.Toolkit.Dump()
n.uiBox = n.Toolkit.GetBox()
// os.Exit(0)
// return n
}
box := n.uiBox
newNode := n.New(title)
ecbox := ui.NewEditableCombobox()
for id, name := range s {
log.Println("Adding Combobox Entry:", id, name)
ecbox.Append(name)
}
ecbox.OnChanged(func(*ui.EditableCombobox) {
test := ecbox.Text()
log.Println("node.Name = '" + n.Name + "' text for '" + title + "' is now: '" + test + "'")
log.Println("need to call node.OnChanged() here")
if (newNode.OnChanged == nil) {
log.Println("node.OnChanged() is nil")
log.Println("need to call node.OnChanged() here", newNode.OnChanged)
newNode.Dump()
} else {
log.Println("need to call node.OnChanged() here", newNode.OnChanged)
newNode.OnChanged(newNode)
}
})
box.Append(ecbox, false)
newNode.uiText = ecbox
return newNode
}
func (n *Node) GetText() string {
if (n.uiText == nil) {
return ""
}
ecbox := n.uiText
return ecbox.Text()
}

174
button.go
View File

@ -1,184 +1,20 @@
package gui package gui
import "log" import "log"
// import "reflect"
import "github.com/andlabs/ui"
import _ "github.com/andlabs/ui/winmanifest"
// import "github.com/davecgh/go-spew/spew"
// This is the default mouse click handler
// Every mouse click that hasn't been assigned to
// something specific will fall into this routine
// By default, all it runs is the call back to
// the main program that is using this library
//
// This routine MUST be here as this is how the andlabs/ui works
// This is the raw routine passed to every button in andlabs libui / ui
//
// There is a []GuiButton which has all the buttons. We search
// for the button and then call the function below
//
func defaultButtonClick(button *ui.Button) {
log.Println("gui.defaultButtonClick() LOOK FOR BUTTON button =", button)
for key, foo := range Data.AllButtons {
if (Config.Debug) {
log.Println("gui.defaultButtonClick() Data.AllButtons =", key, foo)
// spew.Dump(foo)
}
if Data.AllButtons[key].B == button {
log.Println("\tgui.defaultButtonClick() BUTTON MATCHED")
guiButtonClick(Data.AllButtons[key])
return
}
}
log.Println("\tgui.defaultButtonClick() ERROR: BUTTON NOT FOUND")
if (Config.Debug) {
panic("gui.defaultButtonClick() ERROR: UNMAPPED ui.Button")
}
}
func guiButtonClick(button *GuiButton) {
log.Println("\tgui.guiButtonClick() button.Name =", button.Name)
if button.Custom != nil {
log.Println("\tgui.guiButtonClick() DOING CUSTOM FUNCTION")
button.Custom(button)
return
}
if (Data.MouseClick != nil) {
Data.MouseClick(button)
} else {
log.Println("\tgui.guiButtonClick() IGNORING BUTTON. MouseClick() is nil")
}
}
func (n *Node) AddButton(name string, custom func(*Node)) *Node { func (n *Node) AddButton(name string, custom func(*Node)) *Node {
if (n.Toolkit == nil) { if (n.toolkit == nil) {
log.Println("gui.Node.AppendButton() filed node.Toolkit == nil") log.Println("gui.Node.AppendButton() filed node.toolkit == nil")
panic("gui.Node.AppendButton() filed node.Toolkit == nil") panic("gui.Node.AppendButton() filed node.toolkit == nil")
return n return n
} }
/*
button := ui.NewButton(name)
log.Println("reflect.TypeOF(uiBox) =", reflect.TypeOf(n.uiBox))
log.Println("reflect.TypeOF(uiButton) =", reflect.TypeOf(button))
n.uiBox.Append(button, false)
n.uiButton = button
*/
newNode := n.New(name) newNode := n.New(name)
newNode.Toolkit = n.Toolkit.NewButton(name) newNode.toolkit = n.toolkit.NewButton(name)
newNode.Toolkit.Custom = func() { newNode.toolkit.Custom = func() {
log.Println("gui.AppendButton() Button Clicked. Running custom()") log.Println("gui.AppendButton() Button Clicked. Running custom()")
custom(newNode) custom(newNode)
} }
newNode.custom = custom newNode.custom = custom
/*
button.OnClicked(func(*ui.Button) {
log.Println("gui.AppendButton() Button Clicked. Running custom()")
custom(newNode)
})
*/
// panic("AppendButton")
// time.Sleep(3 * time.Second)
return newNode return newNode
} }
func (n *Node) CreateButton(custom func(*GuiButton), name string, values interface {}) *Node {
newNode := n.AddBox(Xaxis, "test CreateButton")
box := newNode.FindBox()
if (box == nil) {
panic("node.CreateButton().FindBox() == nil")
}
newUiB := ui.NewButton(name)
newUiB.OnClicked(defaultButtonClick)
var newB *GuiButton
newB = new(GuiButton)
newB.B = newUiB
if (box.UiBox == nil) {
log.Println("CreateButton() box.Window == nil")
// ErrorWindow(box.Window, "Login Failed", msg) // can't even do this
panic("maybe print an error and return nil? or make a fake button?")
} else {
// uibox := box.UiBox
// uibox.Append(newUiB, true)
}
newB.Box = box
newB.Custom = custom
newB.Values = values
Data.AllButtons = append(Data.AllButtons, newB)
box.Append(newB.B, false)
return newNode
}
func (n *Node) NewButton(box *GuiBox, custom func(*GuiButton), name string, values interface {}) *GuiButton {
return CreateButton(box, custom, name, values)
}
func CreateButton(box *GuiBox, custom func(*GuiButton), name string, values interface {}) *GuiButton {
newUiB := ui.NewButton(name)
newUiB.OnClicked(defaultButtonClick)
var newB *GuiButton
newB = new(GuiButton)
newB.B = newUiB
if (box.Window == nil) {
log.Println("CreateButton() box.Window == nil")
// ErrorWindow(box.Window, "Login Failed", msg) // can't even do this
panic("maybe print an error and return nil? or make a fake button?")
}
newB.Box = box
newB.Custom = custom
newB.Values = values
Data.AllButtons = append(Data.AllButtons, newB)
box.Append(newB.B, false)
return newB
}
func CreateFontButton(box *GuiBox, action string) *GuiButton {
// create a 'fake' button entry for the mouse clicks
var newGB GuiButton
newGB.Name = "FONT"
newGB.FB = ui.NewFontButton()
newGB.Box = box
Data.AllButtons = append(Data.AllButtons, &newGB)
newGB.FB.OnChanged(func (*ui.FontButton) {
log.Println("FontButton.OnChanged() START mouseClick(&newBM)", newGB)
if (Data.MouseClick != nil) {
Data.MouseClick(&newGB)
}
})
return &newGB
}
func CreateColorButton(box *GuiBox, custom func(*GuiButton), name string, values interface {}) *GuiButton {
// create a 'fake' button entry for the mouse clicks
var newCB GuiButton
newCB.Name = name
newCB.CB = ui.NewColorButton()
newCB.Box = box
newCB.Custom = custom
newCB.Values = values
Data.AllButtons = append(Data.AllButtons, &newCB)
newCB.CB.OnChanged(func (*ui.ColorButton) {
log.Println("ColorButton.OnChanged() START Color Button Click")
r, g, b, a := newCB.CB.Color()
log.Println("ColorButton.OnChanged() Color() =", r, g, b, a)
if (newCB.Custom != nil) {
newCB.Custom(&newCB)
} else if (Data.MouseClick != nil) {
Data.MouseClick(&newCB)
}
})
box.Append(newCB.CB, false)
return &newCB
}

View File

@ -32,26 +32,17 @@ func initGUI() {
addDemoTab(w, "A Second Tab") addDemoTab(w, "A Second Tab")
} }
func addDemoTab(window *gui.Node, title string) { func addDemoTab(w *gui.Node, title string) {
var newNode, g *gui.Node var newNode, g *gui.Node
newNode = window.AddTab(title, nil) newNode = w.NewTab(title)
log.Println("addDemoTab() newNode.Dump")
log.Println("addDemoTab() newNode.Dump")
log.Println("addDemoTab() newNode.Dump")
log.Println("addDemoTab() newNode.Dump")
newNode.Dump()
newNode.Toolkit.Dump()
g = newNode.NewGroup("group 1") g = newNode.NewGroup("group 1")
log.Println("addDemoTab() g.Dump")
log.Println("addDemoTab() g.Dump") dd := g.NewDropdown("demoCombo2")
log.Println("addDemoTab() g.Dump") dd.AddDropdown("more 1")
log.Println("addDemoTab() g.Dump") dd.AddDropdown("less 2")
g.Dump() dd.AddDropdown("foo 3")
g.Toolkit.Dump()
// myExit(nil)
g.AddComboBox("demoCombo2", "more 1", "more 2", "more 3")
} }
func myExit(n *gui.Node) { func myExit(n *gui.Node) {

View File

@ -10,6 +10,8 @@ import (
// This initializes the first window // This initializes the first window
// //
// BUG: THIS PROGRAM DOESN'T EXIT PROPERLY (NOT REALLY A BUG)
//
// Then starts a goroutine to demonstrate how to // Then starts a goroutine to demonstrate how to
// inject things into the GUI // inject things into the GUI
func main() { func main() {

View File

@ -37,13 +37,12 @@ func initGUI() {
func addDemoTab(window *gui.Node, title string) { func addDemoTab(window *gui.Node, title string) {
var newNode, g *gui.Node var newNode, g *gui.Node
newNode = window.AddTab(title, nil) newNode = window.NewTab(title)
log.Println("addDemoTab() newNode.Dump") log.Println("addDemoTab() newNode.Dump")
log.Println("addDemoTab() newNode.Dump") log.Println("addDemoTab() newNode.Dump")
log.Println("addDemoTab() newNode.Dump") log.Println("addDemoTab() newNode.Dump")
log.Println("addDemoTab() newNode.Dump") log.Println("addDemoTab() newNode.Dump")
newNode.Dump() newNode.Dump()
newNode.Toolkit.Dump()
g = newNode.NewGroup("group 1") g = newNode.NewGroup("group 1")
log.Println("addDemoTab() g.Dump") log.Println("addDemoTab() g.Dump")
@ -51,9 +50,11 @@ func addDemoTab(window *gui.Node, title string) {
log.Println("addDemoTab() g.Dump") log.Println("addDemoTab() g.Dump")
log.Println("addDemoTab() g.Dump") log.Println("addDemoTab() g.Dump")
g.Dump() g.Dump()
g.Toolkit.Dump()
// os.Exit(0) // os.Exit(0)
g.AddComboBox("demoCombo2", "more 1", "more 2", "more 3") dd := g.NewDropdown("demoCombo2")
dd.AddDropdown("more 1")
dd.AddDropdown("more 2")
dd.AddDropdown("more 3")
} }
func myDefaultExit(n *gui.Node) { func myDefaultExit(n *gui.Node) {

View File

@ -1,357 +0,0 @@
package gui
import (
"log"
// "time"
// "os"
"github.com/andlabs/ui"
_ "github.com/andlabs/ui/winmanifest"
"github.com/davecgh/go-spew/spew"
)
var names = make([]string, 100)
var nodeNames = make([]string, 100)
var bugWin *Node
/*
Creates a window helpful for debugging this package
*/
func DebugWindow() {
Config.Title = "git.wit.org/wit/gui debug fixme"
Config.Width = 300
Config.Height = 200
Config.Exit = StandardClose
bugWin = NewWindow()
bugWin.DebugTab("does this also work?")
// node.DebugTab("WIT GUI Debug Tab")
}
// TODO: remove this crap
// What does this actually do?
// It populates the nodeNames in a map. No, not a map, an array.
// What is the difference again? (other than one being in order and a predefined length)
func addNodeNameBAD(c *ui.Combobox, s string, id string) {
c.Append(s)
// nodeNames[y] = id
// y = y + 1
log.Println("addNodeName:", s)
// time.Sleep(1 * time.Second)
// os.Exit(0)
}
func makeWindowDebug() *ui.Box {
hbox := ui.NewHorizontalBox()
hbox.SetPadded(true)
/////////////////////////////////////////////////////
vbox := addGroup(hbox, "range Data.WindowMap")
cbox := ui.NewCombobox()
for name, _ := range Data.WindowMap {
if (Config.Debug) {
log.Println("range Data.WindowMap() name =", name)
}
addNameBAD(cbox, name)
}
cbox.SetSelected(0)
vbox.Append(cbox, false)
cbox.OnSelected(func(*ui.Combobox) {
x := cbox.Selected()
log.Println("x =", x)
log.Println("names[x] =", names[x])
dumpBox(names[x])
})
/////////////////////////////////////////////////////
vbox = addGroup(hbox, "Debug Window")
b1 := addButton(vbox, "dumpBox(window)")
b1.OnClicked(func(*ui.Button) {
x := cbox.Selected()
log.Println("x =", x)
log.Println("names[x] =", names[x])
dumpBox(names[x])
})
b2 := addButton(vbox, "SetMargined(tab)")
b2.OnClicked(func(*ui.Button) {
x := cbox.Selected()
log.Println("x =", x)
log.Println("FindWindow; names[x] =", names[x])
gw := FindWindow(names[x])
if gw == nil {
return
}
if gw.UiTab == nil {
return
}
if gw.TabNumber == nil {
return
}
scs := spew.ConfigState{MaxDepth: 1}
scs.Dump(gw)
log.Println("gui.dumpBoxes()\tWindow.UiTab =", gw.UiTab)
log.Println("gui.dumpBoxes()\tWindow.TabNumber =", *gw.TabNumber)
gw.UiTab.SetMargined(*gw.TabNumber, true)
})
b3 := addButton(vbox, "Hide(tab)")
b3.OnClicked(func(*ui.Button) {
x := cbox.Selected()
log.Println("x =", x)
log.Println("FindWindow; names[x] =", names[x])
gw := FindWindow(names[x])
if gw == nil {
return
}
if gw.UiTab == nil {
return
}
gw.UiTab.Hide()
})
b4 := addButton(vbox, "Show(tab)")
b4.OnClicked(func(*ui.Button) {
x := cbox.Selected()
log.Println("x =", x)
log.Println("FindWindow; names[x] =", names[x])
gw := FindWindow(names[x])
if gw == nil {
return
}
if gw.UiTab == nil {
return
}
gw.UiTab.Show()
})
b5 := addButton(vbox, "Delete(tab)")
b5.OnClicked(func(*ui.Button) {
x := cbox.Selected()
log.Println("x =", x)
log.Println("FindWindow; names[x] =", names[x])
gw := FindWindow(names[x])
if gw == nil {
return
}
if gw.UiTab == nil {
return
}
if gw.TabNumber == nil {
return
}
gw.UiTab.Delete(*gw.TabNumber)
})
/////////////////////////////////////////////////////
vbox = addGroup(hbox, "Global Debug")
dump3 := addButton(vbox, "Dump Windows")
dump3.OnClicked(func(*ui.Button) {
dumpWindows()
})
dump2 := addButton(vbox, "Dump Boxes")
dump2.OnClicked(func(*ui.Button) {
dumpBoxes()
})
dump1 := addButton(vbox, "Dump MAP")
dump1.OnClicked(func(*ui.Button) {
dumpMap()
})
/////////////////////////////////////////////////////
nodeBox := addGroup(hbox, "Windows:")
nodeCombo := ui.NewCombobox()
for name, node := range Data.NodeMap {
// if (Config.Debug) {
log.Println("range Data.NodeMap() name =", name)
// }
tmp := node.id + " (" + name + ")"
addNodeNameBAD(nodeCombo, tmp, node.id)
}
// scs := spew.ConfigState{MaxDepth: 1}
// scs.Dump(Data.NodeMap)
// os.Exit(0)
nodeCombo.SetSelected(0)
nodeBox.Append(nodeCombo, false)
nodeCombo.OnSelected(func(*ui.Combobox) {
y := nodeCombo.Selected()
log.Println("y =", y)
log.Println("nodeNames[y] =", nodeNames[y])
node := Data.findId(nodeNames[y])
if (node != nil) {
node.Dump()
}
})
/////////////////////////////////////////////////////
vbox = addGroup(hbox, "Node Debug")
n1 := addButton(vbox, "Data.DumpNodeMap()")
n1.OnClicked(func(*ui.Button) {
Data.DumpNodeMap()
})
n1 = addButton(vbox, "Data.ListChildren(false)")
n1.OnClicked(func(*ui.Button) {
Data.ListChildren(false)
})
n1 = addButton(vbox, "Data.ListChildren(true)")
n1.OnClicked(func(*ui.Button) {
Data.ListChildren(true)
})
n1 = addButton(vbox, "Node.Dump()")
n1.OnClicked(func(*ui.Button) {
y := nodeCombo.Selected()
log.Println("y =", y)
log.Println("nodeNames[y] =", nodeNames[y])
node := Data.findId(nodeNames[y])
if (node != nil) {
node.Dump()
}
})
n1 = addButton(vbox, "Node.ListChildren(false)")
n1.OnClicked(func(*ui.Button) {
y := nodeCombo.Selected()
log.Println("y =", y)
log.Println("nodeNames[y] =", nodeNames[y])
node := Data.findId(nodeNames[y])
if (node != nil) {
node.ListChildren(false)
}
})
n1 = addButton(vbox, "Node.ListChildren(true)")
n1.OnClicked(func(*ui.Button) {
y := nodeCombo.Selected()
log.Println("y =", y)
log.Println("nodeNames[y] =", nodeNames[y])
node := Data.findId(nodeNames[y])
if (node != nil) {
node.ListChildren(true)
}
})
n1 = addButton(vbox, "Node.AddDebugTab")
n1.OnClicked(func(*ui.Button) {
y := nodeCombo.Selected()
log.Println("y =", y)
log.Println("nodeNames[y] =", nodeNames[y])
node := Data.findId(nodeNames[y])
if (node != nil) {
node.DebugTab("added this DebugTab")
}
})
return hbox
}
// TODO: remove this crap
// var x int = 0
// var y int = 0
// TODO: remove this crap
func addNameBAD(c *ui.Combobox, s string) {
c.Append(s)
// names[x] = s
// x = x + 1
log.Println("addName:", s)
// time.Sleep(1 * time.Second)
// os.Exit(0)
}
func addGroup(b *ui.Box, name string) *ui.Box {
group := ui.NewGroup(name)
group.SetMargined(true)
b.Append(group, true)
vbox := ui.NewVerticalBox()
vbox.SetPadded(true)
group.SetChild(vbox)
return vbox
}
func dumpBox(s string) {
var name string
var window *GuiWindow
for name, window = range Data.WindowMap {
if name != s {
continue
}
log.Println("gui.DumpBoxes() MAP: ", name)
if window.TabNumber == nil {
log.Println("gui.DumpBoxes() \tWindows.TabNumber = nil")
} else {
log.Println("gui.DumpBoxes() \tWindows.TabNumber =", *window.TabNumber)
}
log.Println("gui.DumpBoxes()\tWindow.name =", window.Name)
// log.Println("gui.DumpBoxes()\tWindow.UiWindow type =", reflect.TypeOf(window.UiWindow))
log.Println("gui.DumpBoxes()\tWindow.UiWindow =", window.UiWindow)
log.Println("gui.DumpBoxes()\tWindow.UiTab =", window.UiTab)
log.Println("gui.dumpBox() BoxMap START")
for name, abox := range window.BoxMap {
log.Printf("gui.DumpBoxes() \tBOX mapname=%-12s abox.Name=%-12s", name, abox.Name)
abox.Dump()
if name == "MAINBOX" {
if Config.Debug {
scs := spew.ConfigState{MaxDepth: 1}
scs.Dump(abox.UiBox)
}
}
}
log.Println("gui.dumpBox() BoxMap END")
if window.UiTab != nil {
pages := window.UiTab.NumPages()
log.Println("gui.DumpBoxes()\tWindow.UiTab.NumPages() =", pages)
// fixme: tabSetMargined(window.UiTab)
if Config.Debug {
scs := spew.ConfigState{MaxDepth: 2}
scs.Dump(window.UiTab)
}
}
}
}
func addButton(box *ui.Box, name string) *ui.Button {
button := ui.NewButton(name)
button.OnClicked(func(*ui.Button) {
log.Println("Should do something here")
})
box.Append(button, false)
return button
}
func DebugTab() {
bugWin.DebugTab("does this work?")
}
func (n *Node) DebugTab(title string) *Node {
var newN *Node
var b *ui.Box
// var uiBox *ui.Box
// time.Sleep(1 * time.Second)
newN = n.AddTabNew(title + " fix makeWindowDebug")
newN.Toolkit.Dump()
b = makeWindowDebug()
newN.Toolkit.SetTabBox(b)
// FIXME: make sure this is getting run to add padding: tabSetMargined(newN.uiTab)
// os.Exit(0)
return newN
}

162
debug.go
View File

@ -1,162 +0,0 @@
package gui
import (
"fmt"
"log"
"time"
"github.com/davecgh/go-spew/spew"
)
// WatchGUI() opens a goroutine
//
// From that goroutine, it dumps out debugging information every 4 seconds
/*
TODO: add configuration triggers on what to dump out
TODO: allow this to be sent to /var/log, syslogd, systemd's journalctl, etc
*/
/*
func watchGUI() {
count := 0
for {
if count > 20 {
log.Println("Sleep() in watchGUI()")
if Config.Debug {
dumpBoxes()
}
count = 0
}
count += 1
time.Sleep(200 * time.Millisecond)
}
}
*/
func dumpWindows() {
for name, _ := range Data.WindowMap {
log.Println("gui.DumpWindows() window =", name)
}
}
func dumpMap() {
for name, window := range Data.WindowMap {
log.Println("gui.DumpBoxes() MAP: ", name)
log.Println("gui.DumpBoxes() BOXES:", name)
for name, abox := range window.BoxMap {
log.Printf("gui.DumpBoxes() \tBOX mapname=%-12s abox.Name=%-12s", name, abox.Name)
}
}
}
func dumpBoxes() {
for name, window := range Data.WindowMap {
log.Println("gui.DumpBoxes() MAP: ", name)
if window.TabNumber == nil {
log.Println("gui.DumpBoxes() \tWindows.TabNumber = nil")
} else {
log.Println("gui.DumpBoxes() \tWindows.TabNumber =", *window.TabNumber)
}
log.Println("gui.DumpBoxes()\tWindow.name =", window.Name)
// log.Println("gui.DumpBoxes()\tWindow.UiWindow type =", reflect.TypeOf(window.UiWindow))
log.Println("gui.DumpBoxes()\tWindow.UiWindow =", window.UiWindow)
log.Println("gui.DumpBoxes()\tWindow.UiTab =", window.UiTab)
for name, abox := range window.BoxMap {
log.Printf("gui.DumpBoxes() \tBOX mapname=%-12s abox.Name=%-12s", name, abox.Name)
if name == "MAINBOX" {
if Config.Debug {
scs := spew.ConfigState{MaxDepth: 1}
scs.Dump(abox.UiBox)
}
}
}
if window.UiTab != nil {
// log.Println("gui.DumpBoxes()\tWindow.UiTab type =", reflect.TypeOf(window.UiTab))
// log.Println("gui.DumpBoxes()\tWindow.UiTab =", window.UiTab)
pages := window.UiTab.NumPages()
log.Println("gui.DumpBoxes()\tWindow.UiTab.NumPages() =", pages)
// for i := 0; i < pages; i++ {
// log.Println("gui.DumpBoxes()\t\tWindow.UiTab.Margined(", i, ") =", window.UiTab.Margined(i))
// }
// tmp := spew.NewDefaultConfig()
// tmp.MaxDepth = 2
// tmp.Dump(window.UiTab)
if Config.Debug {
scs := spew.ConfigState{MaxDepth: 2}
scs.Dump(window.UiTab)
}
}
}
/*
for i, window := range Data.Windows {
if (window.TabNumber == nil) {
log.Println("gui.DumpBoxes() Data.Windows", i, "Name =", window.Name, "TabNumber = nil")
} else {
log.Println("gui.DumpBoxes() Data.Windows", i, "Name =", window.Name, "TabNumber =", *window.TabNumber)
}
}
*/
}
func addTableTab() {
var parts []TableColumnData
for key, foo := range []string{"BG", "TEXTCOLOR", "BUTTON", "TEXTCOLOR", "TEXTCOLOR", "TEXT", "BUTTON", "TEXT", "BUTTON"} {
log.Println(key, foo)
var b TableColumnData
b.CellType = foo
b.Heading = fmt.Sprintf("heading%d", key)
parts = append(parts, b)
}
log.Println("Sleep for 1 second, then try to add new tabs")
time.Sleep(1 * time.Second)
}
func (dn *GuiData) DumpNodeMap() {
log.Println("DebugDataNodeMap():")
for name, node := range dn.NodeMap {
log.Println("\tNode =", node.id, node.Width, node.Height, name)
if (node.children == nil) {
log.Println("\t\tNo children")
} else {
log.Println("\t\tHas children:", node.children)
}
// node.SetName("yahoo")
// log.Println("\tData.NodeMap node =", node)
}
}
/*
func DebugDataNodeChildren() {
if Data.NodeMap == nil {
log.Println("DebugDataNodeChildren() NodeMap == nil")
return
}
log.Println("DebugDataNodeChildren():")
for name, node := range Data.NodeMap {
log.Println("\tNode name =", node.Width, node.Height, name)
if (node.children == nil) {
log.Println("\t\tNo children")
break
}
log.Println("\t\tHas children:", node.children)
}
}
*/
func (dn *GuiData) ListChildren(dump bool) {
if Data.NodeMap == nil {
log.Println("gui.Data.ListChildren() Data.NodeMap == nil")
return
}
log.Println("gui.Data.ListChildren() Data.NodeMap:")
for name, node := range Data.NodeMap {
log.Println("\tgui.Data.ListChildren() node =", node.id, node.Width, node.Height, name)
if (dump == true) {
node.Dump()
}
node.ListChildren(dump)
}
}

1
doc.go
View File

@ -17,6 +17,7 @@ Principles:
* It's ok to guess. We will return something close. * It's ok to guess. We will return something close.
* Hide complexity internally here * Hide complexity internally here
* Isolate the GUI toolkit * Isolate the GUI toolkit
* Function names should follow https://en.wikipedia.org/wiki/Graphical_widget
Quick Start Quick Start

52
dropdown.go Normal file
View File

@ -0,0 +1,52 @@
package gui
import "log"
import toolkit "git.wit.org/wit/gui/toolkit/andlabs"
func (n *Node) NewDropdown(name string) *Node {
var newT *toolkit.Toolkit
var sNode *Node
log.Println("toolkit.NewDropdown() START", name)
// make this generic
if (n.toolkit == nil) {
log.Println("toolkit.NewSlider() toolkit == nil")
panic("toolkit should never be nil")
}
sNode = n.New(name + " part1")
newT = n.toolkit.NewDropdown(name)
newT.Name = name
sNode.custom = n.custom
newT.Custom = func () {
// TODO: make all of this common code to all the widgets
if (n.custom == nil) {
log.Println("Not Running n.custom(n) == nil")
} else {
log.Println("Running n.custom(n)")
sNode.custom(sNode)
}
if (sNode.OnChanged == nil) {
log.Println("Not Running n.OnChanged(n) == nil")
} else {
log.Println("Running n.OnChanged(n)")
sNode.OnChanged(sNode)
}
}
sNode.toolkit = newT
sNode.Dump()
sNode.toolkit.Dump()
// panic("checking Custom()")
return sNode
}
func (n *Node) AddDropdown(name string) {
n.toolkit.AddDropdown(name)
}
func (n *Node) SetDropdown(i int) {
n.toolkit.SetDropdown(i)
}

156
find.go
View File

@ -1,156 +0,0 @@
package gui
import (
"log"
"os"
"github.com/andlabs/ui"
_ "github.com/andlabs/ui/winmanifest"
// "github.com/davecgh/go-spew/spew"
)
func (n *Node) FindTab() *ui.Tab {
return n.uiTab
}
func (n *Node) FindControl() *ui.Control {
return n.uiControl
}
func (n *Node) FindBox() *GuiBox {
if (n.box != nil) {
return n.box
}
if (n.parent != nil) {
p := n.parent
return p.box
}
return n.box
}
func (n *Node) FindWindowBox() *GuiBox {
if (n.box == nil) {
panic("SERIOUS ERROR n.box == nil in FindWindowBox()")
}
return n.box
}
func (w *GuiWindow) FindNode() *Node {
return w.node
}
func (b *GuiBox) FindNode() *Node {
log.Println("gui.FindNode() on GuiBox")
if b.node != nil {
return b.node
}
Data.ListChildren(true)
b.Dump()
log.Println("gui.FindNode() on GuiBox is nil")
os.Exit(-1)
return nil
}
func FindWindow(s string) *GuiWindow {
for name, window := range Data.WindowMap {
if name == s {
return window
}
}
log.Printf("COULD NOT FIND WINDOW " + s)
return nil
}
func FindBox(s string) *GuiBox {
for name, window := range Data.WindowMap {
if name != s {
continue
}
for name, abox := range window.BoxMap {
log.Printf("gui.DumpBoxes() \tBOX mapname=%-12s abox.Name=%-12s", name, abox.Name)
return abox
}
log.Println("gui.FindBox() NEED TO INIT WINDOW name =", name)
}
log.Println("gui.FindBox() COULD NOT FIND BOX", s)
return nil
}
func FindNode(name string) *Node {
if Data.NodeMap == nil {
log.Println("gui.FindNode() gui.Data.NodeMap == nil")
return nil
}
log.Println("gui.FindNode() searching Data.NodeMap:")
for id, node := range Data.NodeMap {
log.Println("\tData.NodeMap name =", node.Width, node.Height, id)
node.Dump()
if (name == node.Name) {
return node
}
newNode := findByName(node, name)
if (newNode != nil) {
return newNode
}
log.Println("gui.FindNode() could not find node name =", name)
os.Exit(-1)
}
log.Println("gui.FindNode() could not find node name =", name)
return nil
}
func (dn *GuiData) findId(id string) *Node {
if Data.NodeMap == nil {
log.Println("gui.Data.findId() map == nil")
return nil
}
// log.Println("Dumping Data.NodeMap:")
for name, node := range Data.NodeMap {
// log.Println("\tData.NodeMap name =", node.id, node.Width, node.Height, name)
if (id == node.id) {
log.Println("\tgui.Data.findId() found node =", node.id, node.Width, node.Height, name)
return node
}
// TODO: fix // Oct 9
// node.findId(id)
}
return nil
}
func findByIdDFS(node *Node, id string) *Node {
log.Println("findByIdDFS()", id, node)
node.Dump()
if node.id == id {
log.Println("Found node id =", id, node)
return node
}
if len(node.children) > 0 {
for _, child := range node.children {
newNode := findByIdDFS(child, id)
if (newNode != nil) {
return newNode
}
}
}
return nil
}
func findByName(node *Node, name string) *Node {
log.Println("findByName()", name, node)
node.Dump()
if node.Name == name {
log.Println("findByName() Found node name =", name, node)
return node
}
if len(node.children) > 0 {
for _, child := range node.children {
newNode := findByName(child, name)
if (newNode != nil) {
return newNode
}
}
}
return nil
}

View File

@ -11,15 +11,15 @@ func (n *Node) NewGroup(name string) *Node {
var gNode *Node var gNode *Node
log.Println("toolkit.NewGroup() START", name) log.Println("toolkit.NewGroup() START", name)
if (n.Toolkit == nil) { if (n.toolkit == nil) {
log.Println("toolkit.NewGroup() Toolkit == nil") log.Println("toolkit.NewGroup() toolkit == nil")
panic("Toolkit should never be nil") panic("toolkit should never be nil")
} }
// make a *Node with a *toolkit.Group // make a *Node with a *toolkit.Group
gNode = n.New(name + " part1") gNode = n.New(name + " part1")
newT = n.Toolkit.NewGroup(name) newT = n.toolkit.NewGroup(name)
gNode.Toolkit = newT gNode.toolkit = newT
log.Println("################## gNode ####### ", name) log.Println("################## gNode ####### ", name)
gNode.Dump() gNode.Dump()
@ -27,5 +27,5 @@ func (n *Node) NewGroup(name string) *Node {
} }
func (n *Node) AddGroup(title string) *Node { func (n *Node) AddGroup(title string) *Node {
return n.NewGroup(title + "deprecated AddGroup") return n.NewGroup(title + " deprecated AddGroup")
} }

70
gui.go
View File

@ -1,70 +0,0 @@
package gui
import (
"github.com/andlabs/ui" // import "time"
"log"
"regexp"
_ "github.com/andlabs/ui/winmanifest"
)
// the _ means we only need this for the init()
const Xaxis = 0 // box that is horizontal
const Yaxis = 1 // box that is vertical
func init() {
log.Println("gui.init() has been run")
Data.buttonMap = make(map[*ui.Button]*GuiButton)
Data.WindowMap = make(map[string]*GuiWindow)
Data.NodeMap = make(map[string]*Node)
Data.NodeSlice = make([]*Node, 0)
Config.counter = 0
Config.prefix = "wit"
Config.DebugNode = false
Config.DebugTabs = false
}
func GuiInit() {
ui.OnShouldQuit(func() bool {
ui.Quit()
return true
})
}
/*
// string handling examples that might be helpful for normalizeInt()
isAlpha := regexp.MustCompile(`^[A-Za-z]+$`).MatchString
for _, username := range []string{"userone", "user2", "user-three"} {
if !isAlpha(username) {
fmt.Printf("%q is not valid\n", username)
}
}
const alpha = "abcdefghijklmnopqrstuvwxyz"
func alphaOnly(s string) bool {
for _, char := range s {
if !strings.Contains(alpha, strings.ToLower(string(char))) {
return false
}
}
return true
}
*/
func normalizeInt(s string) string {
// reg, err := regexp.Compile("[^a-zA-Z0-9]+")
reg, err := regexp.Compile("[^0-9]+")
if err != nil {
log.Println("normalizeInt() regexp.Compile() ERROR =", err)
return s
}
clean := reg.ReplaceAllString(s, "")
log.Println("normalizeInt() s =", clean)
return clean
}

10
int.go
View File

@ -20,12 +20,12 @@ func (n *Node) Int() int {
scs.Dump(n) scs.Dump(n)
} }
if (n.Toolkit == nil) { if (n.toolkit == nil) {
log.Println("gui.Node.Int() for toolkit struct = nil") log.Println("gui.Node.Int() for toolkit struct = nil")
return 0 return 0
} }
i := n.Toolkit.Value() i := n.toolkit.Value()
return i return i
} }
@ -36,11 +36,11 @@ func (n *Node) Value() int {
func (n *Node) SetValue(i int) { func (n *Node) SetValue(i int) {
log.Println("gui.SetValue() START") log.Println("gui.SetValue() START")
if (n.Toolkit == nil) { if (n.toolkit == nil) {
log.Println("gui.Node.SetValue() for toolkit struct = nil") log.Println("gui.Node.SetValue() for toolkit struct = nil")
panic("SetValue failed") panic("SetValue failed")
} }
n.Dump() n.Dump()
n.Toolkit.Dump() n.toolkit.Dump()
n.Toolkit.SetValue(i) n.toolkit.SetValue(i)
} }

46
main.go
View File

@ -2,14 +2,38 @@ package gui
import ( import (
"log" "log"
"github.com/andlabs/ui"
_ "github.com/andlabs/ui/winmanifest"
) )
import toolkit "git.wit.org/wit/gui/toolkit/andlabs"
// the _ means we only need this for the init()
const Xaxis = 0 // box that is horizontal
const Yaxis = 1 // box that is vertical
func init() {
log.Println("gui.init() has been run")
Config.counter = 0
Config.prefix = "wit"
Config.DebugNode = false
Config.DebugTabs = false
title := "master"
w := 640
h := 480
f := StandardClose
Config.master = addNode(title, w, h)
Config.master.custom = f
Config.master.Dump()
}
func Main(f func()) { func Main(f func()) {
log.Println("Starting gui.Main() (using gtk via andlabs/ui)") log.Println("Starting gui.Main() (using gtk via andlabs/ui)")
ui.Main(f) toolkit.Main(f)
} }
// Other goroutines must use this to access the GUI // Other goroutines must use this to access the GUI
@ -17,18 +41,8 @@ func Main(f func()) {
// You can not acess / process the GUI thread directly from // You can not acess / process the GUI thread directly from
// other goroutines. This is due to the nature of how // other goroutines. This is due to the nature of how
// Linux, MacOS and Windows work (they all work differently. suprise. surprise.) // Linux, MacOS and Windows work (they all work differently. suprise. surprise.)
// For example: gui.Queue(addNewTabForColorSelection()) // For example: gui.Queue(NewWindow())
func Queue(f func()) { func Queue(f func()) {
log.Println("Sending function to gui.Main() (using gtk via andlabs/ui)") log.Println("Sending function to gui.Main() (using gtk via andlabs/ui)")
ui.QueueMain(f) toolkit.Queue(f)
} }
/*
func ExampleWindow() {
log.Println("START gui.ExampleWindow()")
Config.Title = "ExampleWindow"
node := NewWindow()
node.AddDebugTab("jcarr Debug")
}
*/

View File

@ -1,241 +0,0 @@
package gui
import (
"log"
// "github.com/davecgh/go-spew/spew"
"github.com/andlabs/ui"
_ "github.com/andlabs/ui/winmanifest"
)
import toolkit "git.wit.org/wit/gui/toolkit/andlabs"
type Element int
// https://ieftimov.com/post/golang-datastructures-trees/
const (
Unknown Element = iota
Window
Tab
Box
Label
Combo
)
func (s Element) String() string {
switch s {
case Window:
return "window"
case Tab:
return "tab"
case Box:
return "box"
case Label:
return "label"
case Combo:
return "combo"
}
return "unknown"
}
// The Node is simply the name and the size of whatever GUI element exists
type Node struct {
id string
Name string
Width int
Height int
parent *Node
children []*Node
window *GuiWindow
box *GuiBox
custom func(*Node)
OnChanged func(*Node)
Toolkit *toolkit.Toolkit
uiControl *ui.Control
uiButton *ui.Button
uiGroup *ui.Group
uiSlider *ui.Slider
uiSpinbox *ui.Spinbox
uiWindow *ui.Window
uiTab *ui.Tab
uiBox *ui.Box
uiText *ui.EditableCombobox
}
func (n *Node) Parent() *Node {
return n.parent
}
func (n *Node) Window() *Node {
return n.parent
}
func (n *Node) Dump() {
IndentPrintln("id = ", n.id)
IndentPrintln("Name = ", n.Name)
IndentPrintln("Width = ", n.Width)
IndentPrintln("Height = ", n.Height)
if (n.parent == nil) {
IndentPrintln("parent = nil")
} else {
IndentPrintln("parent =", n.parent.id)
}
if (n.children != nil) {
IndentPrintln("children = ", n.children)
}
if (n.window != nil) {
IndentPrintln("window = ", n.window)
}
if (n.box != nil) {
IndentPrintln("box = ", n.box)
}
if (n.uiWindow != nil) {
IndentPrintln("uiWindow = ", n.uiWindow)
}
if (n.uiTab != nil) {
IndentPrintln("uiTab = ", n.uiTab)
}
if (n.uiBox != nil) {
IndentPrintln("uiBox = ", n.uiBox)
}
if (n.Toolkit != nil) {
IndentPrintln("Toolkit = ", n.Toolkit)
n.Toolkit.Dump()
}
if (n.uiControl != nil) {
IndentPrintln("uiControl = ", n.uiControl)
}
if (n.uiButton != nil) {
IndentPrintln("uiButton = ", n.uiButton)
}
if (n.custom != nil) {
IndentPrintln("custom = ", n.custom)
}
if (n.OnChanged != nil) {
IndentPrintln("OnChanged = ", n.OnChanged)
}
if (n.id == "") {
// Node structs should never have a nil id.
// I probably shouldn't panic here, but this is just to check the sanity of
// the gui package to make sure it's not exiting
panic("gui.Node.Dump() id == nil TODO: make a unigue id here in the golang gui library")
}
}
func (n *Node) SetBox(box *GuiBox) {
n.box = box
}
func (n *Node) SetName(name string) {
// n.uiType.SetName(name)
if (n.uiWindow != nil) {
log.Println("node is a window. setting title =", name)
n.uiWindow.SetTitle(name)
return
}
log.Println("*ui.Control =", n.uiControl)
return
}
func (n *Node) Append(child *Node) {
// if (n.UiBox == nil) {
// return
// }
n.children = append(n.children, child)
if (Config.Debug) {
log.Println("child node:")
child.Dump()
log.Println("parent node:")
n.Dump()
}
// time.Sleep(3 * time.Second)
}
func (n *Node) List() {
findByIdDFS(n, "test")
}
var listChildrenParent *Node
var listChildrenDepth int = 0
var defaultPadding = " "
func IndentPrintln(a ...interface{}) {
indentPrintln(listChildrenDepth, defaultPadding, a)
}
func indentPrintln(depth int, format string, a ...interface{}) {
var tabs string
for i := 0; i < depth; i++ {
tabs = tabs + format
}
// newFormat := tabs + strconv.Itoa(depth) + " " + format
newFormat := tabs + format
log.Println(newFormat, a)
}
func (n *Node) ListChildren(dump bool) {
indentPrintln(listChildrenDepth, defaultPadding, n.id, n.Width, n.Height, n.Name)
if (dump == true) {
n.Dump()
}
if len(n.children) == 0 {
if (n.parent == nil) {
} else {
if (Config.DebugNode) {
log.Println("\t\t\tparent =",n.parent.id)
}
if (listChildrenParent != nil) {
if (Config.DebugNode) {
log.Println("\t\t\tlistChildrenParent =",listChildrenParent.id)
}
if (listChildrenParent.id != n.parent.id) {
log.Println("parent.child does not match child.parent")
panic("parent.child does not match child.parent")
}
}
}
if (Config.DebugNode) {
log.Println("\t\t", n.id, "has no children")
}
return
}
for _, child := range n.children {
// log.Println("\t\t", child.id, child.Width, child.Height, child.Name)
if (child.parent != nil) {
if (Config.DebugNode) {
log.Println("\t\t\tparent =",child.parent.id)
}
} else {
log.Println("\t\t\tno parent")
panic("no parent")
}
if (dump == true) {
child.Dump()
}
if (Config.DebugNode) {
if (child.children == nil) {
log.Println("\t\t", child.id, "has no children")
} else {
log.Println("\t\t\tHas children:", child.children)
}
}
listChildrenParent = n
listChildrenDepth += 1
child.ListChildren(dump)
listChildrenDepth -= 1
}
return
}

View File

@ -28,13 +28,6 @@ func addNode(title string, w int, h int) *Node {
id := Config.prefix + strconv.Itoa(Config.counter) id := Config.prefix + strconv.Itoa(Config.counter)
Config.counter += 1 Config.counter += 1
n.id = id n.id = id
/*
if (Data.NodeMap[title] != nil) {
panic(fmt.Sprintf("Duplicate window name = %s\n", title))
} else {
Data.NodeMap[title] = &n
}
*/
return &n return &n
} }

View File

@ -10,17 +10,34 @@ func (n *Node) NewSlider(name string, x int, y int) *Node {
log.Println("toolkit.NewSlider() START", name) log.Println("toolkit.NewSlider() START", name)
if (n.Toolkit == nil) { if (n.toolkit == nil) {
log.Println("toolkit.NewSlider() Toolkit == nil") log.Println("toolkit.NewSlider() toolkit == nil")
panic("Toolkit should never be nil") panic("Toolkit should never be nil")
} }
// make a *Node with a *toolkit.Group // make a *Node with a *toolkit.Group
sNode = n.New(name + " part1") sNode = n.New(name + " part1")
newT = n.Toolkit.NewSlider(name, x, y) newT = n.toolkit.NewSlider(name, x, y)
newT.Name = name newT.Name = name
sNode.Toolkit = newT sNode.custom = n.custom
newT.Custom = func () {
// TODO: make all of this common code to all the widgets
if (n.custom == nil) {
log.Println("Not Running n.custom(n) == nil")
} else {
log.Println("Running n.custom(n)")
sNode.custom(sNode)
}
if (sNode.OnChanged == nil) {
log.Println("Not Running n.OnChanged(n) == nil")
} else {
log.Println("Running n.OnChanged(n)")
sNode.OnChanged(sNode)
}
}
sNode.toolkit = newT
sNode.Dump() sNode.Dump()
// panic("checking Custom()")
return sNode return sNode
} }

View File

@ -1,23 +0,0 @@
package gui
import "log"
import toolkit "git.wit.org/wit/gui/toolkit/andlabs"
func (n *Node) NewSpinbox(name string, x int, y int) *Node {
// make new node here
log.Println("toolkit.NewSpinbox", x, y)
newNode := n.New(name)
t := toolkit.NewSpinbox(n.uiBox, name, x, y)
t.OnChanged = func(t *toolkit.Toolkit) {
log.Println("toolkit.NewSpinbox() value =", t.Value())
if (newNode.OnChanged != nil) {
newNode.OnChanged(newNode)
}
}
newNode.Toolkit = t
return newNode
}

26
spinner.go Normal file
View File

@ -0,0 +1,26 @@
package gui
import "log"
import toolkit "git.wit.org/wit/gui/toolkit/andlabs"
func (n *Node) NewSpinner(name string, x int, y int) *Node {
var newT *toolkit.Toolkit
var sNode *Node
log.Println("toolkit.NewSpinner() START", name)
if (n.toolkit == nil) {
log.Println("toolkit.NewSpinner() toolkit == nil")
panic("toolkit should never be nil")
}
// make a *Node with a *toolkit.Group
sNode = n.New(name + " part1")
newT = n.toolkit.NewSpinner(name, x, y)
newT.Name = name
sNode.toolkit = newT
sNode.Dump()
return sNode
}

View File

@ -1,31 +1,38 @@
package gui package gui
import ( import (
"image/color"
"log" "log"
"github.com/andlabs/ui"
"golang.org/x/image/font"
// "github.com/davecgh/go-spew/spew"
// _ "github.com/andlabs/ui/winmanifest"
) )
import toolkit "git.wit.org/wit/gui/toolkit/andlabs"
// //
// All GUI Data Structures and functions that are external // All GUI Data Structures and functions that are external
// If you need cross platform support, these might only // within the toolkit/ abstraction layer
// be the safe way to interact with the GUI
// //
var Data GuiData // More than one Window is not supported in a cross platform
// sense & may never be. On many toolkits you have to have 'tabs'
// Native Windows and MacOS toolkits work with tabs
//
// If that is the case, this code should abstract the concept of
// windows and make everything 'tabs'
//
var Config GuiConfig var Config GuiConfig
type GuiConfig struct { type GuiConfig struct {
// This is the master node. The Binary Tree starts here
master *Node
// These are shortcuts to pass default values to make a new window
Title string Title string
Width int Width int
Height int Height int
Exit func(*Node) Exit func(*Node)
// These are global debugging settings
// TODO: move to a standard logging system
Debug bool Debug bool
DebugNode bool DebugNode bool
DebugTabs bool DebugTabs bool
@ -33,295 +40,190 @@ type GuiConfig struct {
DebugWindow bool DebugWindow bool
DebugToolkit bool DebugToolkit bool
// hacks
depth int depth int
counter int // used to make unique ID's counter int // used to make unique ID's
prefix string prefix string
} }
type GuiData struct { type Widget int
// a fallback default function to handle mouse events
// if nothing else is defined to handle them
MouseClick func(*GuiButton)
// A map of all the entry boxes // https://ieftimov.com/post/golang-datastructures-trees/
AllEntries []*GuiEntry const (
WindowMap map[string]*GuiWindow Unknown Widget = iota
Window
Tab
Frame
Dropbox
Spinner
Label
)
// Store access to everything via binary tree's func (s Widget) String() string {
NodeMap map[string]*Node switch s {
NodeArray []*Node case Window:
NodeSlice []*Node return "Window"
case Tab:
// A map of all buttons everywhere on all return "Tab"
// windows, all tabs, across all goroutines case Frame:
// This is "GLOBAL" return "Frame"
// case Label:
// This has to work this way because of how return "Label"
// andlabs/ui & andlabs/libui work case Dropbox:
AllButtons []*GuiButton return "Dropbox"
buttonMap map[*ui.Button]*GuiButton
}
type GuiTab struct {
Name string // field for human readable name
Number int // the andlabs/ui tab index
Window *GuiWindow // the parent Window
}
//
// stores information on the 'window'
//
// This merges the concept of andlabs/ui *Window and *Tab
//
// More than one Window is not supported in a cross platform
// sense & may never be. On Windows and MacOS, you have to have
// 'tabs'. Even under Linux, more than one Window is currently
// unstable
//
// This code will make a 'GuiWindow' regardless of if it is
// a stand alone window (which is more or less working on Linux)
// or a 'tab' inside a window (which is all that works on MacOS
// and MSWindows.
//
// This struct keeps track of what is in the window so you
// can destroy and replace it with something else
//
type GuiWindow struct {
Name string // field for human readable name
Width int
Height int
Axis int // does it add items to the X or Y axis
TabNumber *int // the andlabs/ui tab index
// the callback function to make the window contents
// MakeWindow func(*GuiBox) *GuiBox
// the components of the window
BoxMap map[string]*GuiBox
EntryMap map[string]*GuiEntry
Area *GuiArea
node *Node
// andlabs/ui abstraction mapping
UiWindow *ui.Window
UiTab *ui.Tab // if this != nil, the window is 'tabbed'
}
func (w *GuiWindow) Dump() {
log.Println("gui.GuiWindow.Dump() Name = ", w.Name)
log.Println("gui.GuiWindow.Dump() node = ", w.node)
log.Println("gui.GuiWindow.Dump() Width = ", w.Width)
log.Println("gui.GuiWindow.Dump() Height = ", w.Height)
}
// GuiBox is any type of ui.Hbox or ui.Vbox
// There can be lots of these for each GuiWindow
type GuiBox struct {
Name string // field for human readable name
Axis int // does it add items to the X or Y axis
Window *GuiWindow // the parent Window
node *Node
// andlabs/ui abstraction mapping
UiBox *ui.Box
}
func (b *GuiBox) Dump() {
log.Println("gui.GuiBox.Dump() Name = ", b.Name)
log.Println("gui.GuiBox.Dump() Axis = ", b.Axis)
log.Println("gui.GuiBox.Dump() GuiWindow = ", b.Window)
log.Println("gui.GuiBox.Dump() node = ", b.node)
log.Println("gui.GuiBox.Dump() UiBox = ", b.UiBox)
}
func (b *GuiBox) SetTitle(title string) {
log.Println("DID IT!", title)
if b.Window == nil {
return
} }
if b.Window.UiWindow == nil { return "unknown"
return }
// The Node is simply the name and the size of whatever GUI element exists
type Node struct {
id string
Name string
Width int
Height int
parent *Node
children []*Node
custom func(*Node)
OnChanged func(*Node)
toolkit *toolkit.Toolkit
}
func (n *Node) Parent() *Node {
return n.parent
}
func (n *Node) Window() *Node {
return n.parent
}
func (n *Node) Dump() {
IndentPrintln("id = ", n.id)
IndentPrintln("Name = ", n.Name)
IndentPrintln("Width = ", n.Width)
IndentPrintln("Height = ", n.Height)
if (n.parent == nil) {
IndentPrintln("parent = nil")
} else {
IndentPrintln("parent =", n.parent.id)
} }
b.Window.UiWindow.SetTitle(title) if (n.children != nil) {
IndentPrintln("children = ", n.children)
}
if (n.toolkit != nil) {
IndentPrintln("toolkit = ", n.toolkit)
n.toolkit.Dump()
}
if (n.custom != nil) {
IndentPrintln("custom = ", n.custom)
}
if (n.OnChanged != nil) {
IndentPrintln("OnChanged = ", n.OnChanged)
}
if (n.id == "") {
// Node structs should never have a nil id.
// I probably shouldn't panic here, but this is just to check the sanity of
// the gui package to make sure it's not exiting
panic("gui.Node.Dump() id == nil TODO: make a unigue id here in the golang gui library")
}
}
func (n *Node) SetName(name string) {
n.toolkit.SetWindowTitle(name)
return return
} }
func (w *GuiWindow) SetNode(n *Node) { func (n *Node) Append(child *Node) {
if (w.node != nil) { n.children = append(n.children, child)
w.Dump() if (Config.Debug) {
panic("gui.SetNode() Error not nil") log.Println("child node:")
} child.Dump()
w.node = n log.Println("parent node:")
if (w.node == nil) { n.Dump()
w.Dump()
panic("gui.SetNode() node == nil")
} }
// time.Sleep(3 * time.Second)
} }
func (b *GuiBox) SetNode(n *Node) { /*
if (b.node != nil) { func (n *Node) List() {
b.Dump() findByIdDFS(n, "test")
panic("gui.SetNode() Error not nil") }
} */
b.node = n
if (b.node == nil) { var listChildrenParent *Node
b.Dump() var listChildrenDepth int = 0
panic("gui.SetNode() node == nil") var defaultPadding = " "
}
func IndentPrintln(a ...interface{}) {
indentPrintln(listChildrenDepth, defaultPadding, a)
} }
func (b *GuiBox) Append(child ui.Control, x bool) { func indentPrintln(depth int, format string, a ...interface{}) {
if b.UiBox == nil { var tabs string
// spew.Dump(b) for i := 0; i < depth; i++ {
b.Dump() tabs = tabs + format
panic("GuiBox.Append() can't work. UiBox == nil") }
// newFormat := tabs + strconv.Itoa(depth) + " " + format
newFormat := tabs + format
log.Println(newFormat, a)
}
func (n *Node) ListChildren(dump bool) {
indentPrintln(listChildrenDepth, defaultPadding, n.id, n.Width, n.Height, n.Name)
if (dump == true) {
n.Dump()
}
if len(n.children) == 0 {
if (n.parent == nil) {
} else {
if (Config.DebugNode) {
log.Println("\t\t\tparent =",n.parent.id)
}
if (listChildrenParent != nil) {
if (Config.DebugNode) {
log.Println("\t\t\tlistChildrenParent =",listChildrenParent.id)
}
if (listChildrenParent.id != n.parent.id) {
log.Println("parent.child does not match child.parent")
panic("parent.child does not match child.parent")
}
}
}
if (Config.DebugNode) {
log.Println("\t\t", n.id, "has no children")
}
return return
} }
b.UiBox.Append(child, x) for _, child := range n.children {
// log.Println("\t\t", child.id, child.Width, child.Height, child.Name)
if (child.parent != nil) {
if (Config.DebugNode) {
log.Println("\t\t\tparent =",child.parent.id)
}
} else {
log.Println("\t\t\tno parent")
panic("no parent")
}
if (dump == true) {
child.Dump()
}
if (Config.DebugNode) {
if (child.children == nil) {
log.Println("\t\t", child.id, "has no children")
} else {
log.Println("\t\t\tHas children:", child.children)
}
}
listChildrenParent = n
listChildrenDepth += 1
child.ListChildren(dump)
listChildrenDepth -= 1
}
return
} }
// Note: every mouse click is handled
// as a 'Button' regardless of where
// the user clicks it. You could probably
// call this 'GuiMouseClick'
type GuiButton struct {
Name string // field for human readable name
Box *GuiBox // what box the button click was in
// a callback function for the main application
Custom func(*GuiButton)
Values interface{}
Color color.RGBA
// andlabs/ui abstraction mapping
B *ui.Button
FB *ui.FontButton
CB *ui.ColorButton
}
// text entry fields
type GuiEntry struct {
Name string // field for human readable name
Edit bool
Last string // the last value
Normalize func(string) string // function to 'normalize' the data
B *GuiButton
Box *GuiBox
// andlabs/ui abstraction mapping
UiEntry *ui.Entry
}
//
// AREA STRUCTURES START
// AREA STRUCTURES START
// AREA STRUCTURES START
//
type GuiArea struct {
Button *GuiButton // what button handles mouse events
Box *GuiBox
UiAttrstr *ui.AttributedString
UiArea *ui.Area
}
type FontString struct {
S string
Size int
F font.Face
W font.Weight
}
//
// AREA STRUCTURES END
// AREA STRUCTURES END
// AREA STRUCTURES END
//
//
// TABLE DATA STRUCTURES START
// TABLE DATA STRUCTURES START
// TABLE DATA STRUCTURES START
//
//
// This is the structure that andlabs/ui uses to pass information
// to the GUI. This is the "authoritative" data.
//
type TableData struct {
RowCount int // This is the number of 'rows' which really means data elements not what the human sees
RowWidth int // This is how wide each row is
Rows []RowData // This is all the table data by row
generatedColumnTypes []ui.TableValue // generate this dynamically
Cells [20]CellData
Human [20]HumanMap
Box *GuiBox
lastRow int
lastColumn int
}
//
// This maps the andlabs/ui & libui components into a "human"
// readable cell reference list. The reason is that there
// are potentially 3 values for each cell. The Text, the Color
// and an image. These are not always needed so the number
// of fields varies between 1 and 3. Internally, the toolkit
// GUI abstraction needs to list all of them, but it's then
// hard to figure out which column goes with the columns that
// you see when you visually are looking at it like a spreadsheet
//
// This makes a map so that we can say "give me the value at
// row 4 and column 2" and find the fields that are needed
//
// TODO: re-add images and the progress bar (works in andlabs/ui)
//
type HumanCellData struct {
Name string // what kind of row is this?
Text string
TextID int
Color color.RGBA
ColorID int
Button *GuiButton
}
type HumanMap struct {
Name string // what kind of row is this?
TextID int
ColorID int
}
type TableColumnData struct {
Index int
CellType string
Heading string
Color string
}
type CellData struct {
Index int
HumanID int
Name string // what type of cell is this?
}
// hmm. will this stand the test of time?
type RowData struct {
Name string // what kind of row is this?
Status string // status of the row?
/*
// TODO: These may or may not be implementable
// depending on if it's possible to detect the bgcolor or what row is selected
click func() // what function to call if the user clicks on it
doubleclick func() // what function to call if the user double clicks on it
*/
HumanData [20]HumanCellData
}
//
// TABLE DATA STRUCTURES END
//

65
tab.go
View File

@ -2,76 +2,25 @@ package gui
import ( import (
"log" "log"
"os"
"github.com/andlabs/ui"
_ "github.com/andlabs/ui/winmanifest"
) )
// import toolkit "git.wit.org/wit/gui/toolkit/andlabs"
// This function should make a new node with the parent and // This function should make a new node with the parent and
// the 'tab' as a child // the 'tab' as a child
func (n *Node) NewTab(title string) *Node { func (n *Node) NewTab(title string) *Node {
log.Println("gui.Node.AddTab() START name =", title) log.Println("gui.Node.NewTab() START name =", title)
return n.AddTabNew(title) // TODO: standardize these checks somewhere
} if (n.toolkit == nil) {
func (n *Node) AddTabNew(title string) *Node {
log.Println("gui.Node.AddTab() START name =", title)
if (n.Toolkit == nil) {
log.Println("FUCK TOOLKIT nil uiWindow =", n.uiWindow)
log.Println("FUCK TOOLKIT nil uiTab =", n.uiTab)
log.Println("FUCK TOOLKIT nil Toolkit =", n.Toolkit)
// return n.AddTab(title) // need to make a toolkit here
n.Dump() n.Dump()
os.Exit(0) panic("NewTab() failed. toolkit == nil")
} }
log.Println("Make new node") log.Println("Make new node")
newN := n.New(title) newN := n.New(title)
log.Println("Add tab to window") log.Println("New tab to window")
t := n.Toolkit.AddTab(title) t := n.toolkit.AddTab(title)
newN.Toolkit = t newN.toolkit = t
n.Append(newN) n.Append(newN)
return newN return newN
} }
func (n *Node) AddTab(title string, uiC *ui.Box) *Node {
return n.AddTabNew(title)
}
/*
func (n *Node) AddTabBAD(title string, uiC *ui.Box) *Node {
parent := n
log.Println("gui.Node.AddTab() START name =", title)
if parent.uiWindow == nil {
parent.Dump()
log.Println("gui.Node.AddTab() ERROR ui.Window == nil")
return nil
}
if parent.uiTab == nil {
inittab := ui.NewTab() // no, not that 'inittab'
parent.uiWindow.SetChild(inittab)
parent.uiWindow.SetMargined(true)
parent.uiTab = inittab
}
tab := parent.uiTab
parent.uiWindow.SetMargined(true)
if (uiC == nil) {
hbox := ui.NewHorizontalBox()
hbox.SetPadded(true)
uiC = hbox
}
tab.Append(title, uiC)
newNode := n.New(title)
newNode.uiTab = tab
newNode.uiBox = uiC
// tabSetMargined(newNode.uiTab)
return newNode
}
*/

62
text.go
View File

@ -2,8 +2,7 @@ package gui
import "log" import "log"
import "errors" import "errors"
import "regexp"
// import toolkit "git.wit.org/wit/gui/toolkit/andlabs"
// functions for handling text related GUI elements // functions for handling text related GUI elements
@ -12,29 +11,52 @@ func (n *Node) NewLabel(text string) *Node {
newNode := n.New(text) newNode := n.New(text)
newNode.Dump() newNode.Dump()
t := n.Toolkit.NewLabel(text) t := n.toolkit.NewLabel(text)
newNode.Toolkit = t newNode.toolkit = t
return newNode return newNode
} }
func (n *Node) SetText(value string) error { func (n *Node) SetText(value string) error {
log.Println("gui.SetText() value =", value) log.Println("gui.SetText() value =", value)
if (n.Toolkit != nil) { panic("redo SetText()")
n.Toolkit.SetText(value)
return nil
}
if (n.uiText != nil) {
n.uiText.SetText(value)
return nil
}
if (n.uiButton != nil) {
n.uiButton.SetText(value)
return nil
}
if (n.uiWindow != nil) {
n.uiWindow.SetTitle(value)
return nil
}
return errors.New("nothing found for gui.Node.SetText()") return errors.New("nothing found for gui.Node.SetText()")
} }
/*
// string handling examples that might be helpful for normalizeInt()
isAlpha := regexp.MustCompile(`^[A-Za-z]+$`).MatchString
for _, username := range []string{"userone", "user2", "user-three"} {
if !isAlpha(username) {
fmt.Printf("%q is not valid\n", username)
}
}
const alpha = "abcdefghijklmnopqrstuvwxyz"
func alphaOnly(s string) bool {
for _, char := range s {
if !strings.Contains(alpha, strings.ToLower(string(char))) {
return false
}
}
return true
}
*/
func normalizeInt(s string) string {
// reg, err := regexp.Compile("[^a-zA-Z0-9]+")
reg, err := regexp.Compile("[^0-9]+")
if err != nil {
log.Println("normalizeInt() regexp.Compile() ERROR =", err)
return s
}
clean := reg.ReplaceAllString(s, "")
log.Println("normalizeInt() s =", clean)
return clean
}
func (n *Node) GetText() string {
return n.toolkit.GetText()
}

View File

@ -14,9 +14,10 @@ func BlankWindow(w *ui.Window) *ui.Box {
return hbox return hbox
} }
func DemoNumbersPage(w *ui.Window) *Toolkit { func (t *Toolkit) DemoNumbersPage() {
var t Toolkit var w *ui.Window
w = t.uiWindow
t.uiBox = makeNumbersPage() t.uiBox = makeNumbersPage()
t.uiBox.SetPadded(true) t.uiBox.SetPadded(true)
w.SetChild(t.uiBox) w.SetChild(t.uiBox)
@ -27,8 +28,6 @@ func DemoNumbersPage(w *ui.Window) *Toolkit {
scs := spew.ConfigState{MaxDepth: 1} scs := spew.ConfigState{MaxDepth: 1}
scs.Dump(t) scs.Dump(t)
} }
return &t
} }
/* /*

View File

@ -0,0 +1,74 @@
package toolkit
import "log"
import "os"
// import "time"
import "github.com/andlabs/ui"
import _ "github.com/andlabs/ui/winmanifest"
import "github.com/davecgh/go-spew/spew"
func (pt *Toolkit) NewDropdown(title string) *Toolkit {
// make new node here
log.Println("gui.Toolbox.NewDropdownCombobox()")
var newt Toolkit
if (pt.uiBox == nil) {
log.Println("gui.ToolboxNode.NewDropdown() node.UiBox == nil. I can't add a range UI element without a place to put it")
os.Exit(0)
return nil
}
s := ui.NewCombobox()
newt.uiCombobox = s
newt.uiBox = pt.uiBox
pt.uiBox.Append(s, false)
// initialize the index
newt.c = 0
newt.val = make(map[int]string)
s.OnSelected(func(spin *ui.Combobox) {
i := spin.Selected()
if (newt.val == nil) {
log.Println("make map didn't work")
os.Exit(0)
}
newt.text = newt.val[i]
val := newt.text
log.Println("gui.Toolbox.ui.Dropdown.OnChanged() val =", i, val)
if (DebugToolkit) {
log.Println("gui.Toolbox.ui.OnChanged() val =", i, val)
scs := spew.ConfigState{MaxDepth: 1}
scs.Dump(newt)
}
if (newt.OnChanged != nil) {
log.Println("gui.Toolbox.OnChanged() trying to run toolkit.OnChanged() entered val =", i, val)
newt.OnChanged(&newt)
return
}
if (newt.Custom != nil) {
log.Println("gui.Toolbox.OnChanged() Running toolkit.Custom()", i, val)
newt.Custom()
return
}
log.Println("gui.Toolbox.Dropdown.OnChanged() ENDED without finding any callback", i, val)
})
return &newt
}
func (t *Toolkit) AddDropdown(title string) {
t.uiCombobox.Append(title)
if (t.val == nil) {
log.Println("make map didn't work")
return
}
t.val[t.c] = title
t.c = t.c + 1
}
func (t Toolkit) SetDropdown(i int) {
t.uiCombobox.SetSelected(i)
}

26
toolkit/andlabs/main.go Normal file
View File

@ -0,0 +1,26 @@
package toolkit
import (
"log"
"github.com/andlabs/ui"
_ "github.com/andlabs/ui/winmanifest"
)
func Main(f func()) {
log.Println("Starting gui.Main() (using gtk via andlabs/ui)")
ui.Main(f)
}
// 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.)
//
// For example: Queue(NewWindow())
//
func Queue(f func()) {
log.Println("Sending function to gui.Main() (using gtk via andlabs/ui)")
ui.QueueMain(f)
}

View File

@ -0,0 +1,25 @@
package gui
import "log"
import "os"
import "github.com/andlabs/ui"
import _ "github.com/andlabs/ui/winmanifest"
func HorizontalBreak(box *GuiBox) {
log.Println("VerticalSeparator added to box =", box.Name)
tmp := ui.NewHorizontalSeparator()
if (box == nil) {
return
}
if (box.UiBox == nil) {
return
}
box.UiBox.Append(tmp, false)
}
func VerticalBreak(box *GuiBox) {
log.Println("VerticalSeparator added to box =", box.Name)
tmp := ui.NewVerticalSeparator()
box.UiBox.Append(tmp, false)
}

View File

@ -0,0 +1,273 @@
package gui
import (
"image/color"
"github.com/andlabs/ui"
// "golang.org/x/image/font"
// "github.com/davecgh/go-spew/spew"
// _ "github.com/andlabs/ui/winmanifest"
)
//
// All GUI Data Structures and functions that are external
// If you need cross platform support, these might only
// be the safe way to interact with the GUI
//
var Data GuiData
var Config GuiConfig
type GuiConfig struct {
Title string
Width int
Height int
Exit func(*Node)
Debug bool
DebugNode bool
DebugTabs bool
DebugTable bool
DebugWindow bool
DebugToolkit bool
depth int
counter int // used to make unique ID's
prefix string
}
type GuiData struct {
// a fallback default function to handle mouse events
// if nothing else is defined to handle them
MouseClick func(*GuiButton)
// A map of all the entry boxes
// AllEntries []*GuiEntry
WindowMap map[string]*GuiWindow
// Store access to everything via binary tree's
NodeMap map[string]*Node
NodeArray []*Node
NodeSlice []*Node
// A map of all buttons everywhere on all
// windows, all tabs, across all goroutines
// This is "GLOBAL"
//
// This has to work this way because of how
// andlabs/ui & andlabs/libui work
AllButtons []*GuiButton
// buttonMap map[*ui.Button]*GuiButton
}
/*
type GuiTab struct {
Name string // field for human readable name
Number int // the andlabs/ui tab index
Window *GuiWindow // the parent Window
}
*/
//
// stores information on the 'window'
//
// This merges the concept of andlabs/ui *Window and *Tab
//
// More than one Window is not supported in a cross platform
// sense & may never be. On Windows and MacOS, you have to have
// 'tabs'. Even under Linux, more than one Window is currently
// unstable
//
// This code will make a 'GuiWindow' regardless of if it is
// a stand alone window (which is more or less working on Linux)
// or a 'tab' inside a window (which is all that works on MacOS
// and MSWindows.
//
// This struct keeps track of what is in the window so you
// can destroy and replace it with something else
//
type GuiWindow struct {
Name string // field for human readable name
Width int
Height int
Axis int // does it add items to the X or Y axis
TabNumber *int // the andlabs/ui tab index
// the callback function to make the window contents
// MakeWindow func(*GuiBox) *GuiBox
// the components of the window
BoxMap map[string]*GuiBox
// EntryMap map[string]*GuiEntry
node *Node
// andlabs/ui abstraction mapping
UiWindow *ui.Window
UiTab *ui.Tab // if this != nil, the window is 'tabbed'
}
/*
func (w *GuiWindow) Dump() {
log.Println("gui.GuiWindow.Dump() Name = ", w.Name)
log.Println("gui.GuiWindow.Dump() node = ", w.node)
log.Println("gui.GuiWindow.Dump() Width = ", w.Width)
log.Println("gui.GuiWindow.Dump() Height = ", w.Height)
}
*/
// GuiBox is any type of ui.Hbox or ui.Vbox
// There can be lots of these for each GuiWindow
type GuiBox struct {
Name string // field for human readable name
Axis int // does it add items to the X or Y axis
Window *GuiWindow // the parent Window
node *Node
// andlabs/ui abstraction mapping
UiBox *ui.Box
}
func (b *GuiBox) Append(child ui.Control, x bool) {
if b.UiBox == nil {
// spew.Dump(b)
// b.Dump()
panic("GuiBox.Append() can't work. UiBox == nil")
return
}
b.UiBox.Append(child, x)
}
// Note: every mouse click is handled
// as a 'Button' regardless of where
// the user clicks it. You could probably
// call this 'GuiMouseClick'
type GuiButton struct {
Name string // field for human readable name
Box *GuiBox // what box the button click was in
// a callback function for the main application
Custom func(*GuiButton)
Values interface{}
Color color.RGBA
// andlabs/ui abstraction mapping
B *ui.Button
FB *ui.FontButton
CB *ui.ColorButton
}
/*
//
// AREA STRUCTURES START
// AREA STRUCTURES START
// AREA STRUCTURES START
//
type GuiArea struct {
Button *GuiButton // what button handles mouse events
Box *GuiBox
UiAttrstr *ui.AttributedString
UiArea *ui.Area
}
type FontString struct {
S string
Size int
F font.Face
W font.Weight
}
//
// AREA STRUCTURES END
// AREA STRUCTURES END
// AREA STRUCTURES END
//
//
// TABLE DATA STRUCTURES START
// TABLE DATA STRUCTURES START
// TABLE DATA STRUCTURES START
//
//
// This is the structure that andlabs/ui uses to pass information
// to the GUI. This is the "authoritative" data.
//
type TableData struct {
RowCount int // This is the number of 'rows' which really means data elements not what the human sees
RowWidth int // This is how wide each row is
Rows []RowData // This is all the table data by row
generatedColumnTypes []ui.TableValue // generate this dynamically
Cells [20]CellData
Human [20]HumanMap
Box *GuiBox
lastRow int
lastColumn int
}
//
// This maps the andlabs/ui & libui components into a "human"
// readable cell reference list. The reason is that there
// are potentially 3 values for each cell. The Text, the Color
// and an image. These are not always needed so the number
// of fields varies between 1 and 3. Internally, the toolkit
// GUI abstraction needs to list all of them, but it's then
// hard to figure out which column goes with the columns that
// you see when you visually are looking at it like a spreadsheet
//
// This makes a map so that we can say "give me the value at
// row 4 and column 2" and find the fields that are needed
//
// TODO: re-add images and the progress bar (works in andlabs/ui)
//
type HumanCellData struct {
Name string // what kind of row is this?
Text string
TextID int
Color color.RGBA
ColorID int
Button *GuiButton
}
type HumanMap struct {
Name string // what kind of row is this?
TextID int
ColorID int
}
type TableColumnData struct {
Index int
CellType string
Heading string
Color string
}
type CellData struct {
Index int
HumanID int
Name string // what type of cell is this?
}
// hmm. will this stand the test of time?
type RowData struct {
Name string // what kind of row is this?
Status string // status of the row?
//
// TODO: These may or may not be implementable
// depending on if it's possible to detect the bgcolor or what row is selected
// click func() // what function to call if the user clicks on it
// doubleclick func() // what function to call if the user double clicks on it
//
HumanData [20]HumanCellData
}
*/
//
// TABLE DATA STRUCTURES END
//

View File

@ -11,11 +11,11 @@ import "github.com/davecgh/go-spew/spew"
// func NewSlider(b *ui.Box, name string *Toolkit { // func NewSlider(b *ui.Box, name string *Toolkit {
func (t Toolkit) NewSlider(title string, x int, y int) *Toolkit { func (t Toolkit) NewSlider(title string, x int, y int) *Toolkit {
// make new node here // make new node here
log.Println("gui.Toolbox.NewSpinbox()", x, y) log.Println("gui.Toolkit.NewSpinbox()", x, y)
var newt Toolkit var newt Toolkit
if (t.uiBox == nil) { if (t.uiBox == nil) {
log.Println("gui.ToolboxNode.NewGroup() node.UiBox == nil. I can't add a range UI element without a place to put it") log.Println("gui.ToolkitNode.NewGroup() node.UiBox == nil. I can't add a range UI element without a place to put it")
log.Println("probably could just make a box here?") log.Println("probably could just make a box here?")
os.Exit(0) os.Exit(0)
return nil return nil
@ -28,16 +28,23 @@ func (t Toolkit) NewSlider(title string, x int, y int) *Toolkit {
s.OnChanged(func(spin *ui.Slider) { s.OnChanged(func(spin *ui.Slider) {
i := spin.Value() i := spin.Value()
log.Println("gui.Toolbox.ui.Slider.OnChanged() val =", i) log.Println("gui.Toolkit.ui.Slider.OnChanged() val =", i)
if (DebugToolkit) { if (DebugToolkit) {
log.Println("gui.Toolbox.ui.OnChanged() val =", i) log.Println("gui.Toolkit.ui.OnChanged() val =", i)
scs := spew.ConfigState{MaxDepth: 1} scs := spew.ConfigState{MaxDepth: 1}
scs.Dump(newt) scs.Dump(newt)
} }
if (t.OnChanged != nil) { if (newt.OnChanged != nil) {
log.Println("gui.Toolbox.OnChanged() entered val =", i) log.Println("gui.Toolkit.OnChanged() trying to run toolkit.OnChanged() entered val =", i)
newt.OnChanged(&newt) newt.OnChanged(&newt)
return
} }
if (newt.Custom != nil) {
log.Println("gui.Toolkit.OnChanged() Running toolkit.Custom()")
newt.Custom()
return
}
log.Println("gui.Toolkit.OnChanged() ENDED without finding any callback")
}) })
return &newt return &newt

View File

@ -1,38 +0,0 @@
package toolkit
import "log"
import "github.com/andlabs/ui"
import _ "github.com/andlabs/ui/winmanifest"
import "github.com/davecgh/go-spew/spew"
func NewSpinbox(b *ui.Box, name string, x int, y int) *Toolkit {
// make new node here
log.Println("gui.Toolbox.NewSpinbox()", x, y)
var t Toolkit
if (b == nil) {
log.Println("gui.ToolboxNode.NewSpinbox() node.UiBox == nil. I can't add a range UI element without a place to put it")
return nil
}
spin := ui.NewSpinbox(x, y)
t.uiSpinbox = spin
t.uiBox = b
t.uiBox.Append(spin, false)
spin.OnChanged(func(spin *ui.Spinbox) {
i := spin.Value()
if (DebugToolkit) {
log.Println("gui.Toolbox.ui.OnChanged() val =", i)
scs := spew.ConfigState{MaxDepth: 1}
scs.Dump(t)
}
if (t.OnChanged != nil) {
log.Println("gui.Toolbox.OnChanged() entered val =", i)
t.OnChanged(&t)
}
})
return &t
}

View File

@ -0,0 +1,42 @@
package toolkit
import "log"
import "os"
import "github.com/andlabs/ui"
import _ "github.com/andlabs/ui/winmanifest"
import "github.com/davecgh/go-spew/spew"
// func NewSlider(b *ui.Box, name string *Toolkit {
func (t Toolkit) NewSpinner(title string, x int, y int) *Toolkit {
// make new node here
log.Println("gui.Toolkit.NewSpinner()", x, y)
var newt Toolkit
if (t.uiBox == nil) {
log.Println("gui.ToolkitNode.NewSpinner() node.UiBox == nil. I can't add a range UI element without a place to put it")
os.Exit(0)
return nil
}
s := ui.NewSpinbox(x, y)
newt.uiSpinbox = s
newt.uiBox = t.uiBox
t.uiBox.Append(s, false)
s.OnChanged(func(s *ui.Spinbox) {
i := s.Value()
if (DebugToolkit) {
log.Println("gui.Toolkit.ui.OnChanged() val =", i)
scs := spew.ConfigState{MaxDepth: 1}
scs.Dump(newt)
}
if (t.OnChanged != nil) {
log.Println("gui.Toolkit.OnChanged() entered val =", i)
newt.OnChanged(&newt)
}
})
return &newt
}

View File

@ -30,6 +30,7 @@ type Toolkit struct {
uiBox2 *ui.Box // temporary hack while implementing tabs uiBox2 *ui.Box // temporary hack while implementing tabs
uiButton *ui.Button uiButton *ui.Button
uiControl *ui.Control uiControl *ui.Control
uiCombobox *ui.Combobox
uiEntry *ui.Entry uiEntry *ui.Entry
uiGroup *ui.Group uiGroup *ui.Group
uiLabel *ui.Label uiLabel *ui.Label
@ -39,6 +40,13 @@ type Toolkit struct {
uiText *ui.EditableCombobox uiText *ui.EditableCombobox
uiWindow *ui.Window uiWindow *ui.Window
UiWindowBad *ui.Window UiWindowBad *ui.Window
// used as a counter to work around limitations of widgets like combobox
// this is probably fucked up and in many ways wrong because of unsafe goroutine threading
// but it's working for now due to the need for need for a correct interaction layer betten toolkits
c int
val map[int]string
text string
} }
func (t *Toolkit) GetText() string { func (t *Toolkit) GetText() string {
@ -53,6 +61,12 @@ func (t *Toolkit) GetText() string {
} }
return t.uiEntry.Text() return t.uiEntry.Text()
} }
if (t.uiCombobox != nil) {
if (DebugToolkit) {
log.Println("gui.Toolkit.GetText() =", t.text)
}
return t.text
}
return "" return ""
} }
@ -131,6 +145,9 @@ func (t *Toolkit) Dump() {
if (t.uiButton != nil) { if (t.uiButton != nil) {
log.Println("gui.Toolkit.Dump() uiButton =", t.uiButton) log.Println("gui.Toolkit.Dump() uiButton =", t.uiButton)
} }
if (t.uiCombobox != nil) {
log.Println("gui.Toolkit.Dump() uiCombobox =", t.uiCombobox)
}
if (t.uiWindow != nil) { if (t.uiWindow != nil) {
log.Println("gui.Toolkit.Dump() uiWindow =", t.uiWindow) log.Println("gui.Toolkit.Dump() uiWindow =", t.uiWindow)
} }
@ -144,6 +161,11 @@ func (t *Toolkit) Dump() {
log.Println("gui.Toolkit.Dump() uiSlider =", t.uiSlider) log.Println("gui.Toolkit.Dump() uiSlider =", t.uiSlider)
} }
if (t.OnExit != nil) { if (t.OnExit != nil) {
log.Println("gui.Toolkit.Dump() uiExit =", t.OnExit) log.Println("gui.Toolkit.Dump() OnExit =", t.OnExit)
} }
if (t.Custom != nil) {
log.Println("gui.Toolkit.Dump() Custom =", t.Custom)
}
log.Println("gui.Toolkit.Dump() c =", t.c)
log.Println("gui.Toolkit.Dump() val =", t.val)
} }

View File

@ -25,21 +25,21 @@ func (t *Toolkit) AddTab(name string) *Toolkit {
var w *ui.Window var w *ui.Window
var newt *Toolkit var newt *Toolkit
log.Println("gui.Toolbox.AddTab() sleep 3") log.Println("gui.toolkit.AddTab() sleep 3")
w = t.uiWindow w = t.uiWindow
if (w == nil) { if (w == nil) {
log.Println("gui.Toolbox.NewTab() node.UiWindow == nil. I can't add a tab without a window") log.Println("gui.toolkit.NewTab() node.UiWindow == nil. I can't add a tab without a window")
return nil return nil
} }
if (t.uiTab == nil) { if (t.uiTab == nil) {
// this means you have to make a new tab // this means you have to make a new tab
log.Println("gui.Toolbox.NewTab() GOOD. This should be the first tab:", name) log.Println("gui.toolkit.NewTab() GOOD. This should be the first tab:", name)
newt = newTab(w, name) newt = newTab(w, name)
t.uiTab = newt.uiTab t.uiTab = newt.uiTab
} else { } else {
log.Println("gui.Toolbox.NewTab() GOOD. This should be an additional tab:", name) log.Println("gui.toolkit.NewTab() GOOD. This should be an additional tab:", name)
newt = t.appendTab(name) newt = t.appendTab(name)
// this means you have to append a tab // this means you have to append a tab
} }
@ -88,17 +88,17 @@ func tabSetMargined(tab *ui.Tab) {
} }
func newTab(w *ui.Window, name string) *Toolkit { func newTab(w *ui.Window, name string) *Toolkit {
log.Println("gui.Toolbox.NewTab() ADD", name) log.Println("gui.toolkit.NewTab() ADD", name)
var t Toolkit var t Toolkit
if (w == nil) { if (w == nil) {
log.Println("gui.Toolbox.NewTab() node.UiWindow == nil. I can't add a tab without a window") log.Println("gui.toolkit.NewTab() node.UiWindow == nil. I can't add a tab without a window")
log.Println("gui.Toolbox.NewTab() node.UiWindow == nil. I can't add a tab without a window") log.Println("gui.toolkit.NewTab() node.UiWindow == nil. I can't add a tab without a window")
log.Println("gui.Toolbox.NewTab() node.UiWindow == nil. I can't add a tab without a window") log.Println("gui.toolkit.NewTab() node.UiWindow == nil. I can't add a tab without a window")
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
return nil return nil
} }
log.Println("gui.Toolbox.AddTab() START name =", name) log.Println("gui.toolkit.AddTab() START name =", name)
// time.Sleep(2 * time.Second) // time.Sleep(2 * time.Second)
tab := ui.NewTab() tab := ui.NewTab()
w.SetMargined(true) w.SetMargined(true)
@ -117,17 +117,17 @@ func newTab(w *ui.Window, name string) *Toolkit {
} }
func (t *Toolkit) appendTab(name string) *Toolkit { func (t *Toolkit) appendTab(name string) *Toolkit {
log.Println("gui.Toolbox.NewTab() ADD", name) log.Println("gui.toolkit.NewTab() ADD", name)
var newT Toolkit var newT Toolkit
if (t.uiWindow == nil) { if (t.uiWindow == nil) {
log.Println("gui.Toolbox.NewTab() node.UiWindow == nil. I can't add a tab without a window") log.Println("gui.toolkit.NewTab() node.UiWindow == nil. I can't add a tab without a window")
log.Println("gui.Toolbox.NewTab() node.UiWindow == nil. I can't add a tab without a window") log.Println("gui.toolkit.NewTab() node.UiWindow == nil. I can't add a tab without a window")
log.Println("gui.Toolbox.NewTab() node.UiWindow == nil. I can't add a tab without a window") log.Println("gui.toolkit.NewTab() node.UiWindow == nil. I can't add a tab without a window")
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
return nil return nil
} }
log.Println("gui.Toolbox.AddTab() START name =", name) log.Println("gui.toolkit.AddTab() START name =", name)
hbox := ui.NewHorizontalBox() // this makes everything go along the horizon hbox := ui.NewHorizontalBox() // this makes everything go along the horizon
// hbox := ui.NewVerticalBox() // hbox := ui.NewVerticalBox()

View File

@ -2,7 +2,6 @@ package toolkit
import ( import (
"log" "log"
"os"
"github.com/andlabs/ui" "github.com/andlabs/ui"
_ "github.com/andlabs/ui/winmanifest" _ "github.com/andlabs/ui/winmanifest"
@ -33,8 +32,6 @@ func NewWindow(title string, x int, y int) *Toolkit {
t.Custom() t.Custom()
} }
log.Println("ui.Window().OnExit() Toolkit.OnExit is nil") log.Println("ui.Window().OnExit() Toolkit.OnExit is nil")
t.Dump()
os.Exit(0)
return true return true
}) })
w.SetMargined(true) w.SetMargined(true)
@ -43,3 +40,13 @@ func NewWindow(title string, x int, y int) *Toolkit {
t.UiWindowBad = w // deprecate this as soon as possible t.UiWindowBad = w // deprecate this as soon as possible
return &t return &t
} }
func (t *Toolkit) SetWindowTitle(title string) {
log.Println("toolkit NewWindow", t.Name, "title", title)
win := t.uiWindow
if (win != nil) {
win.SetTitle(title)
} else {
log.Println("Setting the window title", title)
}
}

119
window-debug.go Normal file
View File

@ -0,0 +1,119 @@
package gui
import (
"log"
)
var names = make([]string, 100)
var nodeNames = make([]string, 100)
var bugWin *Node
/*
Creates a window helpful for debugging this package
*/
func DebugWindow() {
Config.Title = "git.wit.org/wit/gui debug fixme"
Config.Width = 300
Config.Height = 200
Config.Exit = StandardClose
bugWin = NewWindow()
bugWin.DebugTab("WIT GUI Debug Tab")
}
// this function is used by the examples to add a tab
// dynamically to the bugWin node
// TODO: make this smarter once this uses toolkit/
func DebugTab() {
if (bugWin == nil) {
log.Println("Not sure what window to add this to? Use node.DebugTab() instead")
return;
}
bugWin.DebugTab("does this work?")
}
func (n *Node) DebugTab(title string) *Node {
var newN, gog, g1, g2, g3, dd *Node
// time.Sleep(1 * time.Second)
newN = n.NewTab(title)
newN.Dump()
gog = newN.NewGroup("GOLANG")
gog.NewLabel("go language")
gog.AddButton("GO Language Debug", func (*Node) {
GolangDebugWindow()
})
gog.NewLabel("wit/gui package")
gog.AddButton("WIT/GUI Package Debug", func (*Node) {
Config.Width = 640
Config.Height = 480
Queue(DebugWindow)
})
gog.AddButton("Demo wit/gui", func (*Node) {
DemoWindow()
})
gog.AddButton("Demo toolkit andlabs/ui", func (*Node) {
DemoToolkitWindow()
})
g1 = newN.NewGroup("Current Windows")
dd = g1.NewDropdown("Window Dropdown")
log.Println("dd =", dd)
var dump = false
for _, child := range Config.master.children {
log.Println("\t\t", child.id, child.Width, child.Height, child.Name)
if (child.parent != nil) {
log.Println("\t\t\tparent =",child.parent.id)
} else {
log.Println("\t\t\tno parent")
panic("no parent")
}
if (dump == true) {
child.Dump()
}
dd.AddDropdown(child.Name)
}
dd.SetDropdown(0)
g2 = newN.NewGroup("Debug Window")
g2.AddButton("SetMargined(tab)", func (*Node) {
log.Println("\tSTART")
name := dd.GetText()
log.Println("\tENDed with", name)
// gw.UiTab.SetMargined(*gw.TabNumber, true)
})
g2.AddButton("Hide(tab)", func (*Node) {
// gw.UiTab.Hide()
})
g2.AddButton("Show(tab)", func (*Node) {
// gw.UiTab.Show()
})
g2.AddButton("Delete(tab)", func (*Node) {
// gw.UiTab.Delete(*gw.TabNumber)
})
g2.AddButton("change Title", func (*Node) {
// mainWindow.SetText("hello world")
})
/////////////////////////////////////////////////////
g3 = newN.NewGroup("Node Debug")
g3.AddButton("Node.Dump()", func (n *Node) {
n.Dump()
})
g3.AddButton("Node.ListChildren(false)", func (n *Node) {
n.ListChildren(false)
})
g3.AddButton("Node.ListChildren(true)", func (n *Node) {
n.ListChildren(true)
})
g3.AddButton("AddDebugTab()", func (n *Node) {
if (bugWin != nil) {
bugWin.DebugTab("added this DebugTab")
}
})
return newN
}

View File

@ -2,7 +2,7 @@ package gui
import "log" import "log"
// import "time" // import "time"
import toolkit "git.wit.org/wit/gui/toolkit/andlabs" // import toolkit "git.wit.org/wit/gui/toolkit/andlabs"
func NewStandardWindow(title string) *Node { func NewStandardWindow(title string) *Node {
log.Println("NewStandardWindow() creating", title) log.Println("NewStandardWindow() creating", title)
@ -22,14 +22,15 @@ func NewStandardWindow(title string) *Node {
// right now it shows the andlabs/ui/DemoNumbersPage() // right now it shows the andlabs/ui/DemoNumbersPage()
// //
func DemoToolkitWindow() { func DemoToolkitWindow() {
var w, d *Node var w *Node
var tk *toolkit.Toolkit
w = NewStandardWindow("Demo of the GUI Toolkit") w = NewStandardWindow("Demo of the GUI Toolkit")
d = w.New("demo") // d = w.New("demo")
tk = toolkit.DemoNumbersPage(w.uiWindow) w.toolkit.DemoNumbersPage()
/*
tk = w.Toolkit.DemoNumbersPage()
tk.OnChanged = func(t *toolkit.Toolkit) { tk.OnChanged = func(t *toolkit.Toolkit) {
log.Println("toolkit.NewSlider() value =", t.Value()) log.Println("toolkit.NewSlider() value =", t.Value())
if (d.OnChanged != nil) { if (d.OnChanged != nil) {
@ -38,6 +39,7 @@ func DemoToolkitWindow() {
} }
} }
d.Toolkit = tk d.Toolkit = tk
*/
log.Println("ToolkitDemoWindow() END") log.Println("ToolkitDemoWindow() END")
} }

View File

@ -13,7 +13,7 @@ func StandardClose(n *Node) {
// origlog.Println("Should Exit Here") // origlog.Println("Should Exit Here")
// closed = true // closed = true
log.Println("") log.Println("")
log.Println("STANDARD WINDOW CLOSE") log.Println("STANDARD WINDOW CLOSE. Should not exit app.")
log.Println("") log.Println("")
} }

126
window.go
View File

@ -2,103 +2,10 @@ package gui
import ( import (
"log" "log"
"strconv"
// "github.com/andlabs/ui"
// _ "github.com/andlabs/ui/winmanifest"
) )
import toolkit "git.wit.org/wit/gui/toolkit/andlabs" import toolkit "git.wit.org/wit/gui/toolkit/andlabs"
/*
func MessageWindow(gw *GuiWindow, msg1 string, msg2 string) {
ui.MsgBox(gw.UiWindow, msg1, msg2)
}
func ErrorWindow(gw *GuiWindow, msg1 string, msg2 string) {
ui.MsgBoxError(gw.UiWindow, msg1, msg2)
}
*/
func DeleteWindow(name string) {
log.Println("gui.DeleteWindow() START name =", name)
window := Data.WindowMap[name]
if window == nil {
log.Println("gui.DeleteWindow() NO WINDOW WITH name =", name)
return
}
log.Println("gui.DumpBoxes() MAP: ", name)
log.Println("gui.DumpBoxes()\tWindow.name =", window.Name)
if window.TabNumber == nil {
log.Println("gui.DumpBoxes() \tWindows.TabNumber = nil")
}
tab := *window.TabNumber
log.Println("gui.DumpBoxes() \tWindows.TabNumber =", tab)
log.Println("gui.DumpBoxes() \tSHOULD DELETE TAB", tab, "HERE")
log.Println("gui.DeleteWindow() \tSHOULD DELETE TAB", tab, "HERE")
log.Println("gui.DumpBoxes() \tUiTab =", window.UiTab)
tabnum := window.UiTab.NumPages()
log.Println("gui.DumpBoxes() \tUiTab.NumPages() =", tabnum)
if (tabnum > 0) {
window.UiTab.Delete(tab)
}
delete(Data.WindowMap, name)
// renumber tabs here
for name, window := range Data.WindowMap {
log.Println("gui.DumpBoxes() MAP: ", name)
if window.TabNumber == nil {
log.Println("gui.DumpBoxes() \tWindows.TabNumber = nil")
} else {
log.Println("gui.DumpBoxes() \tWindows.TabNumber =", *window.TabNumber)
if tab < *window.TabNumber {
log.Println("gui.DumpBoxes() \tSubtracting 1 from TabNumber")
*window.TabNumber -= 1
log.Println("gui.DumpBoxes() \tWindows.TabNumber is now =", *window.TabNumber)
}
}
}
}
// func mapWindowOld(parent *Node, window *ui.Window, title string, x int, y int) *Node {
func mapWindow(title string, w int, h int) *Node {
log.Println("gui.WindowMap START title =", title)
if Data.WindowMap[title] != nil {
log.Println("Data.WindowMap[title] already exists title =", title)
title = title + Config.prefix + strconv.Itoa(Config.counter)
Config.counter += 1
}
if Data.WindowMap[title] != nil {
log.Println("Data.WindowMap[title] already exists title =", title)
panic("Data.WindowMap[newGuiWindow.Name] already exists")
return nil
}
var newGuiWindow GuiWindow
newGuiWindow.Width = w
newGuiWindow.Height = h
newGuiWindow.Name = title
// newGuiWindow.UiWindow = window
newGuiWindow.BoxMap = make(map[string]*GuiBox)
newGuiWindow.EntryMap = make(map[string]*GuiEntry)
Data.WindowMap[newGuiWindow.Name] = &newGuiWindow
var box GuiBox
box.Window = &newGuiWindow
box.Name = title
node := addNode(title, w, h)
node.box = &box
box.node = node
newGuiWindow.BoxMap["jcarrInitTest"] = &box
return node
}
// This routine creates a blank window with a Title and size (W x H) // This routine creates a blank window with a Title and size (W x H)
// //
// This routine can not have any arguements due to the nature of how // This routine can not have any arguements due to the nature of how
@ -114,34 +21,21 @@ func NewWindow() *Node {
h := Config.Height h := Config.Height
f := Config.Exit f := Config.Exit
n = mapWindow(title, w, h) // Windows are created off of the master node of the Binary Tree
n = Config.master.New(title)
n.custom = f n.custom = f
box := n.box
log.Println("gui.NewWindow() title = box.Name =", box.Name)
t = toolkit.NewWindow(title, w, h) t = toolkit.NewWindow(title, w, h)
t.Custom = func () { t.Custom = func () {
log.Println("GOT TO MY CUSTOM EXIT!!!! for window name:", box.Name) log.Println("Got to wit/gui Window Close for window:", title)
f(n) if (n.custom == nil) {
} log.Println("Got to wit/gui Window Close custom() == nil")
n.Toolkit = t
n.uiWindow = t.UiWindowBad // this is temporary
window := n.uiWindow
/*
ui.OnShouldQuit(func() bool {
log.Println("createWindow().Destroy() on node.Name =", n.Name)
if (f != nil) {
f(n)
} }
return true log.Println("Got to wit/gui Window Close START custom()")
}) n.custom(n)
*/ log.Println("Got to wit/gui Window Close END custom()")
box.Window.UiWindow = window
if(n.uiWindow == nil) {
panic("node.uiWindow == nil. This should never happen")
} }
n.toolkit = t
return n return n
} }