From 46fe81665c20b71571023e2dd607832d725a085e Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Mon, 3 Jun 2019 19:07:39 -0700 Subject: [PATCH 1/2] fixed a commit --- Makefile | 1 + debug.go | 8 ++++- gui.go | 88 +------------------------------------------------------ window.go | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 88 deletions(-) create mode 100644 window.go diff --git a/Makefile b/Makefile index 6353f93..2b7dd82 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ # simple sortcut to push all git changes push: + git checkout devel git pull git add --all -git commit -a -s diff --git a/debug.go b/debug.go index 1a20532..3369be6 100644 --- a/debug.go +++ b/debug.go @@ -40,7 +40,13 @@ func DumpBoxes() { 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()) - spew.Dump(window.UiTab) + // 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 { diff --git a/gui.go b/gui.go index ef1ff49..fca054e 100644 --- a/gui.go +++ b/gui.go @@ -1,7 +1,7 @@ package gui import "log" -import "time" +// import "time" import "regexp" import "github.com/andlabs/ui" @@ -20,80 +20,6 @@ func GuiInit() { }) } -func InitGuiWindow(name string, gw *GuiWindow) *GuiWindow { - log.Println("InitGuiWindow() START") - var newGuiWindow GuiWindow - newGuiWindow.Width = Config.Width - newGuiWindow.Height = Config.Height - newGuiWindow.Name = name - newGuiWindow.MakeWindow = gw.MakeWindow - newGuiWindow.UiWindow = gw.UiWindow - newGuiWindow.UiTab = gw.UiTab - newGuiWindow.BoxMap = make(map[string]*GuiBox) - newGuiWindow.EntryMap = make(map[string]*GuiEntry) - Data.Windows = append(Data.Windows, &newGuiWindow) - - if (Data.WindowMap == nil) { - log.Println("gui.InitGuiWindow() making the Data.WindowMap here") - Data.WindowMap = make(map[string]*GuiWindow) - } - Data.WindowMap[name] = &newGuiWindow - - // make a blank entry for testing - // newGuiWindow.EntryMap["test"] = nil - - if (Data.buttonMap == nil) { - GuiInit() - } - log.Println("InitGuiWindow() END *GuiWindow =", &newGuiWindow) - return &newGuiWindow -} - - -func StartNewWindow(bg bool, name string, callback func(*GuiWindow) *GuiBox) { - log.Println("StartNewWindow() Create a new window") - var junk GuiWindow - junk.MakeWindow = callback - window := InitGuiWindow(name, &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) { - log.Println("InitTabWindow() START. THIS WINDOW IS NOT YET SHOWN") - - gw.UiWindow = ui.NewWindow(gw.Name, int(gw.Width), int(gw.Height), true) - gw.UiWindow.SetBorderless(false) - - gw.UiWindow.OnClosing(func(*ui.Window) bool { - log.Println("InitTabWindow() OnClosing() THIS WINDOW IS CLOSING gw=", gw) - ui.Quit() - return true - }) - - gw.UiTab = ui.NewTab() - gw.UiWindow.SetChild(gw.UiTab) - gw.UiWindow.SetMargined(true) - - - box := gw.MakeWindow(gw) - log.Println("InitTabWindow() END box =", box) - log.Println("InitTabWindow() END gw =", gw) - gw.UiWindow.Show() -} - /* // string handling examples that might be helpful for normalizeInt() isAlpha := regexp.MustCompile(`^[A-Za-z]+$`).MatchString @@ -127,15 +53,3 @@ func normalizeInt(s string) string { log.Println("normalizeInt() s =", clean) return clean } - -func MessageWindow(gw *GuiWindow, msg1 string, msg2 string) { - log.Println("gui.MessageWindow() msg1 =", msg1) - log.Println("gui.MessageWindow() msg2 =", msg2) - ui.MsgBox(gw.UiWindow, msg1, msg2) -} - -func ErrorWindow(gw *GuiWindow, msg1 string, msg2 string) { - log.Println("gui.ErrorWindow() msg1 =", msg1) - log.Println("gui.ErrorWindow() msg2 =", msg2) - ui.MsgBoxError(gw.UiWindow, msg1, msg2) -} diff --git a/window.go b/window.go new file mode 100644 index 0000000..0100778 --- /dev/null +++ b/window.go @@ -0,0 +1,82 @@ +package gui + +import "log" +import "time" +// import "regexp" + +import "github.com/andlabs/ui" +import _ "github.com/andlabs/ui/winmanifest" + +func InitGuiWindow(action string, gw *GuiWindow) *GuiWindow { + log.Println("InitGuiWindow() START") + var newGuiWindow GuiWindow + newGuiWindow.Width = Config.Width + newGuiWindow.Height = Config.Height + newGuiWindow.MakeWindow = gw.MakeWindow + newGuiWindow.UiWindow = gw.UiWindow + newGuiWindow.UiTab = gw.UiTab + newGuiWindow.BoxMap = make(map[string]*GuiBox) + newGuiWindow.EntryMap = make(map[string]*GuiEntry) + newGuiWindow.EntryMap["test"] = nil + Data.Windows = append(Data.Windows, &newGuiWindow) + + if (Data.buttonMap == nil) { + GuiInit() + } + log.Println("InitGuiWindow() END *GuiWindow =", &newGuiWindow) + return &newGuiWindow +} + + +func StartNewWindow(bg bool, action string, callback func(*GuiWindow) *GuiBox) { + log.Println("StartNewWindow() Create a new window") + var junk GuiWindow + junk.MakeWindow = callback +// junk.Action = action + window := InitGuiWindow(action, &junk) + if (bg) { + log.Println("StartNewWindow() START NEW GOROUTINE for ui.Main()") + go ui.Main(func() { + log.Println("gui.StartNewWindow() inside ui.Main()") + go InitTabWindow(window) + }) + time.Sleep(2000 * time.Millisecond) // this might make it more stable on windows? + } else { + log.Println("StartNewWindow() WAITING for ui.Main()") + ui.Main(func() { + log.Println("gui.StartNewWindow() inside ui.Main()") + InitTabWindow(window) + }) + } +} + +func InitTabWindow(gw *GuiWindow) { + log.Println("InitTabWindow() START. THIS WINDOW IS NOT YET SHOWN") + + gw.UiWindow = ui.NewWindow("InitTabWindow()", int(gw.Width), int(gw.Height), true) + gw.UiWindow.SetBorderless(false) + + gw.UiWindow.OnClosing(func(*ui.Window) bool { + log.Println("InitTabWindow() OnClosing() THIS WINDOW IS CLOSING gw=", gw) + ui.Quit() + return true + }) + + gw.UiTab = ui.NewTab() + gw.UiWindow.SetChild(gw.UiTab) + gw.UiWindow.SetMargined(true) + + + box := gw.MakeWindow(gw) + log.Println("InitTabWindow() END box =", box) + log.Println("InitTabWindow() END gw =", gw) + gw.UiWindow.Show() +} + +func MessageWindow(gw *GuiWindow, msg1 string, msg2 string) { + ui.MsgBox(gw.UiWindow, msg1, msg2) +} + +func ErrorWindow(gw *GuiWindow, msg1 string, msg2 string) { + ui.MsgBoxError(gw.UiWindow, msg1, msg2) +} From f68428d13b6bed2336b4814a44b45f243c588ae5 Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Sat, 8 Oct 2022 23:51:48 -0500 Subject: [PATCH 2/2] Try renaming 'Node' to 'Box' --- area.go | 58 ++++++--- box.go | 203 +++++++++++++++++++++++++++++--- button.go | 159 +++++++++++++++++++------ cmds/gui-example/demo-window.go | 4 +- debug-window.go | 172 ++++++++++++++++++++++++++- debug.go | 90 +++++++++++++- demo-window.go | 68 +---------- doc.go | 5 +- entry.go | 104 +++++++++++++--- find.go | 59 ++++++++++ go.mod | 9 +- go.sum | 8 +- gui.go | 6 +- new-structs.go | 111 +++++------------ structs.go | 176 +++++++++++++++++++++++++-- table.go | 14 +-- tableCallbacks.go | 9 +- window.go | 159 +++++++++++++++---------- 18 files changed, 1083 insertions(+), 331 deletions(-) diff --git a/area.go b/area.go index c4e0cae..7c42c6c 100644 --- a/area.go +++ b/area.go @@ -7,14 +7,28 @@ import _ "github.com/andlabs/ui/winmanifest" import "github.com/davecgh/go-spew/spew" -// make this button just to get the default font (but don't display the button) -// There should be another way to do this (?) -func (n *Node) makeGenericArea(newText *ui.AttributedString, custom func(*Node)) { - newNode := n.CreateFontButton("AREA") - newNode.custom = custom - area := new(GuiArea) - newNode.uiArea = ui.NewArea(area) - newNode.uiAttrstr = newText +func makeGenericArea(gb *GuiBox, newText *ui.AttributedString, custom func(*GuiButton)) { + // make this button just to get the default font (but don't display the button) + // There should be another way to do this (?) + var newB *GuiButton + newB = CreateFontButton(gb, "AREA") + newB.Box = gb + newB.Custom = custom + + gw := gb.Window + // initialize the GuiArea{} + gw.Area = new(GuiArea) + gw.Area.Button = newB + gw.Area.Box = gb + gw.Area.UiAttrstr = newText + gw.Area.UiArea = ui.NewArea(gw.Area) + + if (Config.Debug) { + spew.Dump(gw.Area.UiArea) + log.Println("DEBUGGING", Config.Debug) + } else { + log.Println("NOT DEBUGGING AREA mhAH.Button =", gw.Area.Button) + } } func AreaAppendText(newText *ui.AttributedString, what string, attrs ...ui.Attribute) { @@ -38,7 +52,7 @@ func appendWithAttributes(newText *ui.AttributedString, what string, attrs ...ui func (ah GuiArea) Draw(a *ui.Area, p *ui.AreaDrawParams) { tl := ui.DrawNewTextLayout(&ui.DrawTextLayoutParams{ String: ah.UiAttrstr, - DefaultFont: ah.N.uiFontButton.Font(), + DefaultFont: ah.Button.FB.Font(), Width: p.AreaWidth, Align: ui.DrawTextAlign(1), }) @@ -47,7 +61,6 @@ func (ah GuiArea) Draw(a *ui.Area, p *ui.AreaDrawParams) { } func (ah GuiArea) MouseEvent(a *ui.Area, me *ui.AreaMouseEvent) { - /* if (Config.Debug) { log.Println("GOT MouseEvent() ah.Button =", ah.Button) spew.Dump(me) @@ -67,7 +80,6 @@ func (ah GuiArea) MouseEvent(a *ui.Area, me *ui.AreaMouseEvent) { Data.MouseClick(ah.Button) } } - */ } func (ah GuiArea) MouseCrossed(a *ui.Area, left bool) { @@ -95,14 +107,30 @@ func (ah GuiArea) KeyEvent(a *ui.Area, ke *ui.AreaKeyEvent) (handled bool) { return false } -func (n *Node) ShowTextBox(newText *ui.AttributedString, custom func(*Node), name string) { +func (b *GuiBox) ShowTextBox(newText *ui.AttributedString, custom func(*GuiButton), name string) { log.Println("ShowTextBox() START") + gw := b.Window + if (gw == nil) { + log.Println("ShowTextBox() ERROR gw = nil") + return + } + 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 - n.uiBox.SetPadded(true) + b.UiBox.SetPadded(true) // add(gw.BoxMap["MAINBOX"], newbox) - n.makeGenericArea(newText, custom) - n.uiBox.Append(n.area.UiArea, true) + makeGenericArea(b, newText, custom) + b.UiBox.Append(b.Window.Area.UiArea, true) } diff --git a/box.go b/box.go index 67c0c05..7a61f55 100644 --- a/box.go +++ b/box.go @@ -1,7 +1,7 @@ package gui import "log" -// import "os" +import "os" // import "reflect" import "github.com/andlabs/ui" @@ -9,17 +9,190 @@ import _ "github.com/andlabs/ui/winmanifest" // import "github.com/davecgh/go-spew/spew" +// add(nil, newbox, "") // use this when the Window is created. Always called 'MAINBOX' +// add(gw.BoxMap["MAINBOX"], newbox, name) // use this to add a box off the main box +// add(gw.BoxMap["BUTTONBOX"], newbox, name) // use this to add something to the box called 'BUTTONBOX' +// add(box, newbox, name) // add 'newbox' to 'box' and call it 'name' +func add(box *GuiBox, newbox *GuiBox) { + log.Println("gui.add() START box =", box) + log.Println("gui.add() START newbox =", newbox) + if (box == nil) { + log.Println("\tgui.add() add to Window as MAINBOX") + if (newbox.Window.UiTab != nil) { + // create a new tab here + // add the box to it as MAINBOX + log.Println("\tgui.add() add to Window as a UiTab") + // TODO: allow passing where to append + // newbox.Window.UiTab.InsertAt(newbox.Name, 0, newbox.UiBox) + newbox.Window.UiTab.Append(newbox.Name, newbox.UiBox) + // newbox.Window.UiTab.SetMargined(0, true) + + // TODO: figure out how to make a new Tab/Window/Box here + // window := InitGuiWindow(Data.Config, newbox.Name, gw.MakeWindow, gw.UiWindow, gw.UiTab) + // window.UiTab.Delete(0) + // window.MakeWindow(window) + // newbox.Window = window + + newbox.Window.BoxMap["MAINBOX"] = newbox + log.Println("gui.add() END") + panic("gui.add() MAINBOX gui.add() END") + return + } else { + log.Println("\tgui.add() ERROR DONT KNOW HOW TO ADD TO A RAW WINDOW YET") + // 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") + panic("gui.add() gui.add() END") + return + } + log.Println("\tgui.add() adding", newbox.Name, "to", box.Name) + // copy the box settings over + newbox.Window = box.Window + if (box.node == nil) { + box.Dump() + panic("gui.add() ERROR box.node == nil") + } + + if (newbox.UiBox == nil) { + panic("gui.add() ERROR newbox.UiBox == nil") + } + + if (box.UiBox == nil) { + box.Dump() + // panic("gui.add() ERROR box.UiBox == nil") + return + // TODO: fix this whole add() function // Oct 9 + } + box.UiBox.Append(newbox.UiBox, false) + box.Dump() + panic("gui.add()") + + // add the newbox to the Window.BoxMap[] + box.Window.BoxMap[newbox.Name] = newbox + log.Println("gui.add() END") +} + +func (n *Node) AddBox(axis int, name string) *Node { + newBox := new(GuiBox) + newBox.Window = n.window + newBox.Name = name + + if (n.box == nil) { + n.box = newBox + } + + // make a new box & a new node + newNode := n.makeNode(name, 111, 100 + Config.counter) + newNode.box = newBox + Config.counter += 1 + + var uiBox *ui.Box + if (axis == Xaxis) { + uiBox = ui.NewHorizontalBox() + } else { + uiBox = ui.NewVerticalBox() + } + uiBox.SetPadded(true) + newBox.UiBox = uiBox + newNode.uiBox = uiBox + + n.Append(newNode) + // add(n.box, newBox) + return newNode +} + +func (b *GuiBox) NewBox(axis int, name string) *GuiBox { + log.Println("gui.NewBox() START") + n := b.FindNode() + if (n == nil) { + log.Println("gui.NewBox() SERIOUS ERROR. CAN NOT FIND NODE") + os.Exit(0) + } else { + log.Println("gui.NewBox() node =", n.Name) + } + var newbox *GuiBox + newbox = new(GuiBox) + newbox.Window = b.Window + newbox.Name = name + + var uiBox *ui.Box + if (axis == Xaxis) { + uiBox = ui.NewHorizontalBox() + } else { + uiBox = ui.NewVerticalBox() + } + uiBox.SetPadded(true) + newbox.UiBox = uiBox + add(b, newbox) + // panic("gui.NewBox") + return newbox +} + +func HardBox(gw *GuiWindow, axis int, name string) *GuiBox { + log.Println("HardBox() START axis =", axis) + + if (gw.node == nil) { + gw.Dump() + panic("gui.HardBox() gw.node == nil") + } + // add a Vertical Seperator if there is already a box + // Is this right? + box := gw.BoxMap["MAINBOX"] + if (box != nil) { + if (axis == Xaxis) { + VerticalBreak(box) + } else { + HorizontalBreak(box) + } + } + + // make the new vbox + var uiBox *ui.Box + if (axis == Xaxis) { + uiBox = ui.NewHorizontalBox() + } else { + uiBox = ui.NewVerticalBox() + } + uiBox.SetPadded(true) + + // Init a new GuiBox + newbox := new(GuiBox) + newbox.Window = gw + newbox.UiBox = uiBox + newbox.Name = name + + add(gw.BoxMap["MAINBOX"], newbox) + + log.Println("HardBox END") + return newbox +} + +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 { - newNode := n.AddNode(title) box := n.uiBox if (box == nil) { return n } ecbox := ui.NewEditableCombobox() - newNode.uiText = ecbox - // newNode.Dump() - // log.Println("ecbox", ecbox) for id, name := range s { log.Println("Adding Combobox Entry:", id, name) @@ -28,23 +201,21 @@ func (n *Node) AddComboBox(title string, s ...string) *Node { 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 { - newNode.OnChanged() - } + log.Println("node.Name = '" + n.Name + "' text for '" + title + "' is now: '" + test + "'") }) - box.Append(ecbox, Config.Stretchy) + box.Append(ecbox, false) + + newNode := n.AddNode(title) + newNode.uiText = ecbox return newNode } +func (n *Node) OnChanged(f func()) { + f() +} + func (n *Node) GetText() string { - if (n.uiMultilineEntry != nil) { - return n.uiMultilineEntry.Text() - } if (n.uiText == nil) { return "" } diff --git a/button.go b/button.go index 755d9ab..8ad0a3b 100644 --- a/button.go +++ b/button.go @@ -2,14 +2,11 @@ package gui import "log" import "reflect" -// import "image/color" import "github.com/andlabs/ui" import _ "github.com/andlabs/ui/winmanifest" // import "github.com/davecgh/go-spew/spew" -// TODO: bring this generic mouse click function back -// // This is the default mouse click handler // Every mouse click that hasn't been assigned to // something specific will fall into this routine @@ -19,7 +16,41 @@ import _ "github.com/andlabs/ui/winmanifest" // This routine MUST be here as this is how the andlabs/ui works // This is the raw routine passed to every button in andlabs libui / ui // +// There is a []GuiButton which has all the buttons. We search +// for the button and then call the function below // +func defaultButtonClick(button *ui.Button) { + log.Println("gui.defaultButtonClick() LOOK FOR BUTTON button =", button) + for key, foo := range Data.AllButtons { + if (Config.Debug) { + log.Println("gui.defaultButtonClick() Data.AllButtons =", key, foo) + // spew.Dump(foo) + } + if Data.AllButtons[key].B == button { + log.Println("\tgui.defaultButtonClick() BUTTON MATCHED") + guiButtonClick(Data.AllButtons[key]) + return + } + } + 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.uiBox == nil) { @@ -27,12 +58,9 @@ func (n *Node) AddButton(name string, custom func(*Node)) *Node { return n } button := ui.NewButton(name) - if (Config.Debug) { - 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) + log.Println("reflect.TypeOF(uiBox) =", reflect.TypeOf(n.uiBox)) + log.Println("reflect.TypeOF(uiButton) =", reflect.TypeOf(button)) + n.uiBox.Append(button, false) n.uiButton = button newNode := n.makeNode(name, 888, 888 + Config.counter) @@ -43,40 +71,101 @@ func (n *Node) AddButton(name string, custom func(*Node)) *Node { log.Println("gui.AppendButton() Button Clicked. Running custom()") custom(newNode) }) + // panic("AppendButton") + // time.Sleep(3 * time.Second) return newNode } -func (n *Node) CreateFontButton(action string) *Node { - n.uiFontButton = ui.NewFontButton() +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) - n.uiFontButton.OnChanged(func (*ui.FontButton) { - log.Println("FontButton.OnChanged() START") - n.Dump() - }) - n.uiBox.Append(n.uiFontButton, Config.Stretchy) + 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 - // TODO: implement Grid - n.uiGrid = ui.NewGrid() - return n + Data.AllButtons = append(Data.AllButtons, newB) + + box.Append(newB.B, false) + return newNode } -func (n *Node) CreateColorButton(custom func(*Node), name string, values interface {}) *Node { - // create a 'fake' button entry for the mouse clicks - n.uiColorButton = ui.NewColorButton() - n.custom = custom - n.values = values +func CreateButton(box *GuiBox, custom func(*GuiButton), name string, values interface {}) *GuiButton { + newUiB := ui.NewButton(name) + newUiB.OnClicked(defaultButtonClick) - n.uiColorButton.OnChanged(func (*ui.ColorButton) { - log.Println("ColorButton.OnChanged() START Color Button Click") - rgba := n.Color - r, g, b, a := rgba.R, rgba.G, rgba.B, rgba.A - log.Println("ColorButton.OnChanged() Color() =", r, g, b, a) - if (n.custom != nil) { - n.custom(n) - } else if (Data.MouseClick != nil) { - Data.MouseClick(n) + 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) } }) - n.uiBox.Append(n.uiColorButton, Config.Stretchy) - return n + 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/gui-example/demo-window.go b/cmds/gui-example/demo-window.go index f01c1a9..993900d 100644 --- a/cmds/gui-example/demo-window.go +++ b/cmds/gui-example/demo-window.go @@ -33,9 +33,9 @@ func addDemoTab(n *gui.Node, title string) { groupNode1 := newNode.AddGroup("group 1") cbNode := groupNode1.AddComboBox("username", "root", "jcarr", "hugo") - cbNode.OnChanged = func () { + cbNode.OnChanged(func () { username = cbNode.GetText() - } + }) groupNode1.AddComboBox("demoCombo3", "foo 3", "bar", "stuff") groupNode1.Dump() diff --git a/debug-window.go b/debug-window.go index 72272ec..19f276d 100644 --- a/debug-window.go +++ b/debug-window.go @@ -7,7 +7,7 @@ import ( "github.com/andlabs/ui" _ "github.com/andlabs/ui/winmanifest" -// "github.com/davecgh/go-spew/spew" + "github.com/davecgh/go-spew/spew" ) var names = make([]string, 100) @@ -33,6 +33,126 @@ 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) + } + addName(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() @@ -46,7 +166,7 @@ func makeWindowDebug() *ui.Box { } nodeCombo.SetSelected(0) - nodeBox.Append(nodeCombo, Config.Stretchy) + nodeBox.Append(nodeCombo, false) nodeCombo.OnSelected(func(*ui.Combobox) { y := nodeCombo.Selected() @@ -59,7 +179,7 @@ func makeWindowDebug() *ui.Box { }) ///////////////////////////////////////////////////// - vbox := addGroup(hbox, "Node Debug") + vbox = addGroup(hbox, "Node Debug") n1 := addButton(vbox, "Data.DumpNodeMap()") n1.OnClicked(func(*ui.Button) { @@ -148,7 +268,7 @@ func addName(c *ui.Combobox, s string) { func addGroup(b *ui.Box, name string) *ui.Box { group := ui.NewGroup(name) group.SetMargined(true) - b.Append(group, Config.Stretchy) + b.Append(group, true) vbox := ui.NewVerticalBox() vbox.SetPadded(true) @@ -157,6 +277,48 @@ func addGroup(b *ui.Box, name string) *ui.Box { 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) + 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) @@ -164,7 +326,7 @@ func addButton(box *ui.Box, name string) *ui.Button { log.Println("Should do something here") }) - box.Append(button, Config.Stretchy) + box.Append(button, false) return button } diff --git a/debug.go b/debug.go index c895e01..0b0baa4 100644 --- a/debug.go +++ b/debug.go @@ -5,7 +5,7 @@ import ( "log" "time" - // "github.com/davecgh/go-spew/spew" + "github.com/davecgh/go-spew/spew" ) // WatchGUI() opens a goroutine @@ -22,7 +22,7 @@ func WatchGUI() { if count > 20 { log.Println("Sleep() in watchGUI()") if Config.Debug { - // DumpBoxes() + DumpBoxes() } count = 0 } @@ -31,6 +31,71 @@ func WatchGUI() { } } +func DumpWindows() { + for name, _ := range Data.WindowMap { + log.Println("gui.DumpWindows() window =", name) + } +} + +func DumpMap() { + for name, window := range Data.WindowMap { + log.Println("gui.DumpBoxes() MAP: ", name) + 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 @@ -61,6 +126,24 @@ func (dn *GuiData) DumpNodeMap() { } } +/* +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") @@ -68,9 +151,8 @@ func (dn *GuiData) ListChildren(dump bool) { } log.Println("gui.Data.ListChildren() Data.NodeMap:") for name, node := range Data.NodeMap { - listChildrenDepth = 0 + log.Println("\tgui.Data.ListChildren() node =", node.id, node.Width, node.Height, name) if (dump == true) { - log.Println("tgui.Data.ListChildren() node =", node.id, node.Width, node.Height, name) node.Dump() } node.ListChildren(dump) diff --git a/demo-window.go b/demo-window.go index 6cbb5fd..16566c4 100644 --- a/demo-window.go +++ b/demo-window.go @@ -1,6 +1,6 @@ package gui -import "log" +// import "log" import "github.com/andlabs/ui" import _ "github.com/andlabs/ui/winmanifest" @@ -16,7 +16,7 @@ func (n *Node) AddGroup(title string) *Node { } group := ui.NewGroup(title) group.SetMargined(true) - hbox.Append(group, Config.Stretchy) + hbox.Append(group, true) vbox := ui.NewVerticalBox() vbox.SetPadded(true) @@ -26,67 +26,3 @@ func (n *Node) AddGroup(title string) *Node { 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 -} diff --git a/doc.go b/doc.go index 3f8bc64..2b324c9 100644 --- a/doc.go +++ b/doc.go @@ -64,6 +64,9 @@ GUI Usage Errors -Not sure about errors yet. To early to document them. This is a work in progress. +Since it is possible for custom Stringer/error interfaces to panic, spew +detects them and handles them internally by printing the panic information +inline with the output. Since spew is intended to provide deep pretty printing +capabilities on structures, it intentionally does not return any errors. */ package gui diff --git a/entry.go b/entry.go index 524609f..c10b7d0 100644 --- a/entry.go +++ b/entry.go @@ -1,25 +1,45 @@ package gui import "log" -import "errors" -// import "fmt" +import "fmt" import "github.com/andlabs/ui" -// import ui "git.wit.org/interesting/andlabs-ui" import _ "github.com/andlabs/ui/winmanifest" -// import "github.com/davecgh/go-spew/spew" +import "github.com/davecgh/go-spew/spew" // functions for handling text entry boxes +func NewLabel(box *GuiBox, text string) { + box.Append(ui.NewLabel(text), false) +} + func (n *Node) NewLabel(text string) *Node { // make new node here -newNode := n.makeNode(text, 333, 334) + // n.Append(ui.NewLabel(text), false) + newNode := makeNode(n, text, 333, 334) newNode.Dump() + // panic("node.NewLabel()") n.Append(newNode) return newNode } +func (b *GuiBox) GetText(name string) string { + if (b.Window.EntryMap == nil) { + log.Println("gui.GetText() ERROR b.Box.Window.EntryMap == nil") + return "" + } + spew.Dump(b.Window.EntryMap) + if (b.Window.EntryMap[name] == nil) { + log.Println("gui.GetText() ERROR box.Window.EntryMap[", name, "] == nil ") + return "" + } + e := b.Window.EntryMap[name] + log.Println("gui.GetText() box.Window.EntryMap[", name, "] = ", e.UiEntry.Text()) + log.Println("gui.GetText() END") + return e.UiEntry.Text() +} + func (n *Node) SetText(value string) error { log.Println("gui.SetText() value =", value) if (n.uiText != nil) { @@ -30,20 +50,72 @@ func (n *Node) SetText(value string) error { n.uiButton.SetText(value) return nil } - if (n.uiMultilineEntry != nil) { - n.uiMultilineEntry.SetText(value) - return nil - } - n.Dump() - return errors.New("couldn't find something to set the text to") + return nil } -func (n *Node) SetMargined(x bool) { - if (n.uiGroup != nil) { - n.uiGroup.SetMargined(x) - return +func SetText(box *GuiBox, name string, value string) error { + if (box == nil) { + return fmt.Errorf("gui.SetText() ERROR box == nil") } - log.Println("Couldn't find something that has a Margin setting") + if (box.Window.EntryMap == nil) { + return fmt.Errorf("gui.SetText() ERROR b.Box.Window.EntryMap == nil") + } + spew.Dump(box.Window.EntryMap) + if (box.Window.EntryMap[name] == nil) { + return fmt.Errorf("gui.SetText() ERROR box.Window.EntryMap[" + name + "] == nil ") + } + e := box.Window.EntryMap[name] + log.Println("gui.SetText() box.Window.EntryMap[", name, "] = ", e.UiEntry.Text()) + e.UiEntry.SetText(value) + log.Println("gui.SetText() box.Window.EntryMap[", name, "] = ", e.UiEntry.Text()) + log.Println("gui.SetText() END") + return nil +} + +// makeEntryBox(box, "hostname:", "blah.foo.org") { +func MakeEntryVbox(box *GuiBox, a string, startValue string, edit bool, action string) *GuiEntry { + // Start 'Nickname' vertical box + vboxN := ui.NewVerticalBox() + vboxN.SetPadded(true) + vboxN.Append(ui.NewLabel(a), false) + + e := defaultMakeEntry(startValue, edit, action) + + vboxN.Append(e.UiEntry, false) + box.UiBox.Append(vboxN, false) + // End 'Nickname' vertical box + + return e +} + +func MakeEntryHbox(box *GuiBox, a string, startValue string, edit bool, action string) *GuiEntry { + hboxN := ui.NewHorizontalBox() + hboxN.SetPadded(true) + hboxN.Append(ui.NewLabel(a), false) + + e := defaultMakeEntry(startValue, edit, action) + hboxN.Append(e.UiEntry, true) + + box.UiBox.Append(hboxN, true) + + 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) { diff --git a/find.go b/find.go index 15f2714..e046161 100644 --- a/find.go +++ b/find.go @@ -17,6 +17,65 @@ 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") diff --git a/go.mod b/go.mod index 18a5b64..c72bbca 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,9 @@ module git.wit.org/wit/gui -go 1.19 +go 1.17 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 + github.com/andlabs/ui v0.0.0-20200610043537-70a69d6ae31e + github.com/davecgh/go-spew v1.1.1 + golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d ) diff --git a/go.sum b/go.sum index dd2a245..27ff5d2 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,8 @@ -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/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/gui.go b/gui.go index ac75f1e..4174133 100644 --- a/gui.go +++ b/gui.go @@ -14,16 +14,18 @@ const Xaxis = 0 // box that is horizontal const Yaxis = 1 // box that is vertical func init() { - log.Println("gui.init() REMOVE THIS 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 - Config.Stretchy = true } func GuiInit() { diff --git a/new-structs.go b/new-structs.go index f806696..4f9989e 100644 --- a/new-structs.go +++ b/new-structs.go @@ -3,7 +3,6 @@ package gui import ( "log" "fmt" - "image/color" // "reflect" // "github.com/davecgh/go-spew/spew" @@ -45,29 +44,20 @@ type Node struct { Name string Width int Height int - OnChanged func () - Color color.RGBA parent *Node children []*Node - area *GuiArea + window *GuiWindow + box *GuiBox 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 + uiTab *ui.Tab + uiBox *ui.Box + uiText *ui.EditableCombobox } func (n *Node) Parent() *Node { @@ -83,7 +73,6 @@ func (n *Node) Dump() { 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") @@ -92,20 +81,24 @@ func (n *Node) Dump() { } 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() 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") + panic("gui.Node.Dump() id == nil") } } + +func (n *Node) SetBox(box *GuiBox) { + n.box = box +} + func (n *Node) SetName(name string) { // n.uiType.SetName(name) if (n.uiWindow != nil) { @@ -138,22 +131,19 @@ func (n *Node) List() { 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 + var tabs string for i := 0; i < depth; i++ { - space = space + indent + tabs = tabs + "\t" } // newFormat := tabs + strconv.Itoa(depth) + " " + format - newFormat := space + format + newFormat := tabs + format log.Println(newFormat, a) } func (n *Node) ListChildren(dump bool) { - indentPrintln(listChildrenDepth, "", n.id, n.Width, n.Height, n.Name) + indentPrintln(listChildrenDepth, "\t", n.id, n.Width, n.Height, n.Name) if (dump == true) { n.Dump() @@ -212,13 +202,13 @@ func (n *Node) ListChildren(dump bool) { // // This function should make a new node with the parent and // the 'stuff' Node as a child -func (n *Node) AddTabNode(title string) *Node { +func (n *Node) AddTabNode(title string, b *GuiBox) *Node { var newNode *Node parent := n newNode = parent.makeNode(title, 444, 400 + Config.counter) newNode.uiTab = parent.uiTab - // newNode.box = b + newNode.box = b if (Config.DebugNode) { fmt.Println("") @@ -230,62 +220,16 @@ func (n *Node) AddTabNode(title string) *Node { newNode.Dump() } - if (newNode.uiTab != nil) { - log.Println("ERROR: wit/gui/ AddTabNode() Something went wrong tab == nil") + if (newNode.uiTab == nil) { + log.Println("wit/gui/ AddTabNode() Something went wrong tab == nil") // TODO: try to find the tab or window and make them if need be - // newNode.uiTab.Append(title, b.UiBox) + return newNode } + 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) @@ -294,12 +238,20 @@ func (n *Node) AddTab(title string, uiC *ui.Box) *Node { log.Println("gui.Node.AddTab() ERROR ui.Window == nil") return nil } + if parent.box == nil { + parent.Dump() + panic("gui.AddTab() ERROR box == nil") + } if parent.uiTab == nil { inittab := ui.NewTab() // no, not that 'inittab' parent.uiWindow.SetChild(inittab) parent.uiWindow.SetMargined(true) parent.uiTab = inittab + + // parent.Dump() + // panic("gui.AddTab() ERROR uiTab == nil") } + tab := parent.uiTab parent.uiWindow.SetMargined(true) @@ -313,6 +265,7 @@ func (n *Node) AddTab(title string, uiC *ui.Box) *Node { newNode := parent.makeNode(title, 555, 600 + Config.counter) newNode.uiTab = tab newNode.uiBox = uiC + // panic("gui.AddTab() after makeNode()") tabSetMargined(newNode.uiTab) return newNode } diff --git a/structs.go b/structs.go index 79b3fbf..c15f4b7 100644 --- a/structs.go +++ b/structs.go @@ -2,7 +2,7 @@ package gui import ( "image/color" -// "log" + "log" "github.com/andlabs/ui" "golang.org/x/image/font" @@ -22,8 +22,6 @@ type GuiConfig struct { Title string Width int Height int - Stretchy bool - Menu bool Exit func(*Node) Debug bool @@ -40,15 +38,162 @@ type GuiConfig struct { type GuiData struct { // a fallback default function to handle mouse events // if nothing else is defined to handle them - MouseClick func(*Node) + 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 + Area *GuiArea + + node *Node + + // andlabs/ui abstraction mapping + UiWindow *ui.Window + UiTab *ui.Tab // if this != nil, the window is 'tabbed' +} + +func (w *GuiWindow) Dump() { + log.Println("gui.GuiWindow.Dump() Name = ", w.Name) + log.Println("gui.GuiWindow.Dump() node = ", w.node) + log.Println("gui.GuiWindow.Dump() Width = ", w.Width) + log.Println("gui.GuiWindow.Dump() Height = ", w.Height) +} + +// GuiBox is any type of ui.Hbox or ui.Vbox +// There can be lots of these for each GuiWindow +type GuiBox struct { + Name string // field for human readable name + Axis int // does it add items to the X or Y axis + Window *GuiWindow // the parent Window + + node *Node + + // andlabs/ui abstraction mapping + UiBox *ui.Box +} + +func (b *GuiBox) Dump() { + log.Println("gui.GuiBox.Dump() Name = ", b.Name) + log.Println("gui.GuiBox.Dump() Axis = ", b.Axis) + log.Println("gui.GuiBox.Dump() GuiWindow = ", b.Window) + log.Println("gui.GuiBox.Dump() node = ", b.node) + log.Println("gui.GuiBox.Dump() UiBox = ", b.UiBox) +} + +func (b *GuiBox) SetTitle(title string) { + log.Println("DID IT!", title) + if b.Window == nil { + return + } + if b.Window.UiWindow == nil { + return + } + b.Window.UiWindow.SetTitle(title) + 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 (b *GuiBox) SetNode(n *Node) { + if (b.node != nil) { + b.Dump() + panic("gui.SetNode() Error not nil") + } + b.node = n + if (b.node == nil) { + b.Dump() + panic("gui.SetNode() node == nil") + } +} + +func (b *GuiBox) Append(child ui.Control, x bool) { + if b.UiBox == nil { + panic("GuiBox.Append() can't work. UiBox == nil") + return + } + 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 } // text entry fields @@ -58,14 +203,21 @@ type GuiEntry struct { Last string // the last value Normalize func(string) string // function to 'normalize' the data - N *Node + B *GuiButton + Box *GuiBox // andlabs/ui abstraction mapping UiEntry *ui.Entry } +// +// AREA STRUCTURES START +// AREA STRUCTURES START +// AREA STRUCTURES START +// type GuiArea struct { - N *Node // what node to pass mouse events + Button *GuiButton // what button handles mouse events + Box *GuiBox UiAttrstr *ui.AttributedString UiArea *ui.Area @@ -79,6 +231,14 @@ type FontString struct { } // +// AREA STRUCTURES END +// AREA STRUCTURES END +// AREA STRUCTURES END +// + +// +// TABLE DATA STRUCTURES START +// TABLE DATA STRUCTURES START // TABLE DATA STRUCTURES START // @@ -95,7 +255,7 @@ type TableData struct { Cells [20]CellData Human [20]HumanMap - n *Node + Box *GuiBox lastRow int lastColumn int @@ -122,7 +282,7 @@ type HumanCellData struct { TextID int Color color.RGBA ColorID int - N *Node + Button *GuiButton } type HumanMap struct { diff --git a/table.go b/table.go index 378cab2..92ae871 100644 --- a/table.go +++ b/table.go @@ -97,12 +97,13 @@ func InitColumns(mh *TableData, parts []TableColumnData) { } } -func AddTableTab(name string, rowcount int, parts []TableColumnData) *TableData { - n := NewWindow() - return n.AddTableBox(name, rowcount, parts) +func AddTableTab(gw *GuiWindow, name string, rowcount int, parts []TableColumnData) *TableData { + node := NewWindow() + b := node.box + return b.AddTableBox(name, rowcount, parts) } -func (n *Node) AddTableBox(name string, rowcount int, parts []TableColumnData) *TableData { +func (b *GuiBox) AddTableBox(name string, rowcount int, parts []TableColumnData) *TableData { mh := new(TableData) mh.RowCount = rowcount @@ -141,10 +142,9 @@ func (n *Node) AddTableBox(name string, rowcount int, parts []TableColumnData) * // is this needed? // gw.BoxMap[name] = box - // mh.Box = b - mh.n = n + mh.Box = b - n.uiBox.Append(table, true) + b.UiBox.Append(table, true) return mh } diff --git a/tableCallbacks.go b/tableCallbacks.go index f294a9b..6eefd8d 100644 --- a/tableCallbacks.go +++ b/tableCallbacks.go @@ -95,12 +95,9 @@ func defaultSetCellValue(mh *TableData, row int, column int) { humanID := mh.Cells[column].HumanID log.Println("defaultSetCellValue() FOUND THE TABLE BUTTON ", row, humanID) - n := mh.Rows[row].HumanData[humanID].N - if (n != nil) { - // TODO: fixme. removed on Oct 31 2021 - if (n.OnChanged != nil) { - n.OnChanged() - } + button := mh.Rows[row].HumanData[humanID].Button + if (button != nil) { + guiButtonClick(button) return } log.Println("defaultSetCellValue() ERROR: UNKNOWN BUTTON IN TABLE") diff --git a/window.go b/window.go index 50f7073..403638e 100644 --- a/window.go +++ b/window.go @@ -2,36 +2,57 @@ package gui import ( "log" -// "fmt" + "fmt" "strconv" "github.com/andlabs/ui" _ "github.com/andlabs/ui/winmanifest" ) -func findUiWindow() *ui.Window { - for _, node := range Data.NodeMap { - if (node.uiWindow != nil) { - return node.uiWindow +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") + 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) + } } } - return nil } -func MessageWindow(msg1 string, msg2 string) (*Node) { - uiW := findUiWindow() - ui.MsgBox(uiW, msg1, msg2) - // TODO: make new node - return nil -} - -func ErrorWindow(msg1 string, msg2 string) (*Node) { - uiW := findUiWindow() - ui.MsgBoxError(uiW, msg1, msg2) - return nil -} - -func initNode(title string, x int, y int) *Node { +func makeNode(parent *Node, title string, x int, y int) *Node { var node Node node.Name = title node.Width = x @@ -41,17 +62,26 @@ func initNode(title string, x int, y int) *Node { Config.counter += 1 node.id = id - if (Data.NodeMap[title] != nil) { - log.Println("ERROR: Duplicate window name =", title) - // TODO: just change the 'title' to something unique - return Data.NodeMap[title] + // panic("gui.makeNode() START") + if (parent == nil) { + if (Data.NodeMap[title] != nil) { + log.Println("Duplicate window name =", title) + // TODO: just change the 'title' to something unique + panic(fmt.Sprintf("Duplicate window name = %s\n", title)) + return nil + } + // panic("gui.makeNode() before NodeMap()") + Data.NodeMap[title] = &node + Data.NodeArray = append(Data.NodeArray, &node) + Data.NodeSlice = append(Data.NodeSlice, &node) + // panic("gui.makeNode() after NodeMap()") + return &node + } else { + // panic("gui.makeNode() before Append()") + parent.Append(&node) + // panic("gui.makeNode() after Append()") } - Data.NodeMap[title] = &node - Data.NodeArray = append(Data.NodeArray, &node) - Data.NodeSlice = append(Data.NodeSlice, &node) - return &node - // parent.Append(&node) - //node.parent = parent + node.parent = parent return &node } @@ -86,19 +116,15 @@ func (n *Node) AddNode(title string) *Node { } func (n *Node) uiNewWindow(title string, x int, y int) { - w := ui.NewWindow(title, x, y, Config.Menu) + w := ui.NewWindow(title, x, y, false) w.SetBorderless(false) f := Config.Exit w.OnClosing(func(*ui.Window) bool { - log.Println("RUNNING the ui.Window().OnClosing() function") + if (Config.Debug) { + log.Println("ui.Window().OnClosing()") + } 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 }) @@ -109,16 +135,43 @@ func (n *Node) uiNewWindow(title string, x int, y int) { return } -/* func mapWindow(parent *Node, window *ui.Window, title string, x int, y int) *Node { log.Println("gui.WindowMap START title =", title) + if Data.WindowMap[title] != nil { + log.Println("Data.WindowMap[title] already exists title =", title) + 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 = x + newGuiWindow.Height = y + 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 := makeNode(parent, title, x, y) + node.box = &box node.uiWindow = window + box.node = node + + newGuiWindow.BoxMap["jcarrInitTest"] = &box return node } -*/ // This routine creates a blank window with a Title and size (W x H) // @@ -126,29 +179,17 @@ func mapWindow(parent *Node, window *ui.Window, title string, x int, y int) *Nod // 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) + n = mapWindow(nil, nil, title, w, h) + box := n.box + log.Println("gui.NewWindow() title = box.Name =", box.Name) + + n.uiNewWindow(box.Name, w, h) window := n.uiWindow f := Config.Exit @@ -160,9 +201,9 @@ func NewWindow() *Node { return true }) - n.uiWindow = window + box.Window.UiWindow = window if(n.uiWindow == nil) { - log.Println("ERROR: node.uiWindow == nil. This should never happen") + panic("node.uiWindow == nil. This should never happen") } return n }