REFACTOR: refactor everything to gui.Node struct

Signed-off-by: Jeff Carr <jcarr@wit.com>
This commit is contained in:
Jeff Carr 2021-10-31 14:21:36 -05:00
parent 2ccc1b518d
commit f7ead697d3
27 changed files with 1543 additions and 404 deletions

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
*.swp
gui-example/gui-example
cmds/gui-example/gui-example
cmds/gui-demo/gui-demo

10
area.go
View File

@ -107,10 +107,10 @@ func (ah GuiArea) KeyEvent(a *ui.Area, ke *ui.AreaKeyEvent) (handled bool) {
return false
}
func ShowTextBox(box *GuiBox, newText *ui.AttributedString, custom func(*GuiButton), name string) {
func (b *GuiBox) ShowTextBox(newText *ui.AttributedString, custom func(*GuiButton), name string) {
log.Println("ShowTextBox() START")
gw := box.Window
gw := b.Window
if (gw == nil) {
log.Println("ShowTextBox() ERROR gw = nil")
return
@ -127,10 +127,10 @@ func ShowTextBox(box *GuiBox, newText *ui.AttributedString, custom func(*GuiButt
*/
// TODO: allow padded & axis here
box.UiBox.SetPadded(true)
b.UiBox.SetPadded(true)
// add(gw.BoxMap["MAINBOX"], newbox)
makeGenericArea(box, newText, custom)
box.UiBox.Append(box.Window.Area.UiArea, true)
makeGenericArea(b, newText, custom)
b.UiBox.Append(b.Window.Area.UiArea, true)
}

110
box.go
View File

@ -1,6 +1,7 @@
package gui
import "log"
import "os"
// import "reflect"
import "github.com/andlabs/ui"
@ -34,6 +35,7 @@ func add(box *GuiBox, newbox *GuiBox) {
newbox.Window.BoxMap["MAINBOX"] = newbox
log.Println("gui.add() END")
panic("gui.add() MAINBOX gui.add() END")
return
} else {
log.Println("\tgui.add() ERROR DONT KNOW HOW TO ADD TO A RAW WINDOW YET")
@ -41,33 +43,77 @@ func add(box *GuiBox, newbox *GuiBox) {
}
log.Println("\tgui.add() ERROR DON'T KNOW HOW TO add to Window as MAINBOX DONE")
log.Println("gui.add() END")
panic("gui.add() gui.add() END")
return
}
log.Println("\tgui.add() adding", newbox.Name, "to", box.Name)
// copy the box settings over
newbox.Window = box.Window
if (box.UiBox == nil) {
log.Println("\tgui.add() ERROR box.UiBox == nil")
panic("crap")
if (box.node == nil) {
box.Dump()
panic("gui.add() ERROR box.node == nil")
}
if (newbox.UiBox == nil) {
log.Println("\tgui.add() ERROR newbox.UiBox == nil")
panic("crap")
panic("gui.add() ERROR newbox.UiBox == nil")
}
if (box.UiBox == nil) {
box.Dump()
// panic("gui.add() ERROR box.UiBox == nil")
return
// TODO: fix this whole add() function // Oct 9
}
// log.Println("\tgui.add() newbox.UiBox == ", newbox.UiBox.GetParent())
// spew.Dump(newbox.UiBox)
box.UiBox.Append(newbox.UiBox, false)
box.Dump()
panic("gui.add()")
// add the newbox to the Window.BoxMap[]
box.Window.BoxMap[newbox.Name] = newbox
log.Println("gui.add() END")
}
func NewBox(box *GuiBox, axis int, name string) *GuiBox {
log.Println("VerticalBox START")
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.makeNode(name, 111, 100 + Config.counter)
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 (b *GuiBox) NewBox(axis int, name string) *GuiBox {
log.Println("gui.NewBox() START")
n := b.FindNode()
if (n == nil) {
log.Println("gui.NewBox() SERIOUS ERROR. CAN NOT FIND NODE")
os.Exit(0)
} else {
log.Println("gui.NewBox() node =", n.Name)
}
var newbox *GuiBox
newbox = new(GuiBox)
newbox.Window = box.Window
newbox.Window = b.Window
newbox.Name = name
var uiBox *ui.Box
@ -78,13 +124,18 @@ func NewBox(box *GuiBox, axis int, name string) *GuiBox {
}
uiBox.SetPadded(true)
newbox.UiBox = uiBox
add(box, newbox)
add(b, newbox)
// panic("gui.NewBox")
return newbox
}
func HardBox(gw *GuiWindow, axis int, name string) *GuiBox {
log.Println("HardBox() START axis =", axis)
if (gw.node == nil) {
gw.Dump()
panic("gui.HardBox() gw.node == nil")
}
// add a Vertical Seperator if there is already a box
// Is this right?
box := gw.BoxMap["MAINBOX"]
@ -134,3 +185,40 @@ func VerticalBreak(box *GuiBox) {
tmp := ui.NewVerticalSeparator()
box.UiBox.Append(tmp, false)
}
func (n *Node) AddComboBox(title string, s ...string) *Node {
box := n.uiBox
if (box == nil) {
return n
}
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 + "'")
})
box.Append(ecbox, false)
newNode := n.AddNode(title)
newNode.uiText = ecbox
return newNode
}
func (n *Node) OnChanged(f func()) {
f()
}
func (n *Node) GetText() string {
if (n.uiText == nil) {
return ""
}
ecbox := n.uiText
return ecbox.Text()
}

View File

@ -1,10 +1,12 @@
package gui
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
@ -50,6 +52,60 @@ func guiButtonClick(button *GuiButton) {
}
}
func (n *Node) AddButton(name string, custom func(*Node)) *Node {
if (n.uiBox == nil) {
log.Println("gui.Node.AppendButton() filed node.UiBox == nil")
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.makeNode(name, 888, 888 + Config.counter)
newNode.uiButton = button
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
}
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 CreateButton(box *GuiBox, custom func(*GuiButton), name string, values interface {}) *GuiButton {
newUiB := ui.NewButton(name)
newUiB.OnClicked(defaultButtonClick)

5
cmds/gui-demo/Makefile Normal file
View File

@ -0,0 +1,5 @@
run: build
./gui-demo
build:
GO111MODULE="off" go build

View File

@ -0,0 +1,33 @@
package main
import "log"
import "git.wit.org/wit/gui"
func demoClick (n *gui.Node) {
log.Println("demoClick() Dumping node:")
n.Dump()
}
func addDemoTab(n *gui.Node, title string) {
newNode := n.AddTab(title, nil)
if (gui.Config.Debug) {
newNode.Dump()
}
newNode.ListChildren(false)
groupNode1 := newNode.AddGroup("group 1")
groupNode1.AddComboBox("demoCombo1", "foo", "bar", "stuff")
groupNode1.AddComboBox("demoCombo3", "foo 3", "bar", "stuff")
groupNode1.Dump()
butNode1 := groupNode1.AddButton("button1", demoClick)
butNode1.Dump()
butNode2 := groupNode1.AddButton("button2", demoClick)
butNode2.Dump()
groupNode2 := newNode.AddGroup("group 2")
groupNode2.AddComboBox("demoCombo2", "more 1", "more 2", "more 3")
}

68
cmds/gui-demo/main.go Normal file
View File

@ -0,0 +1,68 @@
package main
import (
"log"
"os"
"time"
"git.wit.org/wit/gui"
)
// This initializes the first window
//
// Then starts a goroutine to demonstrate how to
// inject things into the GUI
func main() {
log.Println("Starting my Control Panel")
go gui.Main(initGUI)
watchGUI()
}
// This initializes the first window
func initGUI() {
gui.Config.Title = "WIT GUI Window Demo 1"
gui.Config.Width = 640
gui.Config.Height = 480
gui.Config.Exit = myExit
node1 := gui.NewWindow()
addDemoTab(node1, "A Simple Tab Demo")
gui.Config.Title = "WIT GUI Window Demo 2"
gui.Config.Width = 640
gui.Config.Height = 240
gui.Config.Exit = myExit
node2 := gui.NewWindow()
node2.DemoAndlabsUiTab("A Simple andlabs/ui Tab Demo")
}
// This demonstrates how to properly interact with the GUI
// You can not involke the GUI from external goroutines in most cases.
func watchGUI() {
var i = 1
for {
log.Println("Waiting", i, "seconds")
i += 1
time.Sleep(1 * time.Second)
if i == 4 {
log.Println("Opening a Debug Window via the gui.Queue()")
gui.Config.Width = 800
gui.Config.Height = 300
gui.Config.Exit = myDebugExit
gui.Queue(gui.DebugWindow)
}
}
}
func myExit(n *gui.Node) {
log.Println()
log.Println("Entered myExit() on node.Name =", n.Name)
log.Println()
os.Exit(0)
}
func myDebugExit(n *gui.Node) {
log.Println("Entered myDebugExit() on node.Name =", n.Name)
log.Println("Don't actually os.Exit()")
}

View File

@ -0,0 +1,105 @@
package main
import "log"
import "reflect"
import "git.wit.org/wit/gui"
import "github.com/davecgh/go-spew/spew"
func demoClick (n *gui.Node) {
log.Println("demoClick() Dumping node:")
n.Dump()
}
var username = "jcarr"
var hostname = "fire"
func newClick (n *gui.Node) {
var tmp []string
junk := "ssh -v " + username + "@" + hostname
log.Println("junk = " , junk)
xterm(junk)
log.Println("tmp = " , reflect.ValueOf(tmp).Kind())
// spew.Dump(tmp)
}
func addDemoTab(n *gui.Node, title string) {
newNode := n.AddTab(title, nil)
if (gui.Config.Debug) {
newNode.Dump()
}
newNode.ListChildren(false)
groupNode1 := newNode.AddGroup("group 1")
cbNode := groupNode1.AddComboBox("username", "root", "jcarr", "hugo")
cbNode.OnChanged(func () {
username = cbNode.GetText()
})
groupNode1.AddComboBox("demoCombo3", "foo 3", "bar", "stuff")
groupNode1.Dump()
butNode1 := groupNode1.AddButton("button1", demoClick)
butNode1.Dump()
butNode2 := groupNode1.AddButton("button2", newClick)
butNode2.Dump()
groupNode2 := newNode.AddGroup("group 2")
groupNode2.AddComboBox("demoCombo2", "more 1", "more 2", "more 3")
gNode := newNode.AddGroup("domU")
makeSSHbutton(gNode, "hugo@www", "www.wit.org")
makeSSHbutton(gNode, "check.lab", "check.lab.wit.org")
makeSSHbutton(gNode, "gobuild.lab", "gobuild.lab.wit.org")
makeSSHbutton(gNode, "gobuild2.lab", "gobuild2.lab.wit.org")
/////////////////////////////// Column DNS ////////////////////////////////
gNode = newNode.AddGroup("dns")
makeSSHbutton(gNode, "bind.wit.org", "bind.wit.org")
makeSSHbutton(gNode, "ns1.wit.com", "ns1.wit.com")
makeSSHbutton(gNode, "ns2.wit.com", "ns2.wit.com")
makeSSHbutton(gNode, "coredns", "coredns.lab.wit.org")
/////////////////////////////// PHYS 530 //////////////////////////////////
gNode = newNode.AddGroup("phys 530")
// makeXtermButton(gNode, "openwrt", "SUBDOMAIN", "ssh -4 -v root@openwrt")
gNode.AddButton("openwrt", func (*gui.Node) {
stuff := "ssh -4 -v root@openwrt"
xterm(stuff)
})
makeSSHbutton (gNode, "mirrors", "mirrors.wit.org")
makeSSHbutton (gNode, "node004", "node004.lab.wit.org")
makeSSHbutton (gNode, "lenovo-z70", "lenovo-z70.lab.wit.org")
/////////////////////////////// PHYS 522 //////////////////////////////////
gNode = newNode.AddGroup("phys 522")
// makeXtermButton(gNode, "openwrt2", "SUBDOMAIN", "ssh -4 -v root@openwrt2")
gNode.AddButton("openwrt2", func (*gui.Node) {
stuff := "ssh -4 -v root@openwrt2"
xterm(stuff)
})
makeSSHbutton (gNode, "fire.lab", "fire.lab.wit.org")
makeSSHbutton (gNode, "predator", "predator.lab.wit.org")
/////////////////////////////// FLOAT /////////////////////////////////////
gNode = newNode.AddGroup("float")
makeSSHbutton(gNode, "root@asus-n501vw", "asus-n501vw.lab.wit.org")
}
func makeSSHbutton (n *gui.Node, name string, hostname string) {
bNode := n.AddButton(name, func (*gui.Node) {
var tmp []string
if (username == "") {
username = "root"
}
junk := "ssh -v " + username + "@" + hostname
log.Println("junk = " , junk)
log.Println("username = '" + username + "'")
xterm(junk)
log.Println("tmp = " , reflect.ValueOf(tmp).Kind())
spew.Dump(tmp)
})
bNode.Dump()
}

68
cmds/gui-example/main.go Normal file
View File

@ -0,0 +1,68 @@
package main
import (
"log"
"os"
"time"
"git.wit.org/wit/gui"
)
// This initializes the first window
//
// Then starts a goroutine to demonstrate how to
// inject things into the GUI
func main() {
log.Println("Starting my Control Panel")
go gui.Main(initGUI)
watchGUI()
}
// This initializes the first window
func initGUI() {
gui.Config.Title = "WIT GUI Window Demo 1"
gui.Config.Width = 640
gui.Config.Height = 480
gui.Config.Exit = myExit
node1 := gui.NewWindow()
addDemoTab(node1, "A Simple Tab Demo")
gui.Config.Title = "WIT GUI Window Demo 2"
gui.Config.Width = 640
gui.Config.Height = 240
gui.Config.Exit = myExit
node2 := gui.NewWindow()
node2.DemoAndlabsUiTab("A Simple andlabs/ui Tab Demo")
}
// This demonstrates how to properly interact with the GUI
// You can not involke the GUI from external goroutines in most cases.
func watchGUI() {
var i = 1
for {
log.Println("Waiting", i, "seconds")
i += 1
time.Sleep(1 * time.Second)
if i == 4 {
log.Println("Opening a Debug Window via the gui.Queue()")
gui.Config.Width = 800
gui.Config.Height = 300
gui.Config.Exit = myDebugExit
gui.Queue(gui.DebugWindow)
}
}
}
func myExit(n *gui.Node) {
log.Println()
log.Println("Entered myExit() on node.Name =", n.Name)
log.Println()
os.Exit(0)
}
func myDebugExit(n *gui.Node) {
log.Println("Entered myDebugExit() on node.Name =", n.Name)
log.Println("Don't actually os.Exit()")
}

99
cmds/gui-example/os.go Normal file
View File

@ -0,0 +1,99 @@
package main
import "log"
import "strings"
import "os"
import "os/exec"
import "io/ioutil"
import "errors"
// import "bufio"
// import "github.com/davecgh/go-spew/spew"
/*
import "time"
import "runtime"
import "runtime/debug"
import "runtime/pprof"
import "git.wit.org/wit/gui"
import "git.wit.org/wit/shell"
import "github.com/gobuffalo/packr"
*/
func runSimpleCommand(s string) {
cmd := strings.TrimSpace(s) // this is like 'chomp' in perl
cmd = strings.TrimSuffix(cmd, "\n") // this is like 'chomp' in perl
cmdArgs := strings.Fields(cmd)
runLinuxCommand(cmdArgs)
}
var geom string = "120x30+500+500"
func xterm(cmd string) {
var tmp []string
var argsXterm = []string{"nohup", "xterm", "-geometry", geom}
tmp = append(argsXterm, "-hold", "-e", cmd)
log.Println("xterm cmd=", cmd)
go runCommand(tmp)
}
func runCommand(cmdArgs []string) {
log.Println("runCommand() START", cmdArgs)
process := exec.Command(cmdArgs[0], cmdArgs[1:len(cmdArgs)]...)
// process := exec.Command("xterm", "-e", "ping localhost")
log.Println("runCommand() process.Start()")
process.Start()
log.Println("runCommand() process.Wait()")
err := process.Wait()
lookupError(err)
log.Println("runCommand() NEED TO CHECK THE TIME HERE TO SEE IF THIS WORKED")
log.Println("runCommand() OTHERWISE INFORM THE USER")
log.Println("runCommand() END", cmdArgs)
}
func lookupError(err error) {
var (
ee *exec.ExitError
pe *os.PathError
)
if errors.As(err, &ee) {
log.Println("ran, but non-zero exit code =", ee.ExitCode()) // ran, but non-zero exit code
} else if errors.As(err, &pe) {
log.Printf("os.PathError = %v", pe) // "no such file ...", "permission denied" etc.
} else if err != nil {
log.Printf("something really bad happened general err = %v", err) // something really bad happened!
if exitError, ok := err.(*exec.ExitError); ok {
log.Printf("exitError.ExitCode() is %d\n", exitError.ExitCode())
}
} else {
log.Println("success! // ran without error (exit code zero)")
}
}
func runLinuxCommand(cmdArgs []string) (string, error) {
process := exec.Command(cmdArgs[0], cmdArgs[1:len(cmdArgs)]...)
process.Stdin = os.Stdin
process.Stderr = os.Stderr
stdOut, err := process.StdoutPipe()
if err != nil {
return "", err
}
if err := process.Start(); err != nil {
return "", err
}
bytes, err := ioutil.ReadAll(stdOut)
if err != nil {
return "", err
}
err = process.Wait()
lookupError(err)
log.Println(string(bytes))
return string(bytes), err
}

View File

@ -2,6 +2,8 @@ package gui
import (
"log"
// "fmt"
"strconv"
"github.com/andlabs/ui"
_ "github.com/andlabs/ui/winmanifest"
@ -9,22 +11,36 @@ import (
)
var names = make([]string, 100)
var nodeNames = make([]string, 100)
func makeWindowDebug() ui.Control {
func DebugWindow() {
Config.Title = "DebugWindow()"
node := NewWindow()
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 addNodeName(c *ui.Combobox, s string, id string) {
c.Append(s)
nodeNames[y] = id
y = y + 1
}
func makeWindowDebug() *ui.Box {
hbox := ui.NewHorizontalBox()
hbox.SetPadded(true)
/////////////////////////////////////////////////////
vbox := addGroup(hbox, "Numbers")
pbar := ui.NewProgressBar()
vbox.Append(pbar, false)
/////////////////////////////////////////////////////
vbox = addGroup(hbox, "Window")
vbox := addGroup(hbox, "range Data.WindowMap")
cbox := ui.NewCombobox()
for name, _ := range Data.WindowMap {
log.Println("range Data.WindowMap() name =", name)
if (Config.Debug) {
log.Println("range Data.WindowMap() name =", name)
}
addName(cbox, name)
}
cbox.SetSelected(0)
@ -122,6 +138,11 @@ func makeWindowDebug() ui.Control {
/////////////////////////////////////////////////////
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()
@ -132,11 +153,112 @@ func makeWindowDebug() ui.Control {
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 + ")"
addNodeName(nodeCombo, tmp, node.id)
}
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")
}
})
n1 = addButton(vbox, "Node.DemoAndlabsUiTab")
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.DemoAndlabsUiTab("ran gui.AddDemoAndlabsUiTab() " + strconv.Itoa(Config.counter))
}
})
return hbox
}
// TODO: remove this crap
var x int = 0
var y int = 0
// TODO: remove this crap
func addName(c *ui.Combobox, s string) {
c.Append(s)
names[x] = s
@ -155,33 +277,11 @@ func addGroup(b *ui.Box, name string) *ui.Box {
return vbox
}
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 dumpBox(s string) {
for name, window := range Data.WindowMap {
var name string
var window *GuiWindow
for name, window = range Data.WindowMap {
if name != s {
continue
}
@ -198,6 +298,7 @@ func dumpBox(s string) {
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}
@ -228,3 +329,27 @@ func addButton(box *ui.Box, name string) *ui.Button {
box.Append(button, false)
return button
}
func (n *Node) DebugTab(title string) {
newNode := n.AddTab(title, makeWindowDebug())
if (Config.DebugNode) {
newNode.Dump()
}
tabSetMargined(newNode.uiTab)
}
// This sets _all_ the tabs to Margin = true
//
// TODO: do proper tab tracking (will be complicated). low priority
func tabSetMargined(tab *ui.Tab) {
if (Config.DebugTabs) {
log.Println("tabSetMargined() IGNORE THIS")
}
c := tab.NumPages()
for i := 0; i < c; i++ {
if (Config.DebugTabs) {
log.Println("tabSetMargined() i =", i)
}
tab.SetMargined(i, true)
}
}

View File

@ -8,14 +8,13 @@ import (
"github.com/davecgh/go-spew/spew"
)
// import "reflect"
// import "github.com/andlabs/ui"
// import _ "github.com/andlabs/ui/winmanifest"
//
// Dump out debugging information every 4 seconds
// 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
@ -32,6 +31,12 @@ func WatchGUI() {
}
}
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)
@ -106,3 +111,50 @@ func addTableTab() {
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)
}
}

View File

@ -4,7 +4,19 @@ import "log"
import "github.com/andlabs/ui"
import _ "github.com/andlabs/ui/winmanifest"
func makeWindowTemplate() ui.Control {
// This will create a tab in a window using direct
// calls to andlabs/ui. This can be used to bypass
// the obvuscation added in this package if it is desired
// or needed.
func (n *Node) DemoAndlabsUiTab(title string) {
newNode := n.AddTab(title, makeAndlabsUiTab())
if (Config.DebugNode) {
newNode.Dump()
}
tabSetMargined(newNode.uiTab)
}
func makeAndlabsUiTab() *ui.Box {
hbox := ui.NewHorizontalBox()
hbox.SetPadded(true)

28
demo-window.go Normal file
View File

@ -0,0 +1,28 @@
package gui
// import "log"
import "github.com/andlabs/ui"
import _ "github.com/andlabs/ui/winmanifest"
var mybox *ui.Box
func (n *Node) AddGroup(title string) *Node {
if (n == nil) {
return nil
}
hbox := n.uiBox
if (hbox == nil) {
return n
}
group := ui.NewGroup(title)
group.SetMargined(true)
hbox.Append(group, true)
vbox := ui.NewVerticalBox()
vbox.SetPadded(true)
group.SetChild(vbox)
newNode := n.AddNode(title)
newNode.uiBox = vbox
return newNode
}

72
doc.go Normal file
View File

@ -0,0 +1,72 @@
/*
Package wit/gui implements a abstraction layer for Go visual elements in
a cross platform way. Right now, this abstraction is built on top of
the GUI toolkit 'andlabs/ui' which does the cross platform support.
A quick overview of the features, some general design guidelines
and principles for how this package should generally work:
* GUI elements are stored in a tree of nodes
* When in doubt, it's ok to guess. We will return something close.
* It tries to make your code simple
Quick Start
This section demonstrates how to quickly get started with spew. See the
sections below for further details on formatting and configuration options.
To dump a variable with full newlines, indentation, type, and pointer
information use Dump, Fdump, or Sdump:
package main
import (
"git.wit.org/wit/gui"
)
func main() {
gui.Main(initGUI)
}
// This initializes the first window
func initGUI() {
gui.Config.Title = "WIT GUI Window 1"
gui.Config.Width = 640
gui.Config.Height = 480
node1 := gui.NewWindow()
addDemoTab(node1, "A Simple Tab Demo")
}
func addDemoTab(n *gui.Node, title string) {
newNode := n.AddTab(title, nil)
groupNode1 := newNode.AddGroup("group 1")
groupNode1.AddComboBox("demoCombo2", "more 1", "more 2", "more 3")
}
Configuration Options
Configuration of the GUI is handled by fields in the ConfigType type. For
convenience, all of the top-level functions use a global state available
via the gui.Config global.
The following configuration options are available:
* Width
When creating a new window, this is the width
* Height
When creating a new window, this is the height
* Debug
When 'true' log more output
GUI Usage
Errors
Since it is possible for custom Stringer/error interfaces to panic, spew
detects them and handles them internally by printing the panic information
inline with the output. Since spew is intended to provide deep pretty printing
capabilities on structures, it intentionally does not return any errors.
*/
package gui

View File

@ -13,26 +13,46 @@ func NewLabel(box *GuiBox, text string) {
box.Append(ui.NewLabel(text), false)
}
func GetText(box *GuiBox, name string) string {
if (box == nil) {
log.Println("gui.GetText() ERROR box == nil")
return ""
}
if (box.Window.EntryMap == nil) {
func (n *Node) NewLabel(text string) *Node {
// make new node here
// n.Append(ui.NewLabel(text), false)
newNode := makeNode(n, text, 333, 334)
newNode.Dump()
// panic("node.NewLabel()")
n.Append(newNode)
return newNode
}
func (b *GuiBox) GetText(name string) string {
if (b.Window.EntryMap == nil) {
log.Println("gui.GetText() ERROR b.Box.Window.EntryMap == nil")
return ""
}
spew.Dump(box.Window.EntryMap)
if (box.Window.EntryMap[name] == nil) {
spew.Dump(b.Window.EntryMap)
if (b.Window.EntryMap[name] == nil) {
log.Println("gui.GetText() ERROR box.Window.EntryMap[", name, "] == nil ")
return ""
}
e := box.Window.EntryMap[name]
e := b.Window.EntryMap[name]
log.Println("gui.GetText() box.Window.EntryMap[", name, "] = ", e.UiEntry.Text())
log.Println("gui.GetText() END")
return e.UiEntry.Text()
}
func (n *Node) SetText(value string) error {
log.Println("gui.SetText() value =", value)
if (n.uiText != nil) {
n.uiText.SetText(value)
return nil
}
if (n.uiButton != nil) {
n.uiButton.SetText(value)
return nil
}
return nil
}
func SetText(box *GuiBox, name string, value string) error {
if (box == nil) {
return fmt.Errorf("gui.SetText() ERROR box == nil")
@ -42,7 +62,7 @@ func SetText(box *GuiBox, name string, value string) error {
}
spew.Dump(box.Window.EntryMap)
if (box.Window.EntryMap[name] == nil) {
return fmt.Errorf("gui.SetText() ERROR box.Window.EntryMap[", name, "] == nil ")
return fmt.Errorf("gui.SetText() ERROR box.Window.EntryMap[" + name + "] == nil ")
}
e := box.Window.EntryMap[name]
log.Println("gui.SetText() box.Window.EntryMap[", name, "] = ", e.UiEntry.Text())

45
example_test.go Normal file
View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package gui_test
import (
"git.wit.org/wit/gui"
)
// This example demonstrates how to create a NewWindow()
//
// Interacting with a GUI in a cross platform fashion adds some
// unusual problems. To obvuscate those, andlabs/ui starts a
// goroutine that interacts with the native gui toolkits
// on the Linux, MacOS, Windows, etc.
//
// Because of this oddity, to initialize a new window, the
// function is not passed any arguements and instead passes
// the information via the Config type.
//
func ExampleNewWindow() {
// Define the name and size
gui.Config.Title = "WIT GUI Window 1"
gui.Config.Width = 640
gui.Config.Height = 480
// Create the Window
gui.NewWindow()
// Output:
// You get a window
}

156
find.go Normal file
View File

@ -0,0 +1,156 @@
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

@ -1,43 +0,0 @@
package main
import (
"log"
"os"
"time"
"git.wit.org/wit/gui"
)
func customExit(gw *gui.GuiWindow) {
log.Println("Should Exit Here")
os.Exit(0)
}
func main() {
log.Println("starting my Control Panel")
gui.Config.Width = 800
gui.Config.Height = 300
gui.Config.Exit = customExit
go gui.Main(initGUI)
watchGUI()
}
func initGUI() {
gui.NewWindow("jcarr start", 640, 480)
}
func watchGUI() {
var i = 1
for {
log.Println("Waiting for customExit()", i)
i += 1
time.Sleep(time.Second)
if i == 3 {
log.Println("Sending ExampleWindow to gui.Queue()")
gui.Queue(gui.DebugWindow)
}
}
}

8
gui.go
View File

@ -18,6 +18,14 @@ func init() {
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() {

28
main.go
View File

@ -12,7 +12,7 @@ func Main(f func()) {
ui.Main(f)
}
// Other goroutines must use this
// 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
@ -23,28 +23,12 @@ func Queue(f func()) {
ui.QueueMain(f)
}
/*
func ExampleWindow() {
log.Println("START gui.ExampleWindow()")
title := "Test Window"
box := InitWindow(nil, title, 0)
window := box.Window
log.Println("box =", box)
log.Println("window =", window)
box.AddDebugTab("jcarr Debug")
window.UiWindow.Show()
}
func DebugWindow() {
log.Println("START gui.ExampleWindow()")
title := "Debug Window"
box := InitWindow(nil, title, 0)
window := box.Window
log.Println("box =", box)
log.Println("window =", window)
box.AddDebugTab("jcarr Debug")
window.UiWindow.Show()
Config.Title = "ExampleWindow"
node := NewWindow()
node.AddDebugTab("jcarr Debug")
}
*/

View File

@ -2,12 +2,42 @@ package gui
import (
"log"
"fmt"
// "reflect"
// "github.com/davecgh/go-spew/spew"
"github.com/andlabs/ui"
_ "github.com/andlabs/ui/winmanifest"
)
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"
}
type Node struct {
id string
@ -15,32 +45,227 @@ type Node struct {
Width int
Height int
uiType *ui.Control
parent *Node
children []*Node
window *GuiWindow
box *GuiBox
custom func(*Node)
uiControl *ui.Control
uiButton *ui.Button
uiWindow *ui.Window
uiTab *ui.Tab
uiBox *ui.Box
uiText *ui.EditableCombobox
}
func (n Node) SetName(name string) {
func (n *Node) Parent() *Node {
return n.parent
}
func (n *Node) Window() *Node {
return n.parent
}
func (n *Node) Dump() {
log.Println("gui.Node.Dump() id = ", n.id)
log.Println("gui.Node.Dump() Name = ", n.Name)
log.Println("gui.Node.Dump() Width = ", n.Width)
log.Println("gui.Node.Dump() Height = ", n.Height)
if (n.parent == nil) {
log.Println("gui.Node.Dump() parent = nil")
} else {
log.Println("gui.Node.Dump() parent = ", n.parent.id)
}
log.Println("gui.Node.Dump() children = ", n.children)
log.Println("gui.Node.Dump() window = ", n.window)
log.Println("gui.Node.Dump() box = ", n.box)
log.Println("gui.Node.Dump() uiWindow = ", n.uiWindow)
log.Println("gui.Node.Dump() uiTab = ", n.uiTab)
log.Println("gui.Node.Dump() uiBox = ", n.uiBox)
log.Println("gui.Node.Dump() uiControl = ", n.uiControl)
log.Println("gui.Node.Dump() uiButton = ", n.uiButton)
if (n.id == "") {
panic("gui.Node.Dump() id == nil")
}
}
func (n *Node) SetBox(box *GuiBox) {
n.box = box
}
func (n *Node) SetName(name string) {
// n.uiType.SetName(name)
log.Println("n.uiType =", n.uiType)
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) {
func (n *Node) Append(child *Node) {
// if (n.UiBox == nil) {
// return
// }
// n.uiType.Append(child, x)
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 findByIdDFS(node *Node, id string) *Node {
if node.id == id {
return node
func (n *Node) List() {
findByIdDFS(n, "test")
}
var listChildrenParent *Node
var listChildrenDepth int = 0
func indentPrintln(depth int, format string, a ...interface{}) {
var tabs string
for i := 0; i < depth; i++ {
tabs = tabs + "\t"
}
if len(node.children) > 0 {
for _, child := range node.children {
findByIdDFS(child, id)
// newFormat := tabs + strconv.Itoa(depth) + " " + format
newFormat := tabs + format
log.Println(newFormat, a)
}
func (n *Node) ListChildren(dump bool) {
indentPrintln(listChildrenDepth, "\t", 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 nil
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
}
// The parent Node needs to be the raw Window
// The 'stuff' Node needs to be the contents of the tab
//
// This function should make a new node with the parent and
// the 'stuff' Node as a child
func (n *Node) AddTabNode(title string, b *GuiBox) *Node {
var newNode *Node
parent := n
newNode = parent.makeNode(title, 444, 400 + Config.counter)
newNode.uiTab = parent.uiTab
newNode.box = b
if (Config.DebugNode) {
fmt.Println("")
log.Println("parent:")
parent.Dump()
fmt.Println("")
log.Println("newNode:")
newNode.Dump()
}
if (newNode.uiTab == nil) {
log.Println("wit/gui/ AddTabNode() Something went wrong tab == nil")
// TODO: try to find the tab or window and make them if need be
return newNode
}
newNode.uiTab.Append(title, b.UiBox)
return newNode
}
func (n *Node) AddTab(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.box == nil {
parent.Dump()
panic("gui.AddTab() ERROR box == nil")
}
if parent.uiTab == nil {
inittab := ui.NewTab() // no, not that 'inittab'
parent.uiWindow.SetChild(inittab)
parent.uiWindow.SetMargined(true)
parent.uiTab = inittab
// parent.Dump()
// panic("gui.AddTab() ERROR uiTab == nil")
}
tab := parent.uiTab
parent.uiWindow.SetMargined(true)
if (uiC == nil) {
hbox := ui.NewHorizontalBox()
hbox.SetPadded(true)
uiC = hbox
}
tab.Append(title, uiC)
newNode := parent.makeNode(title, 555, 600 + Config.counter)
newNode.uiTab = tab
newNode.uiBox = uiC
// panic("gui.AddTab() after makeNode()")
tabSetMargined(newNode.uiTab)
return newNode
}

View File

@ -19,11 +19,20 @@ var Data GuiData
var Config GuiConfig
type GuiConfig struct {
Title string
Width int
Height int
Debug bool
DebugTable bool
Exit func(*GuiWindow)
Exit func(*Node)
Debug bool
DebugNode bool
DebugTabs bool
DebugTable bool
DebugWindow bool
depth int
counter int // used to make unique ID's
prefix string
}
type GuiData struct {
@ -35,7 +44,10 @@ type GuiData struct {
AllEntries []*GuiEntry
WindowMap map[string]*GuiWindow
// Windows []*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
@ -45,7 +57,6 @@ type GuiData struct {
// andlabs/ui & andlabs/libui work
AllButtons []*GuiButton
buttonMap map[*ui.Button]*GuiButton
Nodes *Node
}
type GuiTab struct {
@ -87,11 +98,20 @@ type GuiWindow struct {
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 {
@ -99,121 +119,62 @@ type GuiBox struct {
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 (s GuiBox) SetTitle(title string) {
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 s.Window == nil {
if b.Window == nil {
return
}
if s.Window.UiWindow == nil {
if b.Window.UiWindow == nil {
return
}
s.Window.UiWindow.SetTitle(title)
b.Window.UiWindow.SetTitle(title)
return
}
func (s GuiBox) Append(child ui.Control, x bool) {
if s.UiBox == nil {
func (w *GuiWindow) SetNode(n *Node) {
if (w.node != nil) {
w.Dump()
panic("gui.SetNode() Error not nil")
}
w.node = n
if (w.node == nil) {
w.Dump()
panic("gui.SetNode() node == nil")
}
}
func (b *GuiBox) SetNode(n *Node) {
if (b.node != nil) {
b.Dump()
panic("gui.SetNode() Error not nil")
}
b.node = n
if (b.node == nil) {
b.Dump()
panic("gui.SetNode() node == nil")
}
}
func (b *GuiBox) Append(child ui.Control, x bool) {
if b.UiBox == nil {
panic("GuiBox.Append() can't work. UiBox == nil")
return
}
s.UiBox.Append(child, x)
}
/*
func (w GuiWindow) InitWindow(title string) *GuiBox {
if w.UiWindow == nil {
log.Println("gui.InitBox() THIS SHOULD NEVER HAPPEN. Window doesn't exist", w)
return nil
}
tab := ui.NewTab()
w.UiWindow.SetChild(tab)
w.UiWindow.SetMargined(true)
tab.Append(title, InitBlankWindow())
tab.SetMargined(0, true)
w.UiTab = tab
return nil
}
*/
func (s GuiBox) InitTab(title string, custom func() ui.Control) *ui.Tab {
if s.Window == nil {
return nil
}
if s.Window.UiWindow == nil {
return nil
}
window := s.Window.UiWindow
tab := ui.NewTab()
window.SetChild(tab)
window.SetMargined(true)
tab.Append(title, custom())
tab.SetMargined(0, true)
// tab.SetMargined(1, true)
s.Window.UiTab = tab
return tab
}
func (s GuiBox) AddTab(title string, custom ui.Control) *ui.Tab {
if s.Window == nil {
return nil
}
if s.Window.UiTab == nil {
return nil
}
tab := s.Window.UiTab
tab.Append(title, custom)
return tab
}
func (s GuiBox) AddTab2(title string, custom ui.Control) *ui.Tab {
if s.Window == nil {
return nil
}
if s.Window.UiTab == nil {
return nil
}
tab := s.Window.UiTab
tab.Append(title, custom)
return tab
}
func (s GuiBox) AddBoxTab(title string) *GuiBox {
uiTab := s.AddTab2(title, InitBlankWindow())
tabSetMargined(uiTab)
var box *GuiBox
box = HardBox(s.Window, Xaxis, "jcarrAddBoxTab")
box.Window.UiTab = uiTab
return box
}
func (s GuiBox) AddDemoTab(title string) {
uiTab := s.AddTab(title, makeWindowTemplate())
tabSetMargined(uiTab)
}
func (s GuiBox) AddDebugTab(title string) {
uiTab := s.AddTab(title, makeWindowDebug())
tabSetMargined(uiTab)
}
func tabSetMargined(tab *ui.Tab) {
c := tab.NumPages()
for i := 0; i < c; i++ {
log.Println("tabSetMargined() i =", i)
// tab.SetMargined(i, true)
}
b.UiBox.Append(child, x)
}
// Note: every mouse click is handled

View File

@ -98,12 +98,12 @@ func InitColumns(mh *TableData, parts []TableColumnData) {
}
func AddTableTab(gw *GuiWindow, name string, rowcount int, parts []TableColumnData) *TableData {
box := InitWindow(gw, name, Yaxis)
return AddTableBox(box, name, rowcount, parts)
node := NewWindow()
b := node.box
return b.AddTableBox(name, rowcount, parts)
}
func AddTableBox(box *GuiBox, name string, rowcount int, parts []TableColumnData) *TableData {
func (b *GuiBox) AddTableBox(name string, rowcount int, parts []TableColumnData) *TableData {
mh := new(TableData)
mh.RowCount = rowcount
@ -142,9 +142,9 @@ func AddTableBox(box *GuiBox, name string, rowcount int, parts []TableColumnData
// is this needed?
// gw.BoxMap[name] = box
mh.Box = box
mh.Box = b
box.UiBox.Append(table, true)
b.UiBox.Append(table, true)
return mh
}

View File

@ -30,7 +30,8 @@ func (mh *TableData) ColumnTypes(m *ui.TableModel) []ui.TableValue {
}
// TODO: Figure out why this is being called 1000 times a second (10 times for each row & column)
// Nevermind this TODO. Who gives a shit. This is a really smart way to treat the OS toolkits
//
// Nevermind that TODO. Who gives a shit. This is a really smart way to treat the OS toolkits
func (mh *TableData) CellValue(m *ui.TableModel, row, column int) ui.TableValue {
if (Config.DebugTable) {
log.Println("CellValue() row, column =", row, column)

260
window.go
View File

@ -2,40 +2,13 @@ package gui
import (
"log"
"fmt"
"strconv"
"time"
"github.com/andlabs/ui"
// import "regexp"
_ "github.com/andlabs/ui/winmanifest"
)
func initUI(name string, callback func(*GuiBox) *GuiBox) {
ui.Main(func() {
log.Println("gui.initUI() inside ui.Main()")
box := InitWindow(nil, "StartNewWindow"+name, 0)
box = callback(box)
window := box.Window
log.Println("StartNewWindow() box =", box)
window.UiWindow.Show()
})
}
func StartNewWindow(bg bool, name string, axis int, callback func(*GuiBox) *GuiBox) {
log.Println("StartNewWindow() ui.Main() Create a new window")
if bg {
go initUI(name, callback)
time.Sleep(500 * time.Millisecond) // this might make it more stable on windows?
} else {
initUI(name, callback)
}
}
func MessageWindow(gw *GuiWindow, msg1 string, msg2 string) {
ui.MsgBox(gw.UiWindow, msg1, msg2)
}
@ -44,71 +17,6 @@ func ErrorWindow(gw *GuiWindow, msg1 string, msg2 string) {
ui.MsgBoxError(gw.UiWindow, msg1, msg2)
}
//
// This creates a new 'window' (which is just a tab in the window)
// This is this way because on Linux you can have more than one
// actual window but that does not appear to work on the MacOS or Windows
//
func InitWindow(gw *GuiWindow, name string, axis int) *GuiBox {
log.Println("InitGuiWindow() START")
var box *GuiBox
if gw == nil {
box = mapWindow(nil, name, Config.Height, Config.Width)
} else {
box = mapWindow(gw.UiWindow, name, Config.Height, Config.Width)
}
// box.Window = &newGuiWindow
newGuiWindow := box.Window
// This is the first window. One must create it here
if gw == nil {
log.Println("initWindow() ADDING ui.NewWindow()")
newGuiWindow.UiWindow = ui.NewWindow(name, int(newGuiWindow.Height), int(newGuiWindow.Width), true)
newGuiWindow.UiWindow.SetBorderless(false)
// newGuiWindow.UiWindow.SetTitle("test")
newGuiWindow.UiWindow.OnClosing(func(*ui.Window) bool {
log.Println("initTabWindow() OnClosing() THIS WINDOW IS CLOSING newGuiWindow=", newGuiWindow)
// newGuiWindow.UiWindow.Destroy()
if Config.Exit == nil {
ui.Quit()
} else {
// allow a custom exit function
Config.Exit(newGuiWindow)
}
return true
})
newGuiWindow.UiTab = ui.NewTab()
newGuiWindow.UiWindow.SetChild(newGuiWindow.UiTab)
newGuiWindow.UiWindow.SetMargined(true)
tmp := 0
newGuiWindow.TabNumber = &tmp
} else {
newGuiWindow.UiWindow = gw.UiWindow
newGuiWindow.UiTab = gw.UiTab
}
newGuiWindow.BoxMap = make(map[string]*GuiBox)
newGuiWindow.EntryMap = make(map[string]*GuiEntry)
// Data.Windows = append(Data.Windows, &newGuiWindow)
if newGuiWindow.UiTab == nil {
tabnum := 0
newGuiWindow.TabNumber = &tabnum
} else {
tabnum := newGuiWindow.UiTab.NumPages()
newGuiWindow.TabNumber = &tabnum
}
Data.WindowMap[newGuiWindow.Name] = newGuiWindow
log.Println("InitGuiWindow() END *GuiWindow =", newGuiWindow)
return box
}
func DeleteWindow(name string) {
log.Println("gui.DeleteWindow() START name =", name)
window := Data.WindowMap[name]
@ -144,57 +52,102 @@ func DeleteWindow(name string) {
}
}
func CreateWindow(title string, tabname string, x int, y int, custom func() ui.Control) *GuiBox {
box := CreateBlankWindow(title, x, y)
box.InitTab(title, custom)
return box
func makeNode(parent *Node, title string, x int, y int) *Node {
var node Node
node.Name = title
node.Width = x
node.Height = y
id := Config.prefix + strconv.Itoa(Config.counter)
Config.counter += 1
node.id = id
// panic("gui.makeNode() START")
if (parent == nil) {
if (Data.NodeMap[title] != nil) {
log.Println("Duplicate window name =", title)
// TODO: just change the 'title' to something unique
panic(fmt.Sprintf("Duplicate window name = %s\n", title))
return nil
}
// panic("gui.makeNode() before NodeMap()")
Data.NodeMap[title] = &node
Data.NodeArray = append(Data.NodeArray, &node)
Data.NodeSlice = append(Data.NodeSlice, &node)
// panic("gui.makeNode() after NodeMap()")
return &node
} else {
// panic("gui.makeNode() before Append()")
parent.Append(&node)
// panic("gui.makeNode() after Append()")
}
node.parent = parent
return &node
}
func CreateBlankWindow(title string, x int, y int) *GuiBox {
box := mapWindow(nil, title, x, y)
log.Println("gui.CreateBlankWindow() title = box.Name =", box.Name)
func (parent *Node) makeNode(title string, x int, y int) *Node {
var node Node
node.Name = title
node.Width = x
node.Height = y
window := ui.NewWindow(box.Name, x, y, false)
window.SetBorderless(false)
window.OnClosing(func(*ui.Window) bool {
log.Println("createWindow().OnClosing()", box.Name)
id := Config.prefix + strconv.Itoa(Config.counter)
Config.counter += 1
node.id = id
parent.Append(&node)
node.parent = parent
return &node
}
func (n *Node) AddNode(title string) *Node {
var node Node
node.Name = title
node.Width = n.Width
node.Height = n.Height
id := Config.prefix + strconv.Itoa(Config.counter)
Config.counter += 1
node.id = id
n.Append(&node)
node.parent = n
return &node
}
func (n *Node) uiNewWindow(title string, x int, y int) {
w := ui.NewWindow(title, x, y, false)
w.SetBorderless(false)
f := Config.Exit
w.OnClosing(func(*ui.Window) bool {
if (Config.Debug) {
log.Println("ui.Window().OnClosing()")
}
if (f != nil) {
f(n)
}
return true
})
ui.OnShouldQuit(func() bool {
log.Println("createWindow().Destroy()", box.Name)
window.Destroy()
return true
})
window.SetMargined(true)
window.Show()
box.Window.UiWindow = window
return box
w.SetMargined(true)
w.Show()
n.uiWindow = w
// w.node = &node
return
}
func InitBlankWindow() ui.Control {
hbox := ui.NewHorizontalBox()
hbox.SetPadded(true)
return hbox
}
var master = 0
func mapWindow(window *ui.Window, title string, x int, y int) *GuiBox {
func mapWindow(parent *Node, window *ui.Window, title string, x int, y int) *Node {
log.Println("gui.WindowMap START title =", title)
if Data.WindowMap[title] != nil {
log.Println("Data.WindowMap[title] already exists title =", title)
master = master + 1
title = title + " jcarr " + strconv.Itoa(master)
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
}
log.Println("gui.WindowMap START title =", title)
var newGuiWindow GuiWindow
newGuiWindow.Width = x
newGuiWindow.Height = y
@ -210,30 +163,47 @@ func mapWindow(window *ui.Window, title string, x int, y int) *GuiBox {
box.Window = &newGuiWindow
box.Name = title
node := makeNode(parent, title, x, y)
node.box = &box
node.uiWindow = window
box.node = node
newGuiWindow.BoxMap["jcarrInitTest"] = &box
return &box
return node
}
func NewWindow(title string, x int, y int) *GuiBox {
box := mapWindow(nil, title, x, y)
// 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
// it can be passed via the 'andlabs/ui' queue which, because it is
// cross platform, must pass UI changes into the OS threads (that is
// my guess).
func NewWindow() *Node {
title := Config.Title
w := Config.Width
h := Config.Height
var n *Node
n = mapWindow(nil, nil, title, w, h)
box := n.box
log.Println("gui.NewWindow() title = box.Name =", box.Name)
window := ui.NewWindow(box.Name, x, y, false)
window.SetBorderless(false)
window.OnClosing(func(*ui.Window) bool {
log.Println("createWindow().OnClosing()", box.Name)
return true
})
ui.OnShouldQuit(func() bool {
log.Println("createWindow().Destroy()", box.Name)
window.Destroy()
return true
})
n.uiNewWindow(box.Name, w, h)
window := n.uiWindow
window.SetMargined(true)
window.Show()
f := Config.Exit
ui.OnShouldQuit(func() bool {
log.Println("createWindow().Destroy() on node.Name =", n.Name)
if (f != nil) {
f(n)
}
return true
})
box.Window.UiWindow = window
return box
if(n.uiWindow == nil) {
panic("node.uiWindow == nil. This should never happen")
}
return n
}