diff --git a/andlabs/action.go b/andlabs/action.go index b1046ba..28c78d5 100644 --- a/andlabs/action.go +++ b/andlabs/action.go @@ -1,47 +1,99 @@ package main import ( - "strconv" - "go.wit.com/dev/andlabs/ui" + "errors" "go.wit.com/log" "go.wit.com/gui/widget" + "go.wit.com/gui/toolkits/tree" ) +// this will check to make sure that the node +// is valid for making a New TK andlabs widget +// Basically, it makes sure there is a parent ID +// and that there already a widget created +func notNew(n *tree.Node) bool { + if n == nil { + log.Warn("ready() n = nil") + return true + } + if n.TK != nil { + log.Warn("ready() n.TK = nil", n.WidgetId, n.GetProgName()) + return true + } + if n.Parent == nil { + log.Warn("ready() n.Parent = nil", n.WidgetId, n.GetProgName()) + return true + } + if n.Parent.TK == nil { + log.Warn("ready() n.Parent.TK = nil", n.WidgetId, n.GetProgName()) + log.Warn("ready() n.Parent.TK = nil", n.Parent.WidgetId, n.Parent.GetProgName()) + return true + } + // this means you can add a new widgets + return false +} + +func ready(n *tree.Node) bool { + if n == nil { + log.Warn("ready() n = nil") + return false + } + if n.TK == nil { + log.Warn("ready() n.TK = nil", n.WidgetId, n.GetProgName()) + return false + } + if n.Parent == nil { + log.Warn("ready() n.Parent = nil", n.WidgetId, n.GetProgName()) + return false + } + if n.Parent.TK == nil { + log.Warn("ready() n.Parent.TK = nil", n.WidgetId, n.GetProgName()) + log.Warn("ready() n.Parent.TK = nil", n.Parent.WidgetId, n.Parent.GetProgName()) + return false + } + return true +} func (n *node) ready() bool { if n == nil { return false } if n.tk == nil { return false } return true } -func (n *node) show(b bool) { - if n.tk == nil { +func show(n *tree.Node, b bool) { + var tk *guiWidget + tk = n.TK.(*guiWidget) + // tk = getTK(n) + + if tk == nil { return } - if n.tk.uiControl == nil { + if tk.uiControl == nil { return } if (b) { - n.tk.uiControl.Show() + tk.uiControl.Show() } else { - n.tk.uiControl.Hide() + tk.uiControl.Hide() } } -func (n *node) enable(b bool) { +func enable(n *tree.Node, b bool) { + var tk *guiWidget + tk = n.TK.(*guiWidget) if n == nil { panic("WHAT? enable was passed nil. How does this even happen?") } - if n.tk == nil { + if tk == nil { return } - if n.tk.uiControl == nil { + if tk.uiControl == nil { return } if (b) { - n.tk.uiControl.Enable() + tk.uiControl.Enable() } else { - n.tk.uiControl.Disable() + tk.uiControl.Disable() } } @@ -152,73 +204,88 @@ func (n *node) Delete() { func rawAction(a *widget.Action) { log.Log(INFO, "rawAction() START a.ActionType =", a.ActionType, "a.Value", a.Value) - if (a.ActionType == widget.InitToolkit) { - // TODO: make sure to only do this once - // go uiMain.Do(func() { - // ui.Main(demoUI) - // go catchActionChannel() - // }) - // try doing this on toolkit load in init() + if (a.ActionType == widget.ToolkitInit) { + Init() + return + } + switch a.WidgetType { + case widget.Root: + me.treeRoot = me.myTree.AddNode(a) + log.Log(INFO, "doAction() found treeRoot") return } - log.Log(INFO, "rawAction() START a.WidgetId =", a.WidgetId, "a.ParentId =", a.ParentId) + log.Warn("andlabs rawAction() START a.WidgetId =", a.WidgetId, "a.ParentId =", a.ParentId, a.ActionType) switch a.WidgetType { case widget.Flag: log.Log(ERROR, "rawAction() RE-IMPLEMENT LOG FLAGS") return } - n := me.rootNode.findWidgetId(a.WidgetId) + if me.treeRoot == nil { + panic("me.treeRoot == nil") + } + + n := me.treeRoot.FindWidgetId(a.WidgetId) if (a.ActionType == widget.Add) { - ui.QueueMain(func() { + me.treeRoot.ListWidgets() + // ui.QueueMain(func() { add(a) - }) + // }) // TODO: remove this artificial delay // sleep(.001) return } if (a.ActionType == widget.Dump) { - log.Log(NOW, "rawAction() Dump =", a.ActionType, a.WidgetType, n.progname) - me.rootNode.listChildren(true) + log.Log(NOW, "rawAction() Dump =", a.ActionType, a.WidgetType, n.State.ProgName) + // me.rootNode.listChildren(true) return } if (n == nil) { - me.rootNode.listChildren(true) - log.Log(NOW, "rawAction() ERROR findWidgetId found nil", a.ActionType, a.WidgetType) + log.Error(errors.New("andlabs rawAction() ERROR findWidgetId found nil"), a.ActionType, a.WidgetType) log.Log(NOW, "rawAction() ERROR findWidgetId found nil for id =", a.WidgetId) log.Log(NOW, "rawAction() ERROR findWidgetId found nil", a.ActionType, a.WidgetType) log.Log(NOW, "rawAction() ERROR findWidgetId found nil for id =", a.WidgetId) + me.treeRoot.ListWidgets() return - panic("findWidgetId found nil for id = " + strconv.Itoa(a.WidgetId)) + panic("findWidgetId found nil for id = " + string(a.WidgetId)) } switch a.ActionType { case widget.Show: - n.show(true) + show(n, true) + // n.show(true) case widget.Hide: - n.show(false) + show(n, false) + //n.show(false) case widget.Enable: - n.enable(true) + enable(n, true) + // n.enable(true) case widget.Disable: - log.Warn("andlabs got disable for", n.WidgetId, n.progname) - n.enable(false) + log.Warn("andlabs got disable for", n.WidgetId, n.State.ProgName) + enable(n, false) + // n.enable(false) case widget.Get: - n.setText(a) + // n.setText(a) + setText(n, a) case widget.GetText: switch a.WidgetType { case widget.Textbox: - a.Value = n.value + a.Value = n.State.Value } case widget.Set: - n.setText(a) + setText(n, a) + // n.setText(a) case widget.SetText: - n.setText(a) + setText(n, a) + // n.setText(a) case widget.AddText: - n.addText(a) + addText(n, a) + // n.addText(a) + /* case widget.Margin: n.pad(true) case widget.Unmargin: @@ -231,8 +298,7 @@ func rawAction(a *widget.Action) { n.Delete() case widget.Move: log.Log(NOW, "rawAction() attempt to move() =", a.ActionType, a.WidgetType) - newParent := me.rootNode.findWidgetId(a.ParentId) - n.move(newParent) + */ default: log.Log(ERROR, "rawAction() Unknown =", a.ActionType, a.WidgetType) } diff --git a/andlabs/add.go b/andlabs/add.go index ffe2cc4..a47d697 100644 --- a/andlabs/add.go +++ b/andlabs/add.go @@ -6,57 +6,67 @@ import ( ) func add(a *widget.Action) { + log.Warn("andlabs add()", a.WidgetId, a.State.ProgName) if (a.WidgetType == widget.Root) { - me.rootNode = addNode(a) + if me.treeRoot == nil { + me.treeRoot = me.myTree.AddNode(a) + } return } - n := addNode(a) + // n := addNode(a) + n := me.myTree.AddNode(a) - p := n.parent + p := n.Parent switch n.WidgetType { case widget.Window: - newWindow(n) - return - case widget.Tab: - p.newTab(n) - return - case widget.Label: - p.newLabel(n) - return - case widget.Button: - p.newButton(n) - return - case widget.Grid: - p.newGrid(n) - return - case widget.Checkbox: - p.newCheckbox(n) - return - case widget.Spinner: - p.newSpinner(n) - return - case widget.Slider: - p.newSlider(n) - return - case widget.Dropdown: - p.newDropdown(n) - return - case widget.Combobox: - p.newCombobox(n) - return - case widget.Textbox: - p.newTextbox(n) + log.Warn("SPEEDY Add window", n.WidgetId, n.GetProgName()) + newWindow(p, n) return case widget.Group: - p.newGroup(n) + log.Warn("SPEEDY Add Group", n.WidgetId, n.GetProgName()) + newGroup(p, n) + return + case widget.Grid: + newGrid(n) return case widget.Box: - p.newBox(n) + newBox(n) return + /* + case widget.Tab: + newTab(n) + return + */ + case widget.Label: + newLabel(p, n) + return + case widget.Button: + newButton(p, n) + return + case widget.Checkbox: + newCheckbox(p, n) + return + case widget.Spinner: + newSpinner(p, n) + return + case widget.Slider: + newSlider(p, n) + return + case widget.Dropdown: + newDropdown(p, n) + return + case widget.Combobox: + newCombobox(p, n) + return + case widget.Textbox: + newTextbox(p, n) + return + /* case widget.Image: - p.newImage(n) + newImage(p, n) return + */ default: - log.Log(ERROR, "add() error TODO: ", n.WidgetType, n.progname) + log.Log(ERROR, "add() error TODO: ", n.WidgetType, n.State.ProgName) } } diff --git a/andlabs/addText.go b/andlabs/addText.go index cbc9269..d335be2 100644 --- a/andlabs/addText.go +++ b/andlabs/addText.go @@ -3,22 +3,40 @@ package main import ( "go.wit.com/log" "go.wit.com/gui/widget" + "go.wit.com/gui/toolkits/tree" ) -func (n *node) addText(a *widget.Action) { - log.Log(CHANGE, "addText() START with a.Value =", a.Value) - t := n.tk - if (t == nil) { - log.Log(ERROR, "addText error. tk == nil", n.progname, n.WidgetId) +func compareStrings(n *tree.Node, ss []string) { +} + +// func (n *node) addText(a *widget.Action) { +func addText(n *tree.Node, a *widget.Action) { + var tk *guiWidget + tk = n.TK.(*guiWidget) + log.Warn("andlabs addText() START with a.Value =", a.Value) + if (tk == nil) { + log.Log(ERROR, "addText error. tk == nil", n.State.ProgName, n.WidgetId) return } - log.Log(CHANGE, "addText() Attempt on", n.WidgetType, "with", a.Value) + log.Warn("andlabs addText() Attempt on", n.WidgetType, "with", a.Value) switch n.WidgetType { case widget.Dropdown: - n.addDropdownName(widget.GetString(a.Value)) + for i, s := range a.State.Strings { + log.Warn("andlabs a.State.Strings =", i, s) + _, ok := n.Strings[s] + // If the key exists + if ok { + log.Warn("andlabs a.State.Strings is here", i, s) + } else { + log.Warn("andlabs is not here", i, s) + addDropdownName(n, s) + // TODO: make numbers + n.Strings[s] = 21 + } + } case widget.Combobox: - n.addComboboxName(widget.GetString(a.Value)) + addComboboxName(n, widget.GetString(a.Value)) default: log.Log(ERROR, "plugin Send() Don't know how to addText on", n.WidgetType, "yet", a.ActionType) } diff --git a/andlabs/box.go b/andlabs/box.go index d06bf60..df4cfba 100644 --- a/andlabs/box.go +++ b/andlabs/box.go @@ -2,17 +2,19 @@ package main import ( "go.wit.com/gui/widget" + "go.wit.com/gui/toolkits/tree" "go.wit.com/dev/andlabs/ui" _ "go.wit.com/dev/andlabs/ui/winmanifest" ) // make new Box here -func (p *node) newBox(n *node) { +func newBox(n *tree.Node) { + if notNew(n) { return } newt := new(guiWidget) var box *ui.Box - if n.direction == widget.Horizontal { + if n.State.Direction == widget.Horizontal { box = ui.NewHorizontalBox() } else { box = ui.NewVerticalBox() @@ -22,8 +24,8 @@ func (p *node) newBox(n *node) { newt.uiBox = box newt.uiControl = box newt.boxC = 0 - n.tk = newt - p.place(n) + n.TK = newt + place(n.Parent, n) } /* @@ -46,10 +48,11 @@ func (p *node) newBox(n *node) { TODO: handle user killing/closing a window using the OS */ -func (n *node) rawBox() *ui.Box { +// func (n *node) rawBox() *ui.Box { +func rawBox(n *tree.Node) *ui.Box { var box *ui.Box - if n.direction == widget.Horizontal { + if n.State.Direction == widget.Horizontal { box = ui.NewHorizontalBox() } else { box = ui.NewVerticalBox() diff --git a/andlabs/button.go b/andlabs/button.go index 0cc4f52..4bbc8f2 100644 --- a/andlabs/button.go +++ b/andlabs/button.go @@ -1,25 +1,28 @@ package main import ( - "go.wit.com/gui/widget" + "go.wit.com/gui/toolkits/tree" "go.wit.com/dev/andlabs/ui" _ "go.wit.com/dev/andlabs/ui/winmanifest" ) -func (p *node) newButton(n *node) { - t := p.tk +// func (p *node) newButton(n *node) { +func newButton(p *tree.Node, n *tree.Node) { + if notNew(n) { return } + var ptk *guiWidget + ptk = p.TK.(*guiWidget) newt := new(guiWidget) - b := ui.NewButton(widget.GetString(n.value)) + b := ui.NewButton(n.GetLabel()) newt.uiButton = b newt.uiControl = b - newt.parent = t + newt.parent = ptk b.OnClicked(func(*ui.Button) { - n.doUserEvent() + me.myTree.DoUserEvent(n) }) - n.tk = newt - p.place(n) + n.TK = newt + place(p, n) } diff --git a/andlabs/checkbox.go b/andlabs/checkbox.go index d44e458..d447baf 100644 --- a/andlabs/checkbox.go +++ b/andlabs/checkbox.go @@ -1,23 +1,26 @@ package main import ( + "go.wit.com/gui/toolkits/tree" + "go.wit.com/dev/andlabs/ui" _ "go.wit.com/dev/andlabs/ui/winmanifest" ) -func (p *node) newCheckbox(n *node) { +func newCheckbox(p *tree.Node, n *tree.Node) { + if notNew(n) { return } newt := new(guiWidget) - newt.uiCheckbox = ui.NewCheckbox(n.label) + newt.uiCheckbox = ui.NewCheckbox(n.GetLabel()) newt.uiControl = newt.uiCheckbox newt.uiCheckbox.OnToggled(func(spin *ui.Checkbox) { - n.value = newt.checked() - n.doUserEvent() + n.SetValue(newt.checked()) + me.myTree.DoUserEvent(n) }) - n.tk = newt - p.place(n) + n.TK = newt + place(p, n) } func (t *guiWidget) checked() bool { diff --git a/andlabs/combobox.go b/andlabs/combobox.go index 0dd16c6..adfea36 100644 --- a/andlabs/combobox.go +++ b/andlabs/combobox.go @@ -5,10 +5,11 @@ import ( _ "go.wit.com/dev/andlabs/ui/winmanifest" "go.wit.com/log" - "go.wit.com/gui/widget" + "go.wit.com/gui/toolkits/tree" ) -func (p *node) newCombobox(n *node) { +func newCombobox(p, n *tree.Node) { + if notNew(n) { return } newt := new(guiWidget) cb := ui.NewEditableCombobox() @@ -20,46 +21,53 @@ func (p *node) newCombobox(n *node) { newt.val = make(map[int]string) cb.OnChanged(func(spin *ui.EditableCombobox) { - n.value = spin.Text() + n.SetValue(spin.Text()) log.Warn("combobox changed =" + spin.Text() + ".") - n.doUserEvent() + me.myTree.DoUserEvent(n) }) - n.tk = newt - p.place(n) + n.TK = newt + place(p, n) + log.Warn("add combobox entries on create:", n.State.Strings) + log.Warn("add combobox entries on create:", n.State.Strings) + log.Warn("add combobox entries on create:", n.State.Strings) // add the initial combobox entries - for i, s := range n.strings { - log.Warn("add combobox entries on create", n.progname, i, s) - n.addComboboxName(s) + for i, s := range n.State.Strings { + log.Warn("add combobox entries on create", n.GetProgName(), i, s) + addComboboxName(n, s) } - cur := widget.GetString(n.value) - log.Warn("add combobox: TODO: set default value on create", n.progname, cur) - n.setComboboxName(cur) + cur := n.String() + log.Warn("add combobox: TODO: set default value on create", n.GetProgName(), cur) + setComboboxName(n, cur) } -func (n *node) addComboboxName(s string) { - if ! n.ready() { return } +func addComboboxName(n *tree.Node, s string) { + if ! ready(n) { return } + var tk *guiWidget + tk = n.TK.(*guiWidget) log.Log(INFO, "addComboboxName()", n.WidgetId, "add:", s) - n.tk.uiEditableCombobox.Append(s) - if (n.tk.val == nil) { + tk.uiEditableCombobox.Append(s) + if (tk.val == nil) { log.Log(INFO, "make map didn't work") return } - n.tk.val[n.tk.c] = s + tk.val[tk.c] = s // If this is the first menu added, set the dropdown to it - if (n.tk.c == 0) { + if (tk.c == 0) { log.Log(INFO, "THIS IS THE FIRST combobox", s) - n.tk.uiEditableCombobox.SetText(s) + tk.uiEditableCombobox.SetText(s) } - n.tk.c = n.tk.c + 1 + tk.c = tk.c + 1 } -func (n *node) setComboboxName(s string) bool { - if ! n.ready() { return false} +func setComboboxName(n *tree.Node, s string) bool { + if ! ready(n) { return false} + var tk *guiWidget + tk = n.TK.(*guiWidget) log.Log(INFO, "SetComboboxName()", n.WidgetId, ",", s) - n.tk.uiEditableCombobox.SetText(s) + tk.uiEditableCombobox.SetText(s) return false } diff --git a/andlabs/common.go b/andlabs/common.go deleted file mode 120000 index 35417a1..0000000 --- a/andlabs/common.go +++ /dev/null @@ -1 +0,0 @@ -../nocui/common.go \ No newline at end of file diff --git a/andlabs/common.go b/andlabs/common.go new file mode 100644 index 0000000..1cfac84 --- /dev/null +++ b/andlabs/common.go @@ -0,0 +1,61 @@ +package main + +import ( + "go.wit.com/gui/widget" +) + +type node struct { + parent *node + children []*node + + WidgetId int // widget ID + WidgetType widget.WidgetType + ParentId int // parent ID + + state widget.State + + // a reference name for programming and debuggign. Must be unique + progname string + + // the text used for button labesl, window titles, checkbox names, etc + label string + + // horizontal means layout widgets like books on a bookshelf + // vertical means layout widgets like books in a stack + // direction widget.Orientation + direction widget.Orientation + + // This is how the values are passed back and forth + // values from things like checkboxes & dropdown's + value any + + strings []string + + // This is used for things like a slider(0,100) + X int + Y int + + // This is for the grid size & widget position + W int + H int + AtW int + AtH int + + vals []string // dropdown menu items + + // horizontal bool `default:false` + + hasTabs bool // does the window have tabs? + currentTab bool // the visible tab + + // the internal plugin toolkit structure + // in the gtk plugin, it has gtk things like margin & border settings + // in the text console one, it has text console things like colors for menus & buttons + tk *guiWidget +} + +/* +func (n *node) doUserEvent() { + log.Log(ERROR, "doUserEvent() ERROR") +} +*/ diff --git a/andlabs/debug.go b/andlabs/debug.go index 7e6bb24..51048d5 100644 --- a/andlabs/debug.go +++ b/andlabs/debug.go @@ -1,8 +1,6 @@ package main import ( - "strconv" - "go.wit.com/log" // "go.wit.com/gui/widget" ) @@ -94,7 +92,7 @@ func (n *node) dumpWidget(b bool) { } info = n.WidgetType.String() - d = strconv.Itoa(n.WidgetId) + " " + info + " " + n.progname + d = string(n.WidgetId) + " " + info + " " + n.progname var tabs string for i := 0; i < listChildrenDepth; i++ { diff --git a/andlabs/dropdown.go b/andlabs/dropdown.go index 0795264..6a1bd64 100644 --- a/andlabs/dropdown.go +++ b/andlabs/dropdown.go @@ -5,12 +5,13 @@ import ( _ "go.wit.com/dev/andlabs/ui/winmanifest" "go.wit.com/log" - "go.wit.com/gui/widget" + "go.wit.com/gui/toolkits/tree" ) -func (p *node) newDropdown(n *node) { +func newDropdown(p, n *tree.Node) { + if notNew(n) { return } newt := new(guiWidget) - log.Log(INFO, "gui.Toolbox.newDropdown() START", n.progname) + log.Log(INFO, "gui.Toolbox.newDropdown() START", n.GetProgName()) cb := ui.NewCombobox() newt.uiCombobox = cb @@ -24,60 +25,69 @@ func (p *node) newDropdown(n *node) { i := spin.Selected() if (newt.val == nil) { log.Log(ERROR, "make map didn't work") - n.value = "map did not work. ui.Combobox error" + n.SetValue("map did not work. ui.Combobox error") } else { - n.value = newt.val[i] + n.SetValue(newt.val[i]) } - n.doUserEvent() + me.myTree.DoUserEvent(n) }) - n.tk = newt - p.place(n) + n.TK = newt + place(p, n) - if n.strings == nil {return} + log.Warn("add dropdown entries on create:", n.State.Strings) + log.Warn("add dropdown entries on create:", n.State.Strings) + log.Warn("add dropdown entries on create:", n.State.Strings) + if n.State.Strings == nil {return} // add the initial dropdown entries - for i, s := range n.strings { - log.Warn("add dropdown: add entries on create", n.progname, i, s) - n.addDropdownName(s) + for i, s := range n.State.Strings { + log.Warn("add dropdown: add entries on create", n.GetProgName(), i, s) + addDropdownName(n, s) } - cur := widget.GetString(n.value) - log.Warn("add dropdown: set default value on create", n.progname, cur) - n.setDropdownName(cur) + cur := n.String() + log.Warn("add dropdown: set default value on create", n.GetProgName(), cur) + setDropdownName(n, cur) } -func (n *node) SetDropdownInt(i int) { - if ! n.ready() { return } - n.tk.uiCombobox.SetSelected(i) +func setDropdownInt(n *tree.Node, i int) { + if ! ready(n) { return } + var tk *guiWidget + tk = n.TK.(*guiWidget) + tk.uiCombobox.SetSelected(i) } -func (n *node) addDropdownName(s string) { - if ! n.ready() { return } +func addDropdownName(n *tree.Node, s string) { + if ! ready(n) { return } + var tk *guiWidget + tk = n.TK.(*guiWidget) log.Log(INFO, "addDropdownName()", n.WidgetId, "add:", s) - n.tk.uiCombobox.Append(s) - if (n.tk.val == nil) { + tk.uiCombobox.Append(s) + if (tk.val == nil) { log.Log(INFO, "make map didn't work") return } - n.tk.val[n.tk.c] = s + tk.val[tk.c] = s // If this is the first menu added, set the dropdown to it - if (n.tk.c == 0) { + if (tk.c == 0) { log.Log(INFO, "THIS IS THE FIRST Dropdown", s) - n.tk.uiCombobox.SetSelected(0) + tk.uiCombobox.SetSelected(0) } - n.tk.c = n.tk.c + 1 + tk.c = tk.c + 1 } -func (n *node) setDropdownName(s string) bool { - if ! n.ready() { return false} +func setDropdownName(n *tree.Node, s string) bool { + if ! ready(n) { return false} + var tk *guiWidget + tk = n.TK.(*guiWidget) log.Log(INFO, "SetDropdownName()", n.WidgetId, ",", s) - for i, tmp := range n.tk.val { + for i, tmp := range tk.val { if s == tmp { - n.value = s - n.SetDropdownInt(i) + n.SetValue(s) + setDropdownInt(n, i) log.Warn("SetDropdownInt() worked", tmp, i) return true } diff --git a/andlabs/grid.go b/andlabs/grid.go index 2561648..bbb2c8b 100644 --- a/andlabs/grid.go +++ b/andlabs/grid.go @@ -1,6 +1,8 @@ package main import ( + "go.wit.com/gui/toolkits/tree" + "go.wit.com/dev/andlabs/ui" _ "go.wit.com/dev/andlabs/ui/winmanifest" ) @@ -10,9 +12,9 @@ import ( // -- (1,1) -- (2,1) -- (3,1) -- // -- (1,2) -- (2,1) -- (3,1) -- // ----------------------------- -func (p *node) newGrid(n *node) { +func newGrid(n *tree.Node) { + if notNew(n) { return } var newt *guiWidget - newt = new(guiWidget) c := ui.NewGrid() @@ -20,6 +22,6 @@ func (p *node) newGrid(n *node) { newt.uiControl = c c.SetPadded(true) - n.tk = newt - p.place(n) + n.TK = newt + place(n.Parent, n) } diff --git a/andlabs/group.go b/andlabs/group.go index 8faa6a4..efbabd9 100644 --- a/andlabs/group.go +++ b/andlabs/group.go @@ -1,20 +1,22 @@ package main import ( - "go.wit.com/gui/widget" + // "go.wit.com/gui/widget" + "go.wit.com/gui/toolkits/tree" "go.wit.com/dev/andlabs/ui" _ "go.wit.com/dev/andlabs/ui/winmanifest" ) -func (p *node) newGroup(n *node) { +func newGroup(p, n *tree.Node) { + if notNew(n) { return } newt := new(guiWidget) - g := ui.NewGroup(widget.GetString(n.value)) + g := ui.NewGroup(n.GetLabel()) g.SetMargined(true) newt.uiGroup = g newt.uiControl = g - n.tk = newt - p.place(n) + n.TK = newt + place(p, n) } diff --git a/andlabs/image.go b/andlabs/image.go index f5cf941..badd8b4 100644 --- a/andlabs/image.go +++ b/andlabs/image.go @@ -16,7 +16,7 @@ func (p *node) newImage(n *node) { // newt.uiControl = img n.tk = newt - p.place(n) + // p.place(n) } /* if (a.Name == "image") { diff --git a/andlabs/label.go b/andlabs/label.go index bcdaf7a..12bc9c1 100644 --- a/andlabs/label.go +++ b/andlabs/label.go @@ -1,18 +1,19 @@ package main import ( - "go.wit.com/gui/widget" + "go.wit.com/gui/toolkits/tree" "go.wit.com/dev/andlabs/ui" _ "go.wit.com/dev/andlabs/ui/winmanifest" ) -func (p *node) newLabel(n *node) { +func newLabel(p, n *tree.Node) { + if notNew(n) { return } newt := new(guiWidget) - c := ui.NewLabel(widget.GetString(n.value)) + c := ui.NewLabel(n.GetLabel()) newt.uiLabel = c newt.uiControl = c - n.tk = newt - p.place(n) + n.TK = newt + place(p, n) } diff --git a/andlabs/main.go b/andlabs/main.go index 5a6d383..b1e0e47 100644 --- a/andlabs/main.go +++ b/andlabs/main.go @@ -2,8 +2,11 @@ package main import ( "sync" + "runtime/debug" + "go.wit.com/log" "go.wit.com/gui/widget" + "go.wit.com/gui/toolkits/tree" "go.wit.com/dev/andlabs/ui" // the _ means we only need this for the init() @@ -17,7 +20,11 @@ var muAction sync.Mutex func queueMain(currentA widget.Action) { defer func() { if r := recover(); r != nil { - log.Warn("YAHOOOO Recovered in main application:", r) + log.Warn("YAHOOOO Recovered in queueMain() application:", r) + log.Println("Recovered from panic:", r) + log.Println("Stack trace:") + debug.PrintStack() + me.myTree.DoToolkitPanic() } }() ui.QueueMain( func() { @@ -25,29 +32,14 @@ func queueMain(currentA widget.Action) { }) } -func catchActionChannel() { - log.Log(INFO, "catchActionChannel() START") - for { - log.Log(INFO, "catchActionChannel() for loop") - select { - case a := <-pluginChan: - log.Log(INFO, "catchActionChannel() SELECT widget id =", a.WidgetId, a.ProgName) - log.Log(INFO, "catchActionChannel() STUFF", a.WidgetId, a.ActionType, a.WidgetType) - muAction.Lock() - // TODO ui.QueueMain(f) - // TODO ui.QueueMain( func() {rawAction(a)} ) - // rawAction(a) - queueMain(a) - muAction.Unlock() - log.Log(INFO, "catchActionChannel() STUFF END", a.WidgetId, a.ActionType, a.WidgetType) - } - } -} - func guiMain() { defer func() { if r := recover(); r != nil { - log.Warn("YAHOOOO Recovered in main application:", r) + log.Warn("YAHOOOO Recovered in guiMain application:", r) + log.Println("Recovered from panic:", r) + log.Println("Stack trace:") + debug.PrintStack() + me.myTree.DoToolkitPanic() } }() ui.Main(func() { @@ -55,6 +47,10 @@ func guiMain() { }) } +func Init() { + log.Warn("Init() TODO: move init() to here") +} + // This is important. This sets the defaults for the gui. Without this, there isn't correct padding, etc func init() { log.Log(INFO, "Init() START") @@ -63,15 +59,12 @@ func init() { // log.Log(INFO, "init() Setting defaultBehavior = true") setDefaultBehavior(true) + me.myTree = tree.New() + me.myTree.PluginName = "andlabs" + me.myTree.ActionFromChannel = queueMain + // TODO: this is messed up. run ui.Main() from the first add? Initialize it with an empty thing first? // fake out the OS toolkit by making a fake window. This is probably needed for macos & windows // actually, this probably breaks the macos build go guiMain() - - // andlabs = make(map[int]*andlabsT) - pluginChan = make(chan widget.Action, 1) - - log.Log(INFO, "Init() start channel reciever") - go catchActionChannel() - log.Log(INFO, "Init() END") } diff --git a/andlabs/place.go b/andlabs/place.go index 94a16b2..25672e7 100644 --- a/andlabs/place.go +++ b/andlabs/place.go @@ -1,12 +1,15 @@ package main import ( + // "os" "go.wit.com/dev/andlabs/ui" _ "go.wit.com/dev/andlabs/ui/winmanifest" "go.wit.com/log" "go.wit.com/gui/widget" + + "go.wit.com/gui/toolkits/tree" ) // This routine is very specific to this toolkit @@ -33,62 +36,78 @@ import ( // -- (0,0) -- (1,0) -- (1,0) -- // -- (0,1) -- (1,1) -- (1,1) -- // ----------------------------- -func (p *node) place(n *node) bool { - log.Log(INFO, "place() START", n.WidgetType, n.progname) - if (p.tk == nil) { - log.Log(ERROR, "p.tk == nil", p.progname, p.ParentId, p.WidgetType, p.tk) - log.Log(ERROR, "n = ", n.progname, n.ParentId, n.WidgetType, n.tk) - panic("p.tk == nil") +func place(p *tree.Node, n *tree.Node) bool { + log.Warn("SPEEDY newplace() 1 START", n.WidgetId, n.GetProgName(), n.GetLabel(), n.String()) + log.Warn("SPEEDY newplace() n.State.Strings =", n.State.Strings) + log.Log(INFO, "place() 1 START", n.WidgetType, n.GetProgName(), n.GetLabel()) + if ! ready(n) { + log.Warn("place() 1 START not ready()") + return false + } + log.Log(INFO, "place() 1 START ready()") + var tk, ptk *guiWidget + tk = n.TK.(*guiWidget) + ptk = p.TK.(*guiWidget) + log.Warn("SPEEDY newplace() 2 START", n.WidgetId, n.GetProgName(), n.GetLabel()) + + if (ptk == nil) { + log.Log(ERROR, "ptk == nil", p.GetProgName(), p.ParentId, p.WidgetType, ptk) + log.Log(ERROR, "n = ", n.GetProgName(), n.ParentId, n.WidgetType, tk) + log.Warn("SPEEDY ptk == nil", n.WidgetId, n.GetProgName()) + log.Sleep(1) + panic("ptk == nil") } log.Log(INFO, "place() switch", p.WidgetType) + log.Warn("SPEEDY newplace() before switch", n.WidgetId, n.GetProgName()) switch p.WidgetType { case widget.Grid: - log.Log(INFO, "place() Grid try at Parent X,Y =", n.X, n.Y) - n.tk.gridX = n.AtW - 1 - n.tk.gridY = n.AtH - 1 - log.Log(INFO, "place() Grid try at gridX,gridY", n.tk.gridX, n.tk.gridY) - // at the very end, subtract 1 from X & Y since andlabs/ui starts counting at zero - p.tk.uiGrid.Append(n.tk.uiControl, - n.tk.gridX, n.tk.gridY, 1, 1, + tk.gridX = n.State.GridOffset.X - 1 + tk.gridY = n.State.GridOffset.Y - 1 + log.Warn("place() on Grid at gridX,gridY", tk.gridX, tk.gridY) + ptk.uiGrid.Append(tk.uiControl, + tk.gridX, tk.gridY, 1, 1, false, ui.AlignFill, false, ui.AlignFill) return true case widget.Group: - if (p.tk.uiBox == nil) { - log.Log(WARN, "place() andlabs hack group to use add a box", n.progname, n.WidgetType) - p.tk.uiBox = n.rawBox() - p.tk.uiGroup.SetChild(p.tk.uiBox) + if (ptk.uiBox == nil) { + log.Log(WARN, "place() andlabs hack group to use add a box", n.GetProgName(), n.WidgetType) + ptk.uiBox = rawBox(n) + ptk.uiGroup.SetChild(ptk.uiBox) } - p.tk.uiBox.Append(n.tk.uiControl, stretchy) + ptk.uiBox.Append(tk.uiControl, stretchy) return true case widget.Tab: - if (p.tk.uiTab == nil) { - log.Log(ERROR, "p.tk.uiTab == nil for n.WidgetId =", n.WidgetId, "p.tk =", p.tk) - panic("p.tk.uiTab == nil") + if (ptk.uiTab == nil) { + log.Log(ERROR, "ptk.uiTab == nil for n.WidgetId =", n.WidgetId, "ptk =", ptk) + panic("ptk.uiTab == nil") } - if (n.tk.uiControl == nil) { - log.Log(ERROR, "n.tk.uiControl == nil for n.WidgetId =", n.WidgetId, "n.tk =", n.tk) - panic("n.tk.uiControl == nil") + if (tk.uiControl == nil) { + log.Log(ERROR, "tk.uiControl == nil for n.WidgetId =", n.WidgetId, "tk =", tk) + panic("tk.uiControl == nil") } log.Log(ERROR, "CHECK LOGIC ON THIS. APPENDING directly into a window without a tab") - // log.Log(ERROR, "THIS SHOULD NEVER HAPPEN ??????? trying to place() node=", n.WidgetId, n.progname, n.Text, n.WidgetType) - // log.Log(ERROR, "THIS SHOULD NEVER HAPPEN ??????? trying to place() on parent=", p.WidgetId, p.progname, p.Text, p.WidgetType) - // panic("n.tk.uiControl == nil") - p.tk.uiTab.Append(widget.GetString(n.value), n.tk.uiControl) - p.tk.boxC += 1 + // log.Log(ERROR, "THIS SHOULD NEVER HAPPEN ??????? trying to place() node=", n.WidgetId, n.GetProgName(), n.Text, n.WidgetType) + // log.Log(ERROR, "THIS SHOULD NEVER HAPPEN ??????? trying to place() on parent=", p.WidgetId, p.GetProgName(), p.Text, p.WidgetType) + // panic("tk.uiControl == nil") + ptk.uiTab.Append(widget.GetString(n.State.Value), tk.uiControl) + ptk.boxC += 1 return true case widget.Box: - log.Log(INFO, "place() uiBox =", p.tk.uiBox) - log.Log(INFO, "place() uiControl =", n.tk.uiControl) - p.tk.uiBox.Append(n.tk.uiControl, stretchy) - p.tk.boxC += 1 + log.Warn("SPEEDY Add Something to Box", n.WidgetId, n.GetProgName()) + log.Log(INFO, "place() uiBox =", ptk.uiBox) + log.Log(INFO, "place() uiControl =", tk.uiControl) + ptk.uiBox.Append(tk.uiControl, stretchy) + ptk.boxC += 1 return true case widget.Window: - p.tk.uiWindow.SetChild(n.tk.uiControl) + log.Warn("SPEEDY Add Something to Window", n.WidgetId, n.GetProgName()) + ptk.uiWindow.SetChild(tk.uiControl) return true default: log.Log(ERROR, "place() how? Parent =", p.WidgetId, p.WidgetType) } + log.Warn("SPEEDY newplace() return", n.WidgetId, n.GetProgName()) return false } diff --git a/andlabs/setText.go b/andlabs/setText.go index 77beb5c..c5453db 100644 --- a/andlabs/setText.go +++ b/andlabs/setText.go @@ -3,15 +3,18 @@ package main import ( "go.wit.com/log" "go.wit.com/gui/widget" + "go.wit.com/gui/toolkits/tree" ) -func (n *node) setText(a *widget.Action) { +// func (n *node) setText(a *widget.Action) { +func setText(n *tree.Node, a *widget.Action) { name := widget.GetString(a.Value) + var tk *guiWidget + tk = n.TK.(*guiWidget) log.Log(CHANGE, "setText() START with text =", name) - t := n.tk - if (t == nil) { - log.Log(ERROR, "setText error. tk == nil", n.progname, n.WidgetId) + if (tk == nil) { + log.Log(ERROR, "setText error. tk == nil", n.GetProgName(), n.WidgetId) return } log.Log(CHANGE, "setText() Attempt on", n.WidgetType, "with", name) @@ -19,38 +22,38 @@ func (n *node) setText(a *widget.Action) { switch n.WidgetType { case widget.Window: log.Warn("setText() Attempt to set the title to", name) - t.uiWindow.SetTitle(name) + tk.uiWindow.SetTitle(name) case widget.Tab: case widget.Group: - t.uiGroup.SetTitle(name) + tk.uiGroup.SetTitle(name) case widget.Checkbox: - t.uiCheckbox.SetText(name) + tk.uiCheckbox.SetText(name) case widget.Textbox: - if (t.uiEntry != nil) { - t.uiEntry.SetText(name) + if (tk.uiEntry != nil) { + tk.uiEntry.SetText(name) } - if (t.uiMultilineEntry != nil) { - t.uiMultilineEntry.SetText(name) + if (tk.uiMultilineEntry != nil) { + tk.uiMultilineEntry.SetText(name) } case widget.Label: - t.uiLabel.SetText(name) + tk.uiLabel.SetText(name) case widget.Button: - t.uiButton.SetText(name) + tk.uiButton.SetText(name) case widget.Slider: - log.Log(ERROR, "setText() on slider unknown", a.ActionType, "on checkbox", n.progname) + log.Log(ERROR, "setText() on slider unknown", a.ActionType, "on checkbox", n.GetProgName()) case widget.Spinner: - log.Log(ERROR, "setText() on spinner unknown", a.ActionType, "on checkbox", n.progname) + log.Log(ERROR, "setText() on spinner unknown", a.ActionType, "on checkbox", n.GetProgName()) case widget.Dropdown: var orig int var i int = -1 var s string - orig = t.uiCombobox.Selected() + orig = tk.uiCombobox.Selected() log.Log(CHANGE, "try to set the Dropdown to", name, "from", orig) // try to find the string - for i, s = range t.val { + for i, s = range tk.val { log.Log(CHANGE, "i, s", i, s) if (name == s) { - t.uiCombobox.SetSelected(i) + tk.uiCombobox.SetSelected(i) log.Log(CHANGE, "setText() Dropdown worked.", name) return } @@ -62,10 +65,10 @@ func (n *node) setText(a *widget.Action) { } // if the string was never set, then set the dropdown to the last thing added to the menu if (orig == -1) { - t.uiCombobox.SetSelected(i) + tk.uiCombobox.SetSelected(i) } case widget.Combobox: - t.uiEditableCombobox.SetText(name) + tk.uiEditableCombobox.SetText(name) default: log.Log(ERROR, "plugin Send() Don't know how to setText on", n.WidgetType, "yet", a.ActionType) } diff --git a/andlabs/slider.go b/andlabs/slider.go index 0da06f3..5ce393a 100644 --- a/andlabs/slider.go +++ b/andlabs/slider.go @@ -1,22 +1,29 @@ package main import ( + "go.wit.com/gui/toolkits/tree" + "go.wit.com/dev/andlabs/ui" _ "go.wit.com/dev/andlabs/ui/winmanifest" ) -func (p *node) newSlider(n *node) { +func newSlider(p, n *tree.Node) { + if notNew(n) { return } newt := new(guiWidget) - s := ui.NewSlider(n.X, n.Y) + var x, y int + x = n.State.Range.Low + y = n.State.Range.High + + s := ui.NewSlider(x, y) newt.uiSlider = s newt.uiControl = s s.OnChanged(func(spin *ui.Slider) { - n.value = newt.uiSlider.Value() - n.doUserEvent() + n.SetValue(newt.uiSlider.Value()) + me.myTree.DoUserEvent(n) }) - n.tk = newt - p.place(n) + n.TK = newt + place(p, n) } diff --git a/andlabs/spinner.go b/andlabs/spinner.go index 01d3b26..65bd7db 100644 --- a/andlabs/spinner.go +++ b/andlabs/spinner.go @@ -1,22 +1,25 @@ package main import ( + "go.wit.com/gui/toolkits/tree" + "go.wit.com/dev/andlabs/ui" _ "go.wit.com/dev/andlabs/ui/winmanifest" ) -func (p *node) newSpinner(n *node) { +func newSpinner(p, n *tree.Node) { + if notNew(n) { return } newt := new(guiWidget) - s := ui.NewSpinbox(n.X, n.Y) + s := ui.NewSpinbox(n.State.Range.Low,n.State.Range.High) newt.uiSpinbox = s newt.uiControl = s s.OnChanged(func(s *ui.Spinbox) { - n.value = newt.uiSpinbox.Value() - n.doUserEvent() + n.SetValue(newt.uiSpinbox.Value()) + me.myTree.DoUserEvent(n) }) - n.tk = newt - p.place(n) + n.TK = newt + place(p, n) } diff --git a/andlabs/structs.go b/andlabs/structs.go index 87e88e1..e39cbe7 100644 --- a/andlabs/structs.go +++ b/andlabs/structs.go @@ -1,7 +1,11 @@ package main -import "go.wit.com/dev/andlabs/ui" -import _ "go.wit.com/dev/andlabs/ui/winmanifest" +import ( + "go.wit.com/gui/toolkits/tree" + + "go.wit.com/dev/andlabs/ui" + _ "go.wit.com/dev/andlabs/ui/winmanifest" +) // var andlabs map[int]*andlabsT // var callback func(int) bool @@ -11,7 +15,9 @@ import _ "go.wit.com/dev/andlabs/ui/winmanifest" var me config type config struct { - rootNode *node // the base of the binary tree. it should have id == 0 + rootNode *tree.Node // the base of the binary tree. it should have id == 0 + treeRoot *tree.Node // the base of the binary tree. it should have id == 0 + myTree *tree.TreeInfo } // stores the raw toolkit internals diff --git a/andlabs/textbox.go b/andlabs/textbox.go index 30671cd..3748a14 100644 --- a/andlabs/textbox.go +++ b/andlabs/textbox.go @@ -1,21 +1,24 @@ package main import ( + "go.wit.com/gui/toolkits/tree" + "go.wit.com/dev/andlabs/ui" _ "go.wit.com/dev/andlabs/ui/winmanifest" ) -func (p *node) newTextbox(n *node) { +func newTextbox(p, n *tree.Node) { + if notNew(n) { return } newt := new(guiWidget) - if (n.X == 1) { + if (n.State.Range.Low == 1) { e := ui.NewEntry() newt.uiEntry = e newt.uiControl = e e.OnChanged(func(spin *ui.Entry) { - n.value = spin.Text() - n.doUserEvent() + n.SetValue(spin.Text()) + me.myTree.DoUserEvent(n) }) } else { e := ui.NewNonWrappingMultilineEntry() @@ -23,10 +26,10 @@ func (p *node) newTextbox(n *node) { newt.uiControl = e e.OnChanged(func(spin *ui.MultilineEntry) { - n.value = spin.Text() - n.doUserEvent() + n.SetValue(spin.Text()) + me.myTree.DoUserEvent(n) }) } - n.tk = newt - p.place(n) + n.TK = newt + place(p, n) } diff --git a/andlabs/tree.go b/andlabs/tree.go new file mode 100644 index 0000000..400bee4 --- /dev/null +++ b/andlabs/tree.go @@ -0,0 +1,31 @@ +package main + +/* + This code should be common to all gui plugins + + There are some helper functions that are probably going to be + the same everywhere. Mostly due to handling the binary tree structure + and the channel communication + + For now, it's just a symlink to the 'master' version in + ./toolkit/nocui/common.go +*/ + +import ( + "go.wit.com/gui/widget" +) + +// 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.) +// +// this sets the channel to send user events back from the plugin +func Callback(guiCallback chan widget.Action) { + me.myTree.Callback(guiCallback) +} + +func PluginChannel() chan widget.Action { + return me.myTree.PluginChannel() +} diff --git a/andlabs/widget.go b/andlabs/widget.go index 414ca3d..d6d89ba 100644 --- a/andlabs/widget.go +++ b/andlabs/widget.go @@ -2,16 +2,16 @@ package main import ( "go.wit.com/gui/widget" + "go.wit.com/gui/toolkits/tree" ) -// this is specific to the nocui toolkit -func initWidget(n *node) *guiWidget { +func initWidget(n *tree.Node) *guiWidget { var w *guiWidget w = new(guiWidget) if n.WidgetType == widget.Root { n.WidgetId = 0 - me.rootNode = n + me.treeRoot = n return w } return w diff --git a/andlabs/window.go b/andlabs/window.go index d52648e..d517f86 100644 --- a/andlabs/window.go +++ b/andlabs/window.go @@ -6,6 +6,7 @@ import ( "go.wit.com/log" "go.wit.com/gui/widget" + "go.wit.com/gui/toolkits/tree" ) func (t *guiWidget) MessageWindow(msg1 string, msg2 string) { @@ -16,23 +17,24 @@ func (t *guiWidget) ErrorWindow(msg1 string, msg2 string) { ui.MsgBoxError(t.uiWindow, msg1, msg2) } -func newWindow(n *node) { +func newWindow(p, n *tree.Node) { var newt *guiWidget newt = new(guiWidget) // menubar bool is if the OS defined border on the window should be used - win := ui.NewWindow(n.progname, n.X, n.Y, menubar) + win := ui.NewWindow(n.GetProgName(), 640, 480, menubar) win.SetBorderless(canvas) win.SetMargined(margin) win.OnClosing(func(*ui.Window) bool { - n.show(false) - n.doUserEvent() + // show(n, false) + me.myTree.DoWindowCloseEvent(n) return false }) newt.uiWindow = win newt.uiControl = win - n.tk = newt + n.TK = newt + place(p, n) win.Show() return } diff --git a/common/addNode.go b/common/addNode.go deleted file mode 100644 index be769fc..0000000 --- a/common/addNode.go +++ /dev/null @@ -1,68 +0,0 @@ -package main - -/* - These code should be common to all gui plugins - - There are some helper functions that are probably going to be - the same everywhere. Mostly due to handling the binary tree structure - and the channel communication - - For now, it's just a symlink to the 'master' version in - ./toolkit/nocui/common.go -*/ - -import ( - "reflect" - "strconv" - - "go.wit.com/log" - "go.wit.com/gui/widget" -) - -// this is in common.go, do not move it -func addNode(a *widget.Action) *node { - n := new(node) - n.WidgetType = a.WidgetType - n.WidgetId = a.WidgetId - n.ParentId = a.ParentId - - n.state = a.State - - // copy the data from the action message - n.progname = a.ProgName - n.value = a.Value - n.direction = a.Direction - n.strings = a.Strings - - // TODO: these need to be rethought - n.X = a.X - n.Y = a.Y - n.W = a.W - n.H = a.H - n.AtW = a.AtW - n.AtH = a.AtH - - // store the internal toolkit information - n.tk = initWidget(n) - // n.tk = new(guiWidget) - - if (a.WidgetType == widget.Root) { - log.Log(INFO, "addNode() Root") - return n - } - - if (me.rootNode.findWidgetId(a.WidgetId) != nil) { - log.Log(ERROR, "addNode() WidgetId already exists", a.WidgetId) - return me.rootNode.findWidgetId(a.WidgetId) - } - - // add this new widget on the binary tree - n.parent = me.rootNode.findWidgetId(a.ParentId) - if n.parent != nil { - n.parent.children = append(n.parent.children, n) - //w := n.tk - //w.parent = n.parent.tk - //w.parent.children = append(w.parent.children, w) - } - return n -} diff --git a/gocui/common.go b/gocui/common.go deleted file mode 120000 index 35417a1..0000000 --- a/gocui/common.go +++ /dev/null @@ -1 +0,0 @@ -../nocui/common.go \ No newline at end of file diff --git a/gocui/common.go b/gocui/common.go new file mode 100644 index 0000000..3c67133 --- /dev/null +++ b/gocui/common.go @@ -0,0 +1,218 @@ +package main + +/* + These code should be common to all gui plugins + + There are some helper functions that are probably going to be + the same everywhere. Mostly due to handling the binary tree structure + and the channel communication + + For now, it's just a symlink to the 'master' version in + ./toolkit/nocui/common.go +*/ + +import ( + "go.wit.com/log" + "go.wit.com/gui/widget" +) + +// this is the channel we send user events like +// mouse clicks or keyboard events back to the program +var callback chan widget.Action + +// this is the channel we get requests to make widgets +var pluginChan chan widget.Action + +type node struct { + parent *node + children []*node + + WidgetId int // widget ID + WidgetType widget.WidgetType + ParentId int // parent ID + + state widget.State + + // a reference name for programming and debuggign. Must be unique + progname string + + // the text used for button labesl, window titles, checkbox names, etc + label string + + // horizontal means layout widgets like books on a bookshelf + // vertical means layout widgets like books in a stack + // direction widget.Orientation + direction widget.Orientation + + // This is how the values are passed back and forth + // values from things like checkboxes & dropdown's + value any + + strings []string + + // This is used for things like a slider(0,100) + X int + Y int + + // This is for the grid size & widget position + W int + H int + AtW int + AtH int + + vals []string // dropdown menu items + + // horizontal bool `default:false` + + hasTabs bool // does the window have tabs? + currentTab bool // the visible tab + + // the internal plugin toolkit structure + // in the gtk plugin, it has gtk things like margin & border settings + // in the text console one, it has text console things like colors for menus & buttons + tk *guiWidget +} + +// searches the binary tree for a WidgetId +func (n *node) findWidgetId(id int) *node { + if (n == nil) { + return nil + } + + if n.WidgetId == id { + return n + } + + for _, child := range n.children { + newN := child.findWidgetId(id) + if (newN != nil) { + return newN + } + } + return nil +} + +func (n *node) doUserEvent() { + if (callback == nil) { + log.Log(ERROR, "doUserEvent() callback == nil", n.WidgetId) + return + } + var a widget.Action + a.WidgetId = n.WidgetId + a.Value = n.value + a.ActionType = widget.User + log.Log(INFO, "doUserEvent() START: send a user event to the callback channel") + callback <- a + log.Log(INFO, "doUserEvent() END: sent a user event to the callback channel") + return +} + +// 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.) +// +// this sets the channel to send user events back from the plugin +func Callback(guiCallback chan widget.Action) { + callback = guiCallback +} + +func PluginChannel() chan widget.Action { + return pluginChan +} + +/* +func convertString(val any) string { + switch v := val.(type) { + case bool: + n.B = val.(bool) + case string: + n.label = val.(string) + n.S = val.(string) + case int: + n.I = val.(int) + default: + log.Error(errors.New("Set() unknown type"), "v =", v) + } +} +*/ + +/* +// this is in common.go, do not move it +func getString(A any) string { + if A == nil { + log.Warn("getString() got nil") + return "" + } + var k reflect.Kind + k = reflect.TypeOf(A).Kind() + + switch k { + case reflect.Int: + var i int + i = A.(int) + return string(i) + case reflect.String: + return A.(string) + case reflect.Bool: + if A.(bool) == true { + return "true" + } else { + return "false" + } + default: + log.Warn("getString uknown kind", k, "value =", A) + return "" + } + return "" +} +*/ + +// this is in common.go, do not move it +func addNode(a *widget.Action) *node { + n := new(node) + n.WidgetType = a.WidgetType + n.WidgetId = a.WidgetId + n.ParentId = a.ParentId + + n.state = a.State + + // copy the data from the action message + n.progname = a.ProgName + n.value = a.Value + n.direction = a.Direction + n.strings = a.Strings + + // TODO: these need to be rethought + n.X = a.X + n.Y = a.Y + n.W = a.W + n.H = a.H + n.AtW = a.AtW + n.AtH = a.AtH + + // store the internal toolkit information + n.tk = initWidget(n) + // n.tk = new(guiWidget) + + if (a.WidgetType == widget.Root) { + log.Log(INFO, "addNode() Root") + return n + } + + if (me.rootNode.findWidgetId(a.WidgetId) != nil) { + log.Log(ERROR, "addNode() WidgetId already exists", a.WidgetId) + return me.rootNode.findWidgetId(a.WidgetId) + } + + // add this new widget on the binary tree + n.parent = me.rootNode.findWidgetId(a.ParentId) + if n.parent != nil { + n.parent.children = append(n.parent.children, n) + //w := n.tk + //w.parent = n.parent.tk + //w.parent.children = append(w.parent.children, w) + } + return n +} diff --git a/gocui/plugin.go b/gocui/plugin.go index f1834a1..3a122e3 100644 --- a/gocui/plugin.go +++ b/gocui/plugin.go @@ -50,7 +50,7 @@ func action(a *widget.Action) { n.AddText(widget.GetString(a.Value)) case widget.Move: log.Log(NOW, "attempt to move() =", a.ActionType, a.WidgetType, a.ProgName) - case widget.CloseToolkit: + case widget.ToolkitClose: log.Log(NOW, "attempting to close the plugin and release stdout and stderr") standardExit() case widget.Enable: diff --git a/gocui/view.go b/gocui/view.go index b88763c..912cf21 100644 --- a/gocui/view.go +++ b/gocui/view.go @@ -3,7 +3,6 @@ package main import ( "fmt" "errors" - "strconv" "bufio" "strings" @@ -60,7 +59,7 @@ func (n *node) showView() { if (w.cuiName == "") { log.Log(ERROR, "showView() w.cuiName was not set for widget", w) - w.cuiName = strconv.Itoa(n.WidgetId) + w.cuiName = string(n.WidgetId) } // if the gocui element doesn't exist, create it diff --git a/gocui/widget.go b/gocui/widget.go index fba66dd..e739993 100644 --- a/gocui/widget.go +++ b/gocui/widget.go @@ -1,8 +1,6 @@ package main import ( - "strconv" - "go.wit.com/log" "go.wit.com/gui/widget" ) @@ -15,7 +13,7 @@ func initWidget(n *node) *guiWidget { w.frame = true // set the name used by gocui to the id - w.cuiName = strconv.Itoa(n.WidgetId) + w.cuiName = string(n.WidgetId) if n.WidgetType == widget.Root { log.Log(INFO, "setupWidget() FOUND ROOT w.id =", n.WidgetId) diff --git a/nocui/action.go b/nocui/action.go index 892bd54..cf258c1 100644 --- a/nocui/action.go +++ b/nocui/action.go @@ -1,152 +1,87 @@ package main +/* + a simple function to handle widget actions + + You can tie this into your toolkit here. +*/ + import ( "go.wit.com/log" "go.wit.com/gui/widget" + // "go.wit.com/gui/toolkits/tree" ) -func (n *node) show(b bool) { -} - -func (n *node) enable(b bool) { -} - -func (n *node) pad(at widget.ActionType) { - switch n.WidgetType { - case widget.Group: - switch at { - case widget.Margin: - // SetMargined(true) - case widget.Unmargin: - // SetMargined(false) - case widget.Pad: - // SetMargined(true) - case widget.Unpad: - // SetMargined(false) - } - case widget.Tab: - case widget.Window: - case widget.Grid: - case widget.Box: - case widget.Textbox: - log.Log(ERROR, "TODO: implement ActionType =", at) - default: - log.Log(ERROR, "TODO: implement pad() for", at) - } -} - -func (n *node) move(newParent *node) { - p := n.parent - - switch p.WidgetType { - case widget.Group: - case widget.Tab: - // tabSetMargined(tParent.uiTab, true) - case widget.Window: - // t.uiWindow.SetBorderless(false) - case widget.Grid: - // t.uiGrid.SetPadded(true) - case widget.Box: - log.Log(INFO, "TODO: move() where =", p.ParentId) - log.Log(INFO, "TODO: move() for widget =", n.WidgetId) - default: - log.Log(ERROR, "TODO: need to implement move() for type =", n.WidgetType) - log.Log(ERROR, "TODO: need to implement move() for where =", p.ParentId) - log.Log(ERROR, "TODO: need to implement move() for widget =", n.WidgetId) - } -} - -func (n *node) Delete() { - p := n.parent - log.Log(NOW, "uiDelete()", n.WidgetId, "to", p.WidgetId) - - switch p.WidgetType { - case widget.Group: - // tParent.uiGroup.SetMargined(true) - case widget.Tab: - // tabSetMargined(tParent.uiTab, true) - case widget.Window: - // t.uiWindow.SetBorderless(false) - case widget.Grid: - // t.uiGrid.SetPadded(true) - case widget.Box: - log.Log(NOW, "tWidget.boxC =", p.progname) - log.Log(NOW, "is there a tParent parent? =", p.parent) - // this didn't work: - // tWidget.uiControl.Disable() - // sleep(.8) - // tParent.uiBox.Append(tWidget.uiControl, stretchy) - default: - log.Log(ERROR, "TODO: need to implement uiDelete() for widget =", n.WidgetId, n.WidgetType) - log.Log(ERROR, "TODO: need to implement uiDelete() for parent =", p.WidgetId, p.WidgetType) - } -} - -func doAction(a *widget.Action) { +func doAction(a widget.Action) { log.Log(INFO, "doAction() START a.ActionType =", a.ActionType) log.Log(INFO, "doAction() START a.ProgName =", a.ProgName) - if (a.ActionType == widget.InitToolkit) { - // TODO: make sure to only do this once - // go uiMain.Do(func() { - // ui.Main(demoUI) - // go catchActionChannel() - // }) - // try doing this on toolkit load in init() + if (a.ActionType == widget.ToolkitInit) { return } log.Log(INFO, "doAction() START a.WidgetId =", a.WidgetId, "a.ParentId =", a.ParentId) switch a.WidgetType { case widget.Root: - me.rootNode = addNode(a) - log.Log(INFO, "doAction() found rootNode") - return - case widget.Flag: - // flag(&a) + me.treeRoot = me.myTree.AddNode(&a) + log.Log(INFO, "doAction() found treeRoot") return } - n := me.rootNode.findWidgetId(a.WidgetId) - switch a.ActionType { case widget.Add: - addNode(a) + me.myTree.AddNode(&a) + return + } + + n := me.treeRoot.FindWidgetId(a.WidgetId) + if n == nil { + log.Warn("FindId() n == nil", a.WidgetId, a.ActionType) + log.Warn("FindId() n == nil", a.WidgetId, a.ActionType) + log.Warn("FindId() n == nil", a.WidgetId, a.ActionType) + log.Warn("Aaaaa!, return") + return + } + + switch a.ActionType { case widget.Show: - n.show(true) + n.State.Visable = true case widget.Hide: - n.show(false) + n.State.Visable = false case widget.Enable: - n.enable(true) + n.State.Visable = true case widget.Disable: - n.enable(false) + n.State.Visable = false case widget.Get: - // n.setText(a.S) + log.Warn("value =", n.State.Value) case widget.GetText: - switch a.WidgetType { - case widget.Textbox: - a.Value = n.value - } + log.Warn("value =", n.String()) case widget.Set: - // n.setText(a.S) + n.State.Value = a.State.Value case widget.SetText: - // n.setText(a.S) + log.Warn("GOT TO SetText()", a.WidgetId) + log.Warn("GOT TO SetText()", a.WidgetId) + log.Warn("GOT TO SetText()", a.WidgetId) + log.Warn("GOT TO SetText()", a.WidgetId) + if n == nil { + log.Warn("HOT DIGGITY. n == nil") + } + n.State.Value = a.State.Value case widget.AddText: - // n.setText(a.S) + n.State.Strings = append(a.State.Strings, widget.GetString(a.State.Value)) case widget.Margin: - n.pad(widget.Unmargin) + n.State.Pad = true case widget.Unmargin: - n.pad(widget.Margin) + n.State.Pad = false case widget.Pad: - n.pad(widget.Pad) + n.State.Pad = true case widget.Unpad: - n.pad(widget.Unpad) + n.State.Pad = false case widget.Delete: - n.Delete() + log.Warn("doAction() TODO: Delete()") + // n.Delete() case widget.Move: - log.Log(INFO, "doAction() attempt to move() =", a.ActionType, a.WidgetType) - newParent := me.rootNode.findWidgetId(a.ParentId) - n.move(newParent) + log.Warn("doAction() TODO: Move()") default: log.Log(ERROR, "doAction() Unknown =", a.ActionType, a.WidgetType) } diff --git a/nocui/common.go b/nocui/common.go deleted file mode 100644 index 7b79ca0..0000000 --- a/nocui/common.go +++ /dev/null @@ -1,218 +0,0 @@ -package main - -/* - These code should be common to all gui plugins - - There are some helper functions that are probably going to be - the same everywhere. Mostly due to handling the binary tree structure - and the channel communication - - For now, it's just a symlink to the 'master' version in - ./toolkit/nocui/common.go -*/ - -import ( - "go.wit.com/log" - "go.wit.com/gui/widget" -) - -// this is the channel we send user events like -// mouse clicks or keyboard events back to the program -var callback chan widget.Action - -// this is the channel we get requests to make widgets -var pluginChan chan widget.Action - -type node struct { - parent *node - children []*node - - WidgetId int // widget ID - WidgetType widget.WidgetType - ParentId int // parent ID - - state widget.State - - // a reference name for programming and debuggign. Must be unique - progname string - - // the text used for button labesl, window titles, checkbox names, etc - label string - - // horizontal means layout widgets like books on a bookshelf - // vertical means layout widgets like books in a stack - // direction widget.Orientation - direction widget.Orientation - - // This is how the values are passed back and forth - // values from things like checkboxes & dropdown's - value any - - strings []string - - // This is used for things like a slider(0,100) - X int - Y int - - // This is for the grid size & widget position - W int - H int - AtW int - AtH int - - vals []string // dropdown menu items - - // horizontal bool `default:false` - - hasTabs bool // does the window have tabs? - currentTab bool // the visible tab - - // the internal plugin toolkit structure - // in the gtk plugin, it has gtk things like margin & border settings - // in the text console one, it has text console things like colors for menus & buttons - tk *guiWidget -} - -// searches the binary tree for a WidgetId -func (n *node) findWidgetId(id int) *node { - if (n == nil) { - return nil - } - - if n.WidgetId == id { - return n - } - - for _, child := range n.children { - newN := child.findWidgetId(id) - if (newN != nil) { - return newN - } - } - return nil -} - -func (n *node) doUserEvent() { - if (callback == nil) { - log.Log(ERROR, "doUserEvent() callback == nil", n.WidgetId) - return - } - var a widget.Action - a.WidgetId = n.WidgetId - a.Value = n.value - a.ActionType = widget.User - log.Log(INFO, "doUserEvent() START: send a user event to the callback channel") - callback <- a - log.Log(INFO, "doUserEvent() END: sent a user event to the callback channel") - return -} - -// 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.) -// -// this sets the channel to send user events back from the plugin -func Callback(guiCallback chan widget.Action) { - callback = guiCallback -} - -func PluginChannel() chan widget.Action { - return pluginChan -} - -/* -func convertString(val any) string { - switch v := val.(type) { - case bool: - n.B = val.(bool) - case string: - n.label = val.(string) - n.S = val.(string) - case int: - n.I = val.(int) - default: - log.Error(errors.New("Set() unknown type"), "v =", v) - } -} -*/ - -/* -// this is in common.go, do not move it -func getString(A any) string { - if A == nil { - log.Warn("getString() got nil") - return "" - } - var k reflect.Kind - k = reflect.TypeOf(A).Kind() - - switch k { - case reflect.Int: - var i int - i = A.(int) - return strconv.Itoa(i) - case reflect.String: - return A.(string) - case reflect.Bool: - if A.(bool) == true { - return "true" - } else { - return "false" - } - default: - log.Warn("getString uknown kind", k, "value =", A) - return "" - } - return "" -} -*/ - -// this is in common.go, do not move it -func addNode(a *widget.Action) *node { - n := new(node) - n.WidgetType = a.WidgetType - n.WidgetId = a.WidgetId - n.ParentId = a.ParentId - - n.state = a.State - - // copy the data from the action message - n.progname = a.ProgName - n.value = a.Value - n.direction = a.Direction - n.strings = a.Strings - - // TODO: these need to be rethought - n.X = a.X - n.Y = a.Y - n.W = a.W - n.H = a.H - n.AtW = a.AtW - n.AtH = a.AtH - - // store the internal toolkit information - n.tk = initWidget(n) - // n.tk = new(guiWidget) - - if (a.WidgetType == widget.Root) { - log.Log(INFO, "addNode() Root") - return n - } - - if (me.rootNode.findWidgetId(a.WidgetId) != nil) { - log.Log(ERROR, "addNode() WidgetId already exists", a.WidgetId) - return me.rootNode.findWidgetId(a.WidgetId) - } - - // add this new widget on the binary tree - n.parent = me.rootNode.findWidgetId(a.ParentId) - if n.parent != nil { - n.parent.children = append(n.parent.children, n) - //w := n.tk - //w.parent = n.parent.tk - //w.parent.children = append(w.parent.children, w) - } - return n -} diff --git a/nocui/event.go b/nocui/event.go index 97f2aed..9bbafdb 100644 --- a/nocui/event.go +++ b/nocui/event.go @@ -1,11 +1,13 @@ package main +/* import ( "go.wit.com/log" "go.wit.com/gui/widget" + "go.wit.com/gui/toolkits/tree" ) -func (n *node) doWidgetClick() { +func doWidgetClick(n *tree.Node) { switch n.WidgetType { case widget.Root: // THIS IS THE BEGINING OF THE LAYOUT @@ -17,32 +19,33 @@ func (n *node) doWidgetClick() { // rootNode.dumpTree(true) case widget.Window: // setCurrentWindow(w) - n.doUserEvent() + // n.doUserEvent() case widget.Tab: // setCurrentTab(w) case widget.Group: // n.placeWidgets() // n.toggleTree() case widget.Checkbox: - if widget.GetBool(n.value) { + if n.Bool() { // n.setCheckbox(false) } else { // n.setCheckbox(true) } - n.doUserEvent() + // n.doUserEvent() case widget.Grid: // rootNode.hideWidgets() // n.placeGrid() // n.showWidgets() case widget.Box: // n.showWidgetPlacement(logNow, "drawTree()") - if widget.GetBool(n.value) { - log.Log(NOW, "BOX IS HORIZONTAL", n.progname) + if n.Bool() { + log.Log(NOW, "BOX IS HORIZONTAL", n.GetProgName()) } else { - log.Log(NOW, "BOX IS VERTICAL", n.progname) + log.Log(NOW, "BOX IS VERTICAL", n.GetProgName()) } case widget.Button: - n.doUserEvent() + // n.doUserEvent() default: } } +*/ diff --git a/nocui/go.mod b/nocui/go.mod index ec42260..e802e10 100644 --- a/nocui/go.mod +++ b/nocui/go.mod @@ -1,10 +1,3 @@ module go.wit.com/gui/toolkits/nocui go 1.21.4 - -require ( - go.wit.com/gui/widget v1.1.3 - go.wit.com/log v0.5.4 -) - -require go.wit.com/dev/davecgh/spew v1.1.4 // indirect diff --git a/nocui/go.sum b/nocui/go.sum deleted file mode 100644 index 3af9a6c..0000000 --- a/nocui/go.sum +++ /dev/null @@ -1,10 +0,0 @@ -go.wit.com/dev/davecgh/spew v1.1.3 h1:hqnB5qsPgC2cLZaJXqQJspQ5n/Ugry9kyL3tLk0hVzQ= -go.wit.com/dev/davecgh/spew v1.1.3/go.mod h1:sihvWmnQ/09FWplnEmozt90CCVqBtGuPXM811tgfhFA= -go.wit.com/dev/davecgh/spew v1.1.4 h1:C9hj/rjlUpdK+E6aroyLjCbS5MFcyNUOuP1ICLWdNek= -go.wit.com/dev/davecgh/spew v1.1.4/go.mod h1:sihvWmnQ/09FWplnEmozt90CCVqBtGuPXM811tgfhFA= -go.wit.com/gui/widget v1.1.3 h1:GvLzGSOF9tfmoh6HNbFdN+NSlBo2qeS/Ba2TnQQ1A1U= -go.wit.com/gui/widget v1.1.3/go.mod h1:A6/FaiFQtAHTjgo7c4FrokXe6bXX1Cowo35b2Lgi31E= -go.wit.com/log v0.5.3 h1:/zHkniOPusPEuX1R401rMny9uwSO/nSU/QOMx6qoEnE= -go.wit.com/log v0.5.3/go.mod h1:LzIzVxc2xJQxWQBtV9VbV605P4TOxmYDCl+BZF38yGE= -go.wit.com/log v0.5.4 h1:vijLRPTUgChb8J5tx/7Uma/lGTUxeSXosFbheAmL914= -go.wit.com/log v0.5.4/go.mod h1:BaJBfHFqcJSJLXGQ9RHi3XVhPgsStxSMZRlaRxW4kAo= diff --git a/nocui/main.go b/nocui/main.go index f6cfb3b..ebf3fae 100644 --- a/nocui/main.go +++ b/nocui/main.go @@ -1,55 +1,24 @@ package main -import ( - "sync" - "go.wit.com/log" - "go.wit.com/gui/widget" -) - -var muAction sync.Mutex - -func catchActionChannel() { - log.Log(NOW, "catchActionChannel() START") - for { - log.Log(NOW, "catchActionChannel() for loop") - select { - case a := <-pluginChan: - log.Log(NOW, "catchActionChannel() SELECT widget id =", a.WidgetId, a.ProgName) - log.Log(NOW, "catchActionChannel() STUFF", a.WidgetId, a.ActionType, a.WidgetType) - muAction.Lock() - doAction(&a) - muAction.Unlock() - log.Log(NOW, "catchActionChannel() STUFF END", a.WidgetId, a.ActionType, a.WidgetType) - } - } -} - /* -// 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.) -// -// this sets the channel to send user events back from the plugin -func Callback(guiCallback chan widget.Action) { - callback = guiCallback -} + This is reference code for toolkit developers -func PluginChannel() chan widget.Action { - return pluginChan -} + The 'nocui' is a bare minimum toolkit. It's all you need + to interact with the GUI */ -// This is important. This sets the defaults for the gui. Without this, there isn't correct padding, etc +import ( + "go.wit.com/log" + "go.wit.com/gui/toolkits/tree" +) + func init() { log.Log(INFO, "Init()") - // andlabs = make(map[int]*andlabsT) - pluginChan = make(chan widget.Action, 1) + me.myTree = tree.New() + me.myTree.PluginName = "nocui" + me.myTree.ActionFromChannel = doAction - log.Log(NOW, "Init() start channel reciever") - go catchActionChannel() go simpleStdin() - log.Log(NOW, "Init() END") + log.Log(INFO, "Init() END") } diff --git a/nocui/stdin.go b/nocui/stdin.go index f7469c6..f003ee4 100644 --- a/nocui/stdin.go +++ b/nocui/stdin.go @@ -4,6 +4,7 @@ import ( "os" "fmt" "bufio" + "runtime/debug" "strings" "strconv" @@ -12,6 +13,15 @@ import ( ) func simpleStdin() { + defer func() { + if r := recover(); r != nil { + log.Warn("nocui YAHOOOO Recovered in simpleStdin()", r) + log.Println("Recovered from panic:", r) + log.Println("Stack trace:") + debug.PrintStack() + me.myTree.DoToolkitPanic() + } + }() scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { s := scanner.Text() @@ -19,63 +29,46 @@ func simpleStdin() { switch s { case "l": log.Log(NOW, "list widgets") - me.rootNode.listWidgets() + me.treeRoot.ListWidgets() case "b": log.Log(NOW, "show buttons") - me.rootNode.showButtons() + me.treeRoot.ShowButtons() + case "g": + me.myTree.DoToolkitLoad("gocui") + case "a": + me.myTree.DoToolkitLoad("andlabs") case "d": - var a widget.Action - a.ActionType = widget.EnableDebug - callback <- a + me.myTree.DoEnableDebugger() case "": fmt.Println("") fmt.Println("Enter:") fmt.Println("'l': list all widgets") fmt.Println("'b': for buttons") + fmt.Println("'g': load gocui plugin") + fmt.Println("'a': load andlabs plugin") fmt.Println("'d': enable debugging") default: i, _ := strconv.Atoi(s) log.Log(NOW, "got input:", i) - n := me.rootNode.findWidgetId(i) + n := me.treeRoot.FindWidgetId(i) if (n != nil) { - n.dumpWidget("found node") - n.doUserEvent() + n.DumpWidget("found node") + for i, s := range n.State.Strings { + log.Warn("n.State.Strings =", i, s) + } + switch n.WidgetType { + case widget.Root: + log.Warn("this is the root widget") + case widget.Dropdown: + log.Warn("print out dropdown values here") + case widget.Button: + me.myTree.DoUserEvent(n) + case widget.Checkbox: + me.myTree.DoUserEvent(n) + default: + log.Warn("you haven't defined an event for", n.WidgetType) + } } } } } - -func (n *node) showButtons() { - if n.WidgetType == widget.Button { - n.dumpWidget("Button:") - } - - for _, child := range n.children { - child.showButtons() - } -} - -func (n *node) dumpWidget(pad string) { - log.Log(NOW, "node:", pad, n.WidgetId, ",", n.WidgetType, ",", n.progname) -} - -var depth int = 0 - -func (n *node) listWidgets() { - if (n == nil) { - return - } - - var pad string - for i := 0; i < depth; i++ { - pad = pad + " " - } - n.dumpWidget(pad) - - for _, child := range n.children { - depth += 1 - child.listWidgets() - depth -= 1 - } - return -} diff --git a/nocui/structs.go b/nocui/structs.go index 888bcb5..c8a7cb4 100644 --- a/nocui/structs.go +++ b/nocui/structs.go @@ -1,17 +1,22 @@ package main +import ( + "go.wit.com/gui/toolkits/tree" +) + // stores the raw toolkit internals type guiWidget struct { Width int Height int c int - val map[int]string + val map[string]int } // It's probably a terrible idea to call this 'me' var me config type config struct { - rootNode *node // the base of the binary tree. it should have id == 0 + treeRoot *tree.Node // the base of the binary tree. it should have id == 0 + myTree *tree.TreeInfo } diff --git a/nocui/tree.go b/nocui/tree.go new file mode 100644 index 0000000..784e923 --- /dev/null +++ b/nocui/tree.go @@ -0,0 +1,24 @@ +package main + +/* + This is reference code for toolkit developers +*/ + +import ( + "go.wit.com/gui/widget" +) + +// 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.) +// +// this sets the channel to send user events back from the plugin +func Callback(guiCallback chan widget.Action) { + me.myTree.Callback(guiCallback) +} + +func PluginChannel() chan widget.Action { + return me.myTree.PluginChannel() +} diff --git a/nocui/widget.go b/nocui/widget.go deleted file mode 100644 index 6e50705..0000000 --- a/nocui/widget.go +++ /dev/null @@ -1,30 +0,0 @@ -package main - -import ( - "go.wit.com/log" - "go.wit.com/gui/widget" -) - -// this is specific to the nocui toolkit -func initWidget(n *node) *guiWidget { - var w *guiWidget - w = new(guiWidget) - // Set(w, "default") - - if n.WidgetType == widget.Root { - log.Log(INFO, "setupWidget() FOUND ROOT w.id =", n.WidgetId) - n.WidgetId = 0 - me.rootNode = n - return w - } - - if (n.WidgetType == widget.Box) { - if (n.direction == widget.Horizontal) { - // n.horizontal = true - } else { - // n.horizontal = false - } - } - - return w -} diff --git a/tree/addNode.go b/tree/addNode.go new file mode 100644 index 0000000..8c0a789 --- /dev/null +++ b/tree/addNode.go @@ -0,0 +1,47 @@ +package tree + +import ( + "errors" + + "go.wit.com/log" + "go.wit.com/gui/widget" +) + +// this is in common.go, do not move it +func (me *TreeInfo) AddNode(a *widget.Action) *Node { + n := new(Node) + n.WidgetType = a.WidgetType + n.WidgetId = a.WidgetId + n.ParentId = a.ParentId + + n.State = a.State + n.Strings = make(map[string]int) + + if (a.WidgetType == widget.Root) { + log.Info("AddNode() Root") + n.Parent = n + me.treeRoot = n + return n + } + + if (me.treeRoot.FindWidgetId(a.WidgetId) != nil) { + log.Warn("AddNode() WidgetId already exists", a.WidgetId) + log.Warn("probably this is a Show() / Hide() issue") + log.Warn("TODO: figure out what to do here") + return me.treeRoot.FindWidgetId(a.WidgetId) + } + + // add this new widget on the binary tree + p := me.treeRoot.FindWidgetId(a.ParentId) + n.Parent = p + if n.Parent == nil { + log.Error(errors.New("tree.AddNode() ERROR n.Parent == nil"), a.WidgetId, a.ParentId, a.ActionType) + log.Warn("AddNode() ERROR n.Parent == nil", a.WidgetId, a.ParentId, a.ActionType) + log.Warn("AddNode() ERROR n.Parent == nil", a.WidgetId, a.ParentId, a.WidgetType) + return n + } + log.Warn("AddNode() Adding to parent =", p.ParentId, p.WidgetType, p.GetProgName()) + log.Warn("AddNode() Adding child =", n.ParentId, n.WidgetType, n.GetProgName()) + p.children = append(p.children, n) + return n +} diff --git a/tree/common.go b/tree/common.go new file mode 100644 index 0000000..24992de --- /dev/null +++ b/tree/common.go @@ -0,0 +1,35 @@ +package tree + +import ( + "go.wit.com/gui/widget" +) + +func (n *Node) GetProgName() string { + return n.State.ProgName +} + +func (n *Node) GetValue() any { + return n.State.Value +} + +func (n *Node) Bool() bool { + return widget.GetBool(n.State.Value) +} + +func (n *Node) String() string { + return widget.GetString(n.State.Value) +} + +/* avoid this function name as confusing +func (n *Node) GetText() string { + return widget.GetString(n.State.Value) +} +*/ + +func (n *Node) SetValue(a any) { + n.State.Value = a +} + +func (n *Node) GetLabel() string { + return n.State.Label +} diff --git a/tree/debug.go b/tree/debug.go new file mode 100644 index 0000000..c79f35b --- /dev/null +++ b/tree/debug.go @@ -0,0 +1,44 @@ +package tree + +import ( + "go.wit.com/log" + "go.wit.com/gui/widget" +) + +func (n *Node) ShowButtons() { + if n.WidgetType == widget.Button { + n.DumpWidget("Button:") + } + + for _, child := range n.children { + child.ShowButtons() + } +} + +func (n *Node) DumpWidget(pad string) { + log.Warn("node:", pad, n.WidgetId, ",", n.WidgetType, ",", n.GetProgName()) +} + +var depth int = 0 + +func (n *Node) ListWidgets() { + if (n == nil) { + log.Warn("ERRRORRRR: n == nil in ListWidgets()") + log.Warn("ERRRORRRR: n == nil in ListWidgets()") + log.Warn("ERRRORRRR: n == nil in ListWidgets()") + return + } + + var pad string + for i := 0; i < depth; i++ { + pad = pad + " " + } + n.DumpWidget(pad) + + for _, child := range n.children { + depth += 1 + child.ListWidgets() + depth -= 1 + } + return +} diff --git a/tree/event.go b/tree/event.go new file mode 100644 index 0000000..ee74138 --- /dev/null +++ b/tree/event.go @@ -0,0 +1,88 @@ +package tree + +/* + These code should be common to all gui plugins + + There are some helper functions that are probably going to be + the same everywhere. Mostly due to handling the binary tree structure + and the channel communication + + For now, it's just a symlink to the 'master' version in + ./toolkit/nocui/common.go +*/ + +import ( + "go.wit.com/log" + "go.wit.com/gui/widget" +) + +func (me *TreeInfo) DoEnableDebugger() { + if (me.callback == nil) { + log.Warn("DoUserEvent() toolkit panic() callback == nil") + return + } + var a widget.Action + a.ActionType = widget.EnableDebug + a.ProgName = me.PluginName + me.callback <- a + return +} + +func (me *TreeInfo) DoToolkitLoad(s string) { + if (me.callback == nil) { + log.Warn("DoUserEvent() toolkit load callback == nil") + return + } + var a widget.Action + a.ActionType = widget.ToolkitLoad + a.ProgName = me.PluginName + a.Value = s + log.Warn("DoUserEvent() START: toolkit load", s) + me.callback <- a + log.Warn("DoUserEvent() END: toolkit load", s) + return +} + +func (me *TreeInfo) DoToolkitPanic() { + if (me.callback == nil) { + log.Warn("DoUserEvent() toolkit panic() callback == nil") + return + } + var a widget.Action + a.ActionType = widget.ToolkitPanic + a.ProgName = me.PluginName + log.Info("DoUserEvent() START: toolkit panic()") + me.callback <- a + log.Info("DoUserEvent() END: toolkit panic()") + return +} + +func (me *TreeInfo) DoWindowCloseEvent(n *Node) { + if (me.callback == nil) { + log.Warn("DoUserEvent() callback == nil", n.WidgetId) + return + } + var a widget.Action + a.WidgetId = n.WidgetId + a.ActionType = widget.CloseWindow + log.Info("DoUserEvent() START: user closed the window", n.GetProgName()) + me.callback <- a + log.Info("DoUserEvent() END: user closed the window", n.GetProgName()) + return +} + +// Other goroutines must use this to access the GUI +func (me *TreeInfo) DoUserEvent(n *Node) { + if (me.callback == nil) { + log.Warn("DoUserEvent() callback == nil", n.WidgetId) + return + } + var a widget.Action + a.WidgetId = n.WidgetId + a.Value = n.State.Value + a.ActionType = widget.User + log.Info("DoUserEvent() START: send a user event to the callback channel") + me.callback <- a + log.Info("DoUserEvent() END: sent a user event to the callback channel") + return +} diff --git a/tree/init.go b/tree/init.go new file mode 100644 index 0000000..cdbd62a --- /dev/null +++ b/tree/init.go @@ -0,0 +1,58 @@ +package tree + +import ( + "sync" + "errors" + + "go.wit.com/log" + "go.wit.com/gui/widget" +) + +var muAction sync.Mutex + +func (me *TreeInfo) toolkit(a widget.Action) { + if me.ActionFromChannel == nil { + log.Error(errors.New("toolkit ActionFromChannel == nil"), a.WidgetId, a.ActionType, a.WidgetType) + return + } + me.ActionFromChannel(a) +} + +func (me *TreeInfo) catchActionChannel() { + defer func() { + if r := recover(); r != nil { + log.Warn("nocui YAHOOOO Recovered in simpleStdin()", r) + me.DoToolkitPanic() + panic(-1) + } + }() + log.Info("catchActionChannel() START") + for { + log.Info("catchActionChannel() for loop") + select { + case a := <-me.pluginChan: + log.Info("catchActionChannel() SELECT widget id =", a.WidgetId, a.ProgName) + log.Warn("catchActionChannel() STUFF", a.WidgetId, a.ActionType, a.WidgetType) + if a.WidgetType == widget.Dropdown { + log.Warn("Found dropdown", a.WidgetId, a.ActionType, a.WidgetType) + for i, s := range a.State.Strings { + log.Warn("a.State.Strings =", i, s) + } + } + muAction.Lock() + me.toolkit(a) + muAction.Unlock() + log.Info("catchActionChannel() STUFF END", a.WidgetId, a.ActionType, a.WidgetType) + } + } +} + +func New() *TreeInfo { + me := new(TreeInfo) + me.pluginChan = make(chan widget.Action, 1) + + log.Info("Init() start channel reciever") + go me.catchActionChannel() + log.Info("Init() END") + return me +} diff --git a/common/plugin.go b/tree/plugin.go similarity index 56% rename from common/plugin.go rename to tree/plugin.go index bfc9a68..d7468e4 100644 --- a/common/plugin.go +++ b/tree/plugin.go @@ -1,4 +1,4 @@ -package main +package tree /* These code should be common to all gui plugins @@ -12,15 +12,11 @@ package main */ import ( - "reflect" - "strconv" - - "go.wit.com/log" "go.wit.com/gui/widget" ) // searches the binary tree for a WidgetId -func (n *node) findWidgetId(id int) *node { +func (n *Node) FindWidgetId(id int) *Node { if (n == nil) { return nil } @@ -30,7 +26,7 @@ func (n *node) findWidgetId(id int) *node { } for _, child := range n.children { - newN := child.findWidgetId(id) + newN := child.FindWidgetId(id) if (newN != nil) { return newN } @@ -38,21 +34,6 @@ func (n *node) findWidgetId(id int) *node { return nil } -func (n *node) doUserEvent() { - if (callback == nil) { - log.Log(ERROR, "doUserEvent() callback == nil", n.WidgetId) - return - } - var a widget.Action - a.WidgetId = n.WidgetId - a.Value = n.value - a.ActionType = widget.User - log.Log(INFO, "doUserEvent() START: send a user event to the callback channel") - callback <- a - log.Log(INFO, "doUserEvent() END: sent a user event to the callback channel") - return -} - // Other goroutines must use this to access the GUI // // You can not acess / process the GUI thread directly from @@ -60,10 +41,10 @@ func (n *node) doUserEvent() { // Linux, MacOS and Windows work (they all work differently. suprise. surprise.) // // this sets the channel to send user events back from the plugin -func Callback(guiCallback chan widget.Action) { - callback = guiCallback +func (me *TreeInfo) Callback(guiCallback chan widget.Action) { + me.callback = guiCallback } -func PluginChannel() chan widget.Action { - return pluginChan +func (me *TreeInfo) PluginChannel() chan widget.Action { + return me.pluginChan } diff --git a/common/structs.go b/tree/structs.go similarity index 59% rename from common/structs.go rename to tree/structs.go index 32eed8a..e998b6f 100644 --- a/common/structs.go +++ b/tree/structs.go @@ -1,4 +1,4 @@ -package main +package tree /* These code should be common to all gui plugins @@ -12,23 +12,29 @@ package main */ import ( - "reflect" - "strconv" - - "go.wit.com/log" + // "go.wit.com/log" "go.wit.com/gui/widget" ) -// this is the channel we send user events like -// mouse clicks or keyboard events back to the program -var callback chan widget.Action +// var me *TreeInfo -// this is the channel we get requests to make widgets -var pluginChan chan widget.Action +type TreeInfo struct { + // this is the channel we send user events like + // mouse clicks or keyboard events back to the program + callback chan widget.Action + + // this is the channel we get requests to make widgets + pluginChan chan widget.Action + + treeRoot *Node + NodeI interface {} + ActionFromChannel func (widget.Action) () + PluginName string +} type Node struct { - parent *node - children []*node + Parent *Node + children []*Node WidgetId int // widget ID WidgetType widget.WidgetType @@ -36,6 +42,8 @@ type Node struct { State widget.State + Strings map[string]int + // the internal plugin toolkit structure // in the gtk plugin, it has gtk things like margin & border settings // in the text console one, it has text console things like colors for menus & buttons