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 *.swp
cmds/gui-example/gui-example
cmds/gui-demo/gui-demo

View File

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

58
area.go
View File

@ -7,28 +7,14 @@ import _ "github.com/andlabs/ui/winmanifest"
import "github.com/davecgh/go-spew/spew" 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)
// make this button just to get the default font (but don't display the button) // There should be another way to do this (?)
// There should be another way to do this (?) func (n *Node) makeGenericArea(newText *ui.AttributedString, custom func(*Node)) {
var newB *GuiButton newNode := n.CreateFontButton("AREA")
newB = CreateFontButton(gb, "AREA") newNode.custom = custom
newB.Box = gb area := new(GuiArea)
newB.Custom = custom newNode.uiArea = ui.NewArea(area)
newNode.uiAttrstr = newText
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)
}
} }
func AreaAppendText(newText *ui.AttributedString, what string, attrs ...ui.Attribute) { 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) { func (ah GuiArea) Draw(a *ui.Area, p *ui.AreaDrawParams) {
tl := ui.DrawNewTextLayout(&ui.DrawTextLayoutParams{ tl := ui.DrawNewTextLayout(&ui.DrawTextLayoutParams{
String: ah.UiAttrstr, String: ah.UiAttrstr,
DefaultFont: ah.Button.FB.Font(), DefaultFont: ah.N.uiFontButton.Font(),
Width: p.AreaWidth, Width: p.AreaWidth,
Align: ui.DrawTextAlign(1), 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) { func (ah GuiArea) MouseEvent(a *ui.Area, me *ui.AreaMouseEvent) {
/*
if (Config.Debug) { if (Config.Debug) {
log.Println("GOT MouseEvent() ah.Button =", ah.Button) log.Println("GOT MouseEvent() ah.Button =", ah.Button)
spew.Dump(me) spew.Dump(me)
@ -80,6 +67,7 @@ func (ah GuiArea) MouseEvent(a *ui.Area, me *ui.AreaMouseEvent) {
Data.MouseClick(ah.Button) Data.MouseClick(ah.Button)
} }
} }
*/
} }
func (ah GuiArea) MouseCrossed(a *ui.Area, left bool) { 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 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") 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 // 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) n.makeGenericArea(newText, custom)
newbox.UiBox.Append(newbox.Window.Area.UiArea, true) n.uiBox.Append(n.area.UiArea, true)
return newbox
} }

141
box.go
View File

@ -1,6 +1,7 @@
package gui package gui
import "log" import "log"
// import "os"
// import "reflect" // import "reflect"
import "github.com/andlabs/ui" import "github.com/andlabs/ui"
@ -8,123 +9,45 @@ import _ "github.com/andlabs/ui/winmanifest"
// import "github.com/davecgh/go-spew/spew" // import "github.com/davecgh/go-spew/spew"
// add(nil, newbox, "") // use this when the Window is created. Always called 'MAINBOX' func (n *Node) AddComboBox(title string, s ...string) *Node {
// add(gw.BoxMap["MAINBOX"], newbox, name) // use this to add a box off the main box newNode := n.AddNode(title)
// add(gw.BoxMap["BUTTONBOX"], newbox, name) // use this to add something to the box called 'BUTTONBOX' box := n.uiBox
// 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)
if (box == nil) { if (box == nil) {
log.Println("\tgui.add() add to Window as MAINBOX") return n
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)
// TODO: figure out how to make a new Tab/Window/Box here ecbox := ui.NewEditableCombobox()
// window := InitGuiWindow(Data.Config, newbox.Name, gw.MakeWindow, gw.UiWindow, gw.UiTab) newNode.uiText = ecbox
// window.UiTab.Delete(0) // newNode.Dump()
// window.MakeWindow(window) // log.Println("ecbox", ecbox)
// newbox.Window = window
newbox.Window.BoxMap["MAINBOX"] = newbox for id, name := range s {
log.Println("gui.add() END") log.Println("Adding Combobox Entry:", id, name)
return 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 { } else {
log.Println("\tgui.add() ERROR DONT KNOW HOW TO ADD TO A RAW WINDOW YET") newNode.OnChanged()
// add this to the window
} }
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.Append(ecbox, Config.Stretchy)
box.Window.BoxMap[newbox.Name] = newbox return newNode
log.Println("gui.add() END")
} }
func NewBox(box *GuiBox, axis int, name string) *GuiBox { func (n *Node) GetText() string {
log.Println("VerticalBox START") if (n.uiMultilineEntry != nil) {
var newbox *GuiBox return n.uiMultilineEntry.Text()
newbox = new(GuiBox)
newbox.Window = box.Window
newbox.Name = name
var uiBox *ui.Box
if (axis == Xaxis) {
uiBox = ui.NewHorizontalBox()
} else {
uiBox = ui.NewVerticalBox()
} }
uiBox.SetPadded(true) if (n.uiText == nil) {
newbox.UiBox = uiBox return ""
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)
}
} }
ecbox := n.uiText
// make the new vbox return ecbox.Text()
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)
} }

114
button.go
View File

@ -1,10 +1,15 @@
package gui package gui
import "log" import "log"
import "reflect"
// import "image/color"
import "github.com/andlabs/ui" import "github.com/andlabs/ui"
import _ "github.com/andlabs/ui/winmanifest" import _ "github.com/andlabs/ui/winmanifest"
// import "github.com/davecgh/go-spew/spew" // import "github.com/davecgh/go-spew/spew"
// TODO: bring this generic mouse click function back
//
// This is the default mouse click handler // This is the default mouse click handler
// Every mouse click that hasn't been assigned to // Every mouse click that hasn't been assigned to
// something specific will fall into this routine // 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 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 // 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) func (n *Node) AddButton(name string, custom func(*Node)) *Node {
for key, foo := range Data.AllButtons { if (n.uiBox == nil) {
if (Config.Debug) { log.Println("gui.Node.AppendButton() filed node.UiBox == nil")
log.Println("gui.defaultButtonClick() Data.AllButtons =", key, foo) return n
// spew.Dump(foo)
}
if Data.AllButtons[key].B == button {
log.Println("\tgui.defaultButtonClick() BUTTON MATCHED")
guiButtonClick(Data.AllButtons[key])
return
}
} }
log.Println("\tgui.defaultButtonClick() ERROR: BUTTON NOT FOUND") button := ui.NewButton(name)
if (Config.Debug) { 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) { func (n *Node) CreateFontButton(action string) *Node {
log.Println("\tgui.guiButtonClick() button.Name =", button.Name) n.uiFontButton = ui.NewFontButton()
if button.Custom != nil {
log.Println("\tgui.guiButtonClick() DOING CUSTOM FUNCTION") n.uiFontButton.OnChanged(func (*ui.FontButton) {
button.Custom(button) log.Println("FontButton.OnChanged() START")
return n.Dump()
} })
if (Data.MouseClick != nil) { n.uiBox.Append(n.uiFontButton, Config.Stretchy)
Data.MouseClick(button)
} else { // TODO: implement Grid
log.Println("\tgui.guiButtonClick() IGNORING BUTTON. MouseClick() is nil") n.uiGrid = ui.NewGrid()
} return n
} }
func CreateButton(box *GuiBox, custom func(*GuiButton), name string, values interface {}) *GuiButton { func (n *Node) CreateColorButton(custom func(*Node), name string, values interface {}) *Node {
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 {
// create a 'fake' button entry for the mouse clicks // create a 'fake' button entry for the mouse clicks
var newGB GuiButton n.uiColorButton = ui.NewColorButton()
newGB.Name = "FONT" n.custom = custom
newGB.FB = ui.NewFontButton() n.values = values
newGB.Box = box
Data.AllButtons = append(Data.AllButtons, &newGB)
newGB.FB.OnChanged(func (*ui.FontButton) { n.uiColorButton.OnChanged(func (*ui.ColorButton) {
log.Println("FontButton.OnChanged() START mouseClick(&newBM)", newGB) log.Println("ColorButton.OnChanged() START Color Button Click")
if (Data.MouseClick != nil) { rgba := n.Color
Data.MouseClick(&newGB) 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 package gui
import "log" import (
import "time" "fmt"
import "fmt" "log"
import "reflect" "time"
// import "github.com/andlabs/ui" // "github.com/davecgh/go-spew/spew"
// import _ "github.com/andlabs/ui/winmanifest" )
import "github.com/davecgh/go-spew/spew"
// import pb "git.wit.com/wit/witProtobuf"
// WatchGUI() opens a goroutine
// //
// this watches the GUI primarily to process protobuf's // From that goroutine, it dumps out debugging information every 4 seconds
// this is pointless or wrong but I use it for debugging /*
// 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() { func WatchGUI() {
count := 0 count := 0
for { for {
if (count > 20) { if count > 20 {
log.Println("Sleep() in watchGUI()") log.Println("Sleep() in watchGUI()")
if (Config.Debug) { if Config.Debug {
DumpBoxes() // DumpBoxes()
} }
count = 0 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() { func addTableTab() {
var parts []TableColumnData var parts []TableColumnData
@ -78,22 +39,40 @@ func addTableTab() {
var b TableColumnData var b TableColumnData
b.CellType = foo b.CellType = foo
b.Heading = fmt.Sprintf("heading%d", key) b.Heading = fmt.Sprintf("heading%d", key)
parts = append(parts, b) parts = append(parts, b)
} }
log.Println("Sleep for 2 seconds, then try to add new tabs") log.Println("Sleep for 1 second, then try to add new tabs")
time.Sleep(1 * 1000 * 1000 * 1000) time.Sleep(1 * time.Second)
// AddTableTab(Data.Window1.T, 1, "test seven", 7, parts, nil)
} }
/* func (dn *GuiData) DumpNodeMap() {
func runTestHide(b *GuiButton) { log.Println("DebugDataNodeMap():")
log.Println("runTestHide START") for name, node := range dn.NodeMap {
Data.Window1.Box1.Hide() log.Println("\tNode =", node.id, node.Width, node.Height, name)
Data.Window1.Box2.Hide() if (node.children == nil) {
// time.Sleep(2000 * time.Millisecond) log.Println("\t\tNo children")
Data.State = "HIDE" } else {
log.Println("runTestHide END") 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 package gui
import "log" import "log"
import "fmt" import "errors"
// import "fmt"
import "github.com/andlabs/ui" import "github.com/andlabs/ui"
// import ui "git.wit.org/interesting/andlabs-ui"
import _ "github.com/andlabs/ui/winmanifest" 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 // functions for handling text entry boxes
func NewLabel(box *GuiBox, text string) { func (n *Node) NewLabel(text string) *Node {
box.UiBox.Append(ui.NewLabel(text), false) // make new node here
newNode := n.makeNode(text, 333, 334)
newNode.Dump()
n.Append(newNode)
return newNode
} }
func GetText(box *GuiBox, name string) string { func (n *Node) SetText(value string) error {
if (box == nil) { log.Println("gui.SetText() value =", value)
log.Println("gui.GetText() ERROR box == nil") if (n.uiText != nil) {
return "" n.uiText.SetText(value)
return nil
} }
if (box.Window.EntryMap == nil) { if (n.uiButton != nil) {
log.Println("gui.GetText() ERROR b.Box.Window.EntryMap == nil") n.uiButton.SetText(value)
return "" return nil
} }
spew.Dump(box.Window.EntryMap) if (n.uiMultilineEntry != nil) {
if (box.Window.EntryMap[name] == nil) { n.uiMultilineEntry.SetText(value)
log.Println("gui.GetText() ERROR box.Window.EntryMap[", name, "] == nil ") return nil
return ""
} }
e := box.Window.EntryMap[name] n.Dump()
log.Println("gui.GetText() box.Window.EntryMap[", name, "] = ", e.UiEntry.Text()) return errors.New("couldn't find something to set the text to")
log.Println("gui.GetText() END")
return e.UiEntry.Text()
} }
func SetText(box *GuiBox, name string, value string) error { func (n *Node) SetMargined(x bool) {
if (box == nil) { if (n.uiGroup != nil) {
return fmt.Errorf("gui.SetText() ERROR box == nil") n.uiGroup.SetMargined(x)
return
} }
if (box.Window.EntryMap == nil) { log.Println("Couldn't find something that has a Margin setting")
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
} }
func defaultEntryChange(e *ui.Entry) { 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 package gui
import "log" import (
// import "time" "github.com/andlabs/ui" // import "time"
import "regexp" "log"
"regexp"
import "github.com/andlabs/ui" _ "github.com/andlabs/ui/winmanifest"
import _ "github.com/andlabs/ui/winmanifest" )
// the _ means we only need this for the init()
const Xaxis = 0 // box that is horizontal const Xaxis = 0 // box that is horizontal
const Yaxis = 1 // box that is vertical const Yaxis = 1 // box that is vertical
func GuiInit() { func init() {
Data.buttonMap = make(map[*ui.Button]*GuiButton) log.Println("gui.init() REMOVE THIS init()")
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
Config.Stretchy = true
}
func GuiInit() {
ui.OnShouldQuit(func() bool { ui.OnShouldQuit(func() bool {
ui.Quit() ui.Quit()
return true 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 package gui
import "image/color" import (
import "golang.org/x/image/font" "image/color"
// "log"
import "github.com/andlabs/ui" "github.com/andlabs/ui"
import _ "github.com/andlabs/ui/winmanifest" "golang.org/x/image/font"
_ "github.com/andlabs/ui/winmanifest"
)
// //
// All GUI Data Structures and functions that are external // All GUI Data Structures and functions that are external
// If you need cross platform support, these might only // If you need cross platform support, these might only
// be the safe way to interact with the GUI // be the safe way to interact with the GUI
// //
var Data GuiData var Data GuiData
var Config GuiConfig var Config GuiConfig
type GuiConfig struct { type GuiConfig struct {
Width int Title string
Height int Width int
Debug bool Height int
DebugTable bool 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 { 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 // if nothing else is defined to handle them
MouseClick func(*GuiButton) MouseClick func(*Node)
// A map of all the entry boxes // A map of all the entry boxes
AllEntries []*GuiEntry AllEntries []*GuiEntry
Windows []*GuiWindow
WindowMap map[string]*GuiWindow
// A map of all buttons everywhere on all // Store access to everything via binary tree's
// windows, all tabs, across all goroutines NodeMap map[string]*Node
// This is "GLOBAL" NodeArray []*Node
// NodeSlice []*Node
// 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
} }
// text entry fields // text entry fields
type GuiEntry struct { type GuiEntry struct {
Name string // field for human readable name Name string // field for human readable name
Edit bool Edit bool
Last string // the last value Last string // the last value
Normalize func (string) string // function to 'normalize' the data Normalize func(string) string // function to 'normalize' the data
B *GuiButton N *Node
Box *GuiBox
// andlabs/ui abstraction mapping // andlabs/ui abstraction mapping
UiEntry *ui.Entry UiEntry *ui.Entry
} }
// type GuiArea struct {
// AREA STRUCTURES START N *Node // what node to pass mouse events
// AREA STRUCTURES START
// AREA STRUCTURES START
//
type GuiArea struct{
Button *GuiButton // what button handles mouse events
Box *GuiBox
UiAttrstr *ui.AttributedString UiAttrstr *ui.AttributedString
UiArea *ui.Area UiArea *ui.Area
} }
type FontString struct { type FontString struct {
S string S string
Size int Size int
F font.Face F font.Face
W font.Weight W font.Weight
} }
//
// AREA STRUCTURES END
// AREA STRUCTURES END
// AREA STRUCTURES END
//
// //
// TABLE DATA STRUCTURES START // 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. // to the GUI. This is the "authoritative" data.
// //
type TableData struct { type TableData struct {
RowCount int // This is the number of 'rows' which really means data elements not what the human sees 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 RowWidth int // This is how wide each row is
Rows []RowData // This is all the table data by row Rows []RowData // This is all the table data by row
generatedColumnTypes []ui.TableValue // generate this dynamically generatedColumnTypes []ui.TableValue // generate this dynamically
Cells [20]CellData Cells [20]CellData
Human [20]HumanMap Human [20]HumanMap
Box *GuiBox n *Node
lastRow int lastRow int
lastColumn int lastColumn int
} }
// //
@ -185,44 +117,44 @@ type TableData struct {
// TODO: re-add images and the progress bar (works in andlabs/ui) // TODO: re-add images and the progress bar (works in andlabs/ui)
// //
type HumanCellData struct { type HumanCellData struct {
Name string // what kind of row is this? Name string // what kind of row is this?
Text string Text string
TextID int TextID int
Color color.RGBA Color color.RGBA
ColorID int ColorID int
Button *GuiButton N *Node
} }
type HumanMap struct { type HumanMap struct {
Name string // what kind of row is this? Name string // what kind of row is this?
TextID int TextID int
ColorID int ColorID int
} }
type TableColumnData struct { type TableColumnData struct {
Index int Index int
CellType string CellType string
Heading string Heading string
Color string Color string
} }
type CellData struct { type CellData struct {
Index int Index int
HumanID int HumanID int
Name string // what type of cell is this? Name string // what type of cell is this?
} }
// hmm. will this stand the test of time? // hmm. will this stand the test of time?
type RowData struct { type RowData struct {
Name string // what kind of row is this? Name string // what kind of row is this?
Status string // status of the row? Status string // status of the row?
/* /*
// TODO: These may or may not be implementable // TODO: These may or may not be implementable
// depending on if it's possible to detect the bgcolor or what row is selected // 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 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 doubleclick func() // what function to call if the user double clicks on it
*/ */
HumanData [20]HumanCellData 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 := new(TableData)
mh.RowCount = rowcount mh.RowCount = rowcount
@ -134,25 +139,12 @@ func AddTableTab(gw *GuiWindow, name string, rowcount int, parts []TableColumnDa
} }
} }
var gb *GuiBox // is this needed?
gb = new(GuiBox) // gw.BoxMap[name] = box
// mh.Box = b
mh.n = n
vbox := ui.NewVerticalBox() n.uiBox.Append(table, true)
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)
return mh return mh
} }

View File

@ -29,20 +29,9 @@ func (mh *TableData) ColumnTypes(m *ui.TableModel) []ui.TableValue {
return mh.generatedColumnTypes 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) // 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 { func (mh *TableData) CellValue(m *ui.TableModel, row, column int) ui.TableValue {
if (Config.DebugTable) { if (Config.DebugTable) {
log.Println("CellValue() row, column =", row, column) log.Println("CellValue() row, column =", row, column)
@ -106,9 +95,12 @@ func defaultSetCellValue(mh *TableData, row int, column int) {
humanID := mh.Cells[column].HumanID humanID := mh.Cells[column].HumanID
log.Println("defaultSetCellValue() FOUND THE TABLE BUTTON ", row, humanID) log.Println("defaultSetCellValue() FOUND THE TABLE BUTTON ", row, humanID)
button := mh.Rows[row].HumanData[humanID].Button n := mh.Rows[row].HumanData[humanID].N
if (button != nil) { if (n != nil) {
guiButtonClick(button) // TODO: fixme. removed on Oct 31 2021
if (n.OnChanged != nil) {
n.OnChanged()
}
return return
} }
log.Println("defaultSetCellValue() ERROR: UNKNOWN BUTTON IN TABLE") log.Println("defaultSetCellValue() ERROR: UNKNOWN BUTTON IN TABLE")

220
window.go
View File

@ -1,82 +1,168 @@
package gui package gui
import "log" import (
import "time" "log"
// import "regexp" // "fmt"
"strconv"
import "github.com/andlabs/ui" "github.com/andlabs/ui"
import _ "github.com/andlabs/ui/winmanifest" _ "github.com/andlabs/ui/winmanifest"
)
func InitGuiWindow(action string, gw *GuiWindow) *GuiWindow { func findUiWindow() *ui.Window {
log.Println("InitGuiWindow() START") for _, node := range Data.NodeMap {
var newGuiWindow GuiWindow if (node.uiWindow != nil) {
newGuiWindow.Width = Config.Width return node.uiWindow
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()
} }
log.Println("InitGuiWindow() END *GuiWindow =", &newGuiWindow) return nil
return &newGuiWindow
} }
func MessageWindow(msg1 string, msg2 string) (*Node) {
func StartNewWindow(bg bool, action string, callback func(*GuiWindow) *GuiBox) { uiW := findUiWindow()
log.Println("StartNewWindow() Create a new window") ui.MsgBox(uiW, msg1, msg2)
var junk GuiWindow // TODO: make new node
junk.MakeWindow = callback return nil
// 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 InitTabWindow(gw *GuiWindow) { func ErrorWindow(msg1 string, msg2 string) (*Node) {
log.Println("InitTabWindow() START. THIS WINDOW IS NOT YET SHOWN") uiW := findUiWindow()
ui.MsgBoxError(uiW, msg1, msg2)
return nil
}
gw.UiWindow = ui.NewWindow("InitTabWindow()", int(gw.Width), int(gw.Height), true) func initNode(title string, x int, y int) *Node {
gw.UiWindow.SetBorderless(false) var node Node
node.Name = title
node.Width = x
node.Height = y
gw.UiWindow.OnClosing(func(*ui.Window) bool { id := Config.prefix + strconv.Itoa(Config.counter)
log.Println("InitTabWindow() OnClosing() THIS WINDOW IS CLOSING gw=", gw) Config.counter += 1
ui.Quit() 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 return true
}) })
gw.UiTab = ui.NewTab() n.uiWindow = window
gw.UiWindow.SetChild(gw.UiTab) if(n.uiWindow == nil) {
gw.UiWindow.SetMargined(true) log.Println("ERROR: node.uiWindow == nil. This should never happen")
}
return n
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)
} }