Merge branch 'master' into jcarr

This commit is contained in:
Jeff Carr 2022-10-08 23:22:47 -05:00
commit 917527d4dc
30 changed files with 1826 additions and 635 deletions

2
.gitignore vendored
View File

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

View File

@ -1,19 +1,13 @@
# simple sortcut to push all git changes
push:
git checkout devel
git pull
git add --all
-git commit -a -s
git push
all:
@echo
@echo "make examples # will run all the examples"
@echo "make update # full git update"
@echo
# should update every go dependancy (?)
update:
git pull
go get -v -t -u ./...
merge-devel:
git checkout master
git pull origin master
git merge devel
git push origin master
git checkout devel
examples:
make -C gui-example

58
area.go
View File

@ -7,28 +7,14 @@ import _ "github.com/andlabs/ui/winmanifest"
import "github.com/davecgh/go-spew/spew"
func makeGenericArea(gb *GuiBox, newText *ui.AttributedString, custom func(*GuiButton)) {
// make this button just to get the default font (but don't display the button)
// There should be another way to do this (?)
var newB *GuiButton
newB = CreateFontButton(gb, "AREA")
newB.Box = gb
newB.Custom = custom
gw := gb.Window
// initialize the GuiArea{}
gw.Area = new(GuiArea)
gw.Area.Button = newB
gw.Area.Box = gb
gw.Area.UiAttrstr = newText
gw.Area.UiArea = ui.NewArea(gw.Area)
if (Config.Debug) {
spew.Dump(gw.Area.UiArea)
log.Println("DEBUGGING", Config.Debug)
} else {
log.Println("NOT DEBUGGING AREA mhAH.Button =", gw.Area.Button)
}
// make this button just to get the default font (but don't display the button)
// There should be another way to do this (?)
func (n *Node) makeGenericArea(newText *ui.AttributedString, custom func(*Node)) {
newNode := n.CreateFontButton("AREA")
newNode.custom = custom
area := new(GuiArea)
newNode.uiArea = ui.NewArea(area)
newNode.uiAttrstr = newText
}
func AreaAppendText(newText *ui.AttributedString, what string, attrs ...ui.Attribute) {
@ -52,7 +38,7 @@ func appendWithAttributes(newText *ui.AttributedString, what string, attrs ...ui
func (ah GuiArea) Draw(a *ui.Area, p *ui.AreaDrawParams) {
tl := ui.DrawNewTextLayout(&ui.DrawTextLayoutParams{
String: ah.UiAttrstr,
DefaultFont: ah.Button.FB.Font(),
DefaultFont: ah.N.uiFontButton.Font(),
Width: p.AreaWidth,
Align: ui.DrawTextAlign(1),
})
@ -61,6 +47,7 @@ func (ah GuiArea) Draw(a *ui.Area, p *ui.AreaDrawParams) {
}
func (ah GuiArea) MouseEvent(a *ui.Area, me *ui.AreaMouseEvent) {
/*
if (Config.Debug) {
log.Println("GOT MouseEvent() ah.Button =", ah.Button)
spew.Dump(me)
@ -80,6 +67,7 @@ func (ah GuiArea) MouseEvent(a *ui.Area, me *ui.AreaMouseEvent) {
Data.MouseClick(ah.Button)
}
}
*/
}
func (ah GuiArea) MouseCrossed(a *ui.Area, left bool) {
@ -107,28 +95,14 @@ func (ah GuiArea) KeyEvent(a *ui.Area, ke *ui.AreaKeyEvent) (handled bool) {
return false
}
func ShowTextBox(gw *GuiWindow, newText *ui.AttributedString, custom func(*GuiButton), name string) *GuiBox {
func (n *Node) ShowTextBox(newText *ui.AttributedString, custom func(*Node), name string) {
log.Println("ShowTextBox() START")
if (gw == nil) {
log.Println("ShowTextBox() ERROR gw = nil")
return nil
}
log.Println("ShowTextBox() START gw =", gw)
var newbox *GuiBox
newbox = new(GuiBox)
newbox.Window = gw
newbox.Name = name
hbox := ui.NewVerticalBox()
newbox.UiBox = hbox
// TODO: allow padded & axis here
hbox.SetPadded(true)
n.uiBox.SetPadded(true)
add(gw.BoxMap["MAINBOX"], newbox)
// add(gw.BoxMap["MAINBOX"], newbox)
makeGenericArea(newbox, newText, custom)
newbox.UiBox.Append(newbox.Window.Area.UiArea, true)
return newbox
n.makeGenericArea(newText, custom)
n.uiBox.Append(n.area.UiArea, true)
}

141
box.go
View File

@ -1,6 +1,7 @@
package gui
import "log"
// import "os"
// import "reflect"
import "github.com/andlabs/ui"
@ -8,123 +9,45 @@ import _ "github.com/andlabs/ui/winmanifest"
// import "github.com/davecgh/go-spew/spew"
// add(nil, newbox, "") // use this when the Window is created. Always called 'MAINBOX'
// add(gw.BoxMap["MAINBOX"], newbox, name) // use this to add a box off the main box
// add(gw.BoxMap["BUTTONBOX"], newbox, name) // use this to add something to the box called 'BUTTONBOX'
// add(box, newbox, name) // add 'newbox' to 'box' and call it 'name'
func add(box *GuiBox, newbox *GuiBox) {
log.Println("gui.add() START box =", box)
log.Println("gui.add() START newbox =", newbox)
func (n *Node) AddComboBox(title string, s ...string) *Node {
newNode := n.AddNode(title)
box := n.uiBox
if (box == nil) {
log.Println("\tgui.add() add to Window as MAINBOX")
if (newbox.Window.UiTab != nil) {
// create a new tab here
// add the box to it as MAINBOX
log.Println("\tgui.add() add to Window as a UiTab")
// TODO: allow passing where to append
// newbox.Window.UiTab.InsertAt(newbox.Name, 0, newbox.UiBox)
newbox.Window.UiTab.Append(newbox.Name, newbox.UiBox)
newbox.Window.UiTab.SetMargined(0, true)
return n
}
// TODO: figure out how to make a new Tab/Window/Box here
// window := InitGuiWindow(Data.Config, newbox.Name, gw.MakeWindow, gw.UiWindow, gw.UiTab)
// window.UiTab.Delete(0)
// window.MakeWindow(window)
// newbox.Window = window
ecbox := ui.NewEditableCombobox()
newNode.uiText = ecbox
// newNode.Dump()
// log.Println("ecbox", ecbox)
newbox.Window.BoxMap["MAINBOX"] = newbox
log.Println("gui.add() END")
return
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 = '" + newNode.Name + "' text for '" + title + "' is now: '" + test + "'")
if (newNode.OnChanged == nil) {
log.Println("Not doing custom OnChanged since OnChanged == nil")
newNode.Dump()
} else {
log.Println("\tgui.add() ERROR DONT KNOW HOW TO ADD TO A RAW WINDOW YET")
// add this to the window
newNode.OnChanged()
}
log.Println("\tgui.add() ERROR DON'T KNOW HOW TO add to Window as MAINBOX DONE")
log.Println("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 (newbox.UiBox == nil) {
log.Println("\tgui.add() ERROR newbox.UiBox == nil")
panic("crap")
}
// log.Println("\tgui.add() newbox.UiBox == ", newbox.UiBox.GetParent())
// spew.Dump(newbox.UiBox)
box.UiBox.Append(newbox.UiBox, false)
})
// add the newbox to the Window.BoxMap[]
box.Window.BoxMap[newbox.Name] = newbox
log.Println("gui.add() END")
box.Append(ecbox, Config.Stretchy)
return newNode
}
func NewBox(box *GuiBox, axis int, name string) *GuiBox {
log.Println("VerticalBox START")
var newbox *GuiBox
newbox = new(GuiBox)
newbox.Window = box.Window
newbox.Name = name
var uiBox *ui.Box
if (axis == Xaxis) {
uiBox = ui.NewHorizontalBox()
} else {
uiBox = ui.NewVerticalBox()
func (n *Node) GetText() string {
if (n.uiMultilineEntry != nil) {
return n.uiMultilineEntry.Text()
}
uiBox.SetPadded(true)
newbox.UiBox = uiBox
add(box, newbox)
return newbox
}
func HardBox(gw *GuiWindow, axis int, name string) *GuiBox {
log.Println("HardBox() START axis =", axis)
// add a Vertical Seperator if there is already a box
// Is this right?
box := gw.BoxMap["MAINBOX"]
if (box != nil) {
if (axis == Xaxis) {
VerticalBreak(box)
} else {
HorizontalBreak(box)
}
if (n.uiText == nil) {
return ""
}
// make the new vbox
var uiBox *ui.Box
if (axis == Xaxis) {
uiBox = ui.NewHorizontalBox()
} else {
uiBox = ui.NewVerticalBox()
}
uiBox.SetPadded(true)
// Init a new GuiBox
newbox := new(GuiBox)
newbox.Window = gw
newbox.UiBox = uiBox
newbox.Name = name
add(gw.BoxMap["MAINBOX"], newbox)
log.Println("HardBoxk END")
return newbox
}
func HorizontalBreak(box *GuiBox) {
log.Println("VerticalSeparator added to box =", box.Name)
tmp := ui.NewHorizontalSeparator()
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)
ecbox := n.uiText
return ecbox.Text()
}

114
button.go
View File

@ -1,10 +1,15 @@
package gui
import "log"
import "reflect"
// import "image/color"
import "github.com/andlabs/ui"
import _ "github.com/andlabs/ui/winmanifest"
// import "github.com/davecgh/go-spew/spew"
// TODO: bring this generic mouse click function back
//
// This is the default mouse click handler
// Every mouse click that hasn't been assigned to
// something specific will fall into this routine
@ -14,77 +19,64 @@ import _ "github.com/andlabs/ui/winmanifest"
// 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
}
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
}
log.Println("\tgui.defaultButtonClick() ERROR: BUTTON NOT FOUND")
button := ui.NewButton(name)
if (Config.Debug) {
panic("gui.defaultButtonClick() ERROR: UNMAPPED ui.Button")
log.Println("reflect.TypeOF(uiBox) =", reflect.TypeOf(n.uiBox))
log.Println("reflect.TypeOF(uiButton) =", reflect.TypeOf(button))
}
// true == expand, false == make normal size button
n.uiBox.Append(button, Config.Stretchy)
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)
})
return newNode
}
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) CreateFontButton(action string) *Node {
n.uiFontButton = ui.NewFontButton()
n.uiFontButton.OnChanged(func (*ui.FontButton) {
log.Println("FontButton.OnChanged() START")
n.Dump()
})
n.uiBox.Append(n.uiFontButton, Config.Stretchy)
// TODO: implement Grid
n.uiGrid = ui.NewGrid()
return n
}
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.UiBox.Append(newB.B, false)
return newB
}
func CreateFontButton(box *GuiBox, action string) *GuiButton {
func (n *Node) CreateColorButton(custom func(*Node), name string, values interface {}) *Node {
// 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)
n.uiColorButton = ui.NewColorButton()
n.custom = custom
n.values = values
newGB.FB.OnChanged(func (*ui.FontButton) {
log.Println("FontButton.OnChanged() START mouseClick(&newBM)", newGB)
if (Data.MouseClick != nil) {
Data.MouseClick(&newGB)
n.uiColorButton.OnChanged(func (*ui.ColorButton) {
log.Println("ColorButton.OnChanged() START Color Button Click")
rgba := n.Color
r, g, b, a := rgba.R, rgba.G, rgba.B, rgba.A
log.Println("ColorButton.OnChanged() Color() =", r, g, b, a)
if (n.custom != nil) {
n.custom(n)
} else if (Data.MouseClick != nil) {
Data.MouseClick(n)
}
})
return &newGB
n.uiBox.Append(n.uiColorButton, Config.Stretchy)
return n
}

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

@ -0,0 +1,5 @@
run: build
./gui-demo
build:
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,5 @@
run: build
./gui-example
build:
go build

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
}

31
color.go Normal file
View File

@ -0,0 +1,31 @@
package gui
//
// convert between 'standard' golang Color and andlabs/ui Color
//
// import "log"
// import "fmt"
import "image/color"
import "github.com/andlabs/ui"
import _ "github.com/andlabs/ui/winmanifest"
func libuiColorToGOlangColor(rgba color.RGBA) ui.TableColor {
/* a hack to see if colors work differently on macos or windows
if (rgba.R == 72) {
log.Println("SETTING COLOR TO NIL")
log.Println("SETTING COLOR TO NIL")
log.Println("SETTING COLOR TO NIL")
return ui.TableColor{}
}
*/
return ui.TableColor{float64(rgba.R) / 256, float64(rgba.G) / 256, float64(rgba.B) / 256, float64(rgba.A) / 256}
}
/*
func golangColorGOlibuiColorTo (ui.TableColor) (rgba color.RGBA) {
color.RGBA{float64(, 100, 200, 100}
return ui.TableColor{float64(rgba.R) / 256, float64(rgba.G) / 256, float64(rgba.B) / 256, float64(rgba.A) / 256}
}
*/

193
debug-window.go Normal file
View File

@ -0,0 +1,193 @@
package gui
import (
"log"
// "fmt"
"strconv"
"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)
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)
/////////////////////////////////////////////////////
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, Config.Stretchy)
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
x = x + 1
}
func addGroup(b *ui.Box, name string) *ui.Box {
group := ui.NewGroup(name)
group.SetMargined(true)
b.Append(group, Config.Stretchy)
vbox := ui.NewVerticalBox()
vbox.SetPadded(true)
group.SetChild(vbox)
return vbox
}
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, Config.Stretchy)
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)
}
}

113
debug.go
View File

@ -1,27 +1,28 @@
package gui
import "log"
import "time"
import "fmt"
import "reflect"
import (
"fmt"
"log"
"time"
// import "github.com/andlabs/ui"
// import _ "github.com/andlabs/ui/winmanifest"
import "github.com/davecgh/go-spew/spew"
// import pb "git.wit.com/wit/witProtobuf"
// "github.com/davecgh/go-spew/spew"
)
// WatchGUI() opens a goroutine
//
// this watches the GUI primarily to process protobuf's
// this is pointless or wrong but I use it for debugging
//
// 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) {
if count > 20 {
log.Println("Sleep() in watchGUI()")
if (Config.Debug) {
DumpBoxes()
if Config.Debug {
// DumpBoxes()
}
count = 0
}
@ -30,46 +31,6 @@ func WatchGUI() {
}
}
func DumpBoxes() {
for name, window := range Data.WindowMap {
log.Println("gui.DumpBoxes()", name)
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)
if (window.UiTab != nil) {
log.Println("gui.DumpBoxes()\tWindow.UiTab type =", reflect.TypeOf(window.UiTab))
log.Println("gui.DumpBoxes()\tWindow.UiTab =", window.UiTab)
log.Println("gui.DumpBoxes()\tWindow.UiTab.NumPages() =", window.UiTab.NumPages())
// 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 {
log.Println("gui.DumpBoxes() Data.Windows", i, "Name =", window.Name)
for name, abox := range window.BoxMap {
log.Printf("gui.DumpBoxes() \tBOX mapname=%-12s abox.Name=%-12s", name, abox.Name)
/*
if (name == "DEBUG") {
log.Println("\t\twatchGUI() BOX abox =", reflect.TypeOf(abox))
win := abox.Window
log.Println("\t\twatchGUI() BOX win =", reflect.TypeOf(win))
area := win.Area
log.Println("\t\twatchGUI() BOX area =", reflect.TypeOf(area), area.UiArea)
// spew.Dump(area.UiArea)
// area.UiArea.Show()
// time.Sleep(2000 * time.Millisecond)
// os.Exit(0)
}
*/
}
}
}
func addTableTab() {
var parts []TableColumnData
@ -78,22 +39,40 @@ func addTableTab() {
var b TableColumnData
b.CellType = foo
b.Heading = fmt.Sprintf("heading%d", key)
b.Heading = fmt.Sprintf("heading%d", key)
parts = append(parts, b)
}
log.Println("Sleep for 2 seconds, then try to add new tabs")
time.Sleep(1 * 1000 * 1000 * 1000)
// AddTableTab(Data.Window1.T, 1, "test seven", 7, parts, nil)
log.Println("Sleep for 1 second, then try to add new tabs")
time.Sleep(1 * time.Second)
}
/*
func runTestHide(b *GuiButton) {
log.Println("runTestHide START")
Data.Window1.Box1.Hide()
Data.Window1.Box2.Hide()
// time.Sleep(2000 * time.Millisecond)
Data.State = "HIDE"
log.Println("runTestHide END")
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 (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 {
listChildrenDepth = 0
if (dump == true) {
log.Println("tgui.Data.ListChildren() node =", node.id, node.Width, node.Height, name)
node.Dump()
}
node.ListChildren(dump)
}
}
*/

84
demo-window-andlabs-ui.go Normal file
View File

@ -0,0 +1,84 @@
package gui
import "log"
import "github.com/andlabs/ui"
import _ "github.com/andlabs/ui/winmanifest"
// 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)
group := ui.NewGroup("Numbers")
group.SetMargined(true)
hbox.Append(group, true)
vbox := ui.NewVerticalBox()
vbox.SetPadded(true)
group.SetChild(vbox)
spinbox := ui.NewSpinbox(47, 100)
slider := ui.NewSlider(21, 100)
pbar := ui.NewProgressBar()
spinbox.OnChanged(func(*ui.Spinbox) {
slider.SetValue(spinbox.Value())
pbar.SetValue(spinbox.Value())
})
slider.OnChanged(func(*ui.Slider) {
spinbox.SetValue(slider.Value())
pbar.SetValue(slider.Value())
})
vbox.Append(spinbox, false)
vbox.Append(slider, false)
vbox.Append(pbar, false)
ip := ui.NewProgressBar()
ip.SetValue(-1)
vbox.Append(ip, false)
group = ui.NewGroup("Lists")
group.SetMargined(true)
hbox.Append(group, true)
vbox = ui.NewVerticalBox()
vbox.SetPadded(true)
group.SetChild(vbox)
cbox := ui.NewCombobox()
cbox.Append("Combobox Item 1")
cbox.Append("Combobox Item 2")
cbox.Append("Combobox Item 3")
vbox.Append(cbox, false)
ecbox := ui.NewEditableCombobox()
ecbox.Append("Editable Item 1")
ecbox.Append("Editable Item 2")
ecbox.Append("Editable Item 3")
vbox.Append(ecbox, false)
ecbox.OnChanged(func(*ui.EditableCombobox) {
log.Println("test")
test := ecbox.Text()
log.Println("test=", test)
})
rb := ui.NewRadioButtons()
rb.Append("Radio Button 1")
rb.Append("Radio Button 2")
rb.Append("Radio Button 3")
vbox.Append(rb, false)
return hbox
}

92
demo-window.go Normal file
View File

@ -0,0 +1,92 @@
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, Config.Stretchy)
vbox := ui.NewVerticalBox()
vbox.SetPadded(true)
group.SetChild(vbox)
newNode := n.AddNode(title)
newNode.uiBox = vbox
return newNode
}
func (n *Node) MakeBasicControlsPage(title string) *Node {
if (n == nil) {
return nil
}
origbox := n.uiBox
if (origbox == nil) {
return n
}
vbox := ui.NewVerticalBox()
vbox.SetPadded(true)
hbox := ui.NewHorizontalBox()
hbox.SetPadded(true)
vbox.Append(hbox, false)
hbox.Append(ui.NewButton("Button"), false)
hbox.Append(ui.NewCheckbox("Checkbox"), false)
vbox.Append(ui.NewLabel("This is a label. Right now, labels can only span one line."), false)
vbox.Append(ui.NewHorizontalSeparator(), false)
group := ui.NewGroup("Entries")
group.SetMargined(true)
vbox.Append(group, true)
group.SetChild(ui.NewNonWrappingMultilineEntry())
entryForm := ui.NewForm()
entryForm.SetPadded(true)
group.SetChild(entryForm)
entryForm.Append("Entry", ui.NewEntry(), false)
entryForm.Append("Password Entry", ui.NewPasswordEntry(), false)
entryForm.Append("Search Entry", ui.NewSearchEntry(), false)
entryForm.Append("Multiline Entry", ui.NewMultilineEntry(), true)
entryForm.Append("Multiline Entry No Wrap", ui.NewNonWrappingMultilineEntry(), true)
origbox.Append(vbox, false)
newNode := n.AddNode(title)
newNode.uiBox = vbox
return newNode
}
func (n *Node) MakeGroupEdit(title string) *Node {
n.Dump()
group := ui.NewGroup(title)
group.SetMargined(true)
n.uiBox.Append(group, Config.Stretchy)
entrybox := ui.NewNonWrappingMultilineEntry()
group.SetChild(entrybox)
log.Println("entrybox =", entrybox)
n.uiMultilineEntry = entrybox
newNode := n.AddNode(title)
newNode.uiMultilineEntry = entrybox
newNode.uiGroup = group
return newNode
}

69
doc.go Normal file
View File

@ -0,0 +1,69 @@
/*
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
Not sure about errors yet. To early to document them. This is a work in progress.
*/
package gui

112
entry.go
View File

@ -1,103 +1,49 @@
package gui
import "log"
import "fmt"
import "errors"
// import "fmt"
import "github.com/andlabs/ui"
// import ui "git.wit.org/interesting/andlabs-ui"
import _ "github.com/andlabs/ui/winmanifest"
import "github.com/davecgh/go-spew/spew"
// import "github.com/davecgh/go-spew/spew"
// functions for handling text entry boxes
func NewLabel(box *GuiBox, text string) {
box.UiBox.Append(ui.NewLabel(text), false)
func (n *Node) NewLabel(text string) *Node {
// make new node here
newNode := n.makeNode(text, 333, 334)
newNode.Dump()
n.Append(newNode)
return newNode
}
func GetText(box *GuiBox, name string) string {
if (box == nil) {
log.Println("gui.GetText() ERROR box == nil")
return ""
func (n *Node) SetText(value string) error {
log.Println("gui.SetText() value =", value)
if (n.uiText != nil) {
n.uiText.SetText(value)
return nil
}
if (box.Window.EntryMap == nil) {
log.Println("gui.GetText() ERROR b.Box.Window.EntryMap == nil")
return ""
if (n.uiButton != nil) {
n.uiButton.SetText(value)
return nil
}
spew.Dump(box.Window.EntryMap)
if (box.Window.EntryMap[name] == nil) {
log.Println("gui.GetText() ERROR box.Window.EntryMap[", name, "] == nil ")
return ""
if (n.uiMultilineEntry != nil) {
n.uiMultilineEntry.SetText(value)
return nil
}
e := box.Window.EntryMap[name]
log.Println("gui.GetText() box.Window.EntryMap[", name, "] = ", e.UiEntry.Text())
log.Println("gui.GetText() END")
return e.UiEntry.Text()
n.Dump()
return errors.New("couldn't find something to set the text to")
}
func SetText(box *GuiBox, name string, value string) error {
if (box == nil) {
return fmt.Errorf("gui.SetText() ERROR box == nil")
func (n *Node) SetMargined(x bool) {
if (n.uiGroup != nil) {
n.uiGroup.SetMargined(x)
return
}
if (box.Window.EntryMap == nil) {
return fmt.Errorf("gui.SetText() ERROR b.Box.Window.EntryMap == nil")
}
spew.Dump(box.Window.EntryMap)
if (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())
e.UiEntry.SetText(value)
log.Println("gui.SetText() box.Window.EntryMap[", name, "] = ", e.UiEntry.Text())
log.Println("gui.SetText() END")
return nil
}
// makeEntryBox(box, "hostname:", "blah.foo.org") {
func MakeEntryVbox(box *GuiBox, a string, startValue string, edit bool, action string) *GuiEntry {
// Start 'Nickname' vertical box
vboxN := ui.NewVerticalBox()
vboxN.SetPadded(true)
vboxN.Append(ui.NewLabel(a), false)
e := defaultMakeEntry(startValue, edit, action)
vboxN.Append(e.UiEntry, false)
box.UiBox.Append(vboxN, false)
// End 'Nickname' vertical box
return e
}
func MakeEntryHbox(box *GuiBox, a string, startValue string, edit bool, action string) *GuiEntry {
// Start 'Nickname' vertical box
hboxN := ui.NewHorizontalBox()
hboxN.SetPadded(true)
hboxN.Append(ui.NewLabel(a), false)
e := defaultMakeEntry(startValue, edit, action)
hboxN.Append(e.UiEntry, false)
box.UiBox.Append(hboxN, false)
// End 'Nickname' vertical box
return e
}
func AddEntry(box *GuiBox, name string) *GuiEntry {
var ge *GuiEntry
ge = new(GuiEntry)
ue := ui.NewEntry()
ue.SetReadOnly(false)
ue.OnChanged(func(*ui.Entry) {
log.Println("gui.AddEntry() OK. ue.Text() =", ue.Text())
})
box.UiBox.Append(ue, false)
ge.UiEntry = ue
box.Window.EntryMap[name] = ge
return ge
log.Println("Couldn't find something that has a Margin setting")
}
func defaultEntryChange(e *ui.Entry) {

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
}

97
find.go Normal file
View File

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

10
go.mod Normal file
View File

@ -0,0 +1,10 @@
module git.wit.org/wit/gui
go 1.19
require (
git.wit.org/interesting/andlabs-ui v0.0.0-20200610043537-70a69d6ae31e // indirect
github.com/andlabs/ui v0.0.0-20200610043537-70a69d6ae31e // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 // indirect
)

10
go.sum Normal file
View File

@ -0,0 +1,10 @@
git.wit.org/interesting/andlabs-ui v0.0.0-20200610043537-70a69d6ae31e h1:CTg83RH/Poy/HCBbBkRFIqKsdBSsHkLeED6XbMmzZzk=
git.wit.org/interesting/andlabs-ui v0.0.0-20200610043537-70a69d6ae31e/go.mod h1:UuaKXIGj4crFE8XDWljgHTyKi8j4pSd9Vvn+zeHNjkQ=
github.com/andlabs/ui v0.0.0-20200610043537-70a69d6ae31e h1:wSQCJiig/QkoUnpvelSPbLiZNWvh2yMqQTQvIQqSUkU=
github.com/andlabs/ui v0.0.0-20200610043537-70a69d6ae31e/go.mod h1:5G2EjwzgZUPnnReoKvPWVneT8APYbyKkihDVAHUi0II=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 h1:Lj6HJGCSn5AjxRAH2+r35Mir4icalbqku+CLUtjnvXY=
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

31
gui.go
View File

@ -1,21 +1,34 @@
package gui
import "log"
// import "time"
import "regexp"
import (
"github.com/andlabs/ui" // import "time"
"log"
"regexp"
import "github.com/andlabs/ui"
import _ "github.com/andlabs/ui/winmanifest"
_ "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 GuiInit() {
Data.buttonMap = make(map[*ui.Button]*GuiButton)
Data.WindowMap = make(map[string]*GuiWindow)
func init() {
log.Println("gui.init() REMOVE THIS init()")
Data.NodeMap = make(map[string]*Node)
Data.NodeSlice = make([]*Node, 0)
Config.counter = 0
Config.prefix = "wit"
Config.DebugNode = false
Config.DebugTabs = false
Config.Stretchy = true
}
func GuiInit() {
ui.OnShouldQuit(func() bool {
ui.Quit()
ui.Quit()
return true
})
}

34
main.go Normal file
View File

@ -0,0 +1,34 @@
package gui
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: gui.Queue(addNewTabForColorSelection())
func Queue(f func()) {
log.Println("Sending function to gui.Main() (using gtk via andlabs/ui)")
ui.QueueMain(f)
}
/*
func ExampleWindow() {
log.Println("START gui.ExampleWindow()")
Config.Title = "ExampleWindow"
node := NewWindow()
node.AddDebugTab("jcarr Debug")
}
*/

318
new-structs.go Normal file
View File

@ -0,0 +1,318 @@
package gui
import (
"log"
"fmt"
"image/color"
// "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
Name string
Width int
Height int
OnChanged func ()
Color color.RGBA
parent *Node
children []*Node
area *GuiArea
custom func(*Node)
values interface {}
uiControl *ui.Control
uiButton *ui.Button
uiFontButton *ui.FontButton
uiColorButton *ui.ColorButton
uiWindow *ui.Window
uiAttrstr *ui.AttributedString
uiTab *ui.Tab
uiBox *ui.Box
uiArea *ui.Area
uiText *ui.EditableCombobox
uiMultilineEntry *ui.MultilineEntry
uiGroup *ui.Group
uiGrid *ui.Grid
}
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)
log.Println("gui.Node.Dump() OnChanged = ", n.OnChanged)
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)
log.Println("gui.Node.Dump() uiText = ", n.uiText)
if (n.id == "") {
log.Println("THIS SHOULD NOT HAPPEN: gui.Node.Dump() id == nil")
}
}
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 indent string = "\t"
var indent string = " "
func indentPrintln(depth int, format string, a ...interface{}) {
var space string
for i := 0; i < depth; i++ {
space = space + indent
}
// newFormat := tabs + strconv.Itoa(depth) + " " + format
newFormat := space + format
log.Println(newFormat, a)
}
func (n *Node) ListChildren(dump bool) {
indentPrintln(listChildrenDepth, "", 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
}
// 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) *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("ERROR: wit/gui/ AddTabNode() Something went wrong tab == nil")
// TODO: try to find the tab or window and make them if need be
// newNode.uiTab.Append(title, b.UiBox)
}
return newNode
}
func (n *Node) AddHorizontalBreak() *Node {
log.Println("AddHorizontalBreak added to node =", n.Name)
if (n.uiBox != nil) {
tmp := ui.NewHorizontalSeparator()
n.uiBox.Append(tmp, Config.Stretchy)
} else {
n.Dump()
return nil
}
return n
}
func (n *Node) AddVerticalBreak() *Node {
log.Println("AddVerticalBreak added to node =", n.Name)
if (n.uiBox != nil) {
tmp := ui.NewVerticalSeparator()
n.uiBox.Append(tmp, Config.Stretchy)
} else {
n.Dump()
return nil
}
return n
}
func (n *Node) AddHorizontalBox(title string) *Node {
hbox := ui.NewHorizontalBox()
hbox.SetPadded(true)
if (n.uiBox != nil) {
log.Println("add new hbox to uiBox =", n.uiBox)
n.uiBox.Append(hbox, Config.Stretchy)
newNode := n.makeNode(title, 333, 333 + Config.counter)
newNode.parent = n
newNode.uiBox = hbox
// newNode.uiControl = hbox
return newNode
}
if (n.uiTab != nil) {
log.Println("add new hbox to uiTab =", n.uiTab)
n.uiTab.Append(title, hbox)
newNode := n.makeNode(title, 333, 333 + Config.counter)
newNode.parent = n
newNode.uiBox = hbox
// newNode.uiControl = hbox
return newNode
}
return n
}
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.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 := parent.makeNode(title, 555, 600 + Config.counter)
newNode.uiTab = tab
newNode.uiBox = uiC
tabSetMargined(newNode.uiTab)
return newNode
}

View File

@ -1,153 +1,85 @@
package gui
import "image/color"
import "golang.org/x/image/font"
import (
"image/color"
// "log"
import "github.com/andlabs/ui"
import _ "github.com/andlabs/ui/winmanifest"
"github.com/andlabs/ui"
"golang.org/x/image/font"
_ "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
var Data GuiData
var Config GuiConfig
type GuiConfig struct {
Width int
Height int
Debug bool
DebugTable bool
Title string
Width int
Height int
Stretchy bool
Menu bool
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 {
// a fallback default function to handle mouse events
// a fallback default function to handle mouse events
// if nothing else is defined to handle them
MouseClick func(*GuiButton)
MouseClick func(*Node)
// A map of all the entry boxes
AllEntries []*GuiEntry
Windows []*GuiWindow
WindowMap map[string]*GuiWindow
AllEntries []*GuiEntry
// 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
}
//
// 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
// the callback function to make the window contents
MakeWindow func(*GuiWindow) *GuiBox
// the components of the window
BoxMap map[string]*GuiBox
EntryMap map[string]*GuiEntry
Area *GuiArea
// andlabs/ui abstraction mapping
UiWindow *ui.Window
UiTab *ui.Tab // if this != nil, the window is 'tabbed'
}
// 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
// andlabs/ui abstraction mapping
UiBox *ui.Box
}
// 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 {}
// andlabs/ui abstraction mapping
B *ui.Button
FB *ui.FontButton
// Store access to everything via binary tree's
NodeMap map[string]*Node
NodeArray []*Node
NodeSlice []*Node
}
// 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
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
N *Node
// andlabs/ui abstraction mapping
UiEntry *ui.Entry
UiEntry *ui.Entry
}
//
// AREA STRUCTURES START
// AREA STRUCTURES START
// AREA STRUCTURES START
//
type GuiArea struct{
Button *GuiButton // what button handles mouse events
Box *GuiBox
type GuiArea struct {
N *Node // what node to pass mouse events
UiAttrstr *ui.AttributedString
UiArea *ui.Area
UiAttrstr *ui.AttributedString
UiArea *ui.Area
}
type FontString struct {
S string
Size int
F font.Face
W font.Weight
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
//
//
@ -155,18 +87,18 @@ type FontString struct {
// 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
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
Cells [20]CellData
Human [20]HumanMap
Box *GuiBox
n *Node
lastRow int
lastColumn int
lastRow int
lastColumn int
}
//
@ -185,44 +117,44 @@ type TableData struct {
// 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
Name string // what kind of row is this?
Text string
TextID int
Color color.RGBA
ColorID int
N *Node
}
type HumanMap struct {
Name string // what kind of row is this?
TextID int
ColorID int
Name string // what kind of row is this?
TextID int
ColorID int
}
type TableColumnData struct {
Index int
CellType string
Heading string
Color string
Index int
CellType string
Heading string
Color string
}
type CellData struct {
Index int
HumanID int
Name string // what type of cell is this?
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
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
}
//

View File

@ -97,7 +97,12 @@ func InitColumns(mh *TableData, parts []TableColumnData) {
}
}
func AddTableTab(gw *GuiWindow, name string, rowcount int, parts []TableColumnData) *TableData {
func AddTableTab(name string, rowcount int, parts []TableColumnData) *TableData {
n := NewWindow()
return n.AddTableBox(name, rowcount, parts)
}
func (n *Node) AddTableBox(name string, rowcount int, parts []TableColumnData) *TableData {
mh := new(TableData)
mh.RowCount = rowcount
@ -134,25 +139,12 @@ func AddTableTab(gw *GuiWindow, name string, rowcount int, parts []TableColumnDa
}
}
var gb *GuiBox
gb = new(GuiBox)
// is this needed?
// gw.BoxMap[name] = box
// mh.Box = b
mh.n = n
vbox := ui.NewVerticalBox()
vbox.SetPadded(true)
gb.UiBox = vbox
gb.Window = gw
gw.BoxMap[name] = gb
mh.Box = gb
vbox.Append(table, true)
gw.UiTab.Append(name, vbox)
vbox.Append(ui.NewVerticalSeparator(), false)
hbox := ui.NewHorizontalBox()
hbox.SetPadded(true)
vbox.Append(hbox, false)
n.uiBox.Append(table, true)
return mh
}

View File

@ -29,20 +29,9 @@ func (mh *TableData) ColumnTypes(m *ui.TableModel) []ui.TableValue {
return mh.generatedColumnTypes
}
func libuiColorToGOlangColor(rgba color.RGBA) ui.TableColor {
/* a hack to see if colors work differently on macos or windows
if (rgba.R == 72) {
log.Println("SETTING COLOR TO NIL")
log.Println("SETTING COLOR TO NIL")
log.Println("SETTING COLOR TO NIL")
return ui.TableColor{}
}
*/
return ui.TableColor{float64(rgba.R) / 256, float64(rgba.G) / 256, float64(rgba.B) / 256, float64(rgba.A) / 256}
}
// 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)
@ -106,9 +95,12 @@ func defaultSetCellValue(mh *TableData, row int, column int) {
humanID := mh.Cells[column].HumanID
log.Println("defaultSetCellValue() FOUND THE TABLE BUTTON ", row, humanID)
button := mh.Rows[row].HumanData[humanID].Button
if (button != nil) {
guiButtonClick(button)
n := mh.Rows[row].HumanData[humanID].N
if (n != nil) {
// TODO: fixme. removed on Oct 31 2021
if (n.OnChanged != nil) {
n.OnChanged()
}
return
}
log.Println("defaultSetCellValue() ERROR: UNKNOWN BUTTON IN TABLE")

220
window.go
View File

@ -1,82 +1,168 @@
package gui
import "log"
import "time"
// import "regexp"
import (
"log"
// "fmt"
"strconv"
import "github.com/andlabs/ui"
import _ "github.com/andlabs/ui/winmanifest"
"github.com/andlabs/ui"
_ "github.com/andlabs/ui/winmanifest"
)
func InitGuiWindow(action string, gw *GuiWindow) *GuiWindow {
log.Println("InitGuiWindow() START")
var newGuiWindow GuiWindow
newGuiWindow.Width = Config.Width
newGuiWindow.Height = Config.Height
newGuiWindow.MakeWindow = gw.MakeWindow
newGuiWindow.UiWindow = gw.UiWindow
newGuiWindow.UiTab = gw.UiTab
newGuiWindow.BoxMap = make(map[string]*GuiBox)
newGuiWindow.EntryMap = make(map[string]*GuiEntry)
newGuiWindow.EntryMap["test"] = nil
Data.Windows = append(Data.Windows, &newGuiWindow)
if (Data.buttonMap == nil) {
GuiInit()
func findUiWindow() *ui.Window {
for _, node := range Data.NodeMap {
if (node.uiWindow != nil) {
return node.uiWindow
}
}
log.Println("InitGuiWindow() END *GuiWindow =", &newGuiWindow)
return &newGuiWindow
return nil
}
func StartNewWindow(bg bool, action string, callback func(*GuiWindow) *GuiBox) {
log.Println("StartNewWindow() Create a new window")
var junk GuiWindow
junk.MakeWindow = callback
// junk.Action = action
window := InitGuiWindow(action, &junk)
if (bg) {
log.Println("StartNewWindow() START NEW GOROUTINE for ui.Main()")
go ui.Main(func() {
log.Println("gui.StartNewWindow() inside ui.Main()")
go InitTabWindow(window)
})
time.Sleep(2000 * time.Millisecond) // this might make it more stable on windows?
} else {
log.Println("StartNewWindow() WAITING for ui.Main()")
ui.Main(func() {
log.Println("gui.StartNewWindow() inside ui.Main()")
InitTabWindow(window)
})
}
func MessageWindow(msg1 string, msg2 string) (*Node) {
uiW := findUiWindow()
ui.MsgBox(uiW, msg1, msg2)
// TODO: make new node
return nil
}
func InitTabWindow(gw *GuiWindow) {
log.Println("InitTabWindow() START. THIS WINDOW IS NOT YET SHOWN")
func ErrorWindow(msg1 string, msg2 string) (*Node) {
uiW := findUiWindow()
ui.MsgBoxError(uiW, msg1, msg2)
return nil
}
gw.UiWindow = ui.NewWindow("InitTabWindow()", int(gw.Width), int(gw.Height), true)
gw.UiWindow.SetBorderless(false)
func initNode(title string, x int, y int) *Node {
var node Node
node.Name = title
node.Width = x
node.Height = y
gw.UiWindow.OnClosing(func(*ui.Window) bool {
log.Println("InitTabWindow() OnClosing() THIS WINDOW IS CLOSING gw=", gw)
ui.Quit()
id := Config.prefix + strconv.Itoa(Config.counter)
Config.counter += 1
node.id = id
if (Data.NodeMap[title] != nil) {
log.Println("ERROR: Duplicate window name =", title)
// TODO: just change the 'title' to something unique
return Data.NodeMap[title]
}
Data.NodeMap[title] = &node
Data.NodeArray = append(Data.NodeArray, &node)
Data.NodeSlice = append(Data.NodeSlice, &node)
return &node
// parent.Append(&node)
//node.parent = parent
return &node
}
func (parent *Node) makeNode(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
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, Config.Menu)
w.SetBorderless(false)
f := Config.Exit
w.OnClosing(func(*ui.Window) bool {
log.Println("RUNNING the ui.Window().OnClosing() function")
if (f != nil) {
f(n)
} else {
n.Dump()
log.Println("gui.uiWindow().OnClosing() NOT SURE WHAT TO DO HERE")
// TODO: always do this here? // by default delete the node?
name := n.Name
delete(Data.NodeMap, name)
}
return true
})
w.SetMargined(true)
w.Show()
n.uiWindow = w
// w.node = &node
return
}
/*
func mapWindow(parent *Node, window *ui.Window, title string, x int, y int) *Node {
log.Println("gui.WindowMap START title =", title)
node := makeNode(parent, title, x, y)
node.uiWindow = window
return node
}
*/
// 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).
//
// There is probably some way to pass arguements here that I'm can't think of right now
//
func NewWindow() *Node {
title := Config.Title
w := Config.Width
h := Config.Height
if (Data.NodeMap[title] != nil) {
log.Println("Duplicate window name =", title)
Data.NodeMap[title].Dump()
Data.NodeMap[title].ListChildren(false)
uiW := Data.NodeMap[title].uiWindow
if (uiW != nil) {
uiW.Show()
}
log.Println("PROBABLY BAD ERROR: check here to see if window is really alive")
return Data.NodeMap[title]
}
var n *Node
n = initNode(title, w, h)
n.uiNewWindow(title, w, h)
window := n.uiWindow
f := Config.Exit
ui.OnShouldQuit(func() bool {
log.Println("createWindow().Destroy() on node.Name =", n.Name)
if (f != nil) {
f(n)
}
return true
})
gw.UiTab = ui.NewTab()
gw.UiWindow.SetChild(gw.UiTab)
gw.UiWindow.SetMargined(true)
box := gw.MakeWindow(gw)
log.Println("InitTabWindow() END box =", box)
log.Println("InitTabWindow() END gw =", gw)
gw.UiWindow.Show()
}
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)
n.uiWindow = window
if(n.uiWindow == nil) {
log.Println("ERROR: node.uiWindow == nil. This should never happen")
}
return n
}