diff options
Diffstat (limited to 'toolkit/gocui')
| -rw-r--r-- | toolkit/gocui/, | 191 | ||||
| -rw-r--r-- | toolkit/gocui/Makefile | 4 | ||||
| -rw-r--r-- | toolkit/gocui/button.go | 53 | ||||
| -rw-r--r-- | toolkit/gocui/click.go | 165 | ||||
| -rw-r--r-- | toolkit/gocui/color.go | 113 | ||||
| -rw-r--r-- | toolkit/gocui/common.go | 100 | ||||
| -rw-r--r-- | toolkit/gocui/debug.go | 143 | ||||
| -rw-r--r-- | toolkit/gocui/gocui.go | 112 | ||||
| -rw-r--r-- | toolkit/gocui/group.go | 36 | ||||
| -rw-r--r-- | toolkit/gocui/help.go | 49 | ||||
| -rw-r--r-- | toolkit/gocui/keybindings.go | 146 | ||||
| -rw-r--r-- | toolkit/gocui/log.go | 8 | ||||
| -rw-r--r-- | toolkit/gocui/logical.go | 72 | ||||
| -rw-r--r-- | toolkit/gocui/main.go | 40 | ||||
| -rw-r--r-- | toolkit/gocui/mouse.go | 171 | ||||
| -rw-r--r-- | toolkit/gocui/place.go | 221 | ||||
| -rw-r--r-- | toolkit/gocui/plugin.go | 153 | ||||
| -rw-r--r-- | toolkit/gocui/structs.go | 142 | ||||
| -rw-r--r-- | toolkit/gocui/tab.go | 88 | ||||
| -rw-r--r-- | toolkit/gocui/view.go | 86 | ||||
| -rw-r--r-- | toolkit/gocui/views.go | 80 | ||||
| -rw-r--r-- | toolkit/gocui/window.go | 16 |
22 files changed, 1601 insertions, 588 deletions
diff --git a/toolkit/gocui/, b/toolkit/gocui/, new file mode 100644 index 0000000..762f8eb --- /dev/null +++ b/toolkit/gocui/, @@ -0,0 +1,191 @@ +// Copyright 2014 The gocui Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "errors" + "fmt" + "log" + + "github.com/awesome-gocui/gocui" +) + +func main() { + g, err := gocui.NewGui(gocui.OutputNormal, true) + if err != nil { + log.Panicln(err) + } + defer g.Close() + + g.Cursor = false + g.Mouse = true + + g.SetManagerFunc(layout) + + if err := keybindings(g); err != nil { + log.Panicln(err) + } + + if err := g.MainLoop(); err != nil && !errors.Is(err, gocui.ErrQuit) { + log.Panicln(err) + } +} + +var initialMouseX, initialMouseY, xOffset, yOffset int +var globalMouseDown, msgMouseDown, movingMsg bool + +func layout(g *gocui.Gui) error { + maxX, maxY := g.Size() + if _, err := g.View("msg"); msgMouseDown && err == nil { + moveMsg(g) + } + if v, err := g.SetView("global", -1, -1, maxX, maxY, 0); err != nil { + if !errors.Is(err, gocui.ErrUnknownView) { + return err + } + v.Frame = false + } + if v, err := g.SetView("but1", 2, 2, 22, 7, 0); err != nil { + if !errors.Is(err, gocui.ErrUnknownView) { + return err + } + v.SelBgColor = gocui.ColorGreen + v.SelFgColor = gocui.ColorBlack + fmt.Fprintln(v, "Button 1 - line 1") + fmt.Fprintln(v, "Button 1 - line 2") + fmt.Fprintln(v, "Button 1 - line 3") + fmt.Fprintln(v, "Button 1 - line 4") + if _, err := g.SetCurrentView("but1"); err != nil { + return err + } + } + if v, err := g.SetView("but2", 24, 2, 44, 4, 0); err != nil { + if !errors.Is(err, gocui.ErrUnknownView) { + return err + } + v.SelBgColor = gocui.ColorGreen + v.SelFgColor = gocui.ColorBlack + fmt.Fprintln(v, "Button 2 - line 1") + } + updateHighlightedView(g) + return nil +} + +func keybindings(g *gocui.Gui) error { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { + return err + } + for _, n := range []string{"but1", "but2"} { + if err := g.SetKeybinding(n, gocui.MouseLeft, gocui.ModNone, showMsg); err != nil { + return err + } + } + if err := g.SetKeybinding("", gocui.MouseRelease, gocui.ModNone, mouseUp); err != nil { + return err + } + if err := g.SetKeybinding("", gocui.MouseLeft, gocui.ModNone, globalDown); err != nil { + return err + } + if err := g.SetKeybinding("msg", gocui.MouseLeft, gocui.ModNone, msgDown); err != nil { + return err + } + return nil +} + +func quit(g *gocui.Gui, v *gocui.View) error { + return gocui.ErrQuit +} + +func showMsg(g *gocui.Gui, v *gocui.View) error { + var l string + var err error + + if _, err := g.SetCurrentView(v.Name()); err != nil { + return err + } + + _, cy := v.Cursor() + if l, err = v.Line(cy); err != nil { + l = "" + } + + maxX, maxY := g.Size() + if v, err := g.SetView("msg", maxX/2-10, maxY/2, maxX/2+10, maxY/2+2, 0); err == nil || errors.Is(err, gocui.ErrUnknownView) { + v.Clear() + v.SelBgColor = gocui.ColorCyan + v.SelFgColor = gocui.ColorBlack + fmt.Fprintln(v, l) + } + return nil +} + +func updateHighlightedView(g *gocui.Gui) { + mx, my := g.MousePosition() + for _, view := range g.Views() { + view.Highlight = false + } + if v, err := g.ViewByPosition(mx, my); err == nil { + v.Highlight = true + } +} + +func moveMsg(g *gocui.Gui) { + mx, my := g.MousePosition() + if !movingMsg && (mx != initialMouseX || my != initialMouseY) { + movingMsg = true + } + g.SetView("msg", mx-xOffset, my-yOffset, mx-xOffset+20, my-yOffset+2, 0) +} + +func msgDown(g *gocui.Gui, v *gocui.View) error { + initialMouseX, initialMouseY = g.MousePosition() + if vx, vy, _, _, err := g.ViewPosition("msg"); err == nil { + xOffset = initialMouseX - vx + yOffset = initialMouseY - vy + msgMouseDown = true + } + return nil +} + +func globalDown(g *gocui.Gui, v *gocui.View) error { + mx, my := g.MousePosition() + if vx0, vy0, vx1, vy1, err := g.ViewPosition("msg"); err == nil { + if mx >= vx0 && mx <= vx1 && my >= vy0 && my <= vy1 { + return msgDown(g, v) + } + } + globalMouseDown = true + maxX, _ := g.Size() + msg := fmt.Sprintf("Mouse down at: %d,%d", mx, my) + x := mx - len(msg)/2 + if x < 0 { + x = 0 + } else if x+len(msg)+1 > maxX-1 { + x = maxX - 1 - len(msg) - 1 + } + if v, err := g.SetView("globalDown", x, my-1, x+len(msg)+1, my+1, 0); err != nil { + if !errors.Is(err, gocui.ErrUnknownView) { + return err + } + v.WriteString(msg) + } + return nil +} + +func mouseUp(g *gocui.Gui, v *gocui.View) error { + if msgMouseDown { + msgMouseDown = false + if movingMsg { + movingMsg = false + return nil + } else { + g.DeleteView("msg") + } + } else if globalMouseDown { + globalMouseDown = false + g.DeleteView("globalDown") + } + return nil +} diff --git a/toolkit/gocui/Makefile b/toolkit/gocui/Makefile index 597b2b2..35e4e96 100644 --- a/toolkit/gocui/Makefile +++ b/toolkit/gocui/Makefile @@ -9,3 +9,7 @@ plugin: objdump: objdump -t ../gocui.so |less + +log: + reset + tail -f /tmp/witgui.* /tmp/guilogfile diff --git a/toolkit/gocui/button.go b/toolkit/gocui/button.go deleted file mode 100644 index 355dc30..0000000 --- a/toolkit/gocui/button.go +++ /dev/null @@ -1,53 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "strings" - - "github.com/awesome-gocui/gocui" - "git.wit.org/wit/gui/toolkit" -) - -func newButton(parentW *toolkit.Widget, w *toolkit.Widget) { - log(true, "AddButton()", w.Name) - addButton(w.Name) - stringWidget[w.Name] = w - listMap() -} - -func addButton(name string) *gocui.View { - t := len(name) - if (baseGui == nil) { - panic("WTF") - } - v, err := baseGui.SetView(name, currentX, currentY, currentX+t+3, currentY+2, 0) - if err == nil { - log("wit/gui internal plugin error", err) - return nil - } - if !errors.Is(err, gocui.ErrUnknownView) { - log("wit/gui internal plugin error", err) - return nil - } - - v.Wrap = true - fmt.Fprintln(v, " " + name) - fmt.Fprintln(v, strings.Repeat("foo\n", 2)) - - currentView, err := baseGui.SetCurrentView(name) - if err != nil { - log("wit/gui internal plugin error", err) - return nil - } - log("wit/gui addbutton() current view name =", currentView.Name()) - - views = append(views, name) - curView = len(views) - 1 - idxView += 1 - currentY += 3 - if (groupSize < len(name)) { - groupSize = len(name) - } - return currentView -} diff --git a/toolkit/gocui/click.go b/toolkit/gocui/click.go new file mode 100644 index 0000000..9dc1a42 --- /dev/null +++ b/toolkit/gocui/click.go @@ -0,0 +1,165 @@ +package main + +import ( + "fmt" + "errors" + "strconv" + "strings" + + "github.com/awesome-gocui/gocui" + "git.wit.org/wit/gui/toolkit" +) + +func (w *cuiWidget) doWidgetClick() { + switch w.widgetType { + case toolkit.Root: + me.rootNode.redoTabs(true) + // me.rootNode.redoFake(true) + case toolkit.Flag: + me.rootNode.redoColor(true) + case toolkit.Window: + me.rootNode.redoTabs(true) + w.redoBox(true) + w.toggleTree() + me.rootNode.redoColor(true) + case toolkit.Tab: + me.rootNode.redoTabs(true) + w.redoBox(true) + w.toggleTree() + me.rootNode.redoColor(true) + case toolkit.Box: + w.showWidgetPlacement(logNow, "drawTree()") + if (w.horizontal) { + log("BOX IS HORIZONTAL", w.nextW, w.nextH, w.name) + } else { + log("BOX IS VERTICAL", w.nextW, w.nextH, w.name) + } + // w.redoBox(true) + default: + // w.textResize() + // something + } +} + +var toggle bool = true +func (w *cuiWidget) toggleTree() { + if (toggle) { + w.drawTree(toggle) + toggle = false + } else { + w.hideWidgets() + toggle = true + } +} + + +// display the widgets in the binary tree +func (w *cuiWidget) drawTree(draw bool) { + if (w == nil) { + return + } + w.showWidgetPlacement(logNow, "drawTree()") + if (draw) { + w.textResize() + w.drawView() + } else { + me.baseGui.DeleteView(w.cuiName) + w.v = nil + } + + for _, child := range w.children { + child.drawTree(draw) + } +} + +func click(g *gocui.Gui, v *gocui.View) error { + var l string + var err error + + log(logNow, "click() START", v.Name()) + i, err := strconv.Atoi(v.Name()) + if (err != nil) { + log(logNow, "click() Can't find widget. error =", err) + } else { + log(logNow, "click() ok v.Name() =", v.Name()) + w := findWidget(i, me.rootNode) + if (w == nil) { + log(logError, "click() CANT FIND VIEW in binary tree. v.Name =", v.Name()) + return nil + } + log(logNow, "click() Found widget =", w.id, w.name, ",", w.text) + w.doWidgetClick() + return nil + } + + if _, err := g.SetCurrentView(v.Name()); err != nil { + return err + } + + _, cy := v.Cursor() + if l, err = v.Line(cy); err != nil { + l = "" + } + + maxX, maxY := g.Size() + if v, err := g.SetView("msg", maxX/2-10, maxY/2, maxX/2+10, maxY/2+2, 0); err == nil || errors.Is(err, gocui.ErrUnknownView) { + v.Clear() + v.SelBgColor = gocui.ColorCyan + v.SelFgColor = gocui.ColorBlack + fmt.Fprintln(v, l) + } + + // this seems to delete the button(?) + // g.SetViewOnBottom(v.Name()) + log(logNow, "click() END") + return nil +} + +// display the widgets in the binary tree + +func ctrlDown(g *gocui.Gui, v *gocui.View) error { + var widgets []*cuiWidget + var f func (widget *cuiWidget) + w, h := g.MousePosition() + + f = func(widget *cuiWidget) { + if ((widget.logicalSize.w0 < w) && (w < widget.logicalSize.w1)) { + widgets = append(widgets, widget) + } + + for _, child := range widget.children { + f(child) + } + } + f(me.rootNode) + var t string + for i, widget := range widgets { + log(logNow, "ctrlDown() FOUND widget", i, widget.name) + t += widget.cuiName + " " + widget.name + "\n" + // widget.showWidgetPlacement(logNow, "drawTree()") + } + t = strings.TrimSpace(t) + if (me.ctrlDown == nil) { + setupCtrlDownWidget() + } + me.ctrlDown.text = t + me.ctrlDown.realSize.w0 = w + me.ctrlDown.realSize.h0 = h + me.ctrlDown.textResize() + me.ctrlDown.drawView() + + /* + v, err := g.SetView("ctrlDown", maxX/2-10, maxY/2, maxX/2+10, maxY/2+2, 0) + if (err != nil) { + log(logError, "ctrlDown() g.SetView() error:", err) + return + } + v.Clear() + v.SelBgColor = gocui.ColorCyan + v.SelFgColor = gocui.ColorBlack + fmt.Fprintln(v, l) + */ + + log(logNow, "ctrlDown()", w, h) + return nil +} diff --git a/toolkit/gocui/color.go b/toolkit/gocui/color.go new file mode 100644 index 0000000..efe44dd --- /dev/null +++ b/toolkit/gocui/color.go @@ -0,0 +1,113 @@ +package main + +import ( + "math/rand" + "github.com/awesome-gocui/gocui" + "git.wit.org/wit/gui/toolkit" +) + +// ColorBlack ColorRed ColorGreen ColorYellow ColorBlue ColorMagenta ColorCyan ColorWhite +// gocui.GetColor("#FFAA55") // Dark Purple +func (w *cuiWidget) SetDefaultWidgetColor() { + log(logInfo, "SetDefaultWidgetColor() on", w.widgetType, w.name) + v, _ := me.baseGui.View(w.cuiName) + if (v == nil) { + log(logError, "SetDefaultWidgetColor() failed on view == nil") + return + } + // v.BgColor = gocui.GetColor("#FFAA55") // Dark Purple + // v.BgColor = gocui.GetColor("#88AA55") // heavy purple + // v.BgColor = gocui.GetColor("#111111") // crazy red + // v.BgColor = gocui.GetColor("#FF9911") // heavy red + // v.SelBgColor = gocui.GetColor("#FFEE11") // blood red + + // v.BgColor = gocui.GetColor("#55AAFF") // super light grey + // v.BgColor = gocui.GetColor("#FFC0CB") // 'w3c pink' yellow + switch w.widgetType { + case toolkit.Root: + v.FrameColor = gocui.ColorRed + v.BgColor = gocui.GetColor("#B0E0E6") // w3c 'powerder blue' + case toolkit.Flag: + v.FrameColor = gocui.ColorRed + v.BgColor = gocui.GetColor("#B0E0E6") // w3c 'powerder blue' + case toolkit.Window: + v.FgColor = gocui.ColorCyan + v.SelBgColor = gocui.ColorBlue + v.FrameColor = gocui.ColorBlue + case toolkit.Tab: + v.SelBgColor = gocui.ColorBlue + v.FrameColor = gocui.ColorBlue + case toolkit.Button: + v.BgColor = gocui.ColorWhite + v.FrameColor = gocui.ColorGreen + v.SelBgColor = gocui.ColorBlack + v.SelFgColor = gocui.ColorGreen + case toolkit.Label: + v.BgColor = gocui.GetColor("#55AAFF") // super light grey + v.SelBgColor = gocui.GetColor("#55AAFF") // super light grey + case toolkit.Box: + v.FrameColor = gocui.ColorRed + // v.BgColor = gocui.GetColor("#FFC0CB") // 'w3c pink' yellow + v.BgColor = gocui.GetColor("#DDDDDD") // light purple + case toolkit.Grid: + // v.FgColor = gocui.ColorCyan + // v.SelBgColor = gocui.ColorBlue + // v.FrameColor = gocui.ColorBlue + case toolkit.Group: + v.BgColor = gocui.GetColor("#55AAFF") // super light grey + default: + } +} + +// SetColor("#FFAA55") // purple +func (w *cuiWidget) SetColor(c string) { + if (w.v == nil) { + log(logError, "SetColor() failed on view == nil") + return + } + w.v.SelBgColor = gocui.ColorCyan + w.v.SelFgColor = gocui.ColorBlack + switch c { + case "Green": + w.v.BgColor = gocui.ColorGreen + case "Purple": + w.v.BgColor = gocui.GetColor("#FFAA55") + case "Yellow": + w.v.BgColor = gocui.ColorYellow + case "Blue": + w.v.BgColor = gocui.ColorBlue + case "Red": + w.v.BgColor = gocui.ColorRed + default: + w.v.BgColor = gocui.GetColor(c) + } +} + +func (w *cuiWidget) SetDefaultHighlight() { + if (w.v == nil) { + log(logError, "SetColor() failed on view == nil") + return + } +// w.v.SelBgColor = gocui.ColorGreen +// w.v.SelFgColor = gocui.ColorBlack +} + +func randColor() gocui.Attribute { + colors := []string{"Green", "#FFAA55", "Yellow", "Blue", "Red", "Black", "White"} + i := rand.Intn(len(colors)) + log("randColor() i =", i) + return gocui.GetColor(colors[i]) +} + +func (w *cuiWidget) redoColor(draw bool) { + if (w == nil) { + return + } + + sleep(.05) + w.SetDefaultWidgetColor() + + for _, child := range w.children { + child.redoColor(draw) + } +} diff --git a/toolkit/gocui/common.go b/toolkit/gocui/common.go new file mode 100644 index 0000000..2fe82cb --- /dev/null +++ b/toolkit/gocui/common.go @@ -0,0 +1,100 @@ +package main + +import ( + "strconv" + "git.wit.org/wit/gui/toolkit" +// "github.com/awesome-gocui/gocui" +) + +func setupWidget(a *toolkit.Action) *cuiWidget { + var w *cuiWidget + w = new(cuiWidget) + + w.name = a.Name + w.text = a.Text + w.b = a.B + w.i = a.I + w.s = a.S + w.x = a.X + w.y = a.Y + w.width = a.Width + w.height = a.Height + + w.widgetType = a.WidgetType + w.id = a.WidgetId + // set the name used by gocui to the id + w.cuiName = strconv.Itoa(w.id) + + w.parent = findWidget(a.ParentId, me.rootNode) + log(logInfo, "setupWidget() w.id =", w.id, "w.parent", w.parent, "ParentId =", a.ParentId) + if (w.id == 0) { + me.rootNode = w + // this is the rootNode + return w + } + if (w.parent == nil) { + log(logError, "setupWidget() ERROR: PARENT = NIL w.id =", w.id, "w.parent", w.parent, "ParentId =", a.ParentId) + // just use the rootNode (hopefully it's not nil) + w.parent = me.rootNode + // return w + } + if (w.parent == nil) { + log(logError, "setupWidget() ERROR: PARENT = NIL w.id =", w.id, "w.parent", w.parent, "ParentId =", a.ParentId) + me.rootNode = w + return w + } + // add this widget as a child for the parent + w.parent.Append(w) + + if (a.WidgetType == toolkit.Box) { + if (a.B) { + w.horizontal = true + } else { + w.horizontal = false + } + } + + // w.showWidgetPlacement(logNow) + return w +} + +func setupCtrlDownWidget() { + var w *cuiWidget + w = new(cuiWidget) + + w.name = "ctrlDown" + + w.widgetType = toolkit.Flag + w.id = -1 + me.ctrlDown = w + // me.rootNode.Append(w) +} + +func (n *cuiWidget) Append(child *cuiWidget) { + n.children = append(n.children, child) + // child.parent = n +} + +// find widget by number +func findWidget(i int, w *cuiWidget) (*cuiWidget) { + if (w == nil) { + log(logVerbose, "findWidget() Trying to find i =", i, "currently checking against w.id = nil") + return nil + } + log(logVerbose, "findWidget() Trying to find i =", i, "currently checking against w.id =", w.id) + + if (w.id == i) { + log(logInfo, "findWidget() FOUND w.id ==", i, w.widgetType, w.name) + return w + } + + for _, child := range w.children { + newW := findWidget(i, child) + log(logVerbose, "findWidget() Trying to find i =", i, "currently checking against child.id =", child.id) + if (newW != nil) { + return newW + } + } + return nil +} + diff --git a/toolkit/gocui/debug.go b/toolkit/gocui/debug.go index b38fd83..3ecdfdd 100644 --- a/toolkit/gocui/debug.go +++ b/toolkit/gocui/debug.go @@ -1,109 +1,70 @@ package main -import "git.wit.org/wit/gui/toolkit" +import ( + "fmt" -var defaultBehavior bool = true + "git.wit.org/wit/gui/toolkit" +// "github.com/awesome-gocui/gocui" +) -var bookshelf bool // do you want things arranged in the box like a bookshelf or a stack? -var canvas bool // if set to true, the windows are a raw canvas -var menubar bool // for windows -var stretchy bool // expand things like buttons to the maximum size -var padded bool // add space between things like buttons -var margin bool // add space around the frames of windows - -var debugToolkit bool -var debugChange bool -var debugPlugin bool -var debugFlags bool -var debugError bool = true - -// This is important. This sets the defaults for the gui. Without this, there isn't correct padding, etc -func setDefaultBehavior(s bool) { - defaultBehavior = s - if (defaultBehavior) { - log(debugToolkit, "Setting this toolkit to use the default behavior.") - log(debugToolkit, "This is the 'guessing' part as defined by the wit/gui 'Principles'. Refer to the docs.") - stretchy = false - padded = true - menubar = true - margin = true - canvas = false - bookshelf = true // 99% of the time, things make a vertical stack of objects - } else { - log(debugToolkit, "This toolkit is set to ignore the default behavior.") +func actionDump(b bool, a *toolkit.Action) { + if (a == nil) { + log(b, "action = nil") + return } -} -func ShowDebug () { - log(true, "debugToolkit =", debugToolkit) - log(true, "debugChange =", debugChange) - log(true, "debugPlugin =", debugPlugin) - log(true, "debugFlags =", debugFlags) - log(true, "debugError =", debugError) + log(b, "a.Name =", a.Name) + log(b, "a.Text =", a.Text) + log(b, "a.WidgetId =", a.WidgetId) + log(b, "a.ParentId =", a.ParentId) + log(b, "a.B =", a.B) + log(b, "a.S =", a.S) } -/* -func (t *gocuiT) Dump(b bool) { - if ! b { +func (w *cuiWidget) dumpTree(draw bool) { + log(logNow, "dumpTree() START", w) + if (w == nil) { return } - log(b, "Name = ", t.Name, t.Width, t.Height) - if (t.uiBox != nil) { - log(b, "uiBox =", t.uiBox) - } - if (t.uiButton != nil) { - log(b, "uiButton =", t.uiButton) - } - if (t.uiCombobox != nil) { - log(b, "uiCombobox =", t.uiCombobox) - } - if (t.uiWindow != nil) { - log(b, "uiWindow =", t.uiWindow) - } - if (t.uiTab != nil) { - log(b, "uiTab =", t.uiTab) - } - if (t.uiGroup != nil) { - log(b, "uiGroup =", t.uiGroup) - } - if (t.uiEntry != nil) { - log(b, "uiEntry =", t.uiEntry) - } - if (t.uiMultilineEntry != nil) { - log(b, "uiMultilineEntry =", t.uiMultilineEntry) - } - if (t.uiSlider != nil) { - log(b, "uiSlider =", t.uiSlider) - } - if (t.uiCheckbox != nil) { - log(b, "uiCheckbox =", t.uiCheckbox) + w.showWidgetPlacement(logNow, "Tree:") + + for _, child := range w.children { + child.dumpTree(draw) } - widgetDump(b, t.tw) } -*/ -func widgetDump(b bool, w *toolkit.Widget) { +func (w *cuiWidget) showWidgetPlacement(b bool, s string) { if (w == nil) { - log(b, "widget = nil") + log(logError, "WTF w == nil") return } + if (w.id == 0) { + log(logVerbose, "showWidgetPlacement() parent == nil ok. This is the rootNode", w.id, w.cuiName) + return + } + if (w.parent == nil) { + log(logError, "showWidgetPlacement() WTF parent == nil", w.id, w.cuiName) + log(logError, "showWidgetPlacement() WTF parent == nil", w.id, w.cuiName) + log(logError, "showWidgetPlacement() WTF parent == nil", w.id, w.cuiName) + return + } + log(b, "dump()", s, + fmt.Sprintf("(wId,pId)=(%3d,%3d)", w.id, w.parent.id), + fmt.Sprintf("real()=(%3d,%3d,%3d,%3d)", w.realSize.w0, w.realSize.h0, w.realSize.w1, w.realSize.h1), + "next()=(", w.nextW, ",", w.nextH, ")", + "logical()=(", w.logicalSize.w0, ",", w.logicalSize.h0, ",", w.logicalSize.w1, ",", w.logicalSize.h1, ")", + w.widgetType, ",", w.name, "text=", w.text) - /* - log(b, "widget.Name =", w.Name) - // log(b, "widget.Action =", w.Action) - log(b, "widget.Type =", w.Type) - log(b, "widget.Custom =", w.Custom) - log(b, "widget.B =", w.B) - log(b, "widget.I =", w.I) - log(b, "widget.Width =", w.Width) - log(b, "widget.Height =", w.Height) - log(b, "widget.X =", w.X) - log(b, "widget.Y =", w.Y) - */ -} - -/* -func GetDebugToolkit () bool { - return debugToolkit + if (w.realWidth != (w.realSize.w1 - w.realSize.w0)) { + log(b, "dump()", s, + "badsize()=(", w.realWidth, ",", w.realHeight, ")", + "badreal()=(", w.realSize.w0, ",", w.realSize.h0, ",", w.realSize.w1, ",", w.realSize.h1, ")", + w.widgetType, ",", w.name) + } + if (w.realHeight != (w.realSize.h1 - w.realSize.h0)) { + log(b, "dump()", s, + "badsize()=(", w.realWidth, ",", w.realHeight, ")", + "badreal()=(", w.realSize.w0, ",", w.realSize.h0, ",", w.realSize.w1, ",", w.realSize.h1, ")", + w.widgetType, ",", w.name) + } } -*/ diff --git a/toolkit/gocui/gocui.go b/toolkit/gocui/gocui.go deleted file mode 100644 index 0a302bc..0000000 --- a/toolkit/gocui/gocui.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2014 The gocui Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "errors" - "fmt" - "os" - - "git.wit.org/wit/gui/toolkit" - - "github.com/awesome-gocui/gocui" -) - -const delta = 1 - -var ( - views = []string{} - curView = -1 - idxView = 0 - currentX = 5 - currentY = 2 - groupSize = 0 - baseGui *gocui.Gui - helpLabel *gocui.View - err error - ch chan(func ()) - outf *os.File -) - -func Init() { - baseGui, err = gocui.NewGui(gocui.OutputNormal, true) - if err != nil { - exit(err) - } - - baseGui.Highlight = true - baseGui.SelFgColor = gocui.ColorRed - baseGui.SelFrameColor = gocui.ColorRed - - baseGui.Cursor = true - baseGui.Mouse = true - - baseGui.SetManagerFunc(layout) - - if err := initKeybindings(baseGui); err != nil { - exit(err) - } - - viewWidget = make(map[*gocui.View]*toolkit.Widget) - stringWidget = make(map[string]*toolkit.Widget) - - ch = make(chan func()) - - outf, err = os.OpenFile("/tmp/witgui.log", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666) - if err != nil { - exit("error opening file: %v", err) - } - // hmm. where to put this? - // defer outf.Close() - - setOutput(outf) - log("This is a test log entry") -} - -func Queue(f func()) { - log("QUEUEEEEE") - f() -} - -func Main(f func()) { - // close the STDOUT log file - defer outf.Close() - if (baseGui == nil) { - panic("WTF Main()") - } - defer baseGui.Close() - // log.Println("ADDDDDDDD BUTTTTTTTTTON") - // addButton("test 3") - f() - if err := baseGui.MainLoop(); err != nil && !errors.Is(err, gocui.ErrQuit) { - exit(err) - } - baseGui.Close() - os.Exit(0) -} - -func layout(g *gocui.Gui) error { - var err error - maxX, _ := g.Size() - - helpLabel, err = g.SetView("help", maxX-32, 0, maxX-1, 12, 0) - if err != nil { - if !errors.Is(err, gocui.ErrUnknownView) { - return err - } - fmt.Fprintln(helpLabel, "KEYBINDINGS") - fmt.Fprintln(helpLabel, "Enter: Click Button") - fmt.Fprintln(helpLabel, "Tab/Space: Switch Buttons") - fmt.Fprintln(helpLabel, "") - fmt.Fprintln(helpLabel, "h: Help") - fmt.Fprintln(helpLabel, "Backspace: Delete Button") - fmt.Fprintln(helpLabel, "Arrow keys: Move Button") - fmt.Fprintln(helpLabel, "t: Move Button to the top") - fmt.Fprintln(helpLabel, "b: Move Button to the button") - fmt.Fprintln(helpLabel, "STDOUT: /tmp/witgui.log") - fmt.Fprintln(helpLabel, "Ctrl-C or Q: Exit") - } - return nil -} diff --git a/toolkit/gocui/group.go b/toolkit/gocui/group.go deleted file mode 100644 index 2d8600c..0000000 --- a/toolkit/gocui/group.go +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "git.wit.org/wit/gui/toolkit" -) - -func newGroup(parentW *toolkit.Widget, w *toolkit.Widget) { - if (parentW == nil) { - log(debugError, "plugin error. parent widget == nil") - return - } - if (w == nil) { - log(debugPlugin, "plugin error. widget == nil") - return - } - if (w.Name == "") { - w.Name = parentW.Name - } - if (w.Name == "") { - w.Name = "nil newGroup" - } - log("AddGroup", w.Name) - addGroup(w.Name) - stringWidget[w.Name] = w -} - -func addGroup(name string) { - log("addGroup() START name =", name) - log("addGroup() START groupSize =", groupSize, "currentY =", currentY, "currentX =", currentX) - - currentY = 2 - currentX += groupSize + 5 - groupSize = 0 - - log("addGroup() START, RESET Y = 3, RESET X = ", currentX) -} diff --git a/toolkit/gocui/help.go b/toolkit/gocui/help.go new file mode 100644 index 0000000..8796ad6 --- /dev/null +++ b/toolkit/gocui/help.go @@ -0,0 +1,49 @@ +// Copyright 2014 The gocui Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "errors" + "fmt" + + "github.com/awesome-gocui/gocui" +) + +func addHelp() { + me.baseGui.SetManagerFunc(helplayout) +} + +func helplayout(g *gocui.Gui) error { + var err error + maxX, _ := g.Size() + + help, err := g.SetView("help", maxX-32, 0, maxX-1, 17, 0) + if err != nil { + if !errors.Is(err, gocui.ErrUnknownView) { + return err + } + help.SelBgColor = gocui.ColorGreen + help.SelFgColor = gocui.ColorBlack + fmt.Fprintln(help, "KEYBINDINGS") + fmt.Fprintln(help, "Enter: Click Button") + fmt.Fprintln(help, "Tab/Space: Switch Buttons") + fmt.Fprintln(help, "") + fmt.Fprintln(help, "h: Help") + fmt.Fprintln(help, "Backspace: Delete Button") + fmt.Fprintln(help, "Arrow keys: Move Button") + fmt.Fprintln(help, "t: Move Button to the top") + fmt.Fprintln(help, "b: Move Button to the button") + fmt.Fprintln(help, "h: hide buttons") + fmt.Fprintln(help, "s: show buttons") + fmt.Fprintln(help, "p: panic()") + fmt.Fprintln(help, "STDOUT: /tmp/witgui.log") + fmt.Fprintln(help, "Ctrl-C or Q: Exit") + if _, err := g.SetCurrentView("help"); err != nil { + return err + } + } + me.helpLabel = help + return nil +} diff --git a/toolkit/gocui/keybindings.go b/toolkit/gocui/keybindings.go index 43dbf47..18d3097 100644 --- a/toolkit/gocui/keybindings.go +++ b/toolkit/gocui/keybindings.go @@ -6,130 +6,66 @@ package main import ( "github.com/awesome-gocui/gocui" - "git.wit.org/wit/gui/toolkit" ) -func initKeybindings(g *gocui.Gui) error { - log("got to initKeybindings") - if err := g.SetKeybinding("", 'q', gocui.ModNone, - func(g *gocui.Gui, v *gocui.View) error { - return gocui.ErrQuit - }); err != nil { - return err - } - if err := g.SetKeybinding("", 'Q', gocui.ModNone, - func(g *gocui.Gui, v *gocui.View) error { - return gocui.ErrQuit - }); err != nil { - return err - } - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, - func(g *gocui.Gui, v *gocui.View) error { - return gocui.ErrQuit - }); err != nil { - return err - } - if err := g.SetKeybinding("", gocui.KeySpace, gocui.ModNone, - func(g *gocui.Gui, v *gocui.View) error { - return newView(g) - }); err != nil { +func defaultKeybindings(g *gocui.Gui) error { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { return err } - if err := g.SetKeybinding("", gocui.KeyBackspace, gocui.ModNone, - func(g *gocui.Gui, v *gocui.View) error { - return delView(g) - }); err != nil { - return err - } - if err := g.SetKeybinding("", gocui.KeyBackspace2, gocui.ModNone, - func(g *gocui.Gui, v *gocui.View) error { - return delView(g) - }); err != nil { - return err + for _, n := range []string{"but1", "but2", "help", "but3"} { + if err := g.SetKeybinding(n, gocui.MouseLeft, gocui.ModNone, showMsg); err != nil { + return err + } } - if err := g.SetKeybinding("", gocui.KeyTab, gocui.ModNone, - func(g *gocui.Gui, v *gocui.View) error { - log("tab", v.Name()) - return nextView(g, true) - }); err != nil { + if err := g.SetKeybinding("", gocui.MouseRelease, gocui.ModNone, mouseUp); err != nil { return err } - if err := g.SetKeybinding("", gocui.KeyArrowLeft, gocui.ModNone, - func(g *gocui.Gui, v *gocui.View) error { - return moveView(g, v, -delta, 0) - }); err != nil { + if err := g.SetKeybinding("", gocui.MouseLeft, gocui.ModNone, globalDown); err != nil { return err } - if err := g.SetKeybinding("", gocui.KeyArrowRight, gocui.ModNone, - func(g *gocui.Gui, v *gocui.View) error { - return moveView(g, v, delta, 0) - }); err != nil { + if err := g.SetKeybinding("", gocui.MouseLeft, gocui.ModMouseCtrl, ctrlDown); err != nil { return err } - if err := g.SetKeybinding("", gocui.KeyArrowDown, gocui.ModNone, - func(g *gocui.Gui, v *gocui.View) error { - log("down", v.Name()) - return moveView(g, v, 0, delta) - }); err != nil { + /* + if err := g.SetKeybinding("", gocui.MouseLeft, gocui.ModNone, globalDown); err != nil { return err } - if err := g.SetKeybinding("", gocui.KeyArrowUp, gocui.ModNone, - func(g *gocui.Gui, v *gocui.View) error { - log("up", v.Name()) - return moveView(g, v, 0, -delta) - }); err != nil { + */ + if err := g.SetKeybinding("msg", gocui.MouseLeft, gocui.ModNone, msgDown); err != nil { return err } - if err := g.SetKeybinding("", gocui.KeyEnter, gocui.ModNone, + addDebugKeys(g) + return nil +} + +// dump out the widgets +func addDebugKeys(g *gocui.Gui) { + // dump all widget info to the log + g.SetKeybinding("", 'd', gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { - log("enter", v.Name()) - var w *toolkit.Widget - w = stringWidget[v.Name()] - if (w == nil) { - log("COULD NOT FIND WIDGET", v.Name()) - } else { - log("FOUND WIDGET!", w) - if (w.Custom != nil) { - w.Custom() - return nil - } - // if (w.Event != nil) { - // w.Event(w) - // return nil - // } - } + log(logNow, "gocui.SetKeyBinding() dumpTree() START") + me.rootNode.dumpTree(true) return nil - }); err != nil { - return err - } - if err := g.SetKeybinding("", 't', gocui.ModNone, + }) + + // hide all widgets + g.SetKeybinding("", 'h', gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { - _, err := g.SetViewOnTop(views[curView]) - return err - }); err != nil { - return err - } - if err := g.SetKeybinding("", 'b', gocui.ModNone, + me.rootNode.hideWidgets() + return nil + }) + + // show all widgets + g.SetKeybinding("", 's', gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { - _, err := g.SetViewOnBottom(views[curView]) - return err - }); err != nil { - return err - } - if err := g.SetKeybinding("", 'h', gocui.ModNone, + me.rootNode.showWidgets() + return nil + }) + + // panic + g.SetKeybinding("", 'p', gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { - log("help", v.Name()) - tmp, _ := g.SetViewOnTop("help") - log("help 2", tmp.Name()) -// g.SetView("help", 2, 2, 30, 15, 0); - g.SetCurrentView("help") -// moveView(g, tmp, 0, -delta) - if err := g.DeleteView("help"); err != nil { - exit("gocui SetKeybinding()", err) - } + panic("forced panic in gocui") return nil - }); err != nil { - return err - } - return nil + }) } diff --git a/toolkit/gocui/log.go b/toolkit/gocui/log.go index 527d057..222332d 100644 --- a/toolkit/gocui/log.go +++ b/toolkit/gocui/log.go @@ -5,7 +5,15 @@ import ( witlog "git.wit.org/wit/gui/log" ) +// various debugging flags +var logNow bool = true // useful for active development +var logError bool = true +var logWarn bool = false +var logInfo bool = false +var logVerbose bool = false + func log(a ...any) { + witlog.Where = "wit/gocui" witlog.Log(a...) } diff --git a/toolkit/gocui/logical.go b/toolkit/gocui/logical.go new file mode 100644 index 0000000..2c6081b --- /dev/null +++ b/toolkit/gocui/logical.go @@ -0,0 +1,72 @@ +package main + +import ( + // "git.wit.org/wit/gui/toolkit" +) + +var adjusted bool = false + +// expands the logical size of the parents +func (w *cuiWidget) setParentLogical(p *cuiWidget) { + if (w.visable) { + // expand the parent logicalsize to include the widget realSize + if (p.logicalSize.w0 > w.realSize.w0) { + p.logicalSize.w0 = w.realSize.w0 + adjusted = true + } + if (p.logicalSize.h0 > w.realSize.h0) { + p.logicalSize.h0 = w.realSize.h0 + adjusted = true + } + if (p.logicalSize.w1 < w.realSize.w1) { + p.logicalSize.w1 = w.realSize.w1 + adjusted = true + } + if (p.logicalSize.h1 < w.realSize.h1) { + p.logicalSize.h1 = w.realSize.h1 + adjusted = true + } + } else { + // expand the parent logicalsize to include the widget logicalsize + if (p.logicalSize.w0 > w.logicalSize.w0) { + p.logicalSize.w0 = w.logicalSize.w0 + adjusted = true + } + if (p.logicalSize.h0 > w.logicalSize.h0) { + p.logicalSize.h0 = w.logicalSize.h0 + adjusted = true + } + if (p.logicalSize.w1 < w.logicalSize.w1) { + p.logicalSize.w1 = w.logicalSize.w1 + adjusted = true + } + if (p.logicalSize.h1 < w.logicalSize.h1) { + p.logicalSize.h1 = w.logicalSize.h1 + adjusted = true + } + } + if (w.visable) { + // adjust the widget realSize to the top left corner of the logicalsize + if (w.logicalSize.w0 > w.realSize.w0) { + w.realSize.w0 = w.logicalSize.w0 + w.realSize.w1 = w.realSize.w0 + w.realWidth + adjusted = true + } + if (w.logicalSize.h0 > w.realSize.h0) { + w.realSize.h0 = w.logicalSize.h0 + w.realSize.h1 = w.realSize.h0 + w.realHeight + adjusted = true + } + } + w.showWidgetPlacement(logNow, "setParentLogical() widget") + p.showWidgetPlacement(logNow, "setParentLogical() parent") + if (w.id == 0) || (p.id == 0) { + // stop resizing when you hit the root widget + return + } + // pass the logical resizing up + pP := w.parent + if (pP != nil) { + p.setParentLogical(pP) + } +} diff --git a/toolkit/gocui/main.go b/toolkit/gocui/main.go new file mode 100644 index 0000000..11df910 --- /dev/null +++ b/toolkit/gocui/main.go @@ -0,0 +1,40 @@ +// Copyright 2014 The gocui Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "os" +) + +func Init() { + log(logInfo, "Init() of awesome-gocui") + me.defaultWidth = 10 + me.defaultHeight = 2 + me.defaultBehavior = true + + me.horizontalPadding = 20 + me.groupPadding = 2 + me.buttonPadding = 2 +} + +func Exit() { + // TODO: exit correctly + me.baseGui.Close() +} + +func Main(f func()) { + log("start Init()") + + outf, err := os.OpenFile("/tmp/witgui.log", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666) + if err != nil { + exit("error opening file: %v", err) + } + defer outf.Close() + + setOutput(outf) + log("This is a test log entry") + + MouseMain() +} diff --git a/toolkit/gocui/mouse.go b/toolkit/gocui/mouse.go new file mode 100644 index 0000000..196e080 --- /dev/null +++ b/toolkit/gocui/mouse.go @@ -0,0 +1,171 @@ +// Copyright 2014 The gocui Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "errors" + "fmt" + + "github.com/awesome-gocui/gocui" +) + +func MouseMain() { + g, err := gocui.NewGui(gocui.OutputNormal, true) + if err != nil { + panic(err) + } + defer g.Close() + + me.baseGui = g + + g.Cursor = true + g.Mouse = true + + g.SetManagerFunc(layout) + + if err := defaultKeybindings(g); err != nil { + panic(err) + } + + if err := g.MainLoop(); err != nil && !errors.Is(err, gocui.ErrQuit) { + panic(err) + } +} + +func layout(g *gocui.Gui) error { + maxX, maxY := g.Size() + if _, err := g.View("msg"); msgMouseDown && err == nil { + moveMsg(g) + } + if v, err := g.SetView("global", -1, -1, maxX, maxY, 0); err != nil { + if !errors.Is(err, gocui.ErrUnknownView) { + return err + } + v.Frame = false + } + /* + if v, err := g.SetView("but1", 2, 2, 22, 7, 0); err != nil { + if !errors.Is(err, gocui.ErrUnknownView) { + return err + } + v.SelBgColor = gocui.ColorGreen + v.SelFgColor = gocui.ColorBlack + fmt.Fprintln(v, "Button 1 - line 1") + fmt.Fprintln(v, "Button 1 - line 2") + fmt.Fprintln(v, "Button 1 - line 3") + fmt.Fprintln(v, "Button 1 - line 4") + if _, err := g.SetCurrentView("but1"); err != nil { + return err + } + } + if v, err := g.SetView("but2", 24, 2, 44, 4, 0); err != nil { + if !errors.Is(err, gocui.ErrUnknownView) { + return err + } + v.SelBgColor = gocui.ColorGreen + v.SelFgColor = gocui.ColorBlack + fmt.Fprintln(v, "Button 2 - line 1") + } + */ + helplayout(g) + updateHighlightedView(g) + return nil +} + +func quit(g *gocui.Gui, v *gocui.View) error { + return gocui.ErrQuit +} + +func showMsg(g *gocui.Gui, v *gocui.View) error { + var l string + var err error + + if _, err := g.SetCurrentView(v.Name()); err != nil { + return err + } + + _, cy := v.Cursor() + if l, err = v.Line(cy); err != nil { + l = "" + } + + maxX, maxY := g.Size() + if v, err := g.SetView("msg", maxX/2-10, maxY/2, maxX/2+10, maxY/2+2, 0); err == nil || errors.Is(err, gocui.ErrUnknownView) { + v.Clear() + v.SelBgColor = gocui.ColorCyan + v.SelFgColor = gocui.ColorBlack + fmt.Fprintln(v, l) + } + return nil +} + +func updateHighlightedView(g *gocui.Gui) { + mx, my := g.MousePosition() + for _, view := range g.Views() { + view.Highlight = false + } + if v, err := g.ViewByPosition(mx, my); err == nil { + v.Highlight = true + } +} + +func moveMsg(g *gocui.Gui) { + mx, my := g.MousePosition() + if !movingMsg && (mx != initialMouseX || my != initialMouseY) { + movingMsg = true + } + g.SetView("msg", mx-xOffset, my-yOffset, mx-xOffset+20, my-yOffset+2, 0) +} + +func msgDown(g *gocui.Gui, v *gocui.View) error { + initialMouseX, initialMouseY = g.MousePosition() + if vx, vy, _, _, err := g.ViewPosition("msg"); err == nil { + xOffset = initialMouseX - vx + yOffset = initialMouseY - vy + msgMouseDown = true + } + return nil +} + +func globalDown(g *gocui.Gui, v *gocui.View) error { + mx, my := g.MousePosition() + if vx0, vy0, vx1, vy1, err := g.ViewPosition("msg"); err == nil { + if mx >= vx0 && mx <= vx1 && my >= vy0 && my <= vy1 { + return msgDown(g, v) + } + } + globalMouseDown = true + maxX, _ := g.Size() + msg := fmt.Sprintf("Mouse down at: %d,%d", mx, my) + x := mx - len(msg)/2 + if x < 0 { + x = 0 + } else if x+len(msg)+1 > maxX-1 { + x = maxX - 1 - len(msg) - 1 + } + if v, err := g.SetView("globalDown", x, my-1, x+len(msg)+1, my+1, 0); err != nil { + if !errors.Is(err, gocui.ErrUnknownView) { + return err + } + v.WriteString(msg) + } + return nil +} + +func mouseUp(g *gocui.Gui, v *gocui.View) error { + if msgMouseDown { + msgMouseDown = false + if movingMsg { + movingMsg = false + return nil + } else { + g.DeleteView("msg") + } + } else if globalMouseDown { + globalMouseDown = false + g.DeleteView("globalDown") + } + return nil +} diff --git a/toolkit/gocui/place.go b/toolkit/gocui/place.go new file mode 100644 index 0000000..905ebed --- /dev/null +++ b/toolkit/gocui/place.go @@ -0,0 +1,221 @@ +package main + +import ( +// "github.com/awesome-gocui/gocui" + "git.wit.org/wit/gui/toolkit" +) + +var fakeStartWidth int = 80 +var fakeStartHeight int = 0 +func (w *cuiWidget) setFake() { + if (w.visable) { + return + } + t := len(w.name) + // setup fake labels for non-visable things off screen + w.realWidth = t + 2 + w.realHeight = me.defaultHeight + w.realSize.w0 = fakeStartWidth + w.realSize.h0 = fakeStartHeight + w.realSize.w1 = w.realSize.w0 + w.realWidth + w.realSize.h1 = w.realSize.h0 + w.realHeight + fakeStartHeight += 3 + if (fakeStartHeight > 24) { + fakeStartHeight = 0 + fakeStartWidth += 20 + } + w.showWidgetPlacement(logNow, "setFake()") +} + +func findPlace(w *cuiWidget) { + w.visable = true + switch w.widgetType { + case toolkit.Root: + w.visable = false + w.setFake() + case toolkit.Flag: + w.visable = false + w.setFake() + case toolkit.Grid: + w.visable = false + w.setFake() + case toolkit.Box: + w.visable = false + w.setFake() + default: + w.redoBox(true) + } +} + +func (w *cuiWidget) redoBox(draw bool) { + if (w == nil) { + return + } + if (me.rootNode == nil) { + return + } + p := w.parent + if (p == nil) { + log(logInfo, "redoBox()", w.id, "parent == nil") + return + } + + t := len(w.text) + w.visable = true + switch w.widgetType { + case toolkit.Window: + for _, child := range w.children { + child.redoBox(draw) + } + case toolkit.Tab: + for _, child := range w.children { + child.redoBox(draw) + } + case toolkit.Grid: + // hmm + w.logicalSize.w0 = p.nextW + w.logicalSize.h0 = p.nextH + w.logicalSize.w1 = p.nextW + w.logicalSize.h1 = p.nextH + + w.nextW = p.nextW + w.nextH = p.nextH + + var wCount, hCount int + var b bool = true + for _, child := range w.children { + child.redoBox(draw) + if (b) { + wCount += 1 + b = false + } else { + wCount = 0 + w.nextH += 1 + b = true + } + w.nextW = p.nextW + wCount * 20 + w.nextH = p.nextH + hCount * 4 + log(logInfo, "redoBox(GRID) (w,h count)", wCount, hCount, "(X,Y)", w.x, w.y, w.name) + } + w.showWidgetPlacement(logNow, "grid:") + case toolkit.Box: + w.logicalSize.w0 = p.nextW + w.logicalSize.h0 = p.nextH + w.logicalSize.w1 = p.nextW + w.logicalSize.h1 = p.nextH + + w.nextW = p.nextW + w.nextH = p.nextH + for _, child := range w.children { + child.redoBox(draw) + if (w.horizontal) { + log("BOX IS HORIZONTAL", p.nextW, p.nextW, p.name) + log("BOX IS HORIZONTAL", w.nextW, w.nextH, w.name) + log("BOX IS HORIZONTAL") + // expand based on the child width + w.nextW = child.nextW + me.horizontalPadding + // reset height to parent + w.nextH = p.nextH + } else { + log("BOX IS VERTICAL", p.nextW, p.nextW, p.name) + log("BOX IS VERTICAL", w.nextW, w.nextH, w.name) + log("BOX IS VERTICAL") + // go straight down + w.nextW = p.nextW + // expand based on the child height + w.nextH = child.nextH + } + } + w.showWidgetPlacement(logNow, "box:") + case toolkit.Group: + w.realWidth = t + me.buttonPadding + w.realHeight = me.defaultHeight + + w.realSize.w0 = p.nextW + w.realSize.h0 = p.nextH + w.realSize.w1 = w.realSize.w0 + w.realWidth + w.realSize.h1 = w.realHeight + + w.logicalSize.w0 = w.realSize.w0 + w.logicalSize.h0 = w.realSize.h0 + w.logicalSize.w1 = w.realSize.w1 + w.logicalSize.h1 = w.realSize.h1 + + w.nextW = p.nextW + me.groupPadding + w.nextH = p.nextH + me.buttonPadding + for _, child := range w.children { + child.redoBox(draw) + // reset nextW to straight down + w.nextW = p.nextW + 4 + w.nextH = child.nextH + } + // expand the height of the parent now that the group is done + // p.nextW = w.nextW + // p.nextH = w.nextH + w.showWidgetPlacement(logNow, "group:") + default: + w.realWidth = t + 3 + w.realHeight = me.defaultHeight + w.realSize.w0 = p.nextW + w.realSize.h0 = p.nextH + w.realSize.w1 = p.nextW + w.realWidth + w.realSize.h1 = p.nextH + w.realHeight + + w.logicalSize.w0 = p.nextW + w.logicalSize.h0 = p.nextH + w.logicalSize.w1 = p.nextW + w.realWidth + w.logicalSize.h1 = p.nextH + w.realHeight + + w.nextW = w.realSize.w1 + w.nextH = w.realSize.h1 + } +} + +func (w *cuiWidget) boxedPlace() { + t := len(w.name) + if (w.id == 0) { + w.realWidth = 0 + w.realHeight = 0 + return + } + p := w.parent + if (p == nil) { + log(logError, "boxedPlace() parentId widget == nil") + return + } + + w.realWidth = t + 3 + w.realHeight = me.defaultHeight + w.realSize.w0 = p.nextW + w.realSize.h0 = p.nextH + w.realSize.w1 = p.nextW + w.realWidth + w.realSize.h1 = p.nextH + w.realHeight + + w.logicalSize.w0 = p.nextW + w.logicalSize.h0 = p.nextH + w.logicalSize.w1 = p.nextW + w.realWidth + w.logicalSize.h1 = p.nextH + w.realHeight + + w.nextW = w.realSize.w1 + w.nextH = w.realSize.h1 + + w.showWidgetPlacement(logNow, "bP widget") +} + +func (w *cuiWidget) updateLogicalSizes() { + for _, child := range w.children { + child.updateLogicalSizes() + if (w.logicalSize.w0 > child.logicalSize.w0) { + w.logicalSize.w0 = child.logicalSize.w0 + } + if (w.logicalSize.w1 < child.logicalSize.w1) { + w.logicalSize.w1 = child.logicalSize.w1 + } + if (w.logicalSize.h0 > child.logicalSize.h0) { + w.logicalSize.h0 = child.logicalSize.h0 + } + if (w.logicalSize.h1 < child.logicalSize.h1) { + w.logicalSize.h1 = child.logicalSize.h1 + } + } +} diff --git a/toolkit/gocui/plugin.go b/toolkit/gocui/plugin.go index f0f45d3..7c4eee5 100644 --- a/toolkit/gocui/plugin.go +++ b/toolkit/gocui/plugin.go @@ -4,114 +4,77 @@ import ( // if you include more than just this import // then your plugin might be doing something un-ideal (just a guess from 2023/02/27) "git.wit.org/wit/gui/toolkit" - - "github.com/awesome-gocui/gocui" ) -// This is a map between the widgets in wit/gui and the internal structures of gocui -var viewWidget map[*gocui.View]*toolkit.Widget -var stringWidget map[string]*toolkit.Widget - func Quit() { - baseGui.Close() + me.baseGui.Close() } -// This lists out the know mappings -func listMap() { - for v, w := range viewWidget { - log("view =", v.Name, "widget name =", w.Name) - } - for s, w := range stringWidget { - log("string =", s, "widget =", w) +func Action(a *toolkit.Action) { + log(logInfo, "Action() START", a.WidgetId, a.ActionType, a.WidgetType, a.Name) + w := findWidget(a.WidgetId, me.rootNode) + switch a.ActionType { + case toolkit.Add: + w = setupWidget(a) + findPlace(w) + w.drawView() + case toolkit.Show: + if (a.B) { + w.drawView() + } else { + w.hideWidgets() + } + case toolkit.Set: + w.Set(a.A) + case toolkit.SetText: + w.SetText(a.S) + case toolkit.AddText: + w.AddText(a.S) + case toolkit.Move: + log(logNow, "attempt to move() =", a.ActionType, a.WidgetType, a.Name) + default: + log(logError, "Action() Unknown =", a.ActionType, a.WidgetType, a.Name) } + log(logInfo, "Action() END") } - -// -// This should be called ? -// Pass() ? -// This handles all interaction between the wit/gui package (what golang knows about) -// and this plugin that talks to the OS and does scary and crazy things to make -// a GUI on whatever OS or whatever GUI toolkit you might have (GTK, QT, WASM, libcurses) -// -// Once you are here, you should be in a protected goroutine created by the golang wit/gui package -// -// TODO: make sure you can't escape this goroutine -// -func Send(p *toolkit.Widget, c *toolkit.Widget) { - if (p == nil) { - log(debugPlugin, "Send() parent = nil") - } else { - log(debugPlugin, "Send() parent =", p.Name, ",", p.Type) +func (w *cuiWidget) AddText(text string) { + if (w == nil) { + log(logNow, "widget is nil") + return + } + w.vals = append(w.vals, text) + for i, s := range w.vals { + log(logNow, "AddText()", w.name, i, s) } - log(debugPlugin, "Send() child =", c.Name, ",", c.Type) + w.SetText(text) +} - /* - if (c.Action == "SetMargin") { - log(debugError, "need to implement SetMargin here") - setMargin(c, c.B) +func (w *cuiWidget) SetText(text string) { + if (w == nil) { + log(logNow, "widget is nil") return } - */ + w.text = text + w.s = text + w.textResize() + me.baseGui.DeleteView(w.cuiName) + w.drawView() +} - switch c.Type { - /* - case toolkit.Window: - // doWindow(c) - case toolkit.Tab: - // doTab(p, c) - */ - case toolkit.Group: - newGroup(p, c) - case toolkit.Button: - newButton(p, c) - /* - case toolkit.Checkbox: - // doCheckbox(p, c) - case toolkit.Label: - // doLabel(p, c) - case toolkit.Textbox: - // doTextbox(p, c) - case toolkit.Slider: - // doSlider(p, c) - case toolkit.Spinner: - // doSpinner(p, c) - case toolkit.Dropdown: - // doDropdown(p, c) - case toolkit.Combobox: - // doCombobox(p, c) - case toolkit.Grid: - // doGrid(p, c) - */ - /* - case toolkit.Flag: - // log(debugFlags, "plugin Send() flag parent =", p.Name, p.Type) - // log(debugFlags, "plugin Send() flag child =", c.Name, c.Type) - // log(debugFlags, "plugin Send() flag child.Action =", c.Action) - // log(debugFlags, "plugin Send() flag child.S =", c.S) - // log(debugFlags, "plugin Send() flag child.B =", c.B) - // log(debugFlags, "plugin Send() what to flag?") - // should set the checkbox to this value - switch c.S { - case "Toolkit": - debugToolkit = c.B - case "Change": - debugChange = c.B - case "Plugin": - debugPlugin = c.B - case "Flags": - debugFlags = c.B - case "Error": - debugError = c.B - case "Show": - ShowDebug() - default: - log(debugError, "Can't set unknown flag", c.S) - } - */ +func (w *cuiWidget) Set(val any) { + log(logInfo, "Set() value =", val) + var a toolkit.Action + a.ActionType = toolkit.Set + + switch v := val.(type) { + case bool: + w.b = val.(bool) + case string: + w.SetText(val.(string)) + case int: + w.i = val.(int) default: - log(debugError, "plugin Send() unknown parent =", p.Name, p.Type) - log(debugError, "plugin Send() unknown child =", c.Name, c.Type) - log(debugError, "plugin Send() Don't know how to do", c.Type, "yet") + log(logError, "Set() unknown type =", v, "a =", a) } } diff --git a/toolkit/gocui/structs.go b/toolkit/gocui/structs.go new file mode 100644 index 0000000..a3f0207 --- /dev/null +++ b/toolkit/gocui/structs.go @@ -0,0 +1,142 @@ +// LICENSE: same as the go language itself +// Copyright 2023 WIT.COM + +// all structures and variables are local (aka lowercase) +// since the plugin should be isolated to access only +// by functions() to insure everything here is run +// inside a dedicated goroutine + +package main + +import ( + "fmt" + "sync" + "github.com/awesome-gocui/gocui" + "git.wit.org/wit/gui/toolkit" +) + +// const delta = 1 + +// It's probably a terrible idea to call this 'me' +var me config + +type config struct { + baseGui *gocui.Gui // the main gocui handle + rootNode *cuiWidget // the base of the binary tree. it should have id == 0 + ctrlDown *cuiWidget // shown if you click the mouse when the ctrl key is pressed + + callback func(int) + helpLabel *gocui.View + + defaultBehavior bool + defaultWidth int + defaultHeight int + nextW int // where the next window or tab flag should go + + bookshelf bool // do you want things arranged in the box like a bookshelf or a stack? + canvas bool // if set to true, the windows are a raw canvas + menubar bool // for windows + stretchy bool // expand things like buttons to the maximum size + padded bool // add space between things like buttons + margin bool // add space around the frames of windows + + horizontalPadding int + groupPadding int + buttonPadding int +} + +/* +// This is a map between the widgets in wit/gui and the internal structures of gocui +var viewWidget map[*gocui.View]*toolkit.Widget +var stringWidget map[string]*toolkit.Widget +*/ + +var ( +// g *gocui.Gui +// Custom func(string) + + initialMouseX, initialMouseY, xOffset, yOffset int + globalMouseDown, msgMouseDown, movingMsg bool + +// err error +) + +// the gocui way +// the logical size of the widget +// corner starts at in the upper left corner +type rectType struct { + // this is the gocui way + w0, h0, w1, h1 int // left top right bottom +} + +/* +type realSizeT struct { + width, height int +} +*/ + + +type cuiWidget struct { + id int // widget ID + // parentId int + widgetType toolkit.WidgetType + + name string // a descriptive name of the widget + text string // the current text being displayed + cuiName string // what gocui uses to reference the widget + + vals []string // dropdown menu options + + visable bool // widget types like 'box' are 'false' + realWidth int // the real width + realHeight int // the real height + realSize rectType // the display size of this widget + logicalSize rectType // the logical size. Includes all the child widgets + + nextW int + nextH int + + // things from toolkit/action + b bool + i int + s string + x int + y int + width int + height int + + //deprecate +// nextX int +// nextY int + + // horizontal=true means layout widgets like books on a bookshelf + // horizontal=false means layout widgets like books in a stack + horizontal bool `default:false` + + tainted bool + v *gocui.View + + // writeMutex protects locks the write process + writeMutex sync.Mutex + + parent *cuiWidget + children []*cuiWidget +} + +// from the gocui devs: +// Write appends a byte slice into the view's internal buffer. Because +// View implements the io.Writer interface, it can be passed as parameter +// of functions like fmt.Fprintf, fmt.Fprintln, io.Copy, etc. Clear must +// be called to clear the view's buffer. + +func (w *cuiWidget) Write(p []byte) (n int, err error) { + w.tainted = true + w.writeMutex.Lock() + defer w.writeMutex.Unlock() + // v.makeWriteable(v.wx, v.wy) + // v.writeRunes(bytes.Runes(p)) + fmt.Fprintln(w.v, p) + log(logNow, "widget.Write()") + + return len(p), nil +} diff --git a/toolkit/gocui/tab.go b/toolkit/gocui/tab.go new file mode 100644 index 0000000..42e5127 --- /dev/null +++ b/toolkit/gocui/tab.go @@ -0,0 +1,88 @@ +package main + +// implements widgets 'Window' and 'Tab' + +import ( + "git.wit.org/wit/gui/toolkit" +// "github.com/awesome-gocui/gocui" +) + +func (w *cuiWidget) hideWidgets() { + switch w.widgetType { + case toolkit.Root: + case toolkit.Flag: + case toolkit.Window: + case toolkit.Tab: + case toolkit.Box: + case toolkit.Grid: + default: + if (w.v != nil) { + me.baseGui.DeleteView(w.cuiName) + w.v = nil + } + } + for _, child := range w.children { + child.hideWidgets() + } +} + +func (w *cuiWidget) showWidgets() { + w.drawView() + for _, child := range w.children { + child.showWidgets() + } +} + +func (w *cuiWidget) redoTabs(draw bool) { + log(logNow, "redoTabs() START", w.name) + if (w == nil) { + return + } + if (w.widgetType == toolkit.Root) { + w.logicalSize.w0 = 0 + w.logicalSize.h0 = 0 + w.logicalSize.w1 = 0 + w.logicalSize.h1 = 0 + + w.nextW = 2 + w.nextH = 2 + } + + log(logNow, "redoTabs() about to check for window and tab ", w.name) + w.text = w.name + t := len(w.text) + if ((w.widgetType == toolkit.Window) || (w.widgetType == toolkit.Tab)) { + log(logNow, "redoTabs() in Window and Tab", w.name) + w.realWidth = t + 2 + w.realHeight = me.defaultHeight + + w.realSize.w0 = me.rootNode.logicalSize.w1 + w.realSize.h0 = 0 + w.realSize.w1 = w.realSize.w0 + w.realWidth + w.realSize.h1 = w.realHeight + + w.logicalSize.w0 = 0 + w.logicalSize.h0 = 0 + w.logicalSize.w1 = 0 + w.logicalSize.h1 = w.realHeight + + // spaces right 1 space to next tab widget + // spaces down 1 line to the next widget + w.nextW = 2 + w.nextH = w.realHeight + 1 + + me.rootNode.logicalSize.w1 = w.realSize.w1 + 1 + me.rootNode.logicalSize.h1 = 0 + + me.baseGui.DeleteView(w.cuiName) + w.v = nil + w.drawView() + w.showWidgetPlacement(logNow, "redoTabs()") + } + + log(logNow, "redoTabs() about to for loop children", w.name) + for _, child := range w.children { + log(logNow, "redoTabs() got to child", child.name) + child.redoTabs(draw) + } +} diff --git a/toolkit/gocui/view.go b/toolkit/gocui/view.go new file mode 100644 index 0000000..d1d4b51 --- /dev/null +++ b/toolkit/gocui/view.go @@ -0,0 +1,86 @@ +package main + +import ( + "fmt" + "errors" + "strconv" + "bufio" + "strings" + + "github.com/awesome-gocui/gocui" +// "git.wit.org/wit/gui/toolkit" +) + +func splitLines(s string) []string { + var lines []string + sc := bufio.NewScanner(strings.NewReader(s)) + for sc.Scan() { + lines = append(lines, sc.Text()) + } + return lines +} + +func (w *cuiWidget) textResize() { + var width, height int + + for i, s := range splitLines(w.text) { + log(logNow, "textResize() len =", len(s), i, s) + if (width < len(s)) { + width = len(s) + } + height = i + } + w.realWidth = width + 3 + w.realHeight = me.defaultHeight + height + w.realSize.w1 = w.realSize.w0 + w.realWidth + w.realSize.h1 = w.realSize.h0 + w.realHeight + w.showWidgetPlacement(logNow, "textResize()") +} + +func (w *cuiWidget) drawView() { + var err error + if (w.cuiName == "") { + log(logError, "drawView() w.cuiName was not set for widget", w) + w.cuiName = strconv.Itoa(w.id) + } + + if (w.v != nil) { + log(logInfo, "drawView() w.v already defined for widget", w) + v, _ := me.baseGui.View(w.cuiName) + if (v == nil) { + log(logError, "drawView() ERROR view does not really exist", w) + w.v = nil + } else { + return + } + } + + v, _ := me.baseGui.View(w.cuiName) + if (v != nil) { + log(logError, "drawView() already defined for name", w.cuiName) + w.v = v + return + } + + a := w.realSize.w0 + b := w.realSize.h0 + c := w.realSize.w1 + d := w.realSize.h1 + + w.v, err = me.baseGui.SetView(w.cuiName, a, b, c, d, 0) + if err == nil { + log(logError, "drawView() internal plugin error err = nil") + return + } + if !errors.Is(err, gocui.ErrUnknownView) { + log(logError, "drawView() internal plugin error error.IS()", err) + return + } + + me.baseGui.SetKeybinding(w.v.Name(), gocui.MouseLeft, gocui.ModNone, click) + + w.v.Wrap = true + fmt.Fprintln(w.v, " " + w.text) + + // w.SetDefaultWidgetColor() +} diff --git a/toolkit/gocui/views.go b/toolkit/gocui/views.go deleted file mode 100644 index 8b17acf..0000000 --- a/toolkit/gocui/views.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2014 The gocui Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "errors" - "fmt" - "strings" - - "github.com/awesome-gocui/gocui" - // "git.wit.org/wit/gui/toolkit" -) - -func newView(g *gocui.Gui) error { - maxX, maxY := g.Size() - name := fmt.Sprintf("v%v", idxView) - v, err := g.SetView(name, maxX/2-5, maxY/2-5, maxX/2+5, maxY/2+5, 0) - if err == nil { - return err - } - if !errors.Is(err, gocui.ErrUnknownView) { - return err - } - - v.Wrap = true - fmt.Fprintln(v, strings.Repeat(name+" ", 30)) - - if _, err := g.SetCurrentView(name); err != nil { - return err - } - - views = append(views, name) - curView = len(views) - 1 - idxView += 1 - return nil -} - -func delView(g *gocui.Gui) error { - if len(views) <= 1 { - return nil - } - - if err := g.DeleteView(views[curView]); err != nil { - return err - } - views = append(views[:curView], views[curView+1:]...) - - return nextView(g, false) -} - -func nextView(g *gocui.Gui, disableCurrent bool) error { - next := curView + 1 - if next > len(views)-1 { - next = 0 - } - - if _, err := g.SetCurrentView(views[next]); err != nil { - return err - } - - curView = next - return nil -} - -func moveView(g *gocui.Gui, v *gocui.View, dx, dy int) error { - name := v.Name() - x0, y0, x1, y1, err := g.ViewPosition(name) - if err != nil { - return err - } - log(x0, y0, x1, y1) - if _, err := g.SetView(name, x0+dx, y0+dy, x1+dx, y1+dy, 0); err != nil { - return err - } - x0, y0, x1, y1, err = g.ViewPosition(name) - log(x0, y0, x1, y1) - return nil -} diff --git a/toolkit/gocui/window.go b/toolkit/gocui/window.go deleted file mode 100644 index 67948d6..0000000 --- a/toolkit/gocui/window.go +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import ( - "git.wit.org/wit/gui/toolkit" -) - -func NewWindow(w *toolkit.Widget) { - if (w == nil) { - log("wit/gui plugin error. widget == nil") - return - } - if (w.Name == "") { - w.Name = "nil newWindow" - } - log("gui.gocui.AddWindow", w.Name) -} |
