From 1a1881aa4e39e256126972c0cbe7f0db93ee20ec Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Fri, 31 Jan 2025 08:57:32 -0600 Subject: name changes after I haven't looked at this code for some time --- click.go | 243 ----------------------------------------------------- eventKeyboard.go | 90 ++++++++++++++++++++ eventMouse.go | 112 ++++++++++++++++++++++++ eventMouseClick.go | 243 +++++++++++++++++++++++++++++++++++++++++++++++++++++ eventsHandler.go | 89 -------------------- init.go | 179 +++++++++++++++++++++++++++++++++++++++ main.go | 179 --------------------------------------- mouse.go | 107 ----------------------- tree.go | 5 ++ 9 files changed, 629 insertions(+), 618 deletions(-) delete mode 100644 click.go create mode 100644 eventKeyboard.go create mode 100644 eventMouse.go create mode 100644 eventMouseClick.go delete mode 100644 eventsHandler.go create mode 100644 init.go delete mode 100644 main.go delete mode 100644 mouse.go diff --git a/click.go b/click.go deleted file mode 100644 index 919ed87..0000000 --- a/click.go +++ /dev/null @@ -1,243 +0,0 @@ -package main - -import ( - "errors" - - "github.com/awesome-gocui/gocui" - "go.wit.com/log" - "go.wit.com/widget" -) - -func (w *guiWidget) doWidgetClick() { - switch w.WidgetType { - /* - case widget.Root: - // THIS IS THE BEGINING OF THE LAYOUT - log.Log(GOCUI, "doWidgetClick()", w.String()) - wRoot := me.treeRoot.TK.(*guiWidget) - wRoot.redoWindows(0, 0) - case widget.Flag: - log.Log(GOCUI, "doWidgetClick() FLAG widget name =", w.String()) - log.Log(GOCUI, "doWidgetClick() if this is the dropdown menu, handle it here?") - */ - case widget.Window: - log.Log(GOCUI, "doWidgetClick() START on window", w.String()) - // if the user clicked on the current window, do nothing - /* Ignore this for now and redraw the window anyway - if me.currentWindow == w { - if !w.active { - return - } - } - */ - - // if there is a current window, hide it - if me.currentWindow != nil { - me.currentWindow.setColor(&colorWindow) - me.currentWindow.hideWidgets() - me.currentWindow.isCurrent = false - } - - // now set this window as the current window - me.currentWindow = w - me.currentWindow.isCurrent = true - - // draw the current window - log.Log(GOCUI, "doWidgetClick() set currentWindow to", w.String()) - w.setColor(&colorActiveW) - w.DrawAt(3, 2) - w.placeWidgets(3, 2) // compute the sizes & places for each widget - w.active = false - w.showWidgets() - /* - hideFake() - showDebug = true - */ - case widget.Group: - if w.active { - w.active = false - w.placeWidgets(w.startW, w.startH) - w.showWidgets() - } else { - w.active = true - for _, child := range w.children { - child.hideWidgets() - } - } - // w.dumpTree("click end") - case widget.Checkbox: - if w.node.State.Checked { - log.Log(WARN, "checkbox is being set to false") - w.node.State.Checked = false - w.setCheckbox() - } else { - log.Log(WARN, "checkbox is being set to true") - w.node.State.Checked = true - w.setCheckbox() - } - me.myTree.SendUserEvent(w.node) - case widget.Grid: - newR := w.realGocuiSize() - - // w,h := n.logicalSize() - // w := newR.w1 - newR.w0 - // h := newR.h1 - newR.h0 - - w.placeGrid(newR.w0, newR.h0) - w.showWidgets() - case widget.Box: - // w.showWidgetPlacement(logNow, "drawTree()") - if w.node.State.Direction == widget.Horizontal { - log.Log(GOCUI, "BOX IS HORIZONTAL", w.String()) - } else { - log.Log(GOCUI, "BOX IS VERTICAL", w.String()) - } - w.placeWidgets(w.startW, w.startH) - w.toggleTree() - case widget.Button: - // doUserEvent(n) - me.myTree.SendFromUser(w.node) - case widget.Combobox: - log.Log(GOCUI, "do the combobox here") - w.showDropdown() - me.dropdownW = w - case widget.Dropdown: - log.Log(GOCUI, "do the dropdown here") - w.showDropdown() - me.dropdownW = w - default: - } -} - -func click(g *gocui.Gui, v *gocui.View) error { - mouseW, mouseH := me.baseGui.MousePosition() - - log.Log(GOCUI, "click() START gocui name:", v.Name(), mouseW, mouseH) - w := findUnderMouse() - - // if the dropdown view is visible, process it no matter what - if me.dropdownV.Visible() { - me.dropdownV.dropdownClicked(mouseW, mouseH) - } - if w == me.dropdownV { - return nil - } - - if w == nil { - log.Error(errors.New("click() could not find widget for view =" + v.Name())) - } else { - log.Log(GOCUI, "click() Found widget =", w.node.WidgetId, w.String(), ",", w.labelN) - w.doWidgetClick() - } - - rootTK := me.treeRoot.TK.(*guiWidget) - realTK := rootTK.findWidgetByView(v) - if realTK == nil { - log.Error(errors.New("toolkit click() out of reality with gocui. v.Name() not in binary tree " + v.Name())) - log.Log(GOCUI, "click() END FAILURE ON gocui v.Name =", v.Name()) - // return nil // otherwise gocui exits - } - - // double check the widget view really still exists - nameTK := rootTK.findWidgetByName(v.Name()) - if nameTK == nil { - log.Error(errors.New("toolkit click() out of reality with gocui. v.Name() not in binary tree " + v.Name())) - return nil - } - if nameTK.v == nil { - log.Log(GOCUI, "click() maybe this widget has had it's view distroyed?", nameTK.cuiName, nameTK.WidgetType) - log.Log(GOCUI, "yep. it's gone now") - return nil - } - - // SetCurrentView dies if it's sent an non-existent view - if _, err := g.SetCurrentView(v.Name()); err != nil { - log.Log(GOCUI, "click() END v.Name =", v.Name(), "err =", err) - // return err // return causes gocui.MainLoop() to exit. Do we ever want that to happen here? - return nil - } - - log.Log(GOCUI, "click() END gocui name:", v.Name()) - return nil -} - -func findUnderMouse() *guiWidget { - var widgets []*guiWidget - var f func(w *guiWidget) - w, h := me.baseGui.MousePosition() - - // find buttons that are below where the mouse button click - f = func(widget *guiWidget) { - // ignore widgets that are not visible - if widget.Visible() { - if (widget.gocuiSize.w0 <= w) && (w <= widget.gocuiSize.w1) && - (widget.gocuiSize.h0 <= h) && (h <= widget.gocuiSize.h1) { - widgets = append(widgets, widget) - } - } - - for _, child := range widget.children { - f(child) - } - } - rootW := me.treeRoot.TK.(*guiWidget) - f(rootW) - - // search through all the widgets that were below the mouse click - var found *guiWidget - for _, w := range widgets { - // prioritize window buttons. This means if some code covers - // up the window widgets, then it will ignore everything else - // and allow the user (hopefully) to redraw or switch windows - // TODO: display the window widgets on top - if w.WidgetType == widget.Window { - return w - } - } - - // return anything else that is interactive - for _, w := range widgets { - if w.WidgetType == widget.Button { - return w - } - if w.WidgetType == widget.Combobox { - return w - } - if w.WidgetType == widget.Checkbox { - return w - } - w.showWidgetPlacement("findUnderMouse() found something unknown") - found = w - } - // maybe something else was found - return found -} - -// find the widget under the mouse click -func ctrlDown(g *gocui.Gui, v *gocui.View) error { - var found *guiWidget - // var widgets []*node - // var f func (n *node) - found = findUnderMouse() - if me.ctrlDown == nil { - setupCtrlDownWidget() - - var tk *guiWidget - tk = me.ctrlDown.TK.(*guiWidget) - tk.labelN = found.String() - tk.cuiName = "ctrlDown" - // me.ctrlDown.parent = me.rootNode - } - var tk *guiWidget - tk = me.ctrlDown.TK.(*guiWidget) - if found == nil { - found = me.treeRoot.TK.(*guiWidget) - } - tk.labelN = found.String() - newR := found.realGocuiSize() - tk.gocuiSize.w0 = newR.w0 - tk.gocuiSize.h0 = newR.h0 - tk.gocuiSize.w1 = newR.w1 - tk.gocuiSize.h1 = newR.h1 - return nil -} diff --git a/eventKeyboard.go b/eventKeyboard.go new file mode 100644 index 0000000..f8bcf41 --- /dev/null +++ b/eventKeyboard.go @@ -0,0 +1,90 @@ +// Copyright 2017-2025 WIT.COM Inc. All rights reserved. +// Use of this source code is (now) governed by the GPL 3.0 + +package main + +import ( + "github.com/awesome-gocui/gocui" +) + +// tells 'gocui' what to call based on what key was pressed +func registerHandlers(g *gocui.Gui) { + g.SetKeybinding("", '?', gocui.ModNone, theHelp) // 'h' toggles on and off the help menu + g.SetKeybinding("", 'r', gocui.ModNone, widgetRefresh) // screen refresh + g.SetKeybinding("", 'w', gocui.ModNone, doWindow) // close all windows + g.SetKeybinding("", 'q', gocui.ModNone, doExit) // exit + g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, doExit) // exit + g.SetKeybinding("", gocui.KeyCtrlV, gocui.ModNone, doPanic) // forced panic + + // debugging + g.SetKeybinding("", 'd', gocui.ModNone, theLetterD) // 'd' toggles on and off debugging buttons + g.SetKeybinding("", gocui.KeyCtrlD, gocui.ModNone, openDebuggger) // open the debugger + g.SetKeybinding("", 'L', gocui.ModNone, dumpWidgets) // list all widgets + g.SetKeybinding("", 'M', gocui.ModNone, dumpWidgetPlacement) // list all widgets with positions + +} + +func doExit(g *gocui.Gui, v *gocui.View) error { + return nil +} + +func doPanic(g *gocui.Gui, v *gocui.View) error { + return nil +} + +func dumpWidgets(g *gocui.Gui, v *gocui.View) error { + return nil +} + +func dumpWidgetPlacement(g *gocui.Gui, v *gocui.View) error { + return nil +} + +func openDebuggger(g *gocui.Gui, v *gocui.View) error { + return nil +} + +// is run whenever anyone hits 'd' (in an open space) +func theLetterD(g *gocui.Gui, v *gocui.View) error { + // widgets that don't have physical existance in + // a display toolkit are hidden. In the case + // of gocui, they are set as not 'visible' and put offscreen + // or have the size set to zero + // (hopefully anyway) lots of things with the toolkit + // still don't work + + fakeStartWidth = me.FakeW + fakeStartHeight = me.TabH + me.FramePadH + if showDebug { + showFake() + showDebug = false + } else { + hideFake() + showDebug = true + } + return nil +} + +func theHelp(g *gocui.Gui, v *gocui.View) error { + if showHelp { + helplayout() + showHelp = false + if me.dropdownV == nil { + me.dropdownV = makeDropdownView("addWidget() ddview") + } + me.dropdownV.Show() + } else { + me.baseGui.DeleteView("help") + showHelp = true + me.dropdownV.Hide() + } + return nil +} + +func widgetRefresh(g *gocui.Gui, v *gocui.View) error { + return nil +} + +func doWindow(g *gocui.Gui, v *gocui.View) error { + return nil +} diff --git a/eventMouse.go b/eventMouse.go new file mode 100644 index 0000000..88702c3 --- /dev/null +++ b/eventMouse.go @@ -0,0 +1,112 @@ +// Copyright 2017-2025 WIT.COM Inc. All rights reserved. +// Use of this source code is governed by the GPL 3.0 + +// NOTE: our code is under the GPL, not BSD + +// note by jcarr@wit.com in 2025: this is one of the coolest +// things ever what this does. I've tried to improve +// it while I've been working on making a gocui +// GO plugin so it can be generalized as a useful +// console interface. Well done everyone that has +// contributed to this gocui project !!! + +// 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" + + "go.wit.com/log" +) + +// this function uses the mouse position to highlight & unhighlight things +// this is run every time the user moves the mouse over the terminal window +func mouseMove(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 msgDown(g *gocui.Gui, v *gocui.View) error { + initialMouseX, initialMouseY = g.MousePosition() + + // debugging output + log.Log(GOCUI, "msgDown() X,Y", initialMouseX, initialMouseY) + + // + vx, vy, _, _, err := g.ViewPosition("msg") + if err == nil { + xOffset = initialMouseX - vx + yOffset = initialMouseY - vy + msgMouseDown = true + } + return nil +} + +func mouseUp(g *gocui.Gui, v *gocui.View) error { + w, h := g.MousePosition() + + dropdownUnclicked(w, h) + + if msgMouseDown { + msgMouseDown = false + if movingMsg { + movingMsg = false + return nil + } else { + g.DeleteView("msg") + } + } else if globalMouseDown { + globalMouseDown = false + g.DeleteView("globalDown") + } + return nil +} + +// func isMouseInMsg + +// this is where you have to figure out what +// widget was underneath so you can active +// the right response for the toolkit user's app +func mouseDown(g *gocui.Gui, v *gocui.View) error { + mx, my := g.MousePosition() + + vx0, vy0, vx1, vy1, err := g.ViewPosition("msg") + if err == nil { + if mx >= vx0 && mx <= vx1 && my >= vy0 && my <= vy1 { + return msgDown(g, v) + } + } + globalMouseDown = true + + maxX, _ := g.Size() + + findUnderMouse() + + msg := fmt.Sprintf("mouseDown() Mouse really down at: %d,%d", mx, my) + // dropdownClicked(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 + } + log.Log(GOCUI, "mouseDown() about to write out message to 'globalDown' view. msg =", msg) + 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 +} diff --git a/eventMouseClick.go b/eventMouseClick.go new file mode 100644 index 0000000..919ed87 --- /dev/null +++ b/eventMouseClick.go @@ -0,0 +1,243 @@ +package main + +import ( + "errors" + + "github.com/awesome-gocui/gocui" + "go.wit.com/log" + "go.wit.com/widget" +) + +func (w *guiWidget) doWidgetClick() { + switch w.WidgetType { + /* + case widget.Root: + // THIS IS THE BEGINING OF THE LAYOUT + log.Log(GOCUI, "doWidgetClick()", w.String()) + wRoot := me.treeRoot.TK.(*guiWidget) + wRoot.redoWindows(0, 0) + case widget.Flag: + log.Log(GOCUI, "doWidgetClick() FLAG widget name =", w.String()) + log.Log(GOCUI, "doWidgetClick() if this is the dropdown menu, handle it here?") + */ + case widget.Window: + log.Log(GOCUI, "doWidgetClick() START on window", w.String()) + // if the user clicked on the current window, do nothing + /* Ignore this for now and redraw the window anyway + if me.currentWindow == w { + if !w.active { + return + } + } + */ + + // if there is a current window, hide it + if me.currentWindow != nil { + me.currentWindow.setColor(&colorWindow) + me.currentWindow.hideWidgets() + me.currentWindow.isCurrent = false + } + + // now set this window as the current window + me.currentWindow = w + me.currentWindow.isCurrent = true + + // draw the current window + log.Log(GOCUI, "doWidgetClick() set currentWindow to", w.String()) + w.setColor(&colorActiveW) + w.DrawAt(3, 2) + w.placeWidgets(3, 2) // compute the sizes & places for each widget + w.active = false + w.showWidgets() + /* + hideFake() + showDebug = true + */ + case widget.Group: + if w.active { + w.active = false + w.placeWidgets(w.startW, w.startH) + w.showWidgets() + } else { + w.active = true + for _, child := range w.children { + child.hideWidgets() + } + } + // w.dumpTree("click end") + case widget.Checkbox: + if w.node.State.Checked { + log.Log(WARN, "checkbox is being set to false") + w.node.State.Checked = false + w.setCheckbox() + } else { + log.Log(WARN, "checkbox is being set to true") + w.node.State.Checked = true + w.setCheckbox() + } + me.myTree.SendUserEvent(w.node) + case widget.Grid: + newR := w.realGocuiSize() + + // w,h := n.logicalSize() + // w := newR.w1 - newR.w0 + // h := newR.h1 - newR.h0 + + w.placeGrid(newR.w0, newR.h0) + w.showWidgets() + case widget.Box: + // w.showWidgetPlacement(logNow, "drawTree()") + if w.node.State.Direction == widget.Horizontal { + log.Log(GOCUI, "BOX IS HORIZONTAL", w.String()) + } else { + log.Log(GOCUI, "BOX IS VERTICAL", w.String()) + } + w.placeWidgets(w.startW, w.startH) + w.toggleTree() + case widget.Button: + // doUserEvent(n) + me.myTree.SendFromUser(w.node) + case widget.Combobox: + log.Log(GOCUI, "do the combobox here") + w.showDropdown() + me.dropdownW = w + case widget.Dropdown: + log.Log(GOCUI, "do the dropdown here") + w.showDropdown() + me.dropdownW = w + default: + } +} + +func click(g *gocui.Gui, v *gocui.View) error { + mouseW, mouseH := me.baseGui.MousePosition() + + log.Log(GOCUI, "click() START gocui name:", v.Name(), mouseW, mouseH) + w := findUnderMouse() + + // if the dropdown view is visible, process it no matter what + if me.dropdownV.Visible() { + me.dropdownV.dropdownClicked(mouseW, mouseH) + } + if w == me.dropdownV { + return nil + } + + if w == nil { + log.Error(errors.New("click() could not find widget for view =" + v.Name())) + } else { + log.Log(GOCUI, "click() Found widget =", w.node.WidgetId, w.String(), ",", w.labelN) + w.doWidgetClick() + } + + rootTK := me.treeRoot.TK.(*guiWidget) + realTK := rootTK.findWidgetByView(v) + if realTK == nil { + log.Error(errors.New("toolkit click() out of reality with gocui. v.Name() not in binary tree " + v.Name())) + log.Log(GOCUI, "click() END FAILURE ON gocui v.Name =", v.Name()) + // return nil // otherwise gocui exits + } + + // double check the widget view really still exists + nameTK := rootTK.findWidgetByName(v.Name()) + if nameTK == nil { + log.Error(errors.New("toolkit click() out of reality with gocui. v.Name() not in binary tree " + v.Name())) + return nil + } + if nameTK.v == nil { + log.Log(GOCUI, "click() maybe this widget has had it's view distroyed?", nameTK.cuiName, nameTK.WidgetType) + log.Log(GOCUI, "yep. it's gone now") + return nil + } + + // SetCurrentView dies if it's sent an non-existent view + if _, err := g.SetCurrentView(v.Name()); err != nil { + log.Log(GOCUI, "click() END v.Name =", v.Name(), "err =", err) + // return err // return causes gocui.MainLoop() to exit. Do we ever want that to happen here? + return nil + } + + log.Log(GOCUI, "click() END gocui name:", v.Name()) + return nil +} + +func findUnderMouse() *guiWidget { + var widgets []*guiWidget + var f func(w *guiWidget) + w, h := me.baseGui.MousePosition() + + // find buttons that are below where the mouse button click + f = func(widget *guiWidget) { + // ignore widgets that are not visible + if widget.Visible() { + if (widget.gocuiSize.w0 <= w) && (w <= widget.gocuiSize.w1) && + (widget.gocuiSize.h0 <= h) && (h <= widget.gocuiSize.h1) { + widgets = append(widgets, widget) + } + } + + for _, child := range widget.children { + f(child) + } + } + rootW := me.treeRoot.TK.(*guiWidget) + f(rootW) + + // search through all the widgets that were below the mouse click + var found *guiWidget + for _, w := range widgets { + // prioritize window buttons. This means if some code covers + // up the window widgets, then it will ignore everything else + // and allow the user (hopefully) to redraw or switch windows + // TODO: display the window widgets on top + if w.WidgetType == widget.Window { + return w + } + } + + // return anything else that is interactive + for _, w := range widgets { + if w.WidgetType == widget.Button { + return w + } + if w.WidgetType == widget.Combobox { + return w + } + if w.WidgetType == widget.Checkbox { + return w + } + w.showWidgetPlacement("findUnderMouse() found something unknown") + found = w + } + // maybe something else was found + return found +} + +// find the widget under the mouse click +func ctrlDown(g *gocui.Gui, v *gocui.View) error { + var found *guiWidget + // var widgets []*node + // var f func (n *node) + found = findUnderMouse() + if me.ctrlDown == nil { + setupCtrlDownWidget() + + var tk *guiWidget + tk = me.ctrlDown.TK.(*guiWidget) + tk.labelN = found.String() + tk.cuiName = "ctrlDown" + // me.ctrlDown.parent = me.rootNode + } + var tk *guiWidget + tk = me.ctrlDown.TK.(*guiWidget) + if found == nil { + found = me.treeRoot.TK.(*guiWidget) + } + tk.labelN = found.String() + newR := found.realGocuiSize() + tk.gocuiSize.w0 = newR.w0 + tk.gocuiSize.h0 = newR.h0 + tk.gocuiSize.w1 = newR.w1 + tk.gocuiSize.h1 = newR.h1 + return nil +} diff --git a/eventsHandler.go b/eventsHandler.go deleted file mode 100644 index a443431..0000000 --- a/eventsHandler.go +++ /dev/null @@ -1,89 +0,0 @@ -// WIT.COM Inc. 2017-2025 GPL 3.0 - -package main - -import ( - "github.com/awesome-gocui/gocui" -) - -// tells 'gocui' what to call based on what key was pressed -func registerHandlers(g *gocui.Gui) { - g.SetKeybinding("", '?', gocui.ModNone, theHelp) // 'h' toggles on and off the help menu - g.SetKeybinding("", 'r', gocui.ModNone, widgetRefresh) // screen refresh - g.SetKeybinding("", 'w', gocui.ModNone, doWindow) // close all windows - g.SetKeybinding("", 'q', gocui.ModNone, doExit) // exit - g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, doExit) // exit - g.SetKeybinding("", gocui.KeyCtrlV, gocui.ModNone, doPanic) // forced panic - - // debugging - g.SetKeybinding("", 'd', gocui.ModNone, theLetterD) // 'd' toggles on and off debugging buttons - g.SetKeybinding("", gocui.KeyCtrlD, gocui.ModNone, openDebuggger) // open the debugger - g.SetKeybinding("", 'L', gocui.ModNone, dumpWidgets) // list all widgets - g.SetKeybinding("", 'M', gocui.ModNone, dumpWidgetPlacement) // list all widgets with positions - -} - -func doExit(g *gocui.Gui, v *gocui.View) error { - return nil -} - -func doPanic(g *gocui.Gui, v *gocui.View) error { - return nil -} - -func dumpWidgets(g *gocui.Gui, v *gocui.View) error { - return nil -} - -func dumpWidgetPlacement(g *gocui.Gui, v *gocui.View) error { - return nil -} - -func openDebuggger(g *gocui.Gui, v *gocui.View) error { - return nil -} - -// is run whenever anyone hits 'd' (in an open space) -func theLetterD(g *gocui.Gui, v *gocui.View) error { - // widgets that don't have physical existance in - // a display toolkit are hidden. In the case - // of gocui, they are set as not 'visible' and put offscreen - // or have the size set to zero - // (hopefully anyway) lots of things with the toolkit - // still don't work - - fakeStartWidth = me.FakeW - fakeStartHeight = me.TabH + me.FramePadH - if showDebug { - showFake() - showDebug = false - } else { - hideFake() - showDebug = true - } - return nil -} - -func theHelp(g *gocui.Gui, v *gocui.View) error { - if showHelp { - helplayout() - showHelp = false - if me.dropdownV == nil { - me.dropdownV = makeDropdownView("addWidget() ddview") - } - me.dropdownV.Show() - } else { - me.baseGui.DeleteView("help") - showHelp = true - me.dropdownV.Hide() - } - return nil -} - -func widgetRefresh(g *gocui.Gui, v *gocui.View) error { - return nil -} - -func doWindow(g *gocui.Gui, v *gocui.View) error { - return nil -} diff --git a/init.go b/init.go new file mode 100644 index 0000000..c9272f2 --- /dev/null +++ b/init.go @@ -0,0 +1,179 @@ +//gjcarro:pjcarrlugin + +// 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" + "os" + "runtime/debug" + + "github.com/awesome-gocui/gocui" + "go.wit.com/log" + "go.wit.com/toolkits/tree" +) + +// sent via -ldflags +var VERSION string +var BUILDTIME string + +func queueToolkitClose() { + me.baseGui.Close() +} + +func queueSetChecked(n *tree.Node, b bool) { + setChecked(n, b) +} + +// sets defaults and establishes communication +// to this toolkit from the wit/gui golang package +func init() { + log.Log(INFO, "Init() of awesome-gocui") + + // init the config struct default values + Set(&me, "default") + + // Set(&me, "dense") + + me.myTree = tree.New() + me.myTree.PluginName = "gocui" + + me.myTree.NodeAction = newaction + me.myTree.Add = newAdd + me.myTree.SetTitle = newSetTitle + me.myTree.SetLabel = newSetLabel + me.myTree.SetText = newSetText + me.myTree.AddText = newAddText + me.myTree.SetChecked = queueSetChecked + me.myTree.ToolkitClose = queueToolkitClose + + log.Log(NOW, "Init() start pluginChan") + log.Sleep(.1) // probably not needed, but in here for now under development + go mainGogui() + log.Sleep(.1) // probably not needed, but in here for now under development +} + +func standardExit() { + log.Log(NOW, "standardExit() doing baseGui.Close()") + me.baseGui.Close() + log.Log(NOW, "standardExit() doing outf.Close()") + outf.Close() + // log(true, "standardExit() setOutput(os.Stdout)") + // setOutput(os.Stdout) + log.Log(NOW, "standardExit() send back Quit()") + // go sendBackQuit() // don't stall here in case the + // induces a delay in case the callback channel is broken + log.Sleep(1) + log.Log(NOW, "standardExit() exit()") + os.Exit(0) +} + +func standardClose() { + log.Log(NOW, "standardExit() doing baseGui.Close()") + me.baseGui.Close() + log.Log(NOW, "standardExit() doing outf.Close()") + outf.Close() + os.Stdin = os.Stdin + os.Stdout = os.Stdout + os.Stderr = os.Stderr + log.Log(NOW, "standardExit() send back Quit()") +} + +var outf *os.File + +func main() { +} + +var origStdout *os.File +var origStderr *os.File + +func mainGogui() { + defer func() { + if r := recover(); r != nil { + log.Warn("YAHOOOO Recovered in guiMain application:", r) + log.Warn("Recovered from panic:", r) + me.baseGui.Close() + log.CaptureMode(nil) + log.Warn("YAHOOOO Recovered in guiMain application:", r) + log.Warn("Recovered from panic:", r) + me.myTree.SendToolkitPanic() + + return + } + }() + + var err error + + outf, err = os.OpenFile("/tmp/captureMode.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + log.Error(err, "error opening file: %v") + os.Exit(0) + } + origStdout = os.Stdout + os.Stdout = outf + defer outf.Close() + + log.CaptureMode(outf) + + gocuiMain() +} + +// This initializes the gocui package +// it runs SetManagerFunc which passes every input +// event (keyboard, mouse, etc) to the function "gocuiEvent()" +func gocuiMain() { + defer func() { + if r := recover(); r != nil { + log.Warn("YAHOOOO Recovered in gocuiMain()", r) + log.Warn("Recovered from panic:", r) + me.baseGui.Close() + + // allow gocui to close if possible, then print stack + log.Sleep(1) + os.Stdout = origStdout + os.Stderr = origStderr + me.myTree.SendToolkitPanic() + log.Warn("Stack trace:") + debug.PrintStack() + // panic("BUMMER 2") + + // attempt to switch to the nocui toolkit + log.Sleep(1) + me.myTree.SendToolkitLoad("nocui") + log.Sleep(3) + me.myTree.SendToolkitLoad("nocui") + // panic("BUMMER") + return + } + }() + g, err := gocui.NewGui(gocui.OutputNormal, true) + if err != nil { + return + } + defer g.Close() + + me.baseGui = g + + g.Cursor = true + g.Mouse = true + + // this sets the function that is run on every event. For example: + // When you click the mouse, move the mouse, or press a key on the keyboard + // This is equivalent to xev or similar to cat /dev/input on linux + g.SetManagerFunc(gocuiEvent) + + if err := defaultKeybindings(g); err != nil { + // normally panic here + log.Log(NOW, "defaultKeybindings(g) panic err =", err) + panic("gocuiTKdefaultkeybindings OOPS") + } + + if err := g.MainLoop(); err != nil && !errors.Is(err, gocui.ErrQuit) { + log.Log(NOW, "g.MainLoop() panic err =", err) + // normally panic here + panic("gocuiTKmainloop OOPS") + } +} diff --git a/main.go b/main.go deleted file mode 100644 index c9272f2..0000000 --- a/main.go +++ /dev/null @@ -1,179 +0,0 @@ -//gjcarro:pjcarrlugin - -// 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" - "os" - "runtime/debug" - - "github.com/awesome-gocui/gocui" - "go.wit.com/log" - "go.wit.com/toolkits/tree" -) - -// sent via -ldflags -var VERSION string -var BUILDTIME string - -func queueToolkitClose() { - me.baseGui.Close() -} - -func queueSetChecked(n *tree.Node, b bool) { - setChecked(n, b) -} - -// sets defaults and establishes communication -// to this toolkit from the wit/gui golang package -func init() { - log.Log(INFO, "Init() of awesome-gocui") - - // init the config struct default values - Set(&me, "default") - - // Set(&me, "dense") - - me.myTree = tree.New() - me.myTree.PluginName = "gocui" - - me.myTree.NodeAction = newaction - me.myTree.Add = newAdd - me.myTree.SetTitle = newSetTitle - me.myTree.SetLabel = newSetLabel - me.myTree.SetText = newSetText - me.myTree.AddText = newAddText - me.myTree.SetChecked = queueSetChecked - me.myTree.ToolkitClose = queueToolkitClose - - log.Log(NOW, "Init() start pluginChan") - log.Sleep(.1) // probably not needed, but in here for now under development - go mainGogui() - log.Sleep(.1) // probably not needed, but in here for now under development -} - -func standardExit() { - log.Log(NOW, "standardExit() doing baseGui.Close()") - me.baseGui.Close() - log.Log(NOW, "standardExit() doing outf.Close()") - outf.Close() - // log(true, "standardExit() setOutput(os.Stdout)") - // setOutput(os.Stdout) - log.Log(NOW, "standardExit() send back Quit()") - // go sendBackQuit() // don't stall here in case the - // induces a delay in case the callback channel is broken - log.Sleep(1) - log.Log(NOW, "standardExit() exit()") - os.Exit(0) -} - -func standardClose() { - log.Log(NOW, "standardExit() doing baseGui.Close()") - me.baseGui.Close() - log.Log(NOW, "standardExit() doing outf.Close()") - outf.Close() - os.Stdin = os.Stdin - os.Stdout = os.Stdout - os.Stderr = os.Stderr - log.Log(NOW, "standardExit() send back Quit()") -} - -var outf *os.File - -func main() { -} - -var origStdout *os.File -var origStderr *os.File - -func mainGogui() { - defer func() { - if r := recover(); r != nil { - log.Warn("YAHOOOO Recovered in guiMain application:", r) - log.Warn("Recovered from panic:", r) - me.baseGui.Close() - log.CaptureMode(nil) - log.Warn("YAHOOOO Recovered in guiMain application:", r) - log.Warn("Recovered from panic:", r) - me.myTree.SendToolkitPanic() - - return - } - }() - - var err error - - outf, err = os.OpenFile("/tmp/captureMode.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) - if err != nil { - log.Error(err, "error opening file: %v") - os.Exit(0) - } - origStdout = os.Stdout - os.Stdout = outf - defer outf.Close() - - log.CaptureMode(outf) - - gocuiMain() -} - -// This initializes the gocui package -// it runs SetManagerFunc which passes every input -// event (keyboard, mouse, etc) to the function "gocuiEvent()" -func gocuiMain() { - defer func() { - if r := recover(); r != nil { - log.Warn("YAHOOOO Recovered in gocuiMain()", r) - log.Warn("Recovered from panic:", r) - me.baseGui.Close() - - // allow gocui to close if possible, then print stack - log.Sleep(1) - os.Stdout = origStdout - os.Stderr = origStderr - me.myTree.SendToolkitPanic() - log.Warn("Stack trace:") - debug.PrintStack() - // panic("BUMMER 2") - - // attempt to switch to the nocui toolkit - log.Sleep(1) - me.myTree.SendToolkitLoad("nocui") - log.Sleep(3) - me.myTree.SendToolkitLoad("nocui") - // panic("BUMMER") - return - } - }() - g, err := gocui.NewGui(gocui.OutputNormal, true) - if err != nil { - return - } - defer g.Close() - - me.baseGui = g - - g.Cursor = true - g.Mouse = true - - // this sets the function that is run on every event. For example: - // When you click the mouse, move the mouse, or press a key on the keyboard - // This is equivalent to xev or similar to cat /dev/input on linux - g.SetManagerFunc(gocuiEvent) - - if err := defaultKeybindings(g); err != nil { - // normally panic here - log.Log(NOW, "defaultKeybindings(g) panic err =", err) - panic("gocuiTKdefaultkeybindings OOPS") - } - - if err := g.MainLoop(); err != nil && !errors.Is(err, gocui.ErrQuit) { - log.Log(NOW, "g.MainLoop() panic err =", err) - // normally panic here - panic("gocuiTKmainloop OOPS") - } -} diff --git a/mouse.go b/mouse.go deleted file mode 100644 index 4078d70..0000000 --- a/mouse.go +++ /dev/null @@ -1,107 +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. - -// note by jcarr@wit.com in 2025: this is one of the coolest -// things ever what this does. I've tried to improve -// it while I've been working on making a gocui -// GO plugin so it can be generalized as a useful -// console interface. Well done everyone that has -// contributed to this gocui project !!! - -package main - -import ( - "errors" - "fmt" - - "github.com/awesome-gocui/gocui" - - "go.wit.com/log" -) - -// this function uses the mouse position to highlight & unhighlight things -// this is run every time the user moves the mouse over the terminal window -func mouseMove(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 msgDown(g *gocui.Gui, v *gocui.View) error { - initialMouseX, initialMouseY = g.MousePosition() - - // debugging output - log.Log(GOCUI, "msgDown() X,Y", initialMouseX, initialMouseY) - - // - vx, vy, _, _, err := g.ViewPosition("msg") - if err == nil { - xOffset = initialMouseX - vx - yOffset = initialMouseY - vy - msgMouseDown = true - } - return nil -} - -func mouseUp(g *gocui.Gui, v *gocui.View) error { - w, h := g.MousePosition() - - dropdownUnclicked(w, h) - - if msgMouseDown { - msgMouseDown = false - if movingMsg { - movingMsg = false - return nil - } else { - g.DeleteView("msg") - } - } else if globalMouseDown { - globalMouseDown = false - g.DeleteView("globalDown") - } - return nil -} - -// func isMouseInMsg - -// this is where you have to figure out what -// widget was underneath so you can active -// the right response for the toolkit user's app -func mouseDown(g *gocui.Gui, v *gocui.View) error { - mx, my := g.MousePosition() - - vx0, vy0, vx1, vy1, err := g.ViewPosition("msg") - if err == nil { - if mx >= vx0 && mx <= vx1 && my >= vy0 && my <= vy1 { - return msgDown(g, v) - } - } - globalMouseDown = true - - maxX, _ := g.Size() - - findUnderMouse() - - msg := fmt.Sprintf("mouseDown() Mouse really down at: %d,%d", mx, my) - // dropdownClicked(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 - } - log.Log(GOCUI, "mouseDown() about to write out message to 'globalDown' view. msg =", msg) - 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 -} diff --git a/tree.go b/tree.go index 57f283a..4b6e23b 100644 --- a/tree.go +++ b/tree.go @@ -2,6 +2,11 @@ package main /* This is reference code for toolkit developers + + This is how information is passed in GO back to the application + via the GO 'plugin' concept + + TODO: switch this to protocol buffers */ import ( -- cgit v1.2.3