diff --git a/box.go b/box.go deleted file mode 100644 index 77fb844..0000000 --- a/box.go +++ /dev/null @@ -1,105 +0,0 @@ -package gui - -import "log" -import "os" - -import "github.com/andlabs/ui" -import _ "github.com/andlabs/ui/winmanifest" - -func (n *Node) AddBox(axis int, name string) *Node { - newBox := new(GuiBox) - newBox.Window = n.window - newBox.Name = name - - if (n.box == nil) { - n.box = newBox - } - - // make a new box & a new node - newNode := n.New(name) - newNode.box = newBox - Config.counter += 1 - - var uiBox *ui.Box - if (axis == Xaxis) { - uiBox = ui.NewHorizontalBox() - } else { - uiBox = ui.NewVerticalBox() - } - uiBox.SetPadded(true) - newBox.UiBox = uiBox - newNode.uiBox = uiBox - - n.Append(newNode) - // add(n.box, newBox) - return newNode -} - -func HorizontalBreak(box *GuiBox) { - log.Println("VerticalSeparator added to box =", box.Name) - tmp := ui.NewHorizontalSeparator() - if (box == nil) { - return - } - if (box.UiBox == nil) { - return - } - box.UiBox.Append(tmp, false) -} - -func VerticalBreak(box *GuiBox) { - log.Println("VerticalSeparator added to box =", box.Name) - tmp := ui.NewVerticalSeparator() - box.UiBox.Append(tmp, false) -} - -func (n *Node) AddComboBox(title string, s ...string) *Node { - if (n.Toolkit == nil) { - log.Println("AddComboBox.Toolkit is nil", title, s) - n.Dump() - os.Exit(0) - } - if (n.uiBox == nil) { - log.Println("AddComboBox.uiBox is nil", title, s) - n.Toolkit.Dump() - n.uiBox = n.Toolkit.GetBox() - // os.Exit(0) - // return n - } - box := n.uiBox - - newNode := n.New(title) - ecbox := ui.NewEditableCombobox() - - for id, name := range s { - log.Println("Adding Combobox Entry:", id, name) - ecbox.Append(name) - } - - ecbox.OnChanged(func(*ui.EditableCombobox) { - test := ecbox.Text() - log.Println("node.Name = '" + n.Name + "' text for '" + title + "' is now: '" + test + "'") - log.Println("need to call node.OnChanged() here") - if (newNode.OnChanged == nil) { - log.Println("node.OnChanged() is nil") - log.Println("need to call node.OnChanged() here", newNode.OnChanged) - newNode.Dump() - } else { - log.Println("need to call node.OnChanged() here", newNode.OnChanged) - newNode.OnChanged(newNode) - } - }) - - box.Append(ecbox, false) - - newNode.uiText = ecbox - return newNode -} - -func (n *Node) GetText() string { - if (n.uiText == nil) { - return "" - } - ecbox := n.uiText - return ecbox.Text() -} diff --git a/button.go b/button.go index e7ed277..2e2c7b4 100644 --- a/button.go +++ b/button.go @@ -1,184 +1,20 @@ package gui import "log" -// import "reflect" -import "github.com/andlabs/ui" -import _ "github.com/andlabs/ui/winmanifest" -// import "github.com/davecgh/go-spew/spew" - - -// This is the default mouse click handler -// Every mouse click that hasn't been assigned to -// something specific will fall into this routine -// By default, all it runs is the call back to -// the main program that is using this library -// -// This routine MUST be here as this is how the andlabs/ui works -// This is the raw routine passed to every button in andlabs libui / ui -// -// There is a []GuiButton which has all the buttons. We search -// for the button and then call the function below -// -func defaultButtonClick(button *ui.Button) { - log.Println("gui.defaultButtonClick() LOOK FOR BUTTON button =", button) - for key, foo := range Data.AllButtons { - if (Config.Debug) { - log.Println("gui.defaultButtonClick() Data.AllButtons =", key, foo) - // spew.Dump(foo) - } - if Data.AllButtons[key].B == button { - log.Println("\tgui.defaultButtonClick() BUTTON MATCHED") - guiButtonClick(Data.AllButtons[key]) - return - } - } - log.Println("\tgui.defaultButtonClick() ERROR: BUTTON NOT FOUND") - if (Config.Debug) { - panic("gui.defaultButtonClick() ERROR: UNMAPPED ui.Button") - } -} - -func guiButtonClick(button *GuiButton) { - log.Println("\tgui.guiButtonClick() button.Name =", button.Name) - if button.Custom != nil { - log.Println("\tgui.guiButtonClick() DOING CUSTOM FUNCTION") - button.Custom(button) - return - } - if (Data.MouseClick != nil) { - Data.MouseClick(button) - } else { - log.Println("\tgui.guiButtonClick() IGNORING BUTTON. MouseClick() is nil") - } -} func (n *Node) AddButton(name string, custom func(*Node)) *Node { - if (n.Toolkit == nil) { - log.Println("gui.Node.AppendButton() filed node.Toolkit == nil") - panic("gui.Node.AppendButton() filed node.Toolkit == nil") + if (n.toolkit == nil) { + log.Println("gui.Node.AppendButton() filed node.toolkit == nil") + panic("gui.Node.AppendButton() filed node.toolkit == nil") return n } - /* - button := ui.NewButton(name) - log.Println("reflect.TypeOF(uiBox) =", reflect.TypeOf(n.uiBox)) - log.Println("reflect.TypeOF(uiButton) =", reflect.TypeOf(button)) - n.uiBox.Append(button, false) - n.uiButton = button - */ - newNode := n.New(name) - newNode.Toolkit = n.Toolkit.NewButton(name) - newNode.Toolkit.Custom = func() { + newNode.toolkit = n.toolkit.NewButton(name) + newNode.toolkit.Custom = func() { log.Println("gui.AppendButton() Button Clicked. Running custom()") custom(newNode) } newNode.custom = custom - /* - button.OnClicked(func(*ui.Button) { - log.Println("gui.AppendButton() Button Clicked. Running custom()") - custom(newNode) - }) - */ - // panic("AppendButton") - // time.Sleep(3 * time.Second) return newNode } - -func (n *Node) CreateButton(custom func(*GuiButton), name string, values interface {}) *Node { - newNode := n.AddBox(Xaxis, "test CreateButton") - box := newNode.FindBox() - if (box == nil) { - panic("node.CreateButton().FindBox() == nil") - } - newUiB := ui.NewButton(name) - newUiB.OnClicked(defaultButtonClick) - - var newB *GuiButton - newB = new(GuiButton) - newB.B = newUiB - if (box.UiBox == nil) { - log.Println("CreateButton() box.Window == nil") - // ErrorWindow(box.Window, "Login Failed", msg) // can't even do this - panic("maybe print an error and return nil? or make a fake button?") - } else { - // uibox := box.UiBox - // uibox.Append(newUiB, true) - } - newB.Box = box - newB.Custom = custom - newB.Values = values - - Data.AllButtons = append(Data.AllButtons, newB) - - box.Append(newB.B, false) - return newNode -} - -func (n *Node) NewButton(box *GuiBox, custom func(*GuiButton), name string, values interface {}) *GuiButton { - return CreateButton(box, custom, name, values) -} - -func CreateButton(box *GuiBox, custom func(*GuiButton), name string, values interface {}) *GuiButton { - newUiB := ui.NewButton(name) - newUiB.OnClicked(defaultButtonClick) - - var newB *GuiButton - newB = new(GuiButton) - newB.B = newUiB - if (box.Window == nil) { - log.Println("CreateButton() box.Window == nil") - // ErrorWindow(box.Window, "Login Failed", msg) // can't even do this - panic("maybe print an error and return nil? or make a fake button?") - } - newB.Box = box - newB.Custom = custom - newB.Values = values - - Data.AllButtons = append(Data.AllButtons, newB) - - box.Append(newB.B, false) - return newB -} - -func CreateFontButton(box *GuiBox, action string) *GuiButton { - // create a 'fake' button entry for the mouse clicks - var newGB GuiButton - newGB.Name = "FONT" - newGB.FB = ui.NewFontButton() - newGB.Box = box - Data.AllButtons = append(Data.AllButtons, &newGB) - - newGB.FB.OnChanged(func (*ui.FontButton) { - log.Println("FontButton.OnChanged() START mouseClick(&newBM)", newGB) - if (Data.MouseClick != nil) { - Data.MouseClick(&newGB) - } - }) - return &newGB -} - -func CreateColorButton(box *GuiBox, custom func(*GuiButton), name string, values interface {}) *GuiButton { - // create a 'fake' button entry for the mouse clicks - var newCB GuiButton - newCB.Name = name - newCB.CB = ui.NewColorButton() - newCB.Box = box - newCB.Custom = custom - newCB.Values = values - - Data.AllButtons = append(Data.AllButtons, &newCB) - - newCB.CB.OnChanged(func (*ui.ColorButton) { - log.Println("ColorButton.OnChanged() START Color Button Click") - r, g, b, a := newCB.CB.Color() - log.Println("ColorButton.OnChanged() Color() =", r, g, b, a) - if (newCB.Custom != nil) { - newCB.Custom(&newCB) - } else if (Data.MouseClick != nil) { - Data.MouseClick(&newCB) - } - }) - box.Append(newCB.CB, false) - return &newCB -} diff --git a/cmds/consolemouse/main.go b/cmds/consolemouse/main.go index 44ad18d..3f4ce58 100644 --- a/cmds/consolemouse/main.go +++ b/cmds/consolemouse/main.go @@ -32,26 +32,17 @@ func initGUI() { addDemoTab(w, "A Second Tab") } -func addDemoTab(window *gui.Node, title string) { +func addDemoTab(w *gui.Node, title string) { var newNode, g *gui.Node - newNode = window.AddTab(title, nil) - log.Println("addDemoTab() newNode.Dump") - log.Println("addDemoTab() newNode.Dump") - log.Println("addDemoTab() newNode.Dump") - log.Println("addDemoTab() newNode.Dump") - newNode.Dump() - newNode.Toolkit.Dump() + newNode = w.NewTab(title) g = newNode.NewGroup("group 1") - log.Println("addDemoTab() g.Dump") - log.Println("addDemoTab() g.Dump") - log.Println("addDemoTab() g.Dump") - log.Println("addDemoTab() g.Dump") - g.Dump() - g.Toolkit.Dump() - // myExit(nil) - g.AddComboBox("demoCombo2", "more 1", "more 2", "more 3") + + dd := g.NewDropdown("demoCombo2") + dd.AddDropdown("more 1") + dd.AddDropdown("less 2") + dd.AddDropdown("foo 3") } func myExit(n *gui.Node) { diff --git a/cmds/gui-demo/main.go b/cmds/gui-demo/main.go index d89b1b0..54ad449 100644 --- a/cmds/gui-demo/main.go +++ b/cmds/gui-demo/main.go @@ -10,6 +10,8 @@ import ( // This initializes the first window // +// BUG: THIS PROGRAM DOESN'T EXIT PROPERLY (NOT REALLY A BUG) +// // Then starts a goroutine to demonstrate how to // inject things into the GUI func main() { diff --git a/cmds/helloworld/main.go b/cmds/helloworld/main.go index 97af97b..bc1ea5a 100644 --- a/cmds/helloworld/main.go +++ b/cmds/helloworld/main.go @@ -37,13 +37,12 @@ func initGUI() { func addDemoTab(window *gui.Node, title string) { var newNode, g *gui.Node - newNode = window.AddTab(title, nil) + newNode = window.NewTab(title) log.Println("addDemoTab() newNode.Dump") log.Println("addDemoTab() newNode.Dump") log.Println("addDemoTab() newNode.Dump") log.Println("addDemoTab() newNode.Dump") newNode.Dump() - newNode.Toolkit.Dump() g = newNode.NewGroup("group 1") log.Println("addDemoTab() g.Dump") @@ -51,9 +50,11 @@ func addDemoTab(window *gui.Node, title string) { log.Println("addDemoTab() g.Dump") log.Println("addDemoTab() g.Dump") g.Dump() - g.Toolkit.Dump() // os.Exit(0) - g.AddComboBox("demoCombo2", "more 1", "more 2", "more 3") + dd := g.NewDropdown("demoCombo2") + dd.AddDropdown("more 1") + dd.AddDropdown("more 2") + dd.AddDropdown("more 3") } func myDefaultExit(n *gui.Node) { diff --git a/debug-window.go b/debug-window.go deleted file mode 100644 index 776c8e0..0000000 --- a/debug-window.go +++ /dev/null @@ -1,357 +0,0 @@ -package gui - -import ( - "log" -// "time" -// "os" - - "github.com/andlabs/ui" - _ "github.com/andlabs/ui/winmanifest" - "github.com/davecgh/go-spew/spew" -) - -var names = make([]string, 100) -var nodeNames = make([]string, 100) - -var bugWin *Node -/* - Creates a window helpful for debugging this package -*/ -func DebugWindow() { - Config.Title = "git.wit.org/wit/gui debug fixme" - Config.Width = 300 - Config.Height = 200 - Config.Exit = StandardClose - bugWin = NewWindow() - bugWin.DebugTab("does this also work?") - // node.DebugTab("WIT GUI Debug Tab") -} - -// TODO: remove this crap -// What does this actually do? -// It populates the nodeNames in a map. No, not a map, an array. -// What is the difference again? (other than one being in order and a predefined length) -func addNodeNameBAD(c *ui.Combobox, s string, id string) { - c.Append(s) - // nodeNames[y] = id - // y = y + 1 - log.Println("addNodeName:", s) - // time.Sleep(1 * time.Second) - // os.Exit(0) -} - -func makeWindowDebug() *ui.Box { - hbox := ui.NewHorizontalBox() - hbox.SetPadded(true) - - ///////////////////////////////////////////////////// - vbox := addGroup(hbox, "range Data.WindowMap") - cbox := ui.NewCombobox() - - for name, _ := range Data.WindowMap { - if (Config.Debug) { - log.Println("range Data.WindowMap() name =", name) - } - addNameBAD(cbox, name) - } - cbox.SetSelected(0) - - vbox.Append(cbox, false) - - cbox.OnSelected(func(*ui.Combobox) { - x := cbox.Selected() - log.Println("x =", x) - log.Println("names[x] =", names[x]) - dumpBox(names[x]) - }) - - ///////////////////////////////////////////////////// - vbox = addGroup(hbox, "Debug Window") - - b1 := addButton(vbox, "dumpBox(window)") - b1.OnClicked(func(*ui.Button) { - x := cbox.Selected() - log.Println("x =", x) - log.Println("names[x] =", names[x]) - dumpBox(names[x]) - }) - - b2 := addButton(vbox, "SetMargined(tab)") - b2.OnClicked(func(*ui.Button) { - x := cbox.Selected() - log.Println("x =", x) - log.Println("FindWindow; names[x] =", names[x]) - gw := FindWindow(names[x]) - if gw == nil { - return - } - if gw.UiTab == nil { - return - } - if gw.TabNumber == nil { - return - } - scs := spew.ConfigState{MaxDepth: 1} - scs.Dump(gw) - log.Println("gui.dumpBoxes()\tWindow.UiTab =", gw.UiTab) - log.Println("gui.dumpBoxes()\tWindow.TabNumber =", *gw.TabNumber) - gw.UiTab.SetMargined(*gw.TabNumber, true) - }) - - b3 := addButton(vbox, "Hide(tab)") - b3.OnClicked(func(*ui.Button) { - x := cbox.Selected() - log.Println("x =", x) - log.Println("FindWindow; names[x] =", names[x]) - gw := FindWindow(names[x]) - if gw == nil { - return - } - if gw.UiTab == nil { - return - } - gw.UiTab.Hide() - }) - - b4 := addButton(vbox, "Show(tab)") - b4.OnClicked(func(*ui.Button) { - x := cbox.Selected() - log.Println("x =", x) - log.Println("FindWindow; names[x] =", names[x]) - gw := FindWindow(names[x]) - if gw == nil { - return - } - if gw.UiTab == nil { - return - } - gw.UiTab.Show() - }) - - b5 := addButton(vbox, "Delete(tab)") - b5.OnClicked(func(*ui.Button) { - x := cbox.Selected() - log.Println("x =", x) - log.Println("FindWindow; names[x] =", names[x]) - gw := FindWindow(names[x]) - if gw == nil { - return - } - if gw.UiTab == nil { - return - } - if gw.TabNumber == nil { - return - } - gw.UiTab.Delete(*gw.TabNumber) - }) - - ///////////////////////////////////////////////////// - vbox = addGroup(hbox, "Global Debug") - - dump3 := addButton(vbox, "Dump Windows") - dump3.OnClicked(func(*ui.Button) { - dumpWindows() - }) - - dump2 := addButton(vbox, "Dump Boxes") - dump2.OnClicked(func(*ui.Button) { - dumpBoxes() - }) - - dump1 := addButton(vbox, "Dump MAP") - dump1.OnClicked(func(*ui.Button) { - dumpMap() - }) - - ///////////////////////////////////////////////////// - nodeBox := addGroup(hbox, "Windows:") - nodeCombo := ui.NewCombobox() - - for name, node := range Data.NodeMap { - // if (Config.Debug) { - log.Println("range Data.NodeMap() name =", name) - // } - tmp := node.id + " (" + name + ")" - addNodeNameBAD(nodeCombo, tmp, node.id) - } -// scs := spew.ConfigState{MaxDepth: 1} -// scs.Dump(Data.NodeMap) -// os.Exit(0) - nodeCombo.SetSelected(0) - - nodeBox.Append(nodeCombo, false) - - nodeCombo.OnSelected(func(*ui.Combobox) { - y := nodeCombo.Selected() - log.Println("y =", y) - log.Println("nodeNames[y] =", nodeNames[y]) - node := Data.findId(nodeNames[y]) - if (node != nil) { - node.Dump() - } - }) - - ///////////////////////////////////////////////////// - vbox = addGroup(hbox, "Node Debug") - - n1 := addButton(vbox, "Data.DumpNodeMap()") - n1.OnClicked(func(*ui.Button) { - Data.DumpNodeMap() - }) - - n1 = addButton(vbox, "Data.ListChildren(false)") - n1.OnClicked(func(*ui.Button) { - Data.ListChildren(false) - }) - - n1 = addButton(vbox, "Data.ListChildren(true)") - n1.OnClicked(func(*ui.Button) { - Data.ListChildren(true) - }) - - n1 = addButton(vbox, "Node.Dump()") - n1.OnClicked(func(*ui.Button) { - y := nodeCombo.Selected() - log.Println("y =", y) - log.Println("nodeNames[y] =", nodeNames[y]) - node := Data.findId(nodeNames[y]) - if (node != nil) { - node.Dump() - } - }) - - n1 = addButton(vbox, "Node.ListChildren(false)") - n1.OnClicked(func(*ui.Button) { - y := nodeCombo.Selected() - log.Println("y =", y) - log.Println("nodeNames[y] =", nodeNames[y]) - node := Data.findId(nodeNames[y]) - if (node != nil) { - node.ListChildren(false) - } - }) - - n1 = addButton(vbox, "Node.ListChildren(true)") - n1.OnClicked(func(*ui.Button) { - y := nodeCombo.Selected() - log.Println("y =", y) - log.Println("nodeNames[y] =", nodeNames[y]) - node := Data.findId(nodeNames[y]) - if (node != nil) { - node.ListChildren(true) - } - }) - - n1 = addButton(vbox, "Node.AddDebugTab") - n1.OnClicked(func(*ui.Button) { - y := nodeCombo.Selected() - log.Println("y =", y) - log.Println("nodeNames[y] =", nodeNames[y]) - node := Data.findId(nodeNames[y]) - if (node != nil) { - node.DebugTab("added this DebugTab") - } - }) - - return hbox -} - -// TODO: remove this crap -// var x int = 0 -// var y int = 0 - -// TODO: remove this crap -func addNameBAD(c *ui.Combobox, s string) { - c.Append(s) - // names[x] = s - // x = x + 1 - log.Println("addName:", s) - // time.Sleep(1 * time.Second) - // os.Exit(0) -} - -func addGroup(b *ui.Box, name string) *ui.Box { - group := ui.NewGroup(name) - group.SetMargined(true) - b.Append(group, true) - - vbox := ui.NewVerticalBox() - vbox.SetPadded(true) - group.SetChild(vbox) - - return vbox -} - -func dumpBox(s string) { - var name string - var window *GuiWindow - - for name, window = range Data.WindowMap { - if name != s { - continue - } - log.Println("gui.DumpBoxes() MAP: ", name) - if window.TabNumber == nil { - log.Println("gui.DumpBoxes() \tWindows.TabNumber = nil") - } else { - log.Println("gui.DumpBoxes() \tWindows.TabNumber =", *window.TabNumber) - } - log.Println("gui.DumpBoxes()\tWindow.name =", window.Name) - // log.Println("gui.DumpBoxes()\tWindow.UiWindow type =", reflect.TypeOf(window.UiWindow)) - log.Println("gui.DumpBoxes()\tWindow.UiWindow =", window.UiWindow) - log.Println("gui.DumpBoxes()\tWindow.UiTab =", window.UiTab) - log.Println("gui.dumpBox() BoxMap START") - for name, abox := range window.BoxMap { - log.Printf("gui.DumpBoxes() \tBOX mapname=%-12s abox.Name=%-12s", name, abox.Name) - abox.Dump() - if name == "MAINBOX" { - if Config.Debug { - scs := spew.ConfigState{MaxDepth: 1} - scs.Dump(abox.UiBox) - } - } - } - log.Println("gui.dumpBox() BoxMap END") - if window.UiTab != nil { - pages := window.UiTab.NumPages() - log.Println("gui.DumpBoxes()\tWindow.UiTab.NumPages() =", pages) - // fixme: tabSetMargined(window.UiTab) - if Config.Debug { - scs := spew.ConfigState{MaxDepth: 2} - scs.Dump(window.UiTab) - } - } - } -} - -func addButton(box *ui.Box, name string) *ui.Button { - button := ui.NewButton(name) - - button.OnClicked(func(*ui.Button) { - log.Println("Should do something here") - }) - - box.Append(button, false) - return button -} - -func DebugTab() { - bugWin.DebugTab("does this work?") -} - -func (n *Node) DebugTab(title string) *Node { - var newN *Node - var b *ui.Box - // var uiBox *ui.Box - - // time.Sleep(1 * time.Second) - newN = n.AddTabNew(title + " fix makeWindowDebug") - newN.Toolkit.Dump() - b = makeWindowDebug() - newN.Toolkit.SetTabBox(b) - // FIXME: make sure this is getting run to add padding: tabSetMargined(newN.uiTab) - // os.Exit(0) - - return newN -} diff --git a/debug.go b/debug.go deleted file mode 100644 index 7db2847..0000000 --- a/debug.go +++ /dev/null @@ -1,162 +0,0 @@ -package gui - -import ( - "fmt" - "log" - "time" - - "github.com/davecgh/go-spew/spew" -) - -// WatchGUI() opens a goroutine -// -// From that goroutine, it dumps out debugging information every 4 seconds -/* - TODO: add configuration triggers on what to dump out - TODO: allow this to be sent to /var/log, syslogd, systemd's journalctl, etc -*/ -/* -func watchGUI() { - count := 0 - - for { - if count > 20 { - log.Println("Sleep() in watchGUI()") - if Config.Debug { - dumpBoxes() - } - count = 0 - } - count += 1 - time.Sleep(200 * time.Millisecond) - } -} -*/ - -func dumpWindows() { - for name, _ := range Data.WindowMap { - log.Println("gui.DumpWindows() window =", name) - } -} - -func dumpMap() { - for name, window := range Data.WindowMap { - log.Println("gui.DumpBoxes() MAP: ", name) - log.Println("gui.DumpBoxes() BOXES:", name) - for name, abox := range window.BoxMap { - log.Printf("gui.DumpBoxes() \tBOX mapname=%-12s abox.Name=%-12s", name, abox.Name) - } - } -} - -func dumpBoxes() { - for name, window := range Data.WindowMap { - log.Println("gui.DumpBoxes() MAP: ", name) - if window.TabNumber == nil { - log.Println("gui.DumpBoxes() \tWindows.TabNumber = nil") - } else { - log.Println("gui.DumpBoxes() \tWindows.TabNumber =", *window.TabNumber) - } - log.Println("gui.DumpBoxes()\tWindow.name =", window.Name) - // log.Println("gui.DumpBoxes()\tWindow.UiWindow type =", reflect.TypeOf(window.UiWindow)) - log.Println("gui.DumpBoxes()\tWindow.UiWindow =", window.UiWindow) - log.Println("gui.DumpBoxes()\tWindow.UiTab =", window.UiTab) - for name, abox := range window.BoxMap { - log.Printf("gui.DumpBoxes() \tBOX mapname=%-12s abox.Name=%-12s", name, abox.Name) - if name == "MAINBOX" { - if Config.Debug { - scs := spew.ConfigState{MaxDepth: 1} - scs.Dump(abox.UiBox) - } - } - } - if window.UiTab != nil { - // log.Println("gui.DumpBoxes()\tWindow.UiTab type =", reflect.TypeOf(window.UiTab)) - // log.Println("gui.DumpBoxes()\tWindow.UiTab =", window.UiTab) - pages := window.UiTab.NumPages() - log.Println("gui.DumpBoxes()\tWindow.UiTab.NumPages() =", pages) - // for i := 0; i < pages; i++ { - // log.Println("gui.DumpBoxes()\t\tWindow.UiTab.Margined(", i, ") =", window.UiTab.Margined(i)) - // } - // tmp := spew.NewDefaultConfig() - // tmp.MaxDepth = 2 - // tmp.Dump(window.UiTab) - if Config.Debug { - scs := spew.ConfigState{MaxDepth: 2} - scs.Dump(window.UiTab) - } - } - } - /* - for i, window := range Data.Windows { - if (window.TabNumber == nil) { - log.Println("gui.DumpBoxes() Data.Windows", i, "Name =", window.Name, "TabNumber = nil") - } else { - log.Println("gui.DumpBoxes() Data.Windows", i, "Name =", window.Name, "TabNumber =", *window.TabNumber) - } - } - */ -} - -func addTableTab() { - var parts []TableColumnData - - for key, foo := range []string{"BG", "TEXTCOLOR", "BUTTON", "TEXTCOLOR", "TEXTCOLOR", "TEXT", "BUTTON", "TEXT", "BUTTON"} { - log.Println(key, foo) - - var b TableColumnData - b.CellType = foo - b.Heading = fmt.Sprintf("heading%d", key) - parts = append(parts, b) - } - - log.Println("Sleep for 1 second, then try to add new tabs") - time.Sleep(1 * time.Second) -} - -func (dn *GuiData) DumpNodeMap() { - log.Println("DebugDataNodeMap():") - for name, node := range dn.NodeMap { - log.Println("\tNode =", node.id, node.Width, node.Height, name) - if (node.children == nil) { - log.Println("\t\tNo children") - } else { - log.Println("\t\tHas children:", node.children) - } - // node.SetName("yahoo") - // log.Println("\tData.NodeMap node =", node) - } -} - -/* -func DebugDataNodeChildren() { - if Data.NodeMap == nil { - log.Println("DebugDataNodeChildren() NodeMap == nil") - return - } - log.Println("DebugDataNodeChildren():") - for name, node := range Data.NodeMap { - log.Println("\tNode name =", node.Width, node.Height, name) - if (node.children == nil) { - log.Println("\t\tNo children") - break - } - log.Println("\t\tHas children:", node.children) - } -} -*/ - -func (dn *GuiData) ListChildren(dump bool) { - if Data.NodeMap == nil { - log.Println("gui.Data.ListChildren() Data.NodeMap == nil") - return - } - log.Println("gui.Data.ListChildren() Data.NodeMap:") - for name, node := range Data.NodeMap { - log.Println("\tgui.Data.ListChildren() node =", node.id, node.Width, node.Height, name) - if (dump == true) { - node.Dump() - } - node.ListChildren(dump) - } -} diff --git a/doc.go b/doc.go index 25ef728..87f4f67 100644 --- a/doc.go +++ b/doc.go @@ -17,6 +17,7 @@ Principles: * It's ok to guess. We will return something close. * Hide complexity internally here * Isolate the GUI toolkit + * Function names should follow https://en.wikipedia.org/wiki/Graphical_widget Quick Start diff --git a/dropdown.go b/dropdown.go new file mode 100644 index 0000000..eede92f --- /dev/null +++ b/dropdown.go @@ -0,0 +1,52 @@ +package gui + +import "log" + +import toolkit "git.wit.org/wit/gui/toolkit/andlabs" + +func (n *Node) NewDropdown(name string) *Node { + var newT *toolkit.Toolkit + var sNode *Node + + log.Println("toolkit.NewDropdown() START", name) + + // make this generic + if (n.toolkit == nil) { + log.Println("toolkit.NewSlider() toolkit == nil") + panic("toolkit should never be nil") + } + + sNode = n.New(name + " part1") + newT = n.toolkit.NewDropdown(name) + newT.Name = name + sNode.custom = n.custom + newT.Custom = func () { + // TODO: make all of this common code to all the widgets + if (n.custom == nil) { + log.Println("Not Running n.custom(n) == nil") + } else { + log.Println("Running n.custom(n)") + sNode.custom(sNode) + } + if (sNode.OnChanged == nil) { + log.Println("Not Running n.OnChanged(n) == nil") + } else { + log.Println("Running n.OnChanged(n)") + sNode.OnChanged(sNode) + } + } + sNode.toolkit = newT + sNode.Dump() + sNode.toolkit.Dump() + // panic("checking Custom()") + + return sNode +} + +func (n *Node) AddDropdown(name string) { + n.toolkit.AddDropdown(name) +} + +func (n *Node) SetDropdown(i int) { + n.toolkit.SetDropdown(i) +} diff --git a/find.go b/find.go deleted file mode 100644 index e046161..0000000 --- a/find.go +++ /dev/null @@ -1,156 +0,0 @@ -package gui - -import ( - "log" - "os" - - "github.com/andlabs/ui" - _ "github.com/andlabs/ui/winmanifest" -// "github.com/davecgh/go-spew/spew" -) - -func (n *Node) FindTab() *ui.Tab { - return n.uiTab -} - -func (n *Node) FindControl() *ui.Control { - return n.uiControl -} - -func (n *Node) FindBox() *GuiBox { - if (n.box != nil) { - return n.box - } - if (n.parent != nil) { - p := n.parent - return p.box - } - return n.box -} - -func (n *Node) FindWindowBox() *GuiBox { - if (n.box == nil) { - panic("SERIOUS ERROR n.box == nil in FindWindowBox()") - } - return n.box -} - -func (w *GuiWindow) FindNode() *Node { - return w.node -} - -func (b *GuiBox) FindNode() *Node { - log.Println("gui.FindNode() on GuiBox") - if b.node != nil { - return b.node - } - Data.ListChildren(true) - b.Dump() - log.Println("gui.FindNode() on GuiBox is nil") - os.Exit(-1) - return nil -} - -func FindWindow(s string) *GuiWindow { - for name, window := range Data.WindowMap { - if name == s { - return window - } - } - log.Printf("COULD NOT FIND WINDOW " + s) - return nil -} - -func FindBox(s string) *GuiBox { - for name, window := range Data.WindowMap { - if name != s { - continue - } - for name, abox := range window.BoxMap { - log.Printf("gui.DumpBoxes() \tBOX mapname=%-12s abox.Name=%-12s", name, abox.Name) - return abox - } - log.Println("gui.FindBox() NEED TO INIT WINDOW name =", name) - } - log.Println("gui.FindBox() COULD NOT FIND BOX", s) - return nil -} - -func FindNode(name string) *Node { - if Data.NodeMap == nil { - log.Println("gui.FindNode() gui.Data.NodeMap == nil") - return nil - } - log.Println("gui.FindNode() searching Data.NodeMap:") - for id, node := range Data.NodeMap { - log.Println("\tData.NodeMap name =", node.Width, node.Height, id) - node.Dump() - if (name == node.Name) { - return node - } - newNode := findByName(node, name) - if (newNode != nil) { - return newNode - } - log.Println("gui.FindNode() could not find node name =", name) - os.Exit(-1) - } - log.Println("gui.FindNode() could not find node name =", name) - return nil -} - -func (dn *GuiData) findId(id string) *Node { - if Data.NodeMap == nil { - log.Println("gui.Data.findId() map == nil") - return nil - } - // log.Println("Dumping Data.NodeMap:") - for name, node := range Data.NodeMap { - // log.Println("\tData.NodeMap name =", node.id, node.Width, node.Height, name) - if (id == node.id) { - log.Println("\tgui.Data.findId() found node =", node.id, node.Width, node.Height, name) - return node - } - // TODO: fix // Oct 9 - // node.findId(id) - } - return nil -} - -func findByIdDFS(node *Node, id string) *Node { - log.Println("findByIdDFS()", id, node) - node.Dump() - if node.id == id { - log.Println("Found node id =", id, node) - return node - } - - if len(node.children) > 0 { - for _, child := range node.children { - newNode := findByIdDFS(child, id) - if (newNode != nil) { - return newNode - } - } - } - return nil -} - -func findByName(node *Node, name string) *Node { - log.Println("findByName()", name, node) - node.Dump() - if node.Name == name { - log.Println("findByName() Found node name =", name, node) - return node - } - - if len(node.children) > 0 { - for _, child := range node.children { - newNode := findByName(child, name) - if (newNode != nil) { - return newNode - } - } - } - return nil -} diff --git a/group.go b/group.go index 89c15cc..3c81ecd 100644 --- a/group.go +++ b/group.go @@ -11,15 +11,15 @@ func (n *Node) NewGroup(name string) *Node { var gNode *Node log.Println("toolkit.NewGroup() START", name) - if (n.Toolkit == nil) { - log.Println("toolkit.NewGroup() Toolkit == nil") - panic("Toolkit should never be nil") + if (n.toolkit == nil) { + log.Println("toolkit.NewGroup() toolkit == nil") + panic("toolkit should never be nil") } // make a *Node with a *toolkit.Group gNode = n.New(name + " part1") - newT = n.Toolkit.NewGroup(name) - gNode.Toolkit = newT + newT = n.toolkit.NewGroup(name) + gNode.toolkit = newT log.Println("################## gNode ####### ", name) gNode.Dump() @@ -27,5 +27,5 @@ func (n *Node) NewGroup(name string) *Node { } func (n *Node) AddGroup(title string) *Node { - return n.NewGroup(title + "deprecated AddGroup") + return n.NewGroup(title + " deprecated AddGroup") } diff --git a/gui.go b/gui.go deleted file mode 100644 index 4174133..0000000 --- a/gui.go +++ /dev/null @@ -1,70 +0,0 @@ -package gui - -import ( - "github.com/andlabs/ui" // import "time" - "log" - "regexp" - - _ "github.com/andlabs/ui/winmanifest" -) - -// the _ means we only need this for the init() - -const Xaxis = 0 // box that is horizontal -const Yaxis = 1 // box that is vertical - -func init() { - log.Println("gui.init() has been run") - - Data.buttonMap = make(map[*ui.Button]*GuiButton) - Data.WindowMap = make(map[string]*GuiWindow) - Data.NodeMap = make(map[string]*Node) - - Data.NodeSlice = make([]*Node, 0) - - Config.counter = 0 - Config.prefix = "wit" - Config.DebugNode = false - Config.DebugTabs = false -} - -func GuiInit() { - ui.OnShouldQuit(func() bool { - ui.Quit() - return true - }) -} - -/* -// string handling examples that might be helpful for normalizeInt() -isAlpha := regexp.MustCompile(`^[A-Za-z]+$`).MatchString - -for _, username := range []string{"userone", "user2", "user-three"} { - if !isAlpha(username) { - fmt.Printf("%q is not valid\n", username) - } -} - -const alpha = "abcdefghijklmnopqrstuvwxyz" - -func alphaOnly(s string) bool { - for _, char := range s { - if !strings.Contains(alpha, strings.ToLower(string(char))) { - return false - } - } - return true -} -*/ - -func normalizeInt(s string) string { - // reg, err := regexp.Compile("[^a-zA-Z0-9]+") - reg, err := regexp.Compile("[^0-9]+") - if err != nil { - log.Println("normalizeInt() regexp.Compile() ERROR =", err) - return s - } - clean := reg.ReplaceAllString(s, "") - log.Println("normalizeInt() s =", clean) - return clean -} diff --git a/int.go b/int.go index 4a32c52..d2409da 100644 --- a/int.go +++ b/int.go @@ -20,12 +20,12 @@ func (n *Node) Int() int { scs.Dump(n) } - if (n.Toolkit == nil) { + if (n.toolkit == nil) { log.Println("gui.Node.Int() for toolkit struct = nil") return 0 } - i := n.Toolkit.Value() + i := n.toolkit.Value() return i } @@ -36,11 +36,11 @@ func (n *Node) Value() int { func (n *Node) SetValue(i int) { log.Println("gui.SetValue() START") - if (n.Toolkit == nil) { + if (n.toolkit == nil) { log.Println("gui.Node.SetValue() for toolkit struct = nil") panic("SetValue failed") } n.Dump() - n.Toolkit.Dump() - n.Toolkit.SetValue(i) + n.toolkit.Dump() + n.toolkit.SetValue(i) } diff --git a/main.go b/main.go index 70e0e65..bf4a2cf 100644 --- a/main.go +++ b/main.go @@ -2,14 +2,38 @@ package gui import ( "log" - - "github.com/andlabs/ui" - _ "github.com/andlabs/ui/winmanifest" ) +import toolkit "git.wit.org/wit/gui/toolkit/andlabs" + + +// the _ means we only need this for the init() + +const Xaxis = 0 // box that is horizontal +const Yaxis = 1 // box that is vertical + +func init() { + log.Println("gui.init() has been run") + + Config.counter = 0 + Config.prefix = "wit" + Config.DebugNode = false + Config.DebugTabs = false + + title := "master" + w := 640 + h := 480 + f := StandardClose + + Config.master = addNode(title, w, h) + Config.master.custom = f + + Config.master.Dump() +} + func Main(f func()) { log.Println("Starting gui.Main() (using gtk via andlabs/ui)") - ui.Main(f) + toolkit.Main(f) } // Other goroutines must use this to access the GUI @@ -17,18 +41,8 @@ func Main(f func()) { // 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()) +// For example: gui.Queue(NewWindow()) func Queue(f func()) { log.Println("Sending function to gui.Main() (using gtk via andlabs/ui)") - ui.QueueMain(f) + toolkit.Queue(f) } - -/* -func ExampleWindow() { - log.Println("START gui.ExampleWindow()") - - Config.Title = "ExampleWindow" - node := NewWindow() - node.AddDebugTab("jcarr Debug") -} -*/ diff --git a/new-structs.go b/new-structs.go deleted file mode 100644 index c05bf23..0000000 --- a/new-structs.go +++ /dev/null @@ -1,241 +0,0 @@ -package gui - -import ( - "log" - - // "github.com/davecgh/go-spew/spew" - - "github.com/andlabs/ui" - _ "github.com/andlabs/ui/winmanifest" - -) - -import toolkit "git.wit.org/wit/gui/toolkit/andlabs" - -type Element int - -// https://ieftimov.com/post/golang-datastructures-trees/ -const ( - Unknown Element = iota - Window - Tab - Box - Label - Combo -) - -func (s Element) String() string { - switch s { - case Window: - return "window" - case Tab: - return "tab" - case Box: - return "box" - case Label: - return "label" - case Combo: - return "combo" - } - return "unknown" -} - -// The Node is simply the name and the size of whatever GUI element exists -type Node struct { - id string - - Name string - Width int - Height int - - parent *Node - children []*Node - - window *GuiWindow - box *GuiBox - custom func(*Node) - OnChanged func(*Node) - - Toolkit *toolkit.Toolkit - - uiControl *ui.Control - uiButton *ui.Button - uiGroup *ui.Group - uiSlider *ui.Slider - uiSpinbox *ui.Spinbox - uiWindow *ui.Window - uiTab *ui.Tab - uiBox *ui.Box - uiText *ui.EditableCombobox -} - -func (n *Node) Parent() *Node { - return n.parent -} - -func (n *Node) Window() *Node { - return n.parent -} - -func (n *Node) Dump() { - IndentPrintln("id = ", n.id) - IndentPrintln("Name = ", n.Name) - IndentPrintln("Width = ", n.Width) - IndentPrintln("Height = ", n.Height) - - if (n.parent == nil) { - IndentPrintln("parent = nil") - } else { - IndentPrintln("parent =", n.parent.id) - } - if (n.children != nil) { - IndentPrintln("children = ", n.children) - } - - if (n.window != nil) { - IndentPrintln("window = ", n.window) - } - if (n.box != nil) { - IndentPrintln("box = ", n.box) - } - - if (n.uiWindow != nil) { - IndentPrintln("uiWindow = ", n.uiWindow) - } - if (n.uiTab != nil) { - IndentPrintln("uiTab = ", n.uiTab) - } - if (n.uiBox != nil) { - IndentPrintln("uiBox = ", n.uiBox) - } - if (n.Toolkit != nil) { - IndentPrintln("Toolkit = ", n.Toolkit) - n.Toolkit.Dump() - } - if (n.uiControl != nil) { - IndentPrintln("uiControl = ", n.uiControl) - } - if (n.uiButton != nil) { - IndentPrintln("uiButton = ", n.uiButton) - } - if (n.custom != nil) { - IndentPrintln("custom = ", n.custom) - } - if (n.OnChanged != nil) { - IndentPrintln("OnChanged = ", n.OnChanged) - } - if (n.id == "") { - // Node structs should never have a nil id. - // I probably shouldn't panic here, but this is just to check the sanity of - // the gui package to make sure it's not exiting - panic("gui.Node.Dump() id == nil TODO: make a unigue id here in the golang gui library") - } -} - - -func (n *Node) SetBox(box *GuiBox) { - n.box = box -} - -func (n *Node) SetName(name string) { - // n.uiType.SetName(name) - if (n.uiWindow != nil) { - log.Println("node is a window. setting title =", name) - n.uiWindow.SetTitle(name) - return - } - log.Println("*ui.Control =", n.uiControl) - return -} - -func (n *Node) Append(child *Node) { - // if (n.UiBox == nil) { - // return - // } - n.children = append(n.children, child) - if (Config.Debug) { - log.Println("child node:") - child.Dump() - log.Println("parent node:") - n.Dump() - } - // time.Sleep(3 * time.Second) -} - -func (n *Node) List() { - findByIdDFS(n, "test") -} - -var listChildrenParent *Node -var listChildrenDepth int = 0 -var defaultPadding = " " - -func IndentPrintln(a ...interface{}) { - indentPrintln(listChildrenDepth, defaultPadding, a) -} - -func indentPrintln(depth int, format string, a ...interface{}) { - var tabs string - for i := 0; i < depth; i++ { - tabs = tabs + format - } - - // newFormat := tabs + strconv.Itoa(depth) + " " + format - newFormat := tabs + format - log.Println(newFormat, a) -} - -func (n *Node) ListChildren(dump bool) { - indentPrintln(listChildrenDepth, defaultPadding, n.id, n.Width, n.Height, n.Name) - - if (dump == true) { - n.Dump() - } - if len(n.children) == 0 { - if (n.parent == nil) { - } else { - if (Config.DebugNode) { - log.Println("\t\t\tparent =",n.parent.id) - } - if (listChildrenParent != nil) { - if (Config.DebugNode) { - log.Println("\t\t\tlistChildrenParent =",listChildrenParent.id) - } - if (listChildrenParent.id != n.parent.id) { - log.Println("parent.child does not match child.parent") - panic("parent.child does not match child.parent") - } - } - } - if (Config.DebugNode) { - log.Println("\t\t", n.id, "has no children") - } - return - } - for _, child := range n.children { - // log.Println("\t\t", child.id, child.Width, child.Height, child.Name) - if (child.parent != nil) { - if (Config.DebugNode) { - log.Println("\t\t\tparent =",child.parent.id) - } - } else { - log.Println("\t\t\tno parent") - panic("no parent") - } - if (dump == true) { - child.Dump() - } - if (Config.DebugNode) { - if (child.children == nil) { - log.Println("\t\t", child.id, "has no children") - } else { - log.Println("\t\t\tHas children:", child.children) - } - } - listChildrenParent = n - listChildrenDepth += 1 - child.ListChildren(dump) - listChildrenDepth -= 1 - } - return -} diff --git a/node.go b/node.go index 2c63c74..d1b172a 100644 --- a/node.go +++ b/node.go @@ -28,13 +28,6 @@ func addNode(title string, w int, h int) *Node { id := Config.prefix + strconv.Itoa(Config.counter) Config.counter += 1 n.id = id - /* - if (Data.NodeMap[title] != nil) { - panic(fmt.Sprintf("Duplicate window name = %s\n", title)) - } else { - Data.NodeMap[title] = &n - } - */ return &n } diff --git a/slider.go b/slider.go index 7d1a0ba..4ee144c 100644 --- a/slider.go +++ b/slider.go @@ -10,17 +10,34 @@ func (n *Node) NewSlider(name string, x int, y int) *Node { log.Println("toolkit.NewSlider() START", name) - if (n.Toolkit == nil) { - log.Println("toolkit.NewSlider() Toolkit == nil") + if (n.toolkit == nil) { + log.Println("toolkit.NewSlider() toolkit == nil") panic("Toolkit should never be nil") } // make a *Node with a *toolkit.Group sNode = n.New(name + " part1") - newT = n.Toolkit.NewSlider(name, x, y) + newT = n.toolkit.NewSlider(name, x, y) newT.Name = name - sNode.Toolkit = newT + sNode.custom = n.custom + newT.Custom = func () { + // TODO: make all of this common code to all the widgets + if (n.custom == nil) { + log.Println("Not Running n.custom(n) == nil") + } else { + log.Println("Running n.custom(n)") + sNode.custom(sNode) + } + if (sNode.OnChanged == nil) { + log.Println("Not Running n.OnChanged(n) == nil") + } else { + log.Println("Running n.OnChanged(n)") + sNode.OnChanged(sNode) + } + } + sNode.toolkit = newT sNode.Dump() + // panic("checking Custom()") return sNode } diff --git a/spinbox.go b/spinbox.go deleted file mode 100644 index 6d87866..0000000 --- a/spinbox.go +++ /dev/null @@ -1,23 +0,0 @@ -package gui - -import "log" - -import toolkit "git.wit.org/wit/gui/toolkit/andlabs" - -func (n *Node) NewSpinbox(name string, x int, y int) *Node { - // make new node here - log.Println("toolkit.NewSpinbox", x, y) - - newNode := n.New(name) - - t := toolkit.NewSpinbox(n.uiBox, name, x, y) - t.OnChanged = func(t *toolkit.Toolkit) { - log.Println("toolkit.NewSpinbox() value =", t.Value()) - if (newNode.OnChanged != nil) { - newNode.OnChanged(newNode) - } - } - newNode.Toolkit = t - - return newNode -} diff --git a/spinner.go b/spinner.go new file mode 100644 index 0000000..8296ce1 --- /dev/null +++ b/spinner.go @@ -0,0 +1,26 @@ +package gui + +import "log" + +import toolkit "git.wit.org/wit/gui/toolkit/andlabs" + +func (n *Node) NewSpinner(name string, x int, y int) *Node { + var newT *toolkit.Toolkit + var sNode *Node + + log.Println("toolkit.NewSpinner() START", name) + + if (n.toolkit == nil) { + log.Println("toolkit.NewSpinner() toolkit == nil") + panic("toolkit should never be nil") + } + + // make a *Node with a *toolkit.Group + sNode = n.New(name + " part1") + newT = n.toolkit.NewSpinner(name, x, y) + newT.Name = name + sNode.toolkit = newT + sNode.Dump() + + return sNode +} diff --git a/structs.go b/structs.go index fedb34a..d9b5bef 100644 --- a/structs.go +++ b/structs.go @@ -1,31 +1,38 @@ package gui import ( - "image/color" "log" - "github.com/andlabs/ui" - "golang.org/x/image/font" - - // "github.com/davecgh/go-spew/spew" - - // _ "github.com/andlabs/ui/winmanifest" ) +import toolkit "git.wit.org/wit/gui/toolkit/andlabs" + // // All GUI Data Structures and functions that are external -// If you need cross platform support, these might only -// be the safe way to interact with the GUI +// within the toolkit/ abstraction layer // -var Data GuiData +// More than one Window is not supported in a cross platform +// sense & may never be. On many toolkits you have to have 'tabs' +// Native Windows and MacOS toolkits work with tabs +// +// If that is the case, this code should abstract the concept of +// windows and make everything 'tabs' +// + var Config GuiConfig type GuiConfig struct { + // This is the master node. The Binary Tree starts here + master *Node + + // These are shortcuts to pass default values to make a new window Title string Width int Height int Exit func(*Node) + // These are global debugging settings + // TODO: move to a standard logging system Debug bool DebugNode bool DebugTabs bool @@ -33,295 +40,190 @@ type GuiConfig struct { DebugWindow bool DebugToolkit bool + // hacks depth int counter int // used to make unique ID's prefix string } -type GuiData struct { - // a fallback default function to handle mouse events - // if nothing else is defined to handle them - MouseClick func(*GuiButton) +type Widget int - // A map of all the entry boxes - AllEntries []*GuiEntry - WindowMap map[string]*GuiWindow +// https://ieftimov.com/post/golang-datastructures-trees/ +const ( + Unknown Widget = iota + Window + Tab + Frame + Dropbox + Spinner + Label +) - // Store access to everything via binary tree's - NodeMap map[string]*Node - NodeArray []*Node - NodeSlice []*Node - - // A map of all buttons everywhere on all - // windows, all tabs, across all goroutines - // This is "GLOBAL" - // - // This has to work this way because of how - // andlabs/ui & andlabs/libui work - AllButtons []*GuiButton - buttonMap map[*ui.Button]*GuiButton -} - -type GuiTab struct { - Name string // field for human readable name - Number int // the andlabs/ui tab index - Window *GuiWindow // the parent Window -} - -// -// stores information on the 'window' -// -// This merges the concept of andlabs/ui *Window and *Tab -// -// More than one Window is not supported in a cross platform -// sense & may never be. On Windows and MacOS, you have to have -// 'tabs'. Even under Linux, more than one Window is currently -// unstable -// -// This code will make a 'GuiWindow' regardless of if it is -// a stand alone window (which is more or less working on Linux) -// or a 'tab' inside a window (which is all that works on MacOS -// and MSWindows. -// -// This struct keeps track of what is in the window so you -// can destroy and replace it with something else -// -type GuiWindow struct { - Name string // field for human readable name - Width int - Height int - Axis int // does it add items to the X or Y axis - TabNumber *int // the andlabs/ui tab index - - // the callback function to make the window contents - // MakeWindow func(*GuiBox) *GuiBox - - // the components of the window - BoxMap map[string]*GuiBox - EntryMap map[string]*GuiEntry - Area *GuiArea - - node *Node - - // andlabs/ui abstraction mapping - UiWindow *ui.Window - UiTab *ui.Tab // if this != nil, the window is 'tabbed' -} - -func (w *GuiWindow) Dump() { - log.Println("gui.GuiWindow.Dump() Name = ", w.Name) - log.Println("gui.GuiWindow.Dump() node = ", w.node) - log.Println("gui.GuiWindow.Dump() Width = ", w.Width) - log.Println("gui.GuiWindow.Dump() Height = ", w.Height) -} - -// GuiBox is any type of ui.Hbox or ui.Vbox -// There can be lots of these for each GuiWindow -type GuiBox struct { - Name string // field for human readable name - Axis int // does it add items to the X or Y axis - Window *GuiWindow // the parent Window - - node *Node - - // andlabs/ui abstraction mapping - UiBox *ui.Box -} - -func (b *GuiBox) Dump() { - log.Println("gui.GuiBox.Dump() Name = ", b.Name) - log.Println("gui.GuiBox.Dump() Axis = ", b.Axis) - log.Println("gui.GuiBox.Dump() GuiWindow = ", b.Window) - log.Println("gui.GuiBox.Dump() node = ", b.node) - log.Println("gui.GuiBox.Dump() UiBox = ", b.UiBox) -} - -func (b *GuiBox) SetTitle(title string) { - log.Println("DID IT!", title) - if b.Window == nil { - return +func (s Widget) String() string { + switch s { + case Window: + return "Window" + case Tab: + return "Tab" + case Frame: + return "Frame" + case Label: + return "Label" + case Dropbox: + return "Dropbox" } - if b.Window.UiWindow == nil { - return + return "unknown" +} + +// The Node is simply the name and the size of whatever GUI element exists +type Node struct { + id string + + Name string + Width int + Height int + + parent *Node + children []*Node + + custom func(*Node) + OnChanged func(*Node) + + toolkit *toolkit.Toolkit +} + +func (n *Node) Parent() *Node { + return n.parent +} + +func (n *Node) Window() *Node { + return n.parent +} + +func (n *Node) Dump() { + IndentPrintln("id = ", n.id) + IndentPrintln("Name = ", n.Name) + IndentPrintln("Width = ", n.Width) + IndentPrintln("Height = ", n.Height) + + if (n.parent == nil) { + IndentPrintln("parent = nil") + } else { + IndentPrintln("parent =", n.parent.id) } - b.Window.UiWindow.SetTitle(title) + if (n.children != nil) { + IndentPrintln("children = ", n.children) + } + if (n.toolkit != nil) { + IndentPrintln("toolkit = ", n.toolkit) + n.toolkit.Dump() + } + if (n.custom != nil) { + IndentPrintln("custom = ", n.custom) + } + if (n.OnChanged != nil) { + IndentPrintln("OnChanged = ", n.OnChanged) + } + if (n.id == "") { + // Node structs should never have a nil id. + // I probably shouldn't panic here, but this is just to check the sanity of + // the gui package to make sure it's not exiting + panic("gui.Node.Dump() id == nil TODO: make a unigue id here in the golang gui library") + } +} + +func (n *Node) SetName(name string) { + n.toolkit.SetWindowTitle(name) return } -func (w *GuiWindow) SetNode(n *Node) { - if (w.node != nil) { - w.Dump() - panic("gui.SetNode() Error not nil") - } - w.node = n - if (w.node == nil) { - w.Dump() - panic("gui.SetNode() node == nil") +func (n *Node) Append(child *Node) { + 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 (b *GuiBox) SetNode(n *Node) { - if (b.node != nil) { - b.Dump() - panic("gui.SetNode() Error not nil") - } - b.node = n - if (b.node == nil) { - b.Dump() - panic("gui.SetNode() node == nil") - } +/* +func (n *Node) List() { + findByIdDFS(n, "test") +} +*/ + +var listChildrenParent *Node +var listChildrenDepth int = 0 +var defaultPadding = " " + +func IndentPrintln(a ...interface{}) { + indentPrintln(listChildrenDepth, defaultPadding, a) } -func (b *GuiBox) Append(child ui.Control, x bool) { - if b.UiBox == nil { - // spew.Dump(b) - b.Dump() - panic("GuiBox.Append() can't work. UiBox == nil") +func indentPrintln(depth int, format string, a ...interface{}) { + var tabs string + for i := 0; i < depth; i++ { + tabs = tabs + format + } + + // newFormat := tabs + strconv.Itoa(depth) + " " + format + newFormat := tabs + format + log.Println(newFormat, a) +} + +func (n *Node) ListChildren(dump bool) { + indentPrintln(listChildrenDepth, defaultPadding, n.id, n.Width, n.Height, n.Name) + + if (dump == true) { + n.Dump() + } + if len(n.children) == 0 { + if (n.parent == nil) { + } else { + if (Config.DebugNode) { + log.Println("\t\t\tparent =",n.parent.id) + } + if (listChildrenParent != nil) { + if (Config.DebugNode) { + log.Println("\t\t\tlistChildrenParent =",listChildrenParent.id) + } + if (listChildrenParent.id != n.parent.id) { + log.Println("parent.child does not match child.parent") + panic("parent.child does not match child.parent") + } + } + } + if (Config.DebugNode) { + log.Println("\t\t", n.id, "has no children") + } return } - b.UiBox.Append(child, x) + for _, child := range n.children { + // log.Println("\t\t", child.id, child.Width, child.Height, child.Name) + if (child.parent != nil) { + if (Config.DebugNode) { + log.Println("\t\t\tparent =",child.parent.id) + } + } else { + log.Println("\t\t\tno parent") + panic("no parent") + } + if (dump == true) { + child.Dump() + } + if (Config.DebugNode) { + if (child.children == nil) { + log.Println("\t\t", child.id, "has no children") + } else { + log.Println("\t\t\tHas children:", child.children) + } + } + listChildrenParent = n + listChildrenDepth += 1 + child.ListChildren(dump) + listChildrenDepth -= 1 + } + return } - -// Note: every mouse click is handled -// as a 'Button' regardless of where -// the user clicks it. You could probably -// call this 'GuiMouseClick' -type GuiButton struct { - Name string // field for human readable name - Box *GuiBox // what box the button click was in - - // a callback function for the main application - Custom func(*GuiButton) - Values interface{} - Color color.RGBA - - // andlabs/ui abstraction mapping - B *ui.Button - FB *ui.FontButton - CB *ui.ColorButton -} - -// text entry fields -type GuiEntry struct { - Name string // field for human readable name - Edit bool - Last string // the last value - Normalize func(string) string // function to 'normalize' the data - - B *GuiButton - Box *GuiBox - - // andlabs/ui abstraction mapping - UiEntry *ui.Entry -} - -// -// AREA STRUCTURES START -// AREA STRUCTURES START -// AREA STRUCTURES START -// -type GuiArea struct { - Button *GuiButton // what button handles mouse events - Box *GuiBox - - UiAttrstr *ui.AttributedString - UiArea *ui.Area -} - -type FontString struct { - S string - Size int - F font.Face - W font.Weight -} - -// -// AREA STRUCTURES END -// AREA STRUCTURES END -// AREA STRUCTURES END -// - -// -// TABLE DATA STRUCTURES START -// TABLE DATA STRUCTURES START -// TABLE DATA STRUCTURES START -// - -// -// This is the structure that andlabs/ui uses to pass information -// to the GUI. This is the "authoritative" data. -// -type TableData struct { - RowCount int // This is the number of 'rows' which really means data elements not what the human sees - RowWidth int // This is how wide each row is - Rows []RowData // This is all the table data by row - generatedColumnTypes []ui.TableValue // generate this dynamically - - Cells [20]CellData - Human [20]HumanMap - - Box *GuiBox - - lastRow int - lastColumn int -} - -// -// This maps the andlabs/ui & libui components into a "human" -// readable cell reference list. The reason is that there -// are potentially 3 values for each cell. The Text, the Color -// and an image. These are not always needed so the number -// of fields varies between 1 and 3. Internally, the toolkit -// GUI abstraction needs to list all of them, but it's then -// hard to figure out which column goes with the columns that -// you see when you visually are looking at it like a spreadsheet -// -// This makes a map so that we can say "give me the value at -// row 4 and column 2" and find the fields that are needed -// -// TODO: re-add images and the progress bar (works in andlabs/ui) -// -type HumanCellData struct { - Name string // what kind of row is this? - Text string - TextID int - Color color.RGBA - ColorID int - Button *GuiButton -} - -type HumanMap struct { - Name string // what kind of row is this? - TextID int - ColorID int -} - -type TableColumnData struct { - Index int - CellType string - Heading string - Color string -} - -type CellData struct { - Index int - HumanID int - Name string // what type of cell is this? -} - -// hmm. will this stand the test of time? -type RowData struct { - Name string // what kind of row is this? - Status string // status of the row? - /* - // TODO: These may or may not be implementable - // depending on if it's possible to detect the bgcolor or what row is selected - click func() // what function to call if the user clicks on it - doubleclick func() // what function to call if the user double clicks on it - */ - HumanData [20]HumanCellData -} - -// -// TABLE DATA STRUCTURES END -// diff --git a/tab.go b/tab.go index 72dcd17..bade55f 100644 --- a/tab.go +++ b/tab.go @@ -2,76 +2,25 @@ package gui import ( "log" - "os" - - "github.com/andlabs/ui" - _ "github.com/andlabs/ui/winmanifest" ) -// import toolkit "git.wit.org/wit/gui/toolkit/andlabs" - // This function should make a new node with the parent and // the 'tab' as a child func (n *Node) NewTab(title string) *Node { - log.Println("gui.Node.AddTab() START name =", title) + log.Println("gui.Node.NewTab() START name =", title) - return n.AddTabNew(title) -} - -func (n *Node) AddTabNew(title string) *Node { - log.Println("gui.Node.AddTab() START name =", title) - - if (n.Toolkit == nil) { - log.Println("FUCK TOOLKIT nil uiWindow =", n.uiWindow) - log.Println("FUCK TOOLKIT nil uiTab =", n.uiTab) - log.Println("FUCK TOOLKIT nil Toolkit =", n.Toolkit) - // return n.AddTab(title) // need to make a toolkit here + // TODO: standardize these checks somewhere + if (n.toolkit == nil) { n.Dump() - os.Exit(0) + panic("NewTab() failed. toolkit == nil") } log.Println("Make new node") newN := n.New(title) - log.Println("Add tab to window") - t := n.Toolkit.AddTab(title) - newN.Toolkit = t + log.Println("New tab to window") + t := n.toolkit.AddTab(title) + newN.toolkit = t n.Append(newN) return newN } - -func (n *Node) AddTab(title string, uiC *ui.Box) *Node { - return n.AddTabNew(title) -} -/* -func (n *Node) AddTabBAD(title string, uiC *ui.Box) *Node { - parent := n - log.Println("gui.Node.AddTab() START name =", title) - if parent.uiWindow == nil { - parent.Dump() - log.Println("gui.Node.AddTab() ERROR ui.Window == nil") - return nil - } - if parent.uiTab == nil { - inittab := ui.NewTab() // no, not that 'inittab' - parent.uiWindow.SetChild(inittab) - parent.uiWindow.SetMargined(true) - parent.uiTab = inittab - } - tab := parent.uiTab - parent.uiWindow.SetMargined(true) - - if (uiC == nil) { - hbox := ui.NewHorizontalBox() - hbox.SetPadded(true) - uiC = hbox - } - tab.Append(title, uiC) - - newNode := n.New(title) - newNode.uiTab = tab - newNode.uiBox = uiC - // tabSetMargined(newNode.uiTab) - return newNode -} -*/ diff --git a/text.go b/text.go index 69a9002..6f46998 100644 --- a/text.go +++ b/text.go @@ -2,8 +2,7 @@ package gui import "log" import "errors" - -// import toolkit "git.wit.org/wit/gui/toolkit/andlabs" +import "regexp" // functions for handling text related GUI elements @@ -12,29 +11,52 @@ func (n *Node) NewLabel(text string) *Node { newNode := n.New(text) newNode.Dump() - t := n.Toolkit.NewLabel(text) - newNode.Toolkit = t + t := n.toolkit.NewLabel(text) + newNode.toolkit = t return newNode } func (n *Node) SetText(value string) error { log.Println("gui.SetText() value =", value) - if (n.Toolkit != nil) { - n.Toolkit.SetText(value) - return nil - } - if (n.uiText != nil) { - n.uiText.SetText(value) - return nil - } - if (n.uiButton != nil) { - n.uiButton.SetText(value) - return nil - } - if (n.uiWindow != nil) { - n.uiWindow.SetTitle(value) - return nil - } + panic("redo SetText()") return errors.New("nothing found for gui.Node.SetText()") } + +/* +// string handling examples that might be helpful for normalizeInt() +isAlpha := regexp.MustCompile(`^[A-Za-z]+$`).MatchString + +for _, username := range []string{"userone", "user2", "user-three"} { + if !isAlpha(username) { + fmt.Printf("%q is not valid\n", username) + } +} + +const alpha = "abcdefghijklmnopqrstuvwxyz" + +func alphaOnly(s string) bool { + for _, char := range s { + if !strings.Contains(alpha, strings.ToLower(string(char))) { + return false + } + } + return true +} +*/ + +func normalizeInt(s string) string { + // reg, err := regexp.Compile("[^a-zA-Z0-9]+") + reg, err := regexp.Compile("[^0-9]+") + if err != nil { + log.Println("normalizeInt() regexp.Compile() ERROR =", err) + return s + } + clean := reg.ReplaceAllString(s, "") + log.Println("normalizeInt() s =", clean) + return clean +} + +func (n *Node) GetText() string { + return n.toolkit.GetText() +} diff --git a/toolkit/andlabs/demo.go b/toolkit/andlabs/demo.go index 05451ea..1b097d7 100644 --- a/toolkit/andlabs/demo.go +++ b/toolkit/andlabs/demo.go @@ -14,9 +14,10 @@ func BlankWindow(w *ui.Window) *ui.Box { return hbox } -func DemoNumbersPage(w *ui.Window) *Toolkit { - var t Toolkit +func (t *Toolkit) DemoNumbersPage() { + var w *ui.Window + w = t.uiWindow t.uiBox = makeNumbersPage() t.uiBox.SetPadded(true) w.SetChild(t.uiBox) @@ -27,8 +28,6 @@ func DemoNumbersPage(w *ui.Window) *Toolkit { scs := spew.ConfigState{MaxDepth: 1} scs.Dump(t) } - - return &t } /* diff --git a/toolkit/andlabs/dropdown.go b/toolkit/andlabs/dropdown.go new file mode 100644 index 0000000..14cbf14 --- /dev/null +++ b/toolkit/andlabs/dropdown.go @@ -0,0 +1,74 @@ +package toolkit + +import "log" +import "os" +// import "time" + +import "github.com/andlabs/ui" +import _ "github.com/andlabs/ui/winmanifest" + +import "github.com/davecgh/go-spew/spew" + +func (pt *Toolkit) NewDropdown(title string) *Toolkit { + // make new node here + log.Println("gui.Toolbox.NewDropdownCombobox()") + var newt Toolkit + + if (pt.uiBox == nil) { + log.Println("gui.ToolboxNode.NewDropdown() node.UiBox == nil. I can't add a range UI element without a place to put it") + os.Exit(0) + return nil + } + + s := ui.NewCombobox() + newt.uiCombobox = s + newt.uiBox = pt.uiBox + pt.uiBox.Append(s, false) + + // initialize the index + newt.c = 0 + newt.val = make(map[int]string) + + s.OnSelected(func(spin *ui.Combobox) { + i := spin.Selected() + if (newt.val == nil) { + log.Println("make map didn't work") + os.Exit(0) + } + newt.text = newt.val[i] + val := newt.text + log.Println("gui.Toolbox.ui.Dropdown.OnChanged() val =", i, val) + if (DebugToolkit) { + log.Println("gui.Toolbox.ui.OnChanged() val =", i, val) + scs := spew.ConfigState{MaxDepth: 1} + scs.Dump(newt) + } + if (newt.OnChanged != nil) { + log.Println("gui.Toolbox.OnChanged() trying to run toolkit.OnChanged() entered val =", i, val) + newt.OnChanged(&newt) + return + } + if (newt.Custom != nil) { + log.Println("gui.Toolbox.OnChanged() Running toolkit.Custom()", i, val) + newt.Custom() + return + } + log.Println("gui.Toolbox.Dropdown.OnChanged() ENDED without finding any callback", i, val) + }) + + return &newt +} + +func (t *Toolkit) AddDropdown(title string) { + t.uiCombobox.Append(title) + if (t.val == nil) { + log.Println("make map didn't work") + return + } + t.val[t.c] = title + t.c = t.c + 1 +} + +func (t Toolkit) SetDropdown(i int) { + t.uiCombobox.SetSelected(i) +} diff --git a/toolkit/andlabs/main.go b/toolkit/andlabs/main.go new file mode 100644 index 0000000..cea0486 --- /dev/null +++ b/toolkit/andlabs/main.go @@ -0,0 +1,26 @@ +package toolkit + +import ( + "log" + + "github.com/andlabs/ui" + _ "github.com/andlabs/ui/winmanifest" +) + +func Main(f func()) { + log.Println("Starting gui.Main() (using gtk via andlabs/ui)") + ui.Main(f) +} + +// Other goroutines must use this to access the GUI +// +// You can not acess / process the GUI thread directly from +// other goroutines. This is due to the nature of how +// Linux, MacOS and Windows work (they all work differently. suprise. surprise.) +// +// For example: Queue(NewWindow()) +// +func Queue(f func()) { + log.Println("Sending function to gui.Main() (using gtk via andlabs/ui)") + ui.QueueMain(f) +} diff --git a/area.go b/toolkit/andlabs/old/area.go similarity index 100% rename from area.go rename to toolkit/andlabs/old/area.go diff --git a/color.go b/toolkit/andlabs/old/color.go similarity index 100% rename from color.go rename to toolkit/andlabs/old/color.go diff --git a/toolkit/andlabs/old/seperator.go b/toolkit/andlabs/old/seperator.go new file mode 100644 index 0000000..ca152a8 --- /dev/null +++ b/toolkit/andlabs/old/seperator.go @@ -0,0 +1,25 @@ +package gui + +import "log" +import "os" + +import "github.com/andlabs/ui" +import _ "github.com/andlabs/ui/winmanifest" + +func HorizontalBreak(box *GuiBox) { + log.Println("VerticalSeparator added to box =", box.Name) + tmp := ui.NewHorizontalSeparator() + if (box == nil) { + return + } + if (box.UiBox == nil) { + return + } + box.UiBox.Append(tmp, false) +} + +func VerticalBreak(box *GuiBox) { + log.Println("VerticalSeparator added to box =", box.Name) + tmp := ui.NewVerticalSeparator() + box.UiBox.Append(tmp, false) +} diff --git a/toolkit/andlabs/old/structs.go b/toolkit/andlabs/old/structs.go new file mode 100644 index 0000000..4a16438 --- /dev/null +++ b/toolkit/andlabs/old/structs.go @@ -0,0 +1,273 @@ +package gui + +import ( + "image/color" + + "github.com/andlabs/ui" +// "golang.org/x/image/font" + + // "github.com/davecgh/go-spew/spew" + + // _ "github.com/andlabs/ui/winmanifest" +) + +// +// All GUI Data Structures and functions that are external +// If you need cross platform support, these might only +// be the safe way to interact with the GUI +// +var Data GuiData +var Config GuiConfig + +type GuiConfig struct { + Title string + Width int + Height int + Exit func(*Node) + + Debug bool + DebugNode bool + DebugTabs bool + DebugTable bool + DebugWindow bool + DebugToolkit bool + + depth int + counter int // used to make unique ID's + prefix string +} + +type GuiData struct { + // a fallback default function to handle mouse events + // if nothing else is defined to handle them + MouseClick func(*GuiButton) + + // A map of all the entry boxes + // AllEntries []*GuiEntry + WindowMap map[string]*GuiWindow + + // Store access to everything via binary tree's + NodeMap map[string]*Node + NodeArray []*Node + NodeSlice []*Node + + // A map of all buttons everywhere on all + // windows, all tabs, across all goroutines + // This is "GLOBAL" + // + // This has to work this way because of how + // andlabs/ui & andlabs/libui work + AllButtons []*GuiButton +// buttonMap map[*ui.Button]*GuiButton +} + +/* +type GuiTab struct { + Name string // field for human readable name + Number int // the andlabs/ui tab index + Window *GuiWindow // the parent Window +} +*/ + +// +// stores information on the 'window' +// +// This merges the concept of andlabs/ui *Window and *Tab +// +// More than one Window is not supported in a cross platform +// sense & may never be. On Windows and MacOS, you have to have +// 'tabs'. Even under Linux, more than one Window is currently +// unstable +// +// This code will make a 'GuiWindow' regardless of if it is +// a stand alone window (which is more or less working on Linux) +// or a 'tab' inside a window (which is all that works on MacOS +// and MSWindows. +// +// This struct keeps track of what is in the window so you +// can destroy and replace it with something else +// +type GuiWindow struct { + Name string // field for human readable name + Width int + Height int + Axis int // does it add items to the X or Y axis + TabNumber *int // the andlabs/ui tab index + + // the callback function to make the window contents + // MakeWindow func(*GuiBox) *GuiBox + + // the components of the window + BoxMap map[string]*GuiBox + // EntryMap map[string]*GuiEntry + + node *Node + + // andlabs/ui abstraction mapping + UiWindow *ui.Window + UiTab *ui.Tab // if this != nil, the window is 'tabbed' +} + +/* +func (w *GuiWindow) Dump() { + log.Println("gui.GuiWindow.Dump() Name = ", w.Name) + log.Println("gui.GuiWindow.Dump() node = ", w.node) + log.Println("gui.GuiWindow.Dump() Width = ", w.Width) + log.Println("gui.GuiWindow.Dump() Height = ", w.Height) +} +*/ + +// GuiBox is any type of ui.Hbox or ui.Vbox +// There can be lots of these for each GuiWindow +type GuiBox struct { + Name string // field for human readable name + Axis int // does it add items to the X or Y axis + Window *GuiWindow // the parent Window + + node *Node + + // andlabs/ui abstraction mapping + UiBox *ui.Box +} + +func (b *GuiBox) Append(child ui.Control, x bool) { + if b.UiBox == nil { + // spew.Dump(b) + // b.Dump() + panic("GuiBox.Append() can't work. UiBox == nil") + return + } + b.UiBox.Append(child, x) +} + +// Note: every mouse click is handled +// as a 'Button' regardless of where +// the user clicks it. You could probably +// call this 'GuiMouseClick' +type GuiButton struct { + Name string // field for human readable name + Box *GuiBox // what box the button click was in + + // a callback function for the main application + Custom func(*GuiButton) + Values interface{} + Color color.RGBA + + // andlabs/ui abstraction mapping + B *ui.Button + FB *ui.FontButton + CB *ui.ColorButton +} + +/* +// +// AREA STRUCTURES START +// AREA STRUCTURES START +// AREA STRUCTURES START +// +type GuiArea struct { + Button *GuiButton // what button handles mouse events + Box *GuiBox + + UiAttrstr *ui.AttributedString + UiArea *ui.Area +} + +type FontString struct { + S string + Size int + F font.Face + W font.Weight +} + +// +// AREA STRUCTURES END +// AREA STRUCTURES END +// AREA STRUCTURES END +// + +// +// TABLE DATA STRUCTURES START +// TABLE DATA STRUCTURES START +// TABLE DATA STRUCTURES START +// + +// +// This is the structure that andlabs/ui uses to pass information +// to the GUI. This is the "authoritative" data. +// +type TableData struct { + RowCount int // This is the number of 'rows' which really means data elements not what the human sees + RowWidth int // This is how wide each row is + Rows []RowData // This is all the table data by row + generatedColumnTypes []ui.TableValue // generate this dynamically + + Cells [20]CellData + Human [20]HumanMap + + Box *GuiBox + + lastRow int + lastColumn int +} + +// +// This maps the andlabs/ui & libui components into a "human" +// readable cell reference list. The reason is that there +// are potentially 3 values for each cell. The Text, the Color +// and an image. These are not always needed so the number +// of fields varies between 1 and 3. Internally, the toolkit +// GUI abstraction needs to list all of them, but it's then +// hard to figure out which column goes with the columns that +// you see when you visually are looking at it like a spreadsheet +// +// This makes a map so that we can say "give me the value at +// row 4 and column 2" and find the fields that are needed +// +// TODO: re-add images and the progress bar (works in andlabs/ui) +// +type HumanCellData struct { + Name string // what kind of row is this? + Text string + TextID int + Color color.RGBA + ColorID int + Button *GuiButton +} + +type HumanMap struct { + Name string // what kind of row is this? + TextID int + ColorID int +} + +type TableColumnData struct { + Index int + CellType string + Heading string + Color string +} + +type CellData struct { + Index int + HumanID int + Name string // what type of cell is this? +} + +// hmm. will this stand the test of time? +type RowData struct { + Name string // what kind of row is this? + Status string // status of the row? + // + // TODO: These may or may not be implementable + // depending on if it's possible to detect the bgcolor or what row is selected + // click func() // what function to call if the user clicks on it + // doubleclick func() // what function to call if the user double clicks on it + // + HumanData [20]HumanCellData +} +*/ + +// +// TABLE DATA STRUCTURES END +// diff --git a/table.go b/toolkit/andlabs/old/table.go similarity index 100% rename from table.go rename to toolkit/andlabs/old/table.go diff --git a/tableCallbacks.go b/toolkit/andlabs/old/tableCallbacks.go similarity index 100% rename from tableCallbacks.go rename to toolkit/andlabs/old/tableCallbacks.go diff --git a/toolkit/andlabs/slider.go b/toolkit/andlabs/slider.go index 65cf531..05eaba4 100644 --- a/toolkit/andlabs/slider.go +++ b/toolkit/andlabs/slider.go @@ -11,11 +11,11 @@ import "github.com/davecgh/go-spew/spew" // func NewSlider(b *ui.Box, name string *Toolkit { func (t Toolkit) NewSlider(title string, x int, y int) *Toolkit { // make new node here - log.Println("gui.Toolbox.NewSpinbox()", x, y) + log.Println("gui.Toolkit.NewSpinbox()", x, y) var newt Toolkit if (t.uiBox == nil) { - log.Println("gui.ToolboxNode.NewGroup() node.UiBox == nil. I can't add a range UI element without a place to put it") + log.Println("gui.ToolkitNode.NewGroup() node.UiBox == nil. I can't add a range UI element without a place to put it") log.Println("probably could just make a box here?") os.Exit(0) return nil @@ -28,16 +28,23 @@ func (t Toolkit) NewSlider(title string, x int, y int) *Toolkit { s.OnChanged(func(spin *ui.Slider) { i := spin.Value() - log.Println("gui.Toolbox.ui.Slider.OnChanged() val =", i) + log.Println("gui.Toolkit.ui.Slider.OnChanged() val =", i) if (DebugToolkit) { - log.Println("gui.Toolbox.ui.OnChanged() val =", i) + log.Println("gui.Toolkit.ui.OnChanged() val =", i) scs := spew.ConfigState{MaxDepth: 1} scs.Dump(newt) } - if (t.OnChanged != nil) { - log.Println("gui.Toolbox.OnChanged() entered val =", i) + if (newt.OnChanged != nil) { + log.Println("gui.Toolkit.OnChanged() trying to run toolkit.OnChanged() entered val =", i) newt.OnChanged(&newt) + return } + if (newt.Custom != nil) { + log.Println("gui.Toolkit.OnChanged() Running toolkit.Custom()") + newt.Custom() + return + } + log.Println("gui.Toolkit.OnChanged() ENDED without finding any callback") }) return &newt diff --git a/toolkit/andlabs/spinbox.go b/toolkit/andlabs/spinbox.go deleted file mode 100644 index c47fab7..0000000 --- a/toolkit/andlabs/spinbox.go +++ /dev/null @@ -1,38 +0,0 @@ -package toolkit - -import "log" - -import "github.com/andlabs/ui" -import _ "github.com/andlabs/ui/winmanifest" - -import "github.com/davecgh/go-spew/spew" - -func NewSpinbox(b *ui.Box, name string, x int, y int) *Toolkit { - // make new node here - log.Println("gui.Toolbox.NewSpinbox()", x, y) - var t Toolkit - - if (b == nil) { - log.Println("gui.ToolboxNode.NewSpinbox() node.UiBox == nil. I can't add a range UI element without a place to put it") - return nil - } - spin := ui.NewSpinbox(x, y) - t.uiSpinbox = spin - t.uiBox = b - t.uiBox.Append(spin, false) - - spin.OnChanged(func(spin *ui.Spinbox) { - i := spin.Value() - if (DebugToolkit) { - log.Println("gui.Toolbox.ui.OnChanged() val =", i) - scs := spew.ConfigState{MaxDepth: 1} - scs.Dump(t) - } - if (t.OnChanged != nil) { - log.Println("gui.Toolbox.OnChanged() entered val =", i) - t.OnChanged(&t) - } - }) - - return &t -} diff --git a/toolkit/andlabs/spinner.go b/toolkit/andlabs/spinner.go new file mode 100644 index 0000000..12662e5 --- /dev/null +++ b/toolkit/andlabs/spinner.go @@ -0,0 +1,42 @@ +package toolkit + +import "log" +import "os" + +import "github.com/andlabs/ui" +import _ "github.com/andlabs/ui/winmanifest" + +import "github.com/davecgh/go-spew/spew" + +// func NewSlider(b *ui.Box, name string *Toolkit { +func (t Toolkit) NewSpinner(title string, x int, y int) *Toolkit { + // make new node here + log.Println("gui.Toolkit.NewSpinner()", x, y) + var newt Toolkit + + if (t.uiBox == nil) { + log.Println("gui.ToolkitNode.NewSpinner() node.UiBox == nil. I can't add a range UI element without a place to put it") + os.Exit(0) + return nil + } + + s := ui.NewSpinbox(x, y) + newt.uiSpinbox = s + newt.uiBox = t.uiBox + t.uiBox.Append(s, false) + + s.OnChanged(func(s *ui.Spinbox) { + i := s.Value() + if (DebugToolkit) { + log.Println("gui.Toolkit.ui.OnChanged() val =", i) + scs := spew.ConfigState{MaxDepth: 1} + scs.Dump(newt) + } + if (t.OnChanged != nil) { + log.Println("gui.Toolkit.OnChanged() entered val =", i) + newt.OnChanged(&newt) + } + }) + + return &newt +} diff --git a/toolkit/andlabs/structs.go b/toolkit/andlabs/structs.go index a089a12..df34194 100644 --- a/toolkit/andlabs/structs.go +++ b/toolkit/andlabs/structs.go @@ -30,6 +30,7 @@ type Toolkit struct { uiBox2 *ui.Box // temporary hack while implementing tabs uiButton *ui.Button uiControl *ui.Control + uiCombobox *ui.Combobox uiEntry *ui.Entry uiGroup *ui.Group uiLabel *ui.Label @@ -39,6 +40,13 @@ type Toolkit struct { uiText *ui.EditableCombobox uiWindow *ui.Window UiWindowBad *ui.Window + + // used as a counter to work around limitations of widgets like combobox + // this is probably fucked up and in many ways wrong because of unsafe goroutine threading + // but it's working for now due to the need for need for a correct interaction layer betten toolkits + c int + val map[int]string + text string } func (t *Toolkit) GetText() string { @@ -53,6 +61,12 @@ func (t *Toolkit) GetText() string { } return t.uiEntry.Text() } + if (t.uiCombobox != nil) { + if (DebugToolkit) { + log.Println("gui.Toolkit.GetText() =", t.text) + } + return t.text + } return "" } @@ -131,6 +145,9 @@ func (t *Toolkit) Dump() { if (t.uiButton != nil) { log.Println("gui.Toolkit.Dump() uiButton =", t.uiButton) } + if (t.uiCombobox != nil) { + log.Println("gui.Toolkit.Dump() uiCombobox =", t.uiCombobox) + } if (t.uiWindow != nil) { log.Println("gui.Toolkit.Dump() uiWindow =", t.uiWindow) } @@ -144,6 +161,11 @@ func (t *Toolkit) Dump() { log.Println("gui.Toolkit.Dump() uiSlider =", t.uiSlider) } if (t.OnExit != nil) { - log.Println("gui.Toolkit.Dump() uiExit =", t.OnExit) + log.Println("gui.Toolkit.Dump() OnExit =", t.OnExit) } + if (t.Custom != nil) { + log.Println("gui.Toolkit.Dump() Custom =", t.Custom) + } + log.Println("gui.Toolkit.Dump() c =", t.c) + log.Println("gui.Toolkit.Dump() val =", t.val) } diff --git a/toolkit/andlabs/tab.go b/toolkit/andlabs/tab.go index c068022..922515d 100644 --- a/toolkit/andlabs/tab.go +++ b/toolkit/andlabs/tab.go @@ -25,21 +25,21 @@ func (t *Toolkit) AddTab(name string) *Toolkit { var w *ui.Window var newt *Toolkit - log.Println("gui.Toolbox.AddTab() sleep 3") + log.Println("gui.toolkit.AddTab() sleep 3") w = t.uiWindow if (w == nil) { - log.Println("gui.Toolbox.NewTab() node.UiWindow == nil. I can't add a tab without a window") + log.Println("gui.toolkit.NewTab() node.UiWindow == nil. I can't add a tab without a window") return nil } if (t.uiTab == nil) { // this means you have to make a new tab - log.Println("gui.Toolbox.NewTab() GOOD. This should be the first tab:", name) + log.Println("gui.toolkit.NewTab() GOOD. This should be the first tab:", name) newt = newTab(w, name) t.uiTab = newt.uiTab } else { - log.Println("gui.Toolbox.NewTab() GOOD. This should be an additional tab:", name) + log.Println("gui.toolkit.NewTab() GOOD. This should be an additional tab:", name) newt = t.appendTab(name) // this means you have to append a tab } @@ -88,17 +88,17 @@ func tabSetMargined(tab *ui.Tab) { } func newTab(w *ui.Window, name string) *Toolkit { - log.Println("gui.Toolbox.NewTab() ADD", name) + log.Println("gui.toolkit.NewTab() ADD", name) var t Toolkit if (w == nil) { - log.Println("gui.Toolbox.NewTab() node.UiWindow == nil. I can't add a tab without a window") - log.Println("gui.Toolbox.NewTab() node.UiWindow == nil. I can't add a tab without a window") - log.Println("gui.Toolbox.NewTab() node.UiWindow == nil. I can't add a tab without a window") + log.Println("gui.toolkit.NewTab() node.UiWindow == nil. I can't add a tab without a window") + log.Println("gui.toolkit.NewTab() node.UiWindow == nil. I can't add a tab without a window") + log.Println("gui.toolkit.NewTab() node.UiWindow == nil. I can't add a tab without a window") time.Sleep(1 * time.Second) return nil } - log.Println("gui.Toolbox.AddTab() START name =", name) + log.Println("gui.toolkit.AddTab() START name =", name) // time.Sleep(2 * time.Second) tab := ui.NewTab() w.SetMargined(true) @@ -117,17 +117,17 @@ func newTab(w *ui.Window, name string) *Toolkit { } func (t *Toolkit) appendTab(name string) *Toolkit { - log.Println("gui.Toolbox.NewTab() ADD", name) + log.Println("gui.toolkit.NewTab() ADD", name) var newT Toolkit if (t.uiWindow == nil) { - log.Println("gui.Toolbox.NewTab() node.UiWindow == nil. I can't add a tab without a window") - log.Println("gui.Toolbox.NewTab() node.UiWindow == nil. I can't add a tab without a window") - log.Println("gui.Toolbox.NewTab() node.UiWindow == nil. I can't add a tab without a window") + log.Println("gui.toolkit.NewTab() node.UiWindow == nil. I can't add a tab without a window") + log.Println("gui.toolkit.NewTab() node.UiWindow == nil. I can't add a tab without a window") + log.Println("gui.toolkit.NewTab() node.UiWindow == nil. I can't add a tab without a window") time.Sleep(1 * time.Second) return nil } - log.Println("gui.Toolbox.AddTab() START name =", name) + log.Println("gui.toolkit.AddTab() START name =", name) hbox := ui.NewHorizontalBox() // this makes everything go along the horizon // hbox := ui.NewVerticalBox() diff --git a/toolkit/andlabs/window.go b/toolkit/andlabs/window.go index f0357ed..f09a810 100644 --- a/toolkit/andlabs/window.go +++ b/toolkit/andlabs/window.go @@ -2,7 +2,6 @@ package toolkit import ( "log" - "os" "github.com/andlabs/ui" _ "github.com/andlabs/ui/winmanifest" @@ -33,8 +32,6 @@ func NewWindow(title string, x int, y int) *Toolkit { t.Custom() } log.Println("ui.Window().OnExit() Toolkit.OnExit is nil") - t.Dump() - os.Exit(0) return true }) w.SetMargined(true) @@ -43,3 +40,13 @@ func NewWindow(title string, x int, y int) *Toolkit { t.UiWindowBad = w // deprecate this as soon as possible return &t } + +func (t *Toolkit) SetWindowTitle(title string) { + log.Println("toolkit NewWindow", t.Name, "title", title) + win := t.uiWindow + if (win != nil) { + win.SetTitle(title) + } else { + log.Println("Setting the window title", title) + } +} diff --git a/window-debug.go b/window-debug.go new file mode 100644 index 0000000..e5aca66 --- /dev/null +++ b/window-debug.go @@ -0,0 +1,119 @@ +package gui + +import ( + "log" +) + +var names = make([]string, 100) +var nodeNames = make([]string, 100) + +var bugWin *Node +/* + Creates a window helpful for debugging this package +*/ +func DebugWindow() { + Config.Title = "git.wit.org/wit/gui debug fixme" + Config.Width = 300 + Config.Height = 200 + Config.Exit = StandardClose + bugWin = NewWindow() + bugWin.DebugTab("WIT GUI Debug Tab") +} + +// this function is used by the examples to add a tab +// dynamically to the bugWin node +// TODO: make this smarter once this uses toolkit/ +func DebugTab() { + if (bugWin == nil) { + log.Println("Not sure what window to add this to? Use node.DebugTab() instead") + return; + } + bugWin.DebugTab("does this work?") +} + +func (n *Node) DebugTab(title string) *Node { + var newN, gog, g1, g2, g3, dd *Node + + // time.Sleep(1 * time.Second) + newN = n.NewTab(title) + newN.Dump() + + gog = newN.NewGroup("GOLANG") + gog.NewLabel("go language") + gog.AddButton("GO Language Debug", func (*Node) { + GolangDebugWindow() + }) + + gog.NewLabel("wit/gui package") + gog.AddButton("WIT/GUI Package Debug", func (*Node) { + Config.Width = 640 + Config.Height = 480 + Queue(DebugWindow) + }) + gog.AddButton("Demo wit/gui", func (*Node) { + DemoWindow() + }) + gog.AddButton("Demo toolkit andlabs/ui", func (*Node) { + DemoToolkitWindow() + }) + + g1 = newN.NewGroup("Current Windows") + dd = g1.NewDropdown("Window Dropdown") + log.Println("dd =", dd) + + var dump = false + for _, child := range Config.master.children { + log.Println("\t\t", child.id, child.Width, child.Height, child.Name) + if (child.parent != nil) { + log.Println("\t\t\tparent =",child.parent.id) + } else { + log.Println("\t\t\tno parent") + panic("no parent") + } + if (dump == true) { + child.Dump() + } + dd.AddDropdown(child.Name) + } + dd.SetDropdown(0) + + g2 = newN.NewGroup("Debug Window") + g2.AddButton("SetMargined(tab)", func (*Node) { + log.Println("\tSTART") + name := dd.GetText() + log.Println("\tENDed with", name) + // gw.UiTab.SetMargined(*gw.TabNumber, true) + }) + g2.AddButton("Hide(tab)", func (*Node) { + // gw.UiTab.Hide() + }) + g2.AddButton("Show(tab)", func (*Node) { + // gw.UiTab.Show() + }) + g2.AddButton("Delete(tab)", func (*Node) { + // gw.UiTab.Delete(*gw.TabNumber) + }) + g2.AddButton("change Title", func (*Node) { + // mainWindow.SetText("hello world") + }) + + ///////////////////////////////////////////////////// + g3 = newN.NewGroup("Node Debug") + + g3.AddButton("Node.Dump()", func (n *Node) { + n.Dump() + }) + g3.AddButton("Node.ListChildren(false)", func (n *Node) { + n.ListChildren(false) + }) + g3.AddButton("Node.ListChildren(true)", func (n *Node) { + n.ListChildren(true) + }) + g3.AddButton("AddDebugTab()", func (n *Node) { + if (bugWin != nil) { + bugWin.DebugTab("added this DebugTab") + } + }) + + return newN +} diff --git a/window-demo-toolkit.go b/window-demo-toolkit.go index df6268e..0872448 100644 --- a/window-demo-toolkit.go +++ b/window-demo-toolkit.go @@ -2,7 +2,7 @@ package gui import "log" // import "time" -import toolkit "git.wit.org/wit/gui/toolkit/andlabs" +// import toolkit "git.wit.org/wit/gui/toolkit/andlabs" func NewStandardWindow(title string) *Node { log.Println("NewStandardWindow() creating", title) @@ -22,14 +22,15 @@ func NewStandardWindow(title string) *Node { // right now it shows the andlabs/ui/DemoNumbersPage() // func DemoToolkitWindow() { - var w, d *Node - var tk *toolkit.Toolkit + var w *Node w = NewStandardWindow("Demo of the GUI Toolkit") - d = w.New("demo") +// d = w.New("demo") - tk = toolkit.DemoNumbersPage(w.uiWindow) + w.toolkit.DemoNumbersPage() + /* + tk = w.Toolkit.DemoNumbersPage() tk.OnChanged = func(t *toolkit.Toolkit) { log.Println("toolkit.NewSlider() value =", t.Value()) if (d.OnChanged != nil) { @@ -38,6 +39,7 @@ func DemoToolkitWindow() { } } d.Toolkit = tk + */ log.Println("ToolkitDemoWindow() END") } diff --git a/window-golang-debug.go b/window-golang-debug.go index 8598f3a..f963383 100644 --- a/window-golang-debug.go +++ b/window-golang-debug.go @@ -13,7 +13,7 @@ func StandardClose(n *Node) { // origlog.Println("Should Exit Here") // closed = true log.Println("") - log.Println("STANDARD WINDOW CLOSE") + log.Println("STANDARD WINDOW CLOSE. Should not exit app.") log.Println("") } diff --git a/window.go b/window.go index ee0f3df..d314444 100644 --- a/window.go +++ b/window.go @@ -2,103 +2,10 @@ package gui import ( "log" - "strconv" - -// "github.com/andlabs/ui" -// _ "github.com/andlabs/ui/winmanifest" ) import toolkit "git.wit.org/wit/gui/toolkit/andlabs" -/* -func MessageWindow(gw *GuiWindow, msg1 string, msg2 string) { - ui.MsgBox(gw.UiWindow, msg1, msg2) -} - -func ErrorWindow(gw *GuiWindow, msg1 string, msg2 string) { - ui.MsgBoxError(gw.UiWindow, msg1, msg2) -} -*/ - -func DeleteWindow(name string) { - log.Println("gui.DeleteWindow() START name =", name) - window := Data.WindowMap[name] - if window == nil { - log.Println("gui.DeleteWindow() NO WINDOW WITH name =", name) - return - } - - log.Println("gui.DumpBoxes() MAP: ", name) - log.Println("gui.DumpBoxes()\tWindow.name =", window.Name) - if window.TabNumber == nil { - log.Println("gui.DumpBoxes() \tWindows.TabNumber = nil") - } - tab := *window.TabNumber - log.Println("gui.DumpBoxes() \tWindows.TabNumber =", tab) - log.Println("gui.DumpBoxes() \tSHOULD DELETE TAB", tab, "HERE") - log.Println("gui.DeleteWindow() \tSHOULD DELETE TAB", tab, "HERE") - log.Println("gui.DumpBoxes() \tUiTab =", window.UiTab) - tabnum := window.UiTab.NumPages() - log.Println("gui.DumpBoxes() \tUiTab.NumPages() =", tabnum) - if (tabnum > 0) { - window.UiTab.Delete(tab) - } - delete(Data.WindowMap, name) - - // renumber tabs here - for name, window := range Data.WindowMap { - log.Println("gui.DumpBoxes() MAP: ", name) - if window.TabNumber == nil { - log.Println("gui.DumpBoxes() \tWindows.TabNumber = nil") - } else { - log.Println("gui.DumpBoxes() \tWindows.TabNumber =", *window.TabNumber) - if tab < *window.TabNumber { - log.Println("gui.DumpBoxes() \tSubtracting 1 from TabNumber") - *window.TabNumber -= 1 - log.Println("gui.DumpBoxes() \tWindows.TabNumber is now =", *window.TabNumber) - } - } - } -} - -// func mapWindowOld(parent *Node, window *ui.Window, title string, x int, y int) *Node { -func mapWindow(title string, w int, h int) *Node { - log.Println("gui.WindowMap START title =", title) - if Data.WindowMap[title] != nil { - log.Println("Data.WindowMap[title] already exists title =", title) - title = title + Config.prefix + strconv.Itoa(Config.counter) - Config.counter += 1 - } - if Data.WindowMap[title] != nil { - log.Println("Data.WindowMap[title] already exists title =", title) - panic("Data.WindowMap[newGuiWindow.Name] already exists") - return nil - } - - var newGuiWindow GuiWindow - newGuiWindow.Width = w - newGuiWindow.Height = h - newGuiWindow.Name = title - // newGuiWindow.UiWindow = window - - newGuiWindow.BoxMap = make(map[string]*GuiBox) - newGuiWindow.EntryMap = make(map[string]*GuiEntry) - - Data.WindowMap[newGuiWindow.Name] = &newGuiWindow - - var box GuiBox - box.Window = &newGuiWindow - box.Name = title - - node := addNode(title, w, h) - node.box = &box - box.node = node - - newGuiWindow.BoxMap["jcarrInitTest"] = &box - - return node -} - // This routine creates a blank window with a Title and size (W x H) // // This routine can not have any arguements due to the nature of how @@ -114,34 +21,21 @@ func NewWindow() *Node { h := Config.Height f := Config.Exit - n = mapWindow(title, w, h) + // Windows are created off of the master node of the Binary Tree + n = Config.master.New(title) n.custom = f - box := n.box - log.Println("gui.NewWindow() title = box.Name =", box.Name) t = toolkit.NewWindow(title, w, h) t.Custom = func () { - log.Println("GOT TO MY CUSTOM EXIT!!!! for window name:", box.Name) - f(n) - } - n.Toolkit = t - n.uiWindow = t.UiWindowBad // this is temporary - - window := n.uiWindow - - /* - ui.OnShouldQuit(func() bool { - log.Println("createWindow().Destroy() on node.Name =", n.Name) - if (f != nil) { - f(n) + log.Println("Got to wit/gui Window Close for window:", title) + if (n.custom == nil) { + log.Println("Got to wit/gui Window Close custom() == nil") } - return true - }) - */ - - box.Window.UiWindow = window - if(n.uiWindow == nil) { - panic("node.uiWindow == nil. This should never happen") + log.Println("Got to wit/gui Window Close START custom()") + n.custom(n) + log.Println("Got to wit/gui Window Close END custom()") } + n.toolkit = t + return n }