Compare commits

..

No commits in common. "guimaster" and "v0.22.20" have entirely different histories.

31 changed files with 1472 additions and 2185 deletions

1
.gitignore vendored
View File

@ -5,4 +5,3 @@
go.mod
go.sum
gocui
resources/*.so

View File

@ -1,7 +1,7 @@
VERSION = $(shell git describe --tags)
BUILDTIME = $(shell date +%Y.%m.%d)
all: clean goimports vet gocui
all: goimports vet gocui
@ldd gocui.so
vet:
@ -9,7 +9,7 @@ vet:
@echo this go plugin builds okay
gocui:
GO111MODULE=off go build -v -x -buildmode=plugin -o gocui.so \
GO111MODULE=off go build -v -buildmode=plugin -o gocui.so \
-ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
install:
@ -23,9 +23,9 @@ custom:
GO111MODULE=off go build -v -work -buildmode=blah
clean:
rm -f gocui *.so go.*
rm -f gocui gocui.so
rm -f *.pb.go *.patch
go-mod-clean purge
go-mod-clean --purge
# Test the README.md & doc.go file
# this runs pkgsite, the binary that does dev.go.dev

View File

@ -23,16 +23,16 @@ func setChecked(n *tree.Node, b bool) {
// redraw the checkbox
func (tk *guiWidget) setCheckbox() {
if tk.WidgetType() != widget.Checkbox {
log.Log(WARN, "setCheckbox() being run on widget:", tk.WidgetType())
if tk.node.WidgetType != widget.Checkbox {
log.Log(WARN, "setCheckbox() being run on widget:", tk.node.WidgetType)
return
}
if tk.Checked() {
log.Log(WARN, "setCheckbox() got true", tk.Checked())
tk.labelN = "X " + tk.GetLabel()
if tk.node.State.Checked {
log.Log(WARN, "setCheckbox() got true", tk.node.State.Checked)
tk.labelN = "X " + tk.node.State.Label
} else {
log.Log(WARN, "setCheckbox() got false", tk.Checked())
tk.labelN = "_ " + tk.GetLabel()
log.Log(WARN, "setCheckbox() got false", tk.node.State.Checked)
tk.labelN = "_ " + tk.node.State.Label
}
tk.Hide()

554
color.go
View File

@ -3,328 +3,217 @@
package main
import (
"math/rand"
"github.com/awesome-gocui/gocui"
"go.wit.com/log"
)
// simple colors for light and dark
// information about how terminfo works
// https://jvns.ca/blog/2024/10/01/terminal-colours/
// TODO: move all this to a protobuf
import (
"math/rand"
"github.com/gdamore/tcell/v2"
"github.com/awesome-gocui/gocui"
"go.wit.com/log"
)
//w.v.SelBgColor = gocui.ColorCyan
//color.go: w.v.SelFgColor = gocui.ColorBlack
//color.go: w.v.BgColor = gocui.ColorGreen
var none gocui.Attribute = gocui.AttrNone
var lightPurple gocui.Attribute = gocui.GetColor("#DDDDDD") // light purple
var darkPurple gocui.Attribute = gocui.GetColor("#FFAA55") // Dark Purple
var heavyPurple gocui.Attribute = gocui.GetColor("#88AA55") // heavy purple
var powdererBlue gocui.Attribute = gocui.GetColor("#B0E0E6") // w3c 'powerder blue'
var superLightGrey gocui.Attribute = gocui.GetColor("#55AAFF") // super light grey
// Standard defined colors from gocui:
// ColorBlack ColorRed ColorGreen ColorYellow ColorBlue ColorMagenta ColorCyan ColorWhite
// 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
// Normal Text On mouseover
//
// Widget Frame Text background Text background
var colorWindow colorT = colorT{
frame: none,
fg: gocui.ColorBlue,
bg: none,
selFg: gocui.ColorWhite,
// selBg: powdererBlue,
selBg: gocui.ColorBlue,
name: "normal window",
}
var colorActiveW colorT = colorT{
frame: none,
fg: gocui.ColorWhite,
bg: gocui.ColorBlue,
selFg: gocui.ColorBlue,
selBg: none,
name: "normal window",
}
// var colorActiveW colorT = colorT{none, none, powdererBlue, none, powdererBlue, "active window"} // sets the window to blue
var colorTab colorT = colorT{gocui.ColorBlue, gocui.ColorBlue, none, none, powdererBlue, "normal tab"}
var colorActiveT colorT = colorT{gocui.ColorBlue, none, powdererBlue, none, powdererBlue, "active tab"}
// var colorLabel colorT = colorT{none, none, superLightGrey, none, superLightGrey, "normal label"}
// var colorGroup colorT = colorT{none, none, superLightGrey, none, superLightGrey, "normal group"}
var colorDisabled colorT = colorT{
frame: superLightGrey,
fg: superLightGrey,
bg: superLightGrey,
selFg: gocui.ColorBlack,
selBg: gocui.ColorBlack,
name: "disabled widget",
}
var colorLabel colorT = colorT{
frame: gocui.ColorWhite,
fg: none,
bg: none,
selFg: none,
selBg: none,
name: "normal label",
}
var colorGroup colorT = colorT{
frame: none,
fg: none,
bg: none,
selFg: gocui.ColorWhite,
selBg: none,
name: "normal label",
}
var colorButton colorT = colorT{
frame: gocui.ColorGreen,
fg: none,
bg: none,
selFg: gocui.ColorGreen,
selBg: none,
name: "normal button",
}
var colorButtonDense colorT = colorT{
frame: none,
fg: none,
bg: gocui.ColorGreen,
// bg: tcell.ColorGreen,
selFg: none,
selBg: gocui.ColorWhite,
name: "normal button",
}
var colorDropdown colorT = colorT{
frame: gocui.ColorYellow,
fg: none,
bg: none,
selFg: gocui.ColorYellow,
selBg: gocui.ColorBlack,
name: "normal dropdown",
}
var colorCombobox colorT = colorT{
frame: gocui.ColorBlue,
fg: none,
bg: none,
selFg: gocui.ColorBlue,
selBg: gocui.ColorBlack,
name: "normal combobox",
}
var colorCheckbox colorT = colorT{
frame: gocui.ColorRed,
fg: none,
bg: none,
selFg: gocui.ColorRed,
selBg: gocui.ColorWhite,
name: "normal checkbox",
}
// widget debugging colors. these widgets aren't displayed unless you are debugging
var colorRoot colorT = colorT{gocui.ColorRed, none, powdererBlue, none, gocui.ColorBlue, "debug root"}
var colorFlag colorT = colorT{gocui.ColorRed, none, powdererBlue, none, gocui.ColorGreen, "debug flag"}
var colorBox colorT = colorT{gocui.ColorRed, none, lightPurple, none, gocui.ColorCyan, "debug box"}
var colorGrid colorT = colorT{gocui.ColorRed, none, lightPurple, none, gocui.ColorRed, "debug grid"}
var colorNone colorT = colorT{none, none, none, none, none, "debug none"}
// actually sets the colors for the gocui element
// the user will see the colors change when this runs
// TODO: add black/white only flag for ttyS0
// TODO: fix kvm/qemu serial console & SIGWINCH.
// TODO: check minicom (doesn't work)
// TODO: fix riscv boards
// DONE ON ENABLE() WIDGET
// restores the last saved color and makes it active
func (tk *guiWidget) restoreEnableColor() {
if tk.color == nil {
tk.color = new(colorT)
// TODO: or fix kvm/qemu serial console & SIGWINCH.
// TODO: and minicom and uboot and 5 million other things.
// TODO: maybe enough of us could actually do that if we made it a goal.
// TODO: start with riscv boards and fix it universally there
// TODO: so just a small little 'todo' item here
func (tk *guiWidget) setColor(newColor *colorT) {
if tk.color == newColor {
// nothing to do since the colors have nto changed
return
}
tk.color.frame = tk.colorLast.frame
tk.color.fg = tk.colorLast.fg
tk.color.bg = tk.colorLast.bg
tk.color.selFg = tk.colorLast.selFg
tk.color.selBg = tk.colorLast.selBg
tk.activateColor()
}
// DONE ON DISABLE() WIDGET
// makes the button look disabled
func (tk *guiWidget) setColorDisable() {
if tk.color == nil {
tk.color = new(colorT)
}
// save the current color
tk.color.frame = superLightGrey
tk.color.fg = gocui.ColorBlack
tk.color.bg = superLightGrey
tk.color.selFg = superLightGrey
tk.color.selBg = superLightGrey
tk.activateColor()
}
// sets the current gocui highlight colors
func (tk *guiWidget) activateColor() {
tk.color = newColor
if tk.v == nil {
return
}
tk.v.FrameColor = tk.color.frame
tk.v.FgColor = tk.color.fg
tk.v.BgColor = tk.color.bg
tk.v.SelFgColor = tk.color.selFg
tk.v.SelBgColor = tk.color.selBg
if tk.color == nil {
// log.Log(NOW, "Set the node to color = nil")
tk.color = &colorNone
}
// log.Log(NOW, "Set the node to color =", tk.color.name)
tk.Show()
}
// saves the color and makes it active
func (tk *guiWidget) updateColor() {
if tk.v == nil {
func (w *guiWidget) disableColor() {
if w.color != &colorDisabled {
w.defaultColor = w.color
}
w.setColor(&colorDisabled)
}
func (w *guiWidget) enableColor() {
w.setColor(w.defaultColor)
}
func (w *guiWidget) setDefaultHighlight() {
if w.v == nil {
log.Log(ERROR, "SetColor() failed on view == nil")
return
}
if tk.color != nil {
tk.colorLast.frame = tk.color.frame
tk.colorLast.fg = tk.color.fg
tk.colorLast.bg = tk.color.bg
tk.colorLast.selFg = tk.color.selFg
tk.colorLast.selBg = tk.color.selBg
}
tk.activateColor()
w.v.SelBgColor = gocui.ColorGreen
w.v.SelFgColor = gocui.ColorBlack
}
// Below are all the colors. TODO: move to protobuf and save in a config file
func (tk *guiWidget) setColorWindowFrame() {
if tk.color == nil {
tk.color = new(colorT)
}
if me.dark { // use a dark color palette
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.ColorBlack
tk.color.bg = gocui.ColorBlack
tk.color.selFg = gocui.AttrNone
tk.color.selBg = gocui.AttrNone
} else {
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.AttrNone
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.AttrNone
tk.color.selBg = gocui.AttrNone
}
tk.updateColor()
func randColor() gocui.Attribute {
colors := []string{"Green", "#FFAA55", "Yellow", "Blue", "Red", "Black", "White"}
i := rand.Intn(len(colors))
log.Log(NOW, "randColor() i =", i)
return gocui.GetColor(colors[i])
}
// weird. lots of color problems for me on debian sid using the traditional Andy Herzfield 'gnome'
func (tk *guiWidget) setColorWindowTitleActive() {
if tk.color == nil {
tk.color = new(colorT)
}
if me.dark { // use a dark color palette
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.ColorBlue
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.ColorWhite
tk.color.selBg = gocui.ColorBlue
} else {
tk.color.frame = gocui.ColorWhite
tk.color.fg = gocui.ColorWhite
tk.color.bg = gocui.ColorBlue
tk.color.selFg = gocui.ColorWhite
tk.color.selBg = gocui.ColorBlue
func (w *guiWidget) redoColor(draw bool) {
if w == nil {
return
}
tk.updateColor()
log.Sleep(.05)
w.setDefaultHighlight()
// w.setDefaultWidgetColor()
w.Show()
for _, child := range w.children {
child.redoColor(draw)
}
}
func (tk *guiWidget) setColorWindowTitle() {
if tk.color == nil {
tk.color = new(colorT)
}
if me.dark { // use a dark color palette
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.ColorBlue
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.ColorWhite
tk.color.selBg = gocui.ColorBlue
} else {
tk.color.frame = gocui.ColorWhite
tk.color.fg = gocui.ColorBlue
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.ColorWhite
tk.color.selBg = gocui.ColorBlue
}
tk.updateColor()
}
func (tk *guiWidget) setColorBG() {
if tk.color == nil {
tk.color = new(colorT)
}
if me.dark {
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.ColorBlack
tk.color.bg = gocui.ColorBlack
tk.color.selFg = gocui.AttrNone
tk.color.selBg = gocui.AttrNone
} else {
tk.color.frame = gocui.ColorWhite
tk.color.fg = gocui.ColorWhite
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.AttrNone
tk.color.selBg = gocui.AttrNone
}
tk.updateColor()
}
func (tk *guiWidget) setColorLabel() {
if tk.color == nil {
tk.color = new(colorT)
}
if me.dark {
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.ColorWhite
tk.color.bg = gocui.ColorBlack
tk.color.selFg = gocui.ColorWhite
tk.color.selBg = gocui.AttrNone
} else {
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.ColorBlack
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.AttrNone
tk.color.selBg = gocui.ColorWhite
}
tk.updateColor()
}
func (tk *guiWidget) setColorLabelTable() {
if tk.color == nil {
tk.color = new(colorT)
}
if me.dark {
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.ColorWhite
tk.color.bg = gocui.ColorBlack
tk.color.selFg = gocui.ColorWhite
tk.color.selBg = gocui.AttrNone
} else {
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.ColorBlack
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.AttrNone
tk.color.selBg = gocui.ColorGreen
}
tk.updateColor()
}
func (tk *guiWidget) setColorButtonDense() {
if tk.color == nil {
tk.color = new(colorT)
}
if me.dark {
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.ColorBlue
tk.color.bg = gocui.ColorBlack
tk.color.selFg = gocui.ColorWhite
tk.color.selBg = gocui.ColorBlue
} else {
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.ColorWhite
tk.color.bg = gocui.ColorBlue
tk.color.selFg = gocui.ColorBlue
tk.color.selBg = gocui.AttrNone
}
tk.updateColor()
}
func (tk *guiWidget) setColorNotifyIcon() {
if tk.color == nil {
tk.color = new(colorT)
}
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.ColorWhite
tk.color.bg = gocui.ColorBlue
tk.color.selFg = gocui.ColorBlue
tk.color.selBg = gocui.AttrNone
tk.updateColor()
}
func (tk *guiWidget) setColorButton() {
if tk.color == nil {
tk.color = new(colorT)
}
if me.dark {
tk.color.frame = gocui.ColorBlack
tk.color.fg = gocui.ColorBlue
tk.color.bg = gocui.ColorBlack
tk.color.selFg = gocui.ColorWhite
tk.color.selBg = gocui.ColorBlue
} else {
tk.color.frame = gocui.ColorBlue
tk.color.fg = gocui.AttrNone
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.ColorWhite
tk.color.selBg = gocui.ColorBlue
}
tk.updateColor()
}
func (tk *guiWidget) setColorInput() {
if tk.color == nil {
tk.color = new(colorT)
}
if me.dark {
tk.color.frame = gocui.ColorYellow
tk.color.fg = gocui.AttrNone
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.ColorYellow
tk.color.selBg = gocui.ColorBlack
} else {
tk.color.frame = gocui.ColorYellow
tk.color.fg = gocui.AttrNone
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.ColorYellow
tk.color.selBg = gocui.ColorBlack
}
tk.updateColor()
}
func (tk *guiWidget) setColorModal() {
if tk.color == nil {
tk.color = new(colorT)
}
if me.dark {
tk.color.frame = gocui.ColorRed
tk.color.fg = gocui.ColorRed
tk.color.bg = gocui.ColorBlack
tk.color.selFg = gocui.ColorBlack
tk.color.selBg = gocui.AttrNone
} else {
tk.color.frame = gocui.ColorRed
tk.color.fg = gocui.AttrNone
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.AttrNone
tk.color.selBg = gocui.ColorWhite
}
tk.updateColor()
}
// what genius figured this out?
func (tk *guiWidget) setColorTextbox() {
if tk.color == nil {
tk.color = new(colorT)
}
if me.dark {
tk.color.frame = gocui.ColorRed
tk.color.fg = gocui.ColorRed
tk.color.bg = gocui.ColorBlack
tk.color.selFg = gocui.ColorBlack
tk.color.selBg = gocui.AttrNone
} else {
tk.color.frame = gocui.ColorRed
tk.color.fg = gocui.AttrNone
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.AttrNone
tk.color.selBg = gocui.ColorWhite
}
tk.updateColor()
}
// just notes down here
// what genius figured this out?
// originally from github.com/dimasma0305/GoFetch
func get_teminal_color_palette() string {
@ -345,28 +234,51 @@ func get_teminal_color_palette() string {
return color1 + " " + color2 + " " + color3 + " " + color4 + " " + color5 + " " + color6 + " " + color7 + " " + color8
}
func randColor() gocui.Attribute {
colors := []string{"Green", "#FFAA55", "Yellow", "Blue", "Red", "Black", "White"}
i := rand.Intn(len(colors))
log.Log(NOW, "randColor() i =", i)
return gocui.GetColor(colors[i])
func (tk *guiWidget) SetColorRed() {
tk.color = new(colorT)
tk.color.fg = gocui.ColorRed
}
var none gocui.Attribute = gocui.AttrNone
var colorNone colorT = colorT{none, none, none, none, none, "debug none"}
func (tk *guiWidget) setColorBlue() {
// r, g, b :=
// newgreen := gocui.NewRGBColor(tcell.ColorLightBlue.RGB())
var lightPurple gocui.Attribute = gocui.GetColor("#DDDDDD") // light purple
var darkPurple gocui.Attribute = gocui.GetColor("#FFAA55") // Dark Purple
var heavyPurple gocui.Attribute = gocui.GetColor("#88AA55") // heavy purple
var powdererBlue gocui.Attribute = gocui.GetColor("#B0E0E6") // w3c 'powerder blue'
var superLightGrey gocui.Attribute = gocui.GetColor("#55AAFF") // super light grey
// tk.color.fg = gocui.ColorBlue
tk.color.bg = gocui.NewRGBColor(tcell.ColorLightBlue.RGB())
}
// Standard defined colors from gocui:
// ColorBlack ColorRed ColorGreen ColorYellow ColorBlue ColorMagenta ColorCyan ColorWhite
// weird. lots of color problems for me on debian sid using the traditional Andy Herzfield 'gnome'
func (tk *guiWidget) setColorButtonDenseOLD() {
/*
cellgreen := tcell.ColorLightGreen
r, g, b := cellgreen.RGB()
newgreen := gocui.NewRGBColor(r, g, b)
*/
// v.BgColor = gocui.GetColor("#111111") // crazy red
// v.BgColor = gocui.GetColor("#FF9911") // heavy red
// v.SelBgColor = gocui.GetColor("#FFEE11") // blood red
// tk.color.fg = gocui.ColorBlue
if tk.color == nil {
tk.color = new(colorT)
}
lightGreen := gocui.GetColor("0x90EE90")
lightGreen = gocui.GetColor("0x008000")
lightGreen = gocui.NewRGBColor(0x00, 0x80, 0x00)
// v.BgColor = gocui.GetColor("#55AAFF") // super light grey
// v.BgColor = gocui.GetColor("#FFC0CB") // 'w3c pink' yellow
tk.color.frame = gocui.ColorYellow
tk.color.fg = gocui.AttrNone
tk.color.bg = gocui.ColorGreen
tk.color.bg = lightGreen
tk.color.bg = gocui.Attribute(tcell.ColorLightGreen)
tk.color.bg = superLightGrey
// bg: gocui.ColorGreen,
tk.color.selFg = gocui.AttrNone
tk.color.selBg = gocui.ColorGreen
// tk.color = &colorButtonDense
/*
tk.color.selFg = gocui.AttrNone
r, g, b := tcell.ColorLightGreen.RGB()
log.Info("color =", tcell.ColorLightGreen.CSS(), r, g, b)
tk.color.selBg = gocui.NewRGBColor(r, g, b)
*/
}

163
colorNew.go Normal file
View File

@ -0,0 +1,163 @@
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
package main
// simple colors for light and dark
import (
"github.com/awesome-gocui/gocui"
)
func (tk *guiWidget) setColorWindowFrame() {
if tk.color == nil {
tk.color = new(colorT)
}
if me.dark { // use a dark color palette
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.ColorBlack
tk.color.bg = gocui.ColorBlack
tk.color.selFg = gocui.AttrNone
tk.color.selBg = gocui.AttrNone
return
}
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.AttrNone
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.AttrNone
tk.color.selBg = gocui.AttrNone
}
// weird. lots of color problems for me on debian sid using the traditional Andy Herzfield 'gnome'
func (tk *guiWidget) setColorWindowTitle() {
if tk.color == nil {
tk.color = new(colorT)
}
if me.dark { // use a dark color palette
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.ColorBlue
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.ColorWhite
tk.color.selBg = gocui.ColorBlue
return
}
tk.color.frame = gocui.ColorWhite
tk.color.fg = gocui.AttrNone
tk.color.bg = gocui.ColorBlue
tk.color.selFg = gocui.ColorBlue
tk.color.selBg = gocui.AttrNone
}
func (tk *guiWidget) setColorBG() {
if tk.color == nil {
tk.color = new(colorT)
}
if me.dark {
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.ColorBlack
tk.color.bg = gocui.ColorBlack
tk.color.selFg = gocui.AttrNone
tk.color.selBg = gocui.AttrNone
return
}
tk.color.frame = gocui.ColorWhite
tk.color.fg = gocui.ColorWhite
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.AttrNone
tk.color.selBg = gocui.AttrNone
}
func (tk *guiWidget) setColorLabel() {
if tk.color == nil {
tk.color = new(colorT)
}
if me.dark {
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.ColorWhite
tk.color.bg = gocui.ColorBlack
tk.color.selFg = gocui.ColorWhite
tk.color.selBg = gocui.AttrNone
return
}
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.ColorBlack
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.AttrNone
tk.color.selBg = gocui.ColorWhite
}
func (tk *guiWidget) setColorButtonDense() {
if tk.color == nil {
tk.color = new(colorT)
}
if me.dark {
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.ColorBlue
tk.color.bg = gocui.ColorBlack
tk.color.selFg = gocui.ColorWhite
tk.color.selBg = gocui.ColorBlue
return
}
tk.color.frame = gocui.AttrNone
tk.color.fg = gocui.ColorWhite
tk.color.bg = gocui.ColorBlue
tk.color.selFg = gocui.ColorBlue
tk.color.selBg = gocui.AttrNone
}
func (tk *guiWidget) setColorButton() {
if tk.color == nil {
tk.color = new(colorT)
}
if me.dark {
tk.color.frame = gocui.ColorBlack
tk.color.fg = gocui.ColorBlue
tk.color.bg = gocui.ColorBlack
tk.color.selFg = gocui.ColorWhite
tk.color.selBg = gocui.ColorBlue
return
}
tk.color.frame = gocui.ColorBlue
tk.color.fg = gocui.AttrNone
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.ColorWhite
tk.color.selBg = gocui.ColorBlue
}
func (tk *guiWidget) setColorInput() {
if tk.color == nil {
tk.color = new(colorT)
}
if me.dark {
tk.color.frame = gocui.ColorYellow
tk.color.fg = gocui.AttrNone
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.ColorYellow
tk.color.selBg = gocui.ColorBlack
return
}
tk.color.frame = gocui.ColorYellow
tk.color.fg = gocui.AttrNone
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.ColorYellow
tk.color.selBg = gocui.ColorBlack
}
func (tk *guiWidget) setColorModal() {
if tk.color == nil {
tk.color = new(colorT)
}
if me.dark {
tk.color.frame = gocui.ColorRed
tk.color.fg = gocui.ColorRed
tk.color.bg = gocui.ColorBlack
tk.color.selFg = gocui.ColorBlack
tk.color.selBg = gocui.AttrNone
return
}
tk.color.frame = gocui.ColorRed
tk.color.fg = gocui.AttrNone
tk.color.bg = gocui.AttrNone
tk.color.selFg = gocui.AttrNone
tk.color.selBg = gocui.ColorWhite
}

View File

@ -12,9 +12,9 @@ import (
)
func (w *guiWidget) dumpTree(s string) {
// log.Log(ERROR, "dump w", w.WidgetId(), w.WidgetType, w.String())
// log.Log(ERROR, "dump w", w.node.WidgetId, w.WidgetType, w.String())
if w == nil {
log.Log(ERROR, "dump w.TK == nil", w.WidgetId(), w.WidgetType(), w.String())
log.Log(ERROR, "dump w.TK == nil", w.node.WidgetId, w.node.WidgetType, w.String())
return
}
w.dumpWidget("dumpTree() " + s)
@ -25,12 +25,12 @@ func (w *guiWidget) dumpTree(s string) {
}
func (w *guiWidget) dumpWindows(s string) {
// log.Log(ERROR, "dump w", w.WidgetId(), w.WidgetType, w.String())
// log.Log(ERROR, "dump w", w.node.WidgetId, w.WidgetType, w.String())
if w == nil {
log.Log(ERROR, "dump w.TK == nil", w.WidgetId(), w.WidgetType(), w.String())
log.Log(ERROR, "dump w.TK == nil", w.node.WidgetId, w.node.WidgetType, w.String())
return
}
if w.WidgetType() == widget.Window {
if w.node.WidgetType == widget.Window {
s += fmt.Sprintf(" F(%d,%d)", w.force.w0, w.force.h0)
// can't set this here. doesn't work
// w.full.w0 = w.force.w0
@ -49,13 +49,13 @@ func (tk *guiWidget) dumpWidget(s string) {
var s1 string
var pId int
// tk.verifyRect()
if tk.parent == nil {
log.Logf(WARN, "showWidgetPlacement() parent == nil wId=%d cuiName=%s", tk.WidgetId(), tk.cuiName)
if tk.node.Parent == nil {
log.Logf(WARN, "showWidgetPlacement() parent == nil wId=%d cuiName=%s", tk.node.WidgetId, tk.cuiName)
pId = 0
} else {
pId = tk.parent.WidgetId()
pId = tk.node.Parent.WidgetId
}
s1 = fmt.Sprintf("(wId,pId)=(%4d,%4d) ", tk.WidgetId(), pId)
s1 = fmt.Sprintf("(wId,pId)=(%4d,%4d) ", tk.node.WidgetId, pId)
sizeW, sizeH := tk.Size()
hide := "S"
if tk.Hidden() {
@ -69,10 +69,10 @@ func (tk *guiWidget) dumpWidget(s string) {
s1 += fmt.Sprintf(" %3s %3s %3s %3s ", "", "", "", "")
}
s1 += fmt.Sprintf(" full=(%3d,%3d,%3d,%3d)", tk.full.w0, tk.full.h0, tk.full.w1, tk.full.h1)
if tk.parent != nil {
if tk.parent.WidgetType() == widget.Grid {
s1 += fmt.Sprintf("At(%3d,%3d)", tk.GridW(), tk.GridH())
s1 += fmt.Sprintf("(%3d,%3d) ", tk.parent.widths[tk.GridW()], tk.parent.heights[tk.GridH()])
if tk.node.Parent != nil {
if tk.node.Parent.WidgetType == widget.Grid {
s1 += fmt.Sprintf("At(%3d,%3d)", tk.node.State.AtW, tk.node.State.AtH)
s1 += fmt.Sprintf("(%3d,%3d) ", tk.parent.widths[tk.node.State.AtW], tk.parent.heights[tk.node.State.AtH])
} else {
s1 += fmt.Sprintf(" %3s %3s ", "", "")
s1 += fmt.Sprintf(" %3s %3s ", "", "")
@ -81,14 +81,10 @@ func (tk *guiWidget) dumpWidget(s string) {
s1 += fmt.Sprintf(" %3s %3s ", "", "")
}
var end string
if tk.WidgetType() == widget.Box {
end = fmt.Sprintf("%-8s %-8s %s %s", tk.WidgetType(), tk.cuiName, tk.Direction().String(), tk.String())
if tk.node.WidgetType == widget.Box {
end = fmt.Sprintf("%-8s %-8s %s %s", tk.node.WidgetType, tk.cuiName, tk.node.State.Direction.String(), tk.String())
} else {
end = fmt.Sprintf("%-8s %-8s %s", tk.WidgetType(), tk.cuiName, tk.String())
}
if tk.node.InTable() {
// log.Log(GOCUI, "findParentTAble()", tk.labelN, tk.cuiName, tk.node.WidgetId)
end += " (table)"
end = fmt.Sprintf("%-8s %-8s %s", tk.node.WidgetType, tk.cuiName, tk.String())
}
log.Log(GOCUI, s1, s, end)
}

View File

@ -15,12 +15,6 @@ import (
// tells 'gocui' where to send events
func registerHandlers(g *gocui.Gui) {
defer func() {
if r := recover(); r != nil {
log.Info("EVENT BINDINGS recovered in r", r)
return
}
}()
// mouse handlers
g.SetKeybinding("", gocui.MouseLeft, gocui.ModNone, mouseDown) // normal left mouse down
@ -58,7 +52,6 @@ func registerHandlers(g *gocui.Gui) {
g.SetKeybinding("", 'L', gocui.ModNone, printWidgetTree) // 'L' list all widgets in tree view
g.SetKeybinding("", 'f', gocui.ModNone, theFind) // 'f' shows what is under your mouse
g.SetKeybinding("", 'd', gocui.ModNone, theLetterD) // 'd' toggles on and off debugging buttons
g.SetKeybinding("", 'r', gocui.ModNone, reverseStdout) // 'r' turns scrolling of STDOUT upside down
g.SetKeybinding("", 'q', gocui.ModNone, quit) // 'q' only exits gocui. plugin stays alive (?)
}
@ -78,23 +71,6 @@ func theSuperMouse(g *gocui.Gui, v *gocui.View) error {
// use this to test code ideas // put whatever you want here and hit '2' to activate it
func theNotsure(g *gocui.Gui, v *gocui.View) error {
log.Info("got to theNotsure(). now what? dark =", me.dark)
me.refresh = true
log.Info("running VerifyParentId()")
me.treeRoot.VerifyParentId()
/*
if me.debug {
log.Info("debugging off")
me.debug = false
} else {
log.Info("debugging on")
me.debug = true
}
win := findWindowUnderMouse()
if win != nil {
win.dumpWidget("found() win. redrawing window:")
win.makeWindowActive()
}
*/
return nil
}
@ -104,20 +80,18 @@ func theDarkness(g *gocui.Gui, v *gocui.View) error {
log.Info("you have seen the light")
} else {
me.dark = true
log.Info("you have entered into darkness (you may need to trigger SIGWINCH)")
log.Info("or maybe open a new window. notsure. This obviously isn't finished.")
log.Info("submit patches to this and you will definitely get free cloud credits at WIT")
log.Info("you have entered into darkness")
}
return nil
}
func wheelsUp(g *gocui.Gui, v *gocui.View) error {
stdoutWheelsUp()
log.Info("private wheels up")
return nil
}
func wheelsDown(g *gocui.Gui, v *gocui.View) error {
stdoutWheelsDown()
log.Info("you've landed")
return nil
}
@ -132,6 +106,8 @@ func tabCycleWindows(g *gocui.Gui, v *gocui.View) error {
return nil
}
tk.makeWindowActive()
tk.redrawWindow(tk.gocuiSize.w0, tk.gocuiSize.h0)
setThingsOnTop() // sets help, Stdout, etc on the top after windows have been redrawn
return nil
}
@ -141,13 +117,11 @@ func doEsc(g *gocui.Gui, v *gocui.View) error {
me.dropdown.tk.Hide()
me.dropdown.active = false
log.Info("escaped from dropdown")
me.baseGui.SetCurrentView(me.notify.clock.tk.cuiName)
}
if me.textbox.active {
me.textbox.tk.Hide()
me.textbox.active = false
log.Info("escaped from textbox")
me.baseGui.SetCurrentView(me.notify.clock.tk.cuiName)
}
return nil
}
@ -185,19 +159,6 @@ func theFind(g *gocui.Gui, v *gocui.View) error {
return nil
}
func reverseStdout(g *gocui.Gui, v *gocui.View) error {
if me.stdout.reverse {
me.stdout.reverse = false
log.Info("stdout scrolling normal")
} else {
me.stdout.reverse = true
log.Info("stdout scrolling is reversed. this is sometimes useful when you")
log.Info("only need to see a few most recent lines and have the STDOUT window")
log.Info("take up minimal realestate at the bottom of your window")
}
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

View File

@ -8,14 +8,12 @@ import (
"github.com/awesome-gocui/gocui"
"go.wit.com/log"
"go.wit.com/toolkits/tree"
)
func theStdout(g *gocui.Gui, v *gocui.View) error {
// me.stdout.pager = 0
infos := fmt.Sprintf("pager=%d len(%d) ", me.stdout.pager, len(me.stdout.outputS))
infos += fmt.Sprintf("last(%d,%d)", me.stdout.lastW, me.stdout.lastH)
me.stdout.changed = true
if me.stdout.outputOnTop {
if me.stdout.outputOffscreen {
@ -24,44 +22,27 @@ func theStdout(g *gocui.Gui, v *gocui.View) error {
me.stdout.lastW = me.stdout.tk.gocuiSize.w0
me.stdout.lastH = me.stdout.tk.gocuiSize.h0
relocateStdoutOffscreen()
new1 := new(tree.ToolkitConfig)
new1.Plugin = "gocui"
new1.Name = "stdoutoffscreen"
new1.Value = "true"
me.myTree.ConfigSave(new1)
return nil
} else {
me.stdout.outputOffscreen = true
log.Info("stdout moved on screen", infos)
new1 := new(tree.ToolkitConfig)
new1.Plugin = "gocui"
new1.Name = "stdoutoffscreen"
new1.Value = "false"
me.myTree.ConfigSave(new1)
}
// move the stdout window back onscreen
me.stdout.tk.relocateStdout(me.stdout.lastW, me.stdout.lastH)
me.stdout.outputOnTop = false
setThingsOnTop()
new1 := new(tree.ToolkitConfig)
new1.Plugin = "gocui"
new1.Name = "stdoutlevel"
new1.Value = "bottom"
me.myTree.ConfigSave(new1)
// me.baseGui.SetViewOnBottom("msg")
// setBottomBG()
} else {
me.stdout.outputOnTop = true
setThingsOnTop()
new1 := new(tree.ToolkitConfig)
new1.Plugin = "gocui"
new1.Name = "stdoutlevel"
new1.Value = "top"
me.myTree.ConfigSave(new1)
// me.baseGui.SetViewOnTop("msg")
}
return nil
}
func stdoutPgup(g *gocui.Gui, v *gocui.View) error {
me.stdout.pager -= me.stdout.Height() - 2
me.stdout.pager -= 40
if me.stdout.pager < 0 {
me.stdout.pager = 0
}
@ -77,55 +58,21 @@ func stdoutHome(g *gocui.Gui, v *gocui.View) error {
}
func stdoutArrowUp(g *gocui.Gui, v *gocui.View) error {
if me.stdout.reverse {
stdoutWheelsDown()
} else {
stdoutWheelsUp()
}
me.stdout.pager += 1
me.stdout.tk.refreshStdout()
return nil
}
func stdoutArrowDown(g *gocui.Gui, v *gocui.View) error {
if me.stdout.reverse {
stdoutWheelsUp()
} else {
stdoutWheelsDown()
}
me.stdout.pager -= 1
me.stdout.tk.refreshStdout()
return nil
}
func stdoutPgdn(g *gocui.Gui, v *gocui.View) error {
win := findWindowUnderMouse()
if win != nil {
if win.full.Height() > 50 {
log.Info("paging through really large window pager =", win.window.pager)
win.window.pager += 10
return nil
}
}
me.stdout.pager += 10
tk := me.stdout.tk
tk.refreshStdout()
return nil
}
// scrolling up with the mouse wheel (or trackpad)
func stdoutWheelsUp() {
// log.Info("private wheels up")
me.stdout.pager -= 2
if me.stdout.pager < 0 {
me.stdout.pager = 0
}
me.stdout.tk.refreshStdout()
}
// scrolling down with the mouse wheel (or trackpad)
func stdoutWheelsDown() {
// log.Info("you've landed")
me.stdout.pager += 2
if me.stdout.pager > len(me.stdout.outputS) {
me.stdout.pager = len(me.stdout.outputS)
}
me.stdout.tk.refreshStdout()
}

View File

@ -1,13 +1,17 @@
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.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"
"github.com/awesome-gocui/gocui"
"go.wit.com/log"
)
@ -40,36 +44,6 @@ func quit(g *gocui.Gui, v *gocui.View) error {
return gocui.ErrQuit
}
func (tk *guiWidget) SetView() error {
if me.baseGui == nil {
return fmt.Errorf("me.baseGui == nil")
}
r := new(rectType)
r.w0 = tk.gocuiSize.w0
r.h0 = tk.gocuiSize.h0
r.w1 = tk.gocuiSize.w1
r.h1 = tk.gocuiSize.h1
return tk.SetViewRect(r)
}
func (tk *guiWidget) SetViewRect(r *rectType) error {
if me.baseGui == nil {
return fmt.Errorf("me.baseGui == nil")
}
var err error
tk.v, err = me.baseGui.SetView(tk.cuiName, r.w0, r.h0, r.w1, r.h1, 0)
if err != nil {
if !errors.Is(err, gocui.ErrUnknownView) {
log.Log(ERROR, "SetView() global failed on name =", tk.cuiName)
return err
}
}
return nil
}
func SetView(name string, x0, y0, x1, y1 int, overlaps byte) *gocui.View {
if me.baseGui == nil {
log.Log(ERROR, "SetView() ERROR: me.baseGui == nil")

View File

@ -10,6 +10,7 @@ import (
"github.com/awesome-gocui/gocui"
"go.wit.com/log"
"go.wit.com/widget"
)
func mouseUp(g *gocui.Gui, v *gocui.View) error {
@ -21,6 +22,7 @@ func mouseUp(g *gocui.Gui, v *gocui.View) error {
*/
me.mouse.mouseUp = true
// me.mouse.globalMouseDown = false
me.mouse.currentDrag = nil
if me.mouse.double && (time.Since(me.mouse.down) < me.mouse.doubletime) {
@ -44,6 +46,7 @@ func mouseDown(g *gocui.Gui, v *gocui.View) error {
if time.Since(me.mouse.down) < me.mouse.doubletime {
me.mouse.double = true
}
// me.mouse.globalMouseDown = true
me.mouse.mouseUp = false
me.mouse.down = time.Now()
w, h := g.MousePosition()
@ -54,11 +57,11 @@ func mouseDown(g *gocui.Gui, v *gocui.View) error {
if win != nil {
w, h := g.MousePosition()
s := fmt.Sprintf("mouse(%d,%d) ", w, h)
offW := win.full.w1 - w
offH := win.full.h1 - h
offW := win.gocuiSize.w1 - w
offH := win.gocuiSize.h1 - h
s += fmt.Sprintf("corner(%d,%d)", offW, offH)
if (offW < 3) && (offH < 3) {
log.Info("attempting resize on ", s, win.cuiName)
// log.Info("mouse down resize on ", s)
me.mouse.resize = true
// store the stdout corner for computing the drag size
me.stdout.lastW = me.stdout.tk.gocuiSize.w0
@ -69,6 +72,79 @@ func mouseDown(g *gocui.Gui, v *gocui.View) error {
}
win.setAsDragging()
}
return nil
}
if time.Since(me.mouse.down) < me.mouse.clicktime {
log.Info("not yet")
return nil
}
w, h := g.MousePosition()
// if the dropdown is active, never do anything else
if me.dropdown.active {
log.Info("mouseDown() stopping here. dropdwon menu is in effect")
for _, tk := range findByXY(w, h) {
if (tk.node.WidgetType == widget.Flag) && (tk == me.dropdown.tk) {
// log.Info("SENDING CLICK TO Flag (dropdown)")
tk.doWidgetClick(w, h)
me.dropdown.active = false
return nil
}
}
log.Info("never found dropdown at", w, h)
return nil
}
// if the textbox is active, never do anything else
if me.textbox.active {
log.Info("mouseDown() stopping here. textbox widget is open")
for _, tk := range findByXY(w, h) {
if (tk.node.WidgetType == widget.Flag) && (tk == me.textbox.tk) {
me.textbox.active = false
textboxClosed()
return nil
}
}
log.Info("never found textbox at", w, h)
return nil
}
// figre out what window this is
tk := findWindowUnderMouse()
if tk == nil {
log.Info("mouseDown() nothing to click on at", w, h)
return nil
}
tk.makeWindowActive()
// log.Info("SENDING mouseDown() to findWindowUnderMouse()")
if tk.node.WidgetType == widget.Window {
// check to see if this is a direct click on a widget
for _, tk := range tk.findByXYreal(w, h) {
// tk.dumpWidget("mouseDown()")
if tk.node.WidgetType == widget.Button {
// log.Info("SENDING CLICK TO Button")
tk.doWidgetClick(w, h)
return nil
}
if tk.node.WidgetType == widget.Checkbox {
// log.Info("SENDING CLICK TO Checkbox")
tk.doWidgetClick(w, h)
return nil
}
if tk.node.WidgetType == widget.Dropdown {
// log.Info("SENDING CLICK TO Dropdown")
tk.doWidgetClick(w, h)
return nil
}
if tk.node.WidgetType == widget.Textbox {
// log.Info("SENDING CLICK TO Textbox")
tk.doWidgetClick(w, h)
return nil
}
}
}
me.mouse.currentDrag = tk
return nil
}

View File

@ -4,18 +4,107 @@
package main
import (
"github.com/awesome-gocui/gocui"
"fmt"
"go.wit.com/log"
"go.wit.com/widget"
)
func (tk *guiWidget) doButtonClick() {
if tk.IsEnabled() {
tk.dumpWidget("click()") // enable this to debug widget clicks
me.myTree.SendFromUser(tk.node)
/*
// this didn't work. panic()
func (tk *guiWidget) DeleteNode() {
p := tk.parent
for i, child := range p.children {
log.Log(GOCUI, "parent has child:", i, child.node.WidgetId, child.node.GetProgName())
if tk == child {
log.Log(GOCUI, "Found child ==", i, child.node.WidgetId, child.node.GetProgName())
log.Log(GOCUI, "Found n ==", i, tk.node.WidgetId, tk.node.GetProgName())
p.children = append(p.children[:i], p.children[i+1:]...)
}
}
for i, child := range p.children {
log.Log(TREE, "parent now has child:", i, child.WidgetId, child.GetProgName())
}
}
*/
func (tk *guiWidget) doWindowClick() {
w, h := me.baseGui.MousePosition()
tk.dumpWidget(fmt.Sprintf("doWindowClick(%d,%d)", w, h))
// compare the mouse location to the 'X' indicator to close the window
if tk.gocuiSize.inRect(w, h) {
offset := w - tk.gocuiSize.w1
if (offset < 2) && (offset > -2) {
// close enough // close the window here
tk.dumpWidget(fmt.Sprintf("Close Window(%d,%d) (off=%d)", w, h, offset))
tk.hideWindow()
n := tk.node
tk.deleteNode()
me.myTree.SendWindowCloseEvent(n)
/*
n.DeleteNode()
tk.DeleteNode()
*/
return
}
if tk.window.collapsed {
tk.dumpWidget(fmt.Sprintf("collapse = false"))
tk.window.collapsed = false
} else {
log.Info("button is currently disabled by the application")
// tk.dumpWidget("disabled()") // enable this to debug widget clicks
tk.dumpWidget(fmt.Sprintf("collapse = true"))
tk.window.collapsed = true
}
} else {
tk.window.collapsed = false
}
// if there is a current window, hide it
if me.currentWindow != nil {
me.currentWindow.setColor(&colorWindow)
}
// now set this window as the current window
me.currentWindow = tk
tk.redrawWindow(w, h)
setThingsOnTop() // sets help, Stdout, etc on the top after windows have been redrawn
}
// this whole things was impossible to make but it got me where I am now
// the debugging is way way better now with it being visible in the Stdout window
// so now it's possible to redo all this and make it better
func (tk *guiWidget) doWidgetClick(w int, h int) {
tk.dumpWidget(fmt.Sprintf("doWidgetClick(%d,%d)", w, h))
switch tk.node.WidgetType {
case widget.Window:
tk.doWindowClick()
return
case widget.Checkbox:
if tk.node.State.Checked {
log.Log(WARN, "checkbox is being set to false")
tk.node.State.Checked = false
tk.setCheckbox()
} else {
log.Log(WARN, "checkbox is being set to true")
tk.node.State.Checked = true
tk.setCheckbox()
}
me.myTree.SendUserEvent(tk.node)
case widget.Button:
me.myTree.SendFromUser(tk.node)
case widget.Combobox:
tk.showDropdown()
case widget.Dropdown:
tk.showDropdown()
case widget.Textbox:
tk.showTextbox()
case widget.Flag:
tk.dropdownClicked(w, h)
case widget.Stdout:
tk.dumpWidget("stdout click()")
default:
tk.dumpWidget("undef click()")
}
}
@ -26,12 +115,12 @@ func doMouseClick(w int, h int) {
if me.dropdown.active || me.textbox.active {
// can't drag or do anything when dropdown or textbox are visible
for _, tk := range findByXY(w, h) {
if tk.WidgetId() == me.dropdown.wId {
log.Info("got dropdown click", w, h, tk.cuiName)
if tk.node.WidgetId == me.dropdown.wId {
log.Info("got dropdwon click", w, h, tk.cuiName)
tk.dropdownClicked(w, h)
return
}
if tk.WidgetId() == me.textbox.wId {
if tk.node.WidgetId == me.textbox.wId {
log.Info("got textbox click", w, h, tk.cuiName)
textboxClosed()
return
@ -42,63 +131,26 @@ func doMouseClick(w int, h int) {
}
win := findWindowUnderMouse()
if win == nil {
log.Log(INFO, "click() nothing was at:", w, h)
log.Log(INFO, "click() check if", w, h, "is the libnotify icon")
if me.notify.icon.tk != nil && me.notify.icon.tk.gocuiSize.inRect(w, h) {
log.Log(GOCUI, "click() is libnotify.icon!")
if me.notify.icon.active {
log.Info("show notify.icon here")
setNotifyIconText("[X]")
me.notify.icon.active = false
} else {
log.Info("hide notify.icon here")
setNotifyIconText("[ ]")
me.notify.icon.active = true
}
return
}
if me.notify.clock.tk != nil && me.notify.clock.tk.gocuiSize.inRect(w, h) {
log.Log(GOCUI, "click() is the clock!")
if me.showHelp {
log.Info("show help")
showHelp()
} else {
log.Info("hide help")
hideHelp()
}
return
}
return
}
if !win.isWindowActive() {
win.makeWindowActive()
return
} else {
// potentally the user is closing the window
if win.checkWindowClose(w, h) {
return
}
}
if win != nil {
// look in this window for widgets
// widgets have priority. send the click here first
for _, tk := range win.findByXYreal(w, h) {
switch tk.WidgetType() {
switch tk.node.WidgetType {
case widget.Checkbox:
if tk.Checked() {
if tk.node.State.Checked {
log.Log(WARN, "checkbox is being set to false")
tk.SetChecked(false)
tk.node.State.Checked = false
tk.setCheckbox()
} else {
log.Log(WARN, "checkbox is being set to true")
tk.SetChecked(true)
tk.node.State.Checked = true
tk.setCheckbox()
}
me.myTree.SendUserEvent(tk.node)
return
case widget.Button:
tk.doButtonClick()
tk.dumpWidget("click()") // enable this to debug widget clicks
me.myTree.SendFromUser(tk.node)
return
case widget.Combobox:
tk.showDropdown()
@ -107,28 +159,39 @@ func doMouseClick(w int, h int) {
tk.showDropdown()
return
case widget.Textbox:
log.Log(WARN, "TODO: textbox click")
tk.prepTextbox()
return
case widget.Label:
if tk.node.InTable() {
if tk.node.State.AtH == 0 {
log.Log(NOW, "todo: sort by column here")
tk.dumpWidget("sort")
}
}
tk.showTextbox()
return
default:
// TODO: enable the GUI debugger in gocui
// tk.dumpWidget("undef click()") // enable this to debug widget clicks
}
}
}
log.Info("you clicked on a window, but not any widgets", win.cuiName)
win.redrawWindow(win.gocuiSize.w0, win.gocuiSize.h0)
me.stdout.outputOnTop = false
setThingsOnTop()
return
}
// todo: use this?
func ctrlDown(g *gocui.Gui, v *gocui.View) error {
log.Info("todo: clicked with ctrlDown")
return nil
var found bool
for _, tk := range findByXY(w, h) {
// will show you everything found on a mouse click. great for debugging!
// tk.dumpWidget("click()")
if tk.node.WidgetType == widget.Stdout {
// don't send clicks to the stdout debugging window
// continue
}
found = true
// tk.doWidgetClick(w, h)
return
}
if found {
return
}
log.Log(GOCUI, "click() nothing was at:", w, h)
return
}
func doMouseDoubleClick(w int, h int) {
@ -142,12 +205,14 @@ func doMouseDoubleClick(w int, h int) {
}
for _, tk := range findByXY(w, h) {
if tk.WidgetType() == widget.Window {
tk.makeWindowActive()
if tk.node.WidgetType == widget.Window {
tk.redrawWindow(tk.gocuiSize.w0, tk.gocuiSize.h0)
me.stdout.outputOnTop = false
setThingsOnTop()
return
}
if tk.WidgetType() == widget.Stdout {
if tk.node.WidgetType == widget.Stdout {
if me.stdout.outputOnTop {
me.stdout.outputOnTop = false
setThingsOnTop()

View File

@ -23,16 +23,16 @@ import (
// 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) {
me.ok = true // this tells init() it's okay to work with gocui
// this runs while the user moves the mouse. this highlights text
// toggle off all highlight views except for whatever is under the mouse
// START HIGHLIGHTING
for _, view := range g.Views() {
view.Highlight = false
}
w, h := g.MousePosition()
// TODO: try to highlight entire grid rows
if v, err := g.ViewByPosition(w, h); err == nil {
// block anything from highlighting while a dialog box is open
// todo: identify and highlight grid rows here
if me.dropdown.active || me.textbox.active {
if me.dropdown.tk != nil && me.dropdown.tk.v == v {
v.Highlight = true
@ -45,19 +45,7 @@ func mouseMove(g *gocui.Gui) {
}
}
// old hack. create the 'msg' view if it does not yet exist
// TODO: put this somewhere more correct
if widgetView, _ := g.View("msg"); widgetView == nil {
me.stdout.changed = true
if createStdout(g) {
return
}
return
}
// END HIGHLIGHTING
// Super Mouse Mode. very useful for debugging in the past. also, just fun
// very useful for debugging in the past. also, just fun
if me.supermouse {
w, h := g.MousePosition()
for _, tk := range findByXY(w, h) {
@ -66,19 +54,33 @@ func mouseMove(g *gocui.Gui) {
}
}
if me.mouse.mouseUp {
return
}
// EVERYTHING BELOW THIS IS RELATED TO MOUSE DRAGGING
// has the mouse been pressed down long enough to start dragging?
if time.Since(me.mouse.down) < me.mouse.clicktime {
// not dragging
// log.Info("not yet")
return
}
if me.dropdown.active || me.textbox.active {
// can't drag
// can't drag or do anything when dropdown or textbox are visible
return
}
// okay, the mouse is down and it has been long enough
// the user is trying to drag something. let's figure out what
// create the 'msg' view if it does not yet exist // TODO: put this somewhere more correct
if widgetView, _ := g.View("msg"); widgetView == nil {
if createStdout(g) {
return
}
return
}
/*
if me.mouse.globalMouseDown && (me.dropdown.active || me.textbox.active) {
log.Info("can't drag while dropdown or textbox are active", w, h)
return
}
*/
if me.mouse.mouseUp {
return
}
@ -88,8 +90,43 @@ func mouseMove(g *gocui.Gui) {
me.mouse.currentDrag.moveNew()
return
}
log.Info(fmt.Sprintf("gocui gui toolkit plugin error. nothing to drag at (%d,%d)", w, h))
log.Info(fmt.Sprintf("gui toolkit error. nothing to drag at (%d,%d)", w, h))
return
// if me.mouse.globalMouseDown {
// log.Info("msgMouseDown == true")
// plugin will segfault if you don't keep this inside a check for msgMouseDown
// don't move this code out of here
/*
// new function that is smarter
if tk := findWindowUnderMouse(); tk != nil {
tk.setAsDragging()
return
}
// first look for windows
for _, tk := range findByXY(w, h) {
if tk.node.WidgetType == widget.Window {
tk.setAsDragging()
return
}
}
// now look for the STDOUT window
for _, tk := range findByXY(w, h) {
if tk.node.WidgetType == widget.Flag {
tk.setAsDragging()
return
}
}
for _, tk := range findByXY(w, h) {
if tk.node.WidgetType == widget.Stdout {
tk.setAsDragging()
// tk.moveNew()
return
}
found = true
}
*/
}
func (tk *guiWidget) setAsDragging() {
@ -101,18 +138,26 @@ func (tk *guiWidget) setAsDragging() {
// this is how the window gets dragged around
func (tk *guiWidget) moveNew() {
w, h := me.baseGui.MousePosition()
if tk.WidgetType() == widget.Window {
if tk.node.WidgetType == widget.Window {
tk.window.wasDragged = true
// compute the new location based off how far the mouse has moved
// since the mouse button was pressed down
tk.gocuiSize.w0 = tk.lastW + w - me.mouse.downW
tk.gocuiSize.h0 = tk.lastH + h - me.mouse.downH
tk.makeWindowActive()
newW := tk.lastW + w - me.mouse.downW
newH := tk.lastH + h - me.mouse.downH
tk.redrawWindow(newW, newH)
setThingsOnTop() // sets help, Stdout, etc on the top after windows have been redrawn
return
}
if tk.WidgetType() == widget.Stdout {
if tk.node.WidgetType == widget.Flag {
me.baseGui.SetView(tk.cuiName, w-3, h-3, w+20, h+20, 0)
// tk.verifyRect()
s := fmt.Sprintf("move(%dx%d) %s ###", w, h, tk.cuiName)
tk.dumpWidget(s)
return
}
if tk.node.WidgetType == widget.Stdout {
if me.mouse.resize {
newW := w - me.stdout.lastW
newH := h - me.stdout.lastH
@ -130,7 +175,7 @@ func (tk *guiWidget) moveNew() {
tk.relocateStdout(newW, newH)
// log.Info("Resize false", w, h, newW, newH)
}
setThingsOnTop() // sets help, Stdout, etc on the top after windows have been redrawn
me.stdout.changed = true
}
// always place the help menu on top
setThingsOnTop() // sets help, Stdout, etc on the top after windows have been redrawn
}

88
find.go
View File

@ -61,7 +61,7 @@ func (tk *guiWidget) findByXYreal(w int, h int) []*guiWidget {
if tk.full.inRect(w, h) {
widgets = append(widgets, tk)
}
// log.Log(GOCUI, "findByXY() found", widget.WidgetType(), w, h)
// log.Log(GOCUI, "findByXY() found", widget.node.WidgetType, w, h)
// }
// }
// tk.verifyRect()
@ -84,7 +84,7 @@ func findWindows() []*guiWidget {
func (tk *guiWidget) findWindows() []*guiWidget {
var found []*guiWidget
if tk.WidgetType() == widget.Window {
if tk.node.WidgetType == widget.Window {
found = append(found, tk)
}
@ -94,6 +94,25 @@ func (tk *guiWidget) findWindows() []*guiWidget {
return found
}
// find the BG widget.
// This widget is always in the background and covers the whole screen.
// gocui seems to not return mouse events unless there is something there
func (tk *guiWidget) findBG() *guiWidget {
if tk.node.WidgetType == widget.Stdout {
if tk.node.WidgetId != me.stdout.wId {
tk.isBG = true
return tk
}
}
for _, child := range tk.children {
if found := child.findBG(); found != nil {
return found
}
}
return nil
}
// used by gocui.TabKey to rotate through the windows
func findNextWindow() *guiWidget {
var found bool
@ -129,6 +148,13 @@ func findWindowUnderMouse() *guiWidget {
}
}
/*
// print out the window list
for _, tk := range me.allwin {
log.Info("findWindowUnderMouse() print:", tk.labelN, tk.window.active, tk.window.order)
}
*/
// now check if the active window is below the mouse
for _, tk := range me.allwin {
if tk.window.active {
@ -145,6 +171,12 @@ func findWindowUnderMouse() *guiWidget {
return a.window.order - b.window.order
})
/*
// print out the window list
for _, tk := range me.allwin {
log.Info("findWindowUnderMouse() print:", tk.labelN, tk.window.active, tk.window.order)
}
*/
for _, win := range me.allwin {
if win.full.inRect(w, h) {
// log.Info(fmt.Sprintf("findWindowUnderMouse() found %s window (%dx%d)", win.cuiName, w, h))
@ -163,8 +195,14 @@ func findWindowUnderMouse() *guiWidget {
return nil
}
// todo: use this?
func ctrlDown(g *gocui.Gui, v *gocui.View) error {
log.Info("todo: clicked with ctrlDown")
return nil
}
func (tk *guiWidget) findParentWindow() *guiWidget {
if tk.WidgetType() == widget.Window {
if tk.node.WidgetType == widget.Window {
return tk
}
if tk.parent == nil {
@ -172,47 +210,3 @@ func (tk *guiWidget) findParentWindow() *guiWidget {
}
return tk.parent.findParentWindow()
}
func (tk *guiWidget) findWidgetByName(name string) *guiWidget {
if tk.cuiName == name {
return tk
}
for _, child := range tk.children {
found := child.findWidgetByName(name)
if found != nil {
return found
}
}
return nil
}
func (tk *guiWidget) findWidgetByView(v *gocui.View) *guiWidget {
if tk.v == v {
return tk
}
if tk.cuiName == v.Name() {
log.Log(NOW, "findWidget() error. names are mismatched or out of sync", tk.cuiName)
log.Log(NOW, "findWidget() or maybe the view has been deleted")
// return tk
}
for _, child := range tk.children {
found := child.findWidgetByView(v)
if found != nil {
return found
}
}
return nil
}
func (tk *guiWidget) findWidgetById(id int) *guiWidget {
if tk.WidgetId() == id {
return tk
}
for _, child := range tk.children {
found := child.findWidgetById(id)
if found != nil {
return found
}
}
return nil
}

116
help.go
View File

@ -1,7 +1,7 @@
// Copyright 2014 The gocui Authors. All rights reserved.
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
// Prior 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.
@ -11,6 +11,7 @@ import (
"errors"
"fmt"
"strings"
"time"
"github.com/awesome-gocui/gocui"
log "go.wit.com/log"
@ -25,20 +26,16 @@ import (
var helpText []string = []string{"Help Menu",
"",
"Tab toggle through windows",
"'O' toggle STDOUT",
"'H' toggle this gocui menu",
"'D' toggle light/dark mode",
"CTRL-z background to shell",
"CTRL-c quit()",
"H: toggle z(H)elp",
"D: toggle light/dark mode",
"Tab: toggle through windows",
"q: quit()",
"",
"Debugging:",
"'S' Supermouse mode",
"'M' list all widget positions",
"'L' list all widgets in tree",
"<Pgup> scroll up the STDOUT window",
"<Pgdn> scroll down the STDOUT window",
"'r' reverse STDOUT scrolling",
"O: toggle (O)output (os.STDOUT)",
"S: super mouse",
"M: list all widgets positions",
"L: list all widgets in tree",
}
func hideHelp() {
@ -69,18 +66,17 @@ func showHelp() error {
}
}
a := maxX - (newW + me.FramePadW)
b := me.notify.help.offsetH
c := maxX - 1
d := me.notify.help.offsetH + len(helpText) + me.FramePadH
help, err := g.SetView("help", a, b, c, d, 0)
help, err := g.SetView("help", maxX-(newW+me.FramePadW), 0, maxX-1, len(helpText)+me.FramePadH, 0)
if err != nil {
if !errors.Is(err, gocui.ErrUnknownView) {
return err
}
help.SelBgColor = gocui.ColorGreen
help.SelFgColor = gocui.ColorBlack
// fmt.Fprintln(help, "Enter: Click Button")
// fmt.Fprintln(help, "Tab/Space: Switch Buttons")
// fmt.Fprintln(help, "Backspace: Delete Button")
// fmt.Fprintln(help, "Arrow keys: Move Button")
fmt.Fprintln(help, strings.Join(helpText, "\n"))
@ -90,19 +86,85 @@ func showHelp() error {
}
g.SetViewOnTop("help")
me.helpLabel = help
/*
if me.treeRoot == nil {
log.Info("gogui makeClock() error. treeRoot == nil")
return nil
} else {
if me.clock.tk == nil {
makeClock()
me.clock.tk.MoveToOffset(maxX-10, 1)
me.clock.tk.Hide()
me.clock.tk.Show()
}
if me.clock.tk != nil {
me.clock.tk.MoveToOffset(maxX-10, 1)
me.clock.tk.Hide()
me.clock.tk.Show()
}
if me.stdout.tk == nil {
makeOutputWidget(me.baseGui, "made this in showHelp()")
msg := fmt.Sprintf("test to stdout from in showHelp() %d\n", me.ecount)
me.stdout.Write([]byte(msg))
log.Log(NOW, "log.log(NOW) test")
}
}
*/
return nil
}
func makeClock() {
me.clock.tk = makeNewFlagWidget(me.clock.wId)
me.clock.tk.dumpWidget("init() clock")
w, h := me.baseGui.MousePosition()
me.clock.tk.MoveToOffset(w, h)
me.clock.tk.labelN = time.Now().Format("15:04:05")
me.clock.tk.frame = false
me.clock.tk.setColorLabel()
me.clock.tk.Show()
me.clock.active = true
me.clock.tk.dumpWidget("showClock()")
}
// in the very end of redrawing things, this will place the help and stdout on the top or botton
// depending on the state the user has chosen
func setThingsOnTop() {
if me.showHelp { // terrible variable name. FIXME
// log.Info("help does not exist")
} else {
me.baseGui.SetViewOnTop("help")
}
if me.clock.tk != nil {
me.baseGui.SetViewOnTop(me.clock.tk.v.Name())
}
if me.dark {
me.stdout.tk.v.FgColor = gocui.ColorWhite
me.stdout.tk.v.BgColor = gocui.ColorBlack
} else {
me.stdout.tk.v.FgColor = gocui.ColorBlack
me.stdout.tk.v.BgColor = gocui.AttrNone
}
if me.stdout.outputOnTop {
me.baseGui.SetViewOnTop("msg")
} else {
me.baseGui.SetViewOnBottom("msg")
}
if me.stdout.startOnscreen {
log.Info("attempting to locate stdout on screen for the first time")
me.stdout.tk.relocateStdout(me.stdout.lastW, me.stdout.lastH)
me.stdout.startOnscreen = false
}
setBottomBG()
}
func setBottomBG() {
// this attempts to find the "BG" widget and set it to the background on the very very bottom
rootTK := me.treeRoot.TK.(*guiWidget)
if tk := rootTK.findBG(); tk != nil {
// log.Info("found BG. setting to bottom", tk.cuiName)
if me.dark {
tk.v.BgColor = gocui.ColorBlack
} else {
tk.v.BgColor = gocui.ColorWhite
}
tk.v.Clear()
me.baseGui.SetViewOnBottom(tk.cuiName)
w, h := me.baseGui.Size()
me.baseGui.SetView(tk.cuiName, -1, -1, w+1, h+1, 0)
}
}

482
init.go
View File

@ -9,13 +9,9 @@ package main
import (
"errors"
"fmt"
"os"
"runtime"
"runtime/debug"
"runtime/pprof"
"strconv"
"strings"
"time"
"github.com/awesome-gocui/gocui"
@ -27,130 +23,49 @@ import (
var VERSION string
var BUILDTIME string
var PLUGIN string = "gocui"
// this is called at the very initial connection
// between the app and this gocui plugin
// this is a good place to initialize gocui's default behavior
func toolkitInit() {
log.Log(INFO, "gocui toolkitInit() me.ok =", me.ok)
if me.baseGui == nil {
log.Info("gocui baseGui is still nil")
standardExit()
}
if me.treeRoot == nil {
log.Info("gocui treeRoot is still nil")
standardExit()
}
// w := me.treeRoot.TK.(*guiWidget)
// w.dumpTree("MM")
// w.dumpWindows("WW")
// SETUP HELP START
me.baseGui.Update(testRefresh)
log.Log(INFO, "gocui toolkitInit() trying showHelp() me.ok =", me.ok)
showHelp()
hideHelp()
// SETUP HELP END
// SETUP STDOUT START
if me.stdout.tk == nil {
makeOutputWidget(me.baseGui, "from setThingsOnTop()")
}
// time.Sleep(300 * time.Millisecond)
log.Log(INFO, "gocui toolkitInit() me.ok =", me.ok)
me.baseGui.Update(testRefresh)
if !me.stdout.init {
log.Log(INFO, "gocui toolkitInit() stdout.Init me.ok =", me.ok)
me.stdout.init = true
relocateStdoutOffscreen()
}
// time.Sleep(1 * time.Second)
me.stdout.outputOnTop = false
setThingsOnTop()
// SETUP STDOUT END
// SETUP BG
if me.BG.tk == nil {
me.BG.tk = makeNewInternalWidget(me.BG.wId)
}
// SETUP libnotify clock and menu
me.notify.clock.once.Do(makeNotifyClock)
me.notify.icon.once.Do(makeNotifyIcon)
// TODO: for some reason, this makes the background doesn't display
// PUT INIT DEBUG COOE HERE
var toggle bool
for i := 0; i < 4; i++ {
// enable this to show early debugging
// w := me.treeRoot.TK.(*guiWidget)
// w.dumpTree("MM")
// w.dumpWindows("WW")
time.Sleep(100 * time.Millisecond)
if toggle {
toggle = false
// log.Info("gocui toolkitInit() put testing true stuff here")
} else {
toggle = true
// log.Info("gocui toolkitInit() put testing false stuff here")
}
setBottomBG()
}
// PUT INIT DEBUG COOE HERE END
// TEST TEXTBOX START
// time.Sleep(1 * time.Second)
log.Log(INFO, "gocui toolkitInit() me.ok =", me.ok)
me.baseGui.Update(testRefresh)
if me.textbox.tk == nil {
log.Log(INFO, "gocui toolkitInit() initTextbox me.ok =", me.ok)
initTextbox()
}
// TEST TEXTBOX END
}
func toolkitClose() {
func queueToolkitClose() {
me.baseGui.Close()
}
// a GO GUI plugin should initTree in init()
// this should be done before the application
// starts trying to open up a channel
func init() {
me.myTree = initTree()
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 initPlugin() {
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(me.outf, "PANIC: initPlugin() recovered %v\n", r)
return
}
}()
func init() {
log.Log(INFO, "Init() of awesome-gocui")
var err error
// init the config struct default values
Set(&me, "default")
// initial stdout window settings
me.stdout.w = 180
me.stdout.h = 40
me.stdout.lastW = 4
me.stdout.lastH = 20
// just make up unique values for these
me.dropdown.wId = -77
me.textbox.wId = -55
me.stdout.wId = -4
me.clock.wId = -5
me.mouse.mouseUp = true
me.mouse.clicktime = time.Millisecond * 200
me.mouse.doubletime = time.Millisecond * 400
me.myTree = tree.New()
me.myTree.PluginName = "gocui"
go refreshGocui()
// read in defaults from config protobuf
if val, err := me.myTree.ConfigFind("stdout"); err == nil {
if val == "true" {
me.stdout.startOnscreen = true
// me.stdout.Write([]byte("starting with stdout onscreen\n"))
}
if val == "disable" {
log.Log(INFO, "gocui: attempt to COMPLETELY DISABLE STDOUT LOG")
me.stdout.disable = true
}
}
if val, err := me.myTree.ConfigFind("stdoutoffscreen"); err == nil {
if val == "false" {
// log.Log(NOW, "gocui: START ON SCREEN TRUE")
me.stdout.startOnscreen = true
me.stdout.Write([]byte("starting with stdout onscreen\n"))
} else {
me.stdout.Write([]byte("starting with stdout offscreen\n"))
}
}
if val, err := me.myTree.ConfigFind("dark"); err == nil {
@ -163,159 +78,30 @@ func initPlugin() {
me.dark = true
}
}
// todo: make this a tmp file that goes away
if !me.stdout.disable {
tmpFile, err := os.CreateTemp("", "gocui-*.log")
if err != nil {
fmt.Println("Error creating temp file:", err)
standardExit()
}
// defer os.Remove(tmpFile.Name())
log.Log(INFO, "stdout.disable == true. writing to", tmpFile.Name())
me.outf = tmpFile
// todo: some early output still goes to the /tmp/ file
//time.Sleep(200 * time.Millisecond)
log.CaptureMode(me.stdout)
}
me.starttime = time.Now()
log.Log(INFO, "Init() of awesome-gocui")
// init the config struct default values
Set(&me, "default")
// initial app window settings
// initial stdout window settings
me.stdout.w = 180
me.stdout.h = 40
me.stdout.lastW = 4
me.stdout.lastH = 20
if val, err := me.myTree.ConfigFind("stdoutsize"); err == nil {
parts := strings.Fields(val)
if len(parts) == 4 {
log.Info("initial stdout settings:", parts, "setting startOnscreen = true")
me.stdout.w, _ = strconv.Atoi(parts[0])
me.stdout.h, _ = strconv.Atoi(parts[1])
me.stdout.lastW, _ = strconv.Atoi(parts[2])
me.stdout.lastH, _ = strconv.Atoi(parts[3])
me.stdout.startOnscreen = true
} else {
log.Info("initial stdout settings parse error:", parts)
}
}
// just make up unique values for these
me.dropdown.wId = -77
me.textbox.wId = -55
me.stdout.wId = -4
me.BG.wId = -22
// the clock widget id and offset
me.notify.clock.wId = -5
me.notify.clock.offsetW = 13
me.notify.clock.offsetH = 1
me.notify.icon.wId = -6
me.notify.icon.offsetW = 4
me.notify.icon.offsetH = 1
me.notify.help.wId = -7
me.notify.help.offsetH = 3
Set(&me.dropdown, "default")
// s := fmt.Sprintln("fake default check =", me.FakeW, "dropdown.Id", me.dropdown.Id)
// me.stdout.Write([]byte(s))
me.mouse.mouseUp = true
me.mouse.clicktime = time.Millisecond * 200
me.mouse.doubletime = time.Millisecond * 400
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
me.newWindowTrigger = make(chan *guiWidget, 1)
go newWindowTrigger()
go refreshGocui()
log.Log(NOW, "Init() start pluginChan")
if me.stdout.disable {
log.Info("Using STDOUT")
} else {
log.Info("Using gocui STDOUT")
os.Stdout = me.outf
log.CaptureMode(me.outf)
}
// init gocui
g, err := gocui.NewGui(gocui.OutputNormal, true)
if err != nil {
os.Exit(-1)
return
}
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)
// register how the 'gocui' will work as a GO toolkit plugin
// all applications will use these keys. they are universal.
// registered event handlers still have the events sent to gocuiEvent() above
registerHandlers(g)
time.Sleep(100 * time.Millisecond)
if me.outf != nil {
fmt.Fprintln(me.outf, "hello world", time.Since(me.starttime))
}
// coreStdout()
// createStdout(g)
// tell 'tree' that we are okay to start talking to
me.myTree.InitOK()
me.ok = true // this tells init() it's okay to work with gocui
go gocuiMain()
}
// This goroutine sits in gocui's MainLoop()
func gocuiMain() {
defer func() {
if r := recover(); r != nil {
log.Warn("PANIC ecovered in gocuiMain()", r)
if me.outf == nil {
debug.PrintStack()
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
panic(os.Stdout)
} else {
fmt.Fprintf(me.outf, "PANIC recovered in r = %v", r)
os.Stderr = me.outf
os.Stdout = me.outf
debug.PrintStack()
pprof.Lookup("goroutine").WriteTo(me.outf, 1)
panic(me.outf)
}
}
}()
// me.stdout.Write([]byte("begin gogui.MainLoop()\n"))
if err := me.baseGui.MainLoop(); err != nil && !errors.Is(err, gocui.ErrQuit) {
log.Log(NOW, "g.MainLoop() panic err =", err)
// normally panic here
panic("gocuiTKmainloop OOPS")
}
// 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()
if me.outf != nil {
log.Log(NOW, "standardExit() doing outf.Close()")
me.outf.Close()
os.Remove(me.outf.Name())
}
outf.Close()
// log(true, "standardExit() setOutput(os.Stdout)")
// setOutput(os.Stdout)
log.Log(NOW, "standardExit() send back Quit()")
@ -330,17 +116,109 @@ func standardClose() {
log.Log(NOW, "standardExit() doing baseGui.Close()")
me.baseGui.Close()
log.Log(NOW, "standardExit() doing outf.Close()")
me.outf.Close()
os.Remove(me.outf.Name())
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.Info("error opening file:", err)
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)
// register how the 'gocui' will work as a GO toolkit plugin
// all applications will use these keys. they are universal.
// registered event handlers still have the events sent to gocuiEvent() above
registerHandlers(g)
me.stdout.Write([]byte("begin gogui.MainLoop()\n"))
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")
}
}
// this hack is to wait for the application to send something
// before trying to do anything. todo: rethink this someday
func waitOK() {
@ -352,17 +230,6 @@ func waitOK() {
}
}
// this hack is to wait for the application to send something
// before trying to do anything. todo: rethink this someday
func waitFirstWindow() {
for {
if me.firstWindowOk {
return
}
time.Sleep(10 * time.Millisecond)
}
}
// empty function. this triggers gocui to refresh the screen
func testRefresh(*gocui.Gui) error {
// log.Info("in testRefresh")
@ -371,94 +238,59 @@ func testRefresh(*gocui.Gui) error {
// refresh the screen 10 times a second
func refreshGocui() {
defer func() {
if r := recover(); r != nil {
if me.outf == nil {
log.Info("INIT PLUGIN recovered in r", r)
} else {
fmt.Fprintln(me.outf, "INIT PLUGIN recovered in r", r)
}
return
}
}()
var lastRefresh time.Time
lastRefresh = time.Now()
me.refresh = false
for {
time.Sleep(100 * time.Millisecond)
// log.Info("refresh checking ok")
if !me.ok {
continue
}
// redraw the windows if something has changed
if time.Since(lastRefresh) > 1000*time.Millisecond {
if me.refresh {
log.Log(NOW, "newWindowTrigger() sending refresh to channel")
me.newWindowTrigger <- me.treeRoot.TK.(*guiWidget)
me.refresh = false
}
if me.stdout.changed {
me.stdout.changed = false
lastRefresh = time.Now()
new1 := new(tree.ToolkitConfig)
new1.Plugin = "gocui"
new1.Name = "stdoutsize"
width := me.stdout.tk.gocuiSize.w1 - me.stdout.tk.gocuiSize.w0
height := me.stdout.tk.gocuiSize.h1 - me.stdout.tk.gocuiSize.h0
new1.Value = fmt.Sprintf("%d %d %d %d", width, height, me.stdout.tk.gocuiSize.w0, me.stdout.tk.gocuiSize.h0)
me.myTree.ConfigSave(new1)
// log.Log(NOW, "newWindowTrigger() gocui setting stdout size =", new1.Value)
// me.stdout.tk.dumpWidget("save")
}
}
// this code updates the clock
if time.Since(lastRefresh) > 1000*time.Millisecond {
// artificially pause clock while dragging.
// this is a reminder to make this refresh code smarter
// after the switch to protocol buffers
me.myTree.Lock()
if me.mouse.mouseUp {
// log.Info("refresh now on mouseUp")
// todo: add logic here to see if the application has changed anything
libNotifyUpdate()
lastRefresh = time.Now()
me.baseGui.Update(testRefresh)
if me.clock.tk != nil && !me.showHelp {
// also double check the gocui view exists
if me.clock.tk.v != nil {
me.clock.tk.v.Clear()
me.clock.tk.labelN = time.Now().Format("15:04:05")
me.clock.tk.v.WriteString(me.clock.tk.labelN)
}
}
} else {
if time.Since(lastRefresh) > 3*time.Second {
libNotifyUpdate()
// log.Info("refresh skip on mouseDown")
// me.baseGui.Update()
}
lastRefresh = time.Now()
}
}
me.myTree.Unlock()
}
}
}
// set the widget start width & height
func newWindowTrigger() {
// log.Log(NOW, "newWindowTriggerl() START")
log.Log(NOW, "newWindowTriggerl() START")
for {
// log.Log(NOW, "GO plugin toolkit made a new window")
select {
case tk := <-me.newWindowTrigger:
// log.Log(NOW, "newWindowTrigger() got new window", tk.cuiName)
// time.Sleep(200 * time.Millisecond)
time.Sleep(200 * time.Millisecond)
waitOK()
me.myTree.Lock()
// time.Sleep(200 * time.Millisecond)
redoWindows(me.FirstWindowW, me.FirstWindowH)
me.firstWindowOk = true
redoWindows(1, -1)
if !me.stdout.init {
me.stdout.init = true
relocateStdoutOffscreen()
}
if me.textbox.tk == nil {
initTextbox()
}
tk.makeWindowActive()
me.myTree.Unlock()
// place the new window relative to the mouse
tk.redrawWindow(me.mouse.downW+8, me.mouse.downH-2)
// tk.redrawWindow(tk.gocuiSize.w0, tk.gocuiSize.h0)
setThingsOnTop() // sets help, Stdout, etc on the top after windows have been redrawn
// log.Log(NOW, "newWindowTrigger() after sleep")
}
}
}

View File

@ -1,295 +0,0 @@
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
// this file implements a libnotify-like menu
// also there is SIGWINCH resizing
package main
import (
"fmt"
"time"
"github.com/awesome-gocui/gocui"
log "go.wit.com/log"
"go.wit.com/toolkits/tree"
"go.wit.com/widget"
)
// create a new widget in the binary tree
func makeNewInternalWidget(wId int) *guiWidget {
if me.treeRoot == nil {
log.Info("GOGUI Init ERROR. treeRoot == nil")
return nil
}
n := new(tree.Node)
n.WidgetType = widget.Flag
n.WidgetId = wId
n.ParentId = 0
// store the internal toolkit information
tk := new(guiWidget)
tk.frame = true
tk.node = n
tk.node.Parent = me.treeRoot
// set the name used by gocui to the id
tk.cuiName = fmt.Sprintf("%d DR", wId)
tk.setColorInput()
// add this new widget on the binary tree
tk.parent = me.treeRoot.TK.(*guiWidget)
if tk.parent == nil {
panic("makeNewFlagWidget() didn't get treeRoot guiWidget")
} else {
tk.parent.children = append(tk.parent.children, tk)
}
n.TK = tk
return tk
}
func makeNotifyClock() {
if me.treeRoot == nil {
log.Info("gogui makeClock() error. treeRoot == nil")
return
}
me.notify.clock.tk = makeNewInternalWidget(me.notify.clock.wId)
// me.notify.clock.tk.dumpWidget("init() clock")
me.notify.clock.tk.MoveToOffset(0, 0)
me.notify.clock.tk.labelN = time.Now().Format("15:04:05")
me.notify.clock.tk.frame = false
me.notify.clock.tk.setColorLabel()
me.notify.clock.tk.Show()
me.notify.clock.active = true
// me.notify.clock.tk.dumpWidget("notifyClock()")
}
func makeNotifyIcon() {
if me.treeRoot == nil {
log.Info("gogui makeClock() error. treeRoot == nil")
return
}
me.notify.icon.tk = makeNewInternalWidget(me.notify.icon.wId)
// me.notify.icon.tk.dumpWidget("init() menu")
w, _ := me.baseGui.Size()
me.notify.icon.tk.MoveToOffset(w-5, me.notify.icon.offsetH)
me.notify.icon.tk.labelN = "[ ]"
me.notify.icon.tk.frame = false
me.notify.icon.tk.setColorNotifyIcon()
me.notify.icon.tk.Show()
me.notify.icon.active = true
// me.notify.icon.tk.dumpWidget("notifyIcon()")
}
func libNotifyUpdate() {
if me.baseGui == nil {
log.Info("libNotifyUpdate error baseGui == nil")
return
}
// refresh GOCUI
me.baseGui.Update(testRefresh)
// me.baseGui.UpdateAsync(testRefresh) // Async option. probably don't need this?
if me.notify.clock.tk == nil {
log.Info("libNotifyUpdate error clock.tk == nil")
return
}
// check for SIGWINCH. If so, move the libnotify clock
w, h := me.baseGui.Size()
if me.winchW != w || me.winchH != h {
if me.winchW == 0 && me.winchH == 0 {
// this isn't really SIGWINCH. This is the app starting
} else {
log.Printf("gocui: long live SIGWINCH! (w,h) is now (%d,%d)\n", w, h)
}
me.winchW = w
me.winchH = h
me.notify.clock.tk.MoveToOffset(w-me.notify.clock.offsetW, me.notify.clock.offsetH)
me.notify.clock.tk.Hide()
me.notify.clock.tk.Show()
sigWinchBG()
sigWinchIcon()
}
// update the time
me.notify.clock.tk.v.Clear()
me.notify.clock.tk.labelN = time.Now().Format("15:04:05")
me.notify.clock.tk.v.WriteString(me.notify.clock.tk.labelN)
hardDrawAtgocuiSize(me.notify.clock.tk)
// hardDrawUnderMouse(me.notify.clock.tk, "clock")
// log.Info("libNotifyUpdate updated clock", me.notify.clock.tk.labelN)
if me.notify.icon.tk == nil {
log.Info("libNotifyUpdate error menu.tk == nil")
return
}
if me.notify.icon.tk.v == nil {
log.Info("libNotifyUpdate error menu.tk.v == nil")
return
}
// update the menu
hardDrawAtgocuiSize(me.notify.icon.tk)
me.notify.icon.tk.setColorNotifyIcon()
me.baseGui.SetViewOnTop(me.notify.icon.tk.v.Name())
me.baseGui.SetViewOnTop(me.notify.clock.tk.v.Name())
}
func setNotifyIconText(s string) {
me.notify.icon.tk.v.Clear()
me.notify.icon.tk.labelN = s
me.notify.icon.tk.v.WriteString(me.notify.icon.tk.labelN)
hardDrawAtgocuiSize(me.notify.icon.tk)
me.notify.icon.tk.setColorNotifyIcon()
me.baseGui.SetViewOnTop(me.notify.icon.tk.v.Name())
log.Info("setNotifyIconText() updated menu to:", me.notify.icon.tk.labelN)
// print out the window list // TODO: put this in libnotify
for _, tk := range me.allwin {
log.Info("known window Window", tk.labelN, tk.window.active, tk.window.order)
}
if s == "[X]" {
log.Warn("should turn on help window here")
showHelp()
} else {
log.Warn("should turn off help window here")
hideHelp()
}
}
// in the very end of redrawing things, this will place the help and stdout on the top or botton
// depending on the state the user has chosen
func setThingsOnTop() {
if me.showHelp { // terrible variable name. FIXME
// log.Info("help does not exist")
} else {
me.baseGui.SetViewOnTop("help")
}
if me.notify.clock.tk != nil {
me.baseGui.SetViewOnTop(me.notify.clock.tk.v.Name())
}
if me.notify.icon.tk != nil {
if me.notify.icon.tk.v != nil {
me.baseGui.SetViewOnTop(me.notify.icon.tk.v.Name())
}
}
if me.stdout.tk == nil {
makeOutputWidget(me.baseGui, "from setThingsOnTop()")
}
if me.stdout.tk == nil {
return
}
if me.stdout.tk.v == nil {
return
}
if me.dark {
me.stdout.tk.v.FgColor = gocui.ColorWhite
me.stdout.tk.v.BgColor = gocui.ColorBlack
} else {
me.stdout.tk.v.FgColor = gocui.ColorBlack
me.stdout.tk.v.BgColor = gocui.AttrNone
}
if me.stdout.outputOnTop {
me.baseGui.SetViewOnTop("msg")
} else {
me.baseGui.SetViewOnBottom("msg")
}
if me.stdout.startOnscreen {
// log.Info("THIS TRIGGERS STDOUT") // todo: make a proper init() & move this there
me.stdout.tk.relocateStdout(me.stdout.lastW, me.stdout.lastH)
me.stdout.startOnscreen = false
}
setBottomBG()
}
// useful for debuggging
func hardDrawUnderMouse(tk *guiWidget, name string) {
if tk.v != nil {
tk.Hide()
}
w, h := me.baseGui.MousePosition()
r := new(rectType)
r.w0 = w
r.h0 = h
r.w1 = w + 8
r.h1 = h + 4
if err := tk.SetViewRect(r); err != nil {
log.Info("hardDrawUnderMouse() err", tk.cuiName, err)
tk.dumpWidget("hardDrawERR")
}
tk.v.Frame = false
tk.v.Clear()
tk.v.WriteString(tk.labelN + "\n" + name)
}
func hardDrawAtgocuiSize(tk *guiWidget) {
if tk.v != nil {
tk.Hide()
}
if err := tk.SetView(); err != nil {
log.Info("hardDrawAtgocuiSize() err ok widget", tk.cuiName)
tk.dumpWidget("hardDrawERR")
}
tk.v.Frame = false
tk.v.Clear()
tk.v.WriteString(tk.labelN)
// log.Verbose("hardDrawAtgocuiSize() err ok widget", tk.cuiName, a, b, c, d, tk.v.Name())
}
func sigWinchIcon() {
w, _ := me.baseGui.Size()
me.notify.icon.tk.MoveToOffset(w-me.notify.icon.offsetW, me.notify.icon.offsetH)
me.notify.icon.tk.Hide()
me.notify.icon.tk.Show()
}
func sigWinchBG() {
tk := me.BG.tk
w, h := me.baseGui.Size()
tk.gocuiSize.w0 = -1
tk.gocuiSize.h0 = -1
tk.gocuiSize.w1 = w + 1
tk.gocuiSize.h1 = h + 1
if err := tk.SetView(); err != nil {
tk.dumpWidget("sigWinchBGerr()")
log.Log(ERROR, "sigWinchBG()", err)
}
log.Log(INFO, "background resized to", tk.gocuiSize)
}
// find the "BG" widget and set it to the background on the very very bottom
func setBottomBG() {
if me.BG.tk == nil {
log.Info("background tk widget not initialized")
return
}
tk := me.BG.tk
// log.Info("found BG. setting to bottom", tk.cuiName)
if tk.v == nil {
sigWinchBG()
return
}
if me.dark {
tk.v.BgColor = gocui.ColorBlack
} else {
tk.v.BgColor = gocui.ColorWhite
}
tk.v.Clear()
me.baseGui.SetViewOnBottom(tk.cuiName)
w, h := me.baseGui.Size()
tk.gocuiSize.w0 = -1
tk.gocuiSize.h0 = -1
tk.gocuiSize.w1 = w + 1
tk.gocuiSize.h1 = h + 1
tk.SetView()
}

63
node.go
View File

@ -1,63 +0,0 @@
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
package main
import (
"go.wit.com/widget"
)
func (tk *guiWidget) WidgetType() widget.WidgetType {
if tk.node == nil {
return widget.Label
}
return tk.node.WidgetType
}
func (tk *guiWidget) WidgetId() int {
return tk.node.WidgetId
}
func (tk *guiWidget) GetLabel() string {
return tk.node.GetLabel()
}
func (tk *guiWidget) IsEnabled() bool {
return tk.node.IsEnabled()
}
func (tk *guiWidget) Checked() bool {
return tk.node.State.Checked
}
func (tk *guiWidget) Hidden() bool {
if tk.node == nil {
return false
}
if tk.parent == nil {
return tk.node.Hidden()
}
if tk.parent.WidgetId() == 0 {
return tk.node.Hidden()
}
if tk.parent.Hidden() {
return true
}
return tk.node.Hidden()
}
func (tk *guiWidget) Direction() widget.Orientation {
return tk.node.State.Direction
}
func (tk *guiWidget) GridW() int {
return tk.node.State.AtW
}
func (tk *guiWidget) GridH() int {
return tk.node.State.AtH
}
func (tk *guiWidget) SetChecked(b bool) {
tk.node.State.Checked = b
}

View File

@ -34,7 +34,7 @@ func (tk *guiWidget) Position() (int, int) {
}
func (w *guiWidget) placeBox(startW int, startH int) {
if w.WidgetType() != widget.Box {
if w.node.WidgetType != widget.Box {
return
}
@ -50,7 +50,7 @@ func (w *guiWidget) placeBox(startW int, startH int) {
// re-get the Size (they should not have changed, but maybe they can?)
// TODO: figure this out or report that they did
sizeW, sizeH = child.Size()
if w.Direction() == widget.Vertical {
if w.node.State.Direction == widget.Vertical {
log.Log(INFO, "BOX IS VERTICAL ", w.String(), "newWH()", newW, newH, "child()", sizeW, sizeH, child.String())
// expand based on the child height
newH += sizeH
@ -77,7 +77,7 @@ func (tk *guiWidget) placeWidgets(startW int, startH int) (int, int) {
tk.startW = startW
tk.startH = startH
switch tk.WidgetType() {
switch tk.node.WidgetType {
case widget.Window:
tk.full.w0 = startW
tk.full.h0 = startH
@ -143,17 +143,11 @@ func (tk *guiWidget) placeWidgets(startW int, startH int) (int, int) {
// tk.dumpWidget(fmt.Sprintf("PlaceGroup(%d,%d)", maxW, newH))
return maxW, newH
case widget.Button:
if tk.isDense() && tk.isInGrid() {
if tk.isWindowDense() && tk.isInGrid() {
tk.frame = false
// tk.color = nil
// tk.defaultColor = nil
/*
if tk.IsEnabled() {
tk.color = nil
tk.defaultColor = nil
tk.setColorButtonDense()
} else {
tk.setColorDisable()
}
*/
// if tk.full.Height() > 0 {
tk.full.h1 = tk.full.h0
// }
@ -167,16 +161,8 @@ func (tk *guiWidget) placeWidgets(startW int, startH int) (int, int) {
return 0, 0
}
func (tk *guiWidget) isDense() bool {
if tk.node.InTable() {
return true
}
return tk.isWindowDense()
}
func (tk *guiWidget) isWindowDense() bool {
if tk.WidgetType() == widget.Window {
if tk.node.WidgetType == widget.Window {
return tk.window.dense
}
if tk.parent == nil {
@ -186,7 +172,7 @@ func (tk *guiWidget) isWindowDense() bool {
}
func (tk *guiWidget) isInGrid() bool {
if tk.WidgetType() == widget.Grid {
if tk.node.WidgetType == widget.Grid {
return true
}
if tk.parent == nil {
@ -197,10 +183,12 @@ func (tk *guiWidget) isInGrid() bool {
func (w *guiWidget) placeGrid(startW int, startH int) (int, int) {
// w.showWidgetPlacement("grid0:")
if w.WidgetType() != widget.Grid {
if w.node.WidgetType != widget.Grid {
return 0, 0
}
dense := w.isWindowDense()
w.full.w0 = startW
w.full.h0 = startH
@ -209,22 +197,22 @@ func (w *guiWidget) placeGrid(startW int, startH int) (int, int) {
childW, childH := child.placeWidgets(child.startW, child.startH)
// set the child's realWidth, and grid offset
if w.widths[child.GridW()] < childW {
w.widths[child.GridW()] = childW
if w.widths[child.node.State.AtW] < childW {
w.widths[child.node.State.AtW] = childW
}
if w.heights[child.GridH()] < childH {
w.heights[child.GridH()] = childH
if w.heights[child.node.State.AtH] < childH {
w.heights[child.node.State.AtH] = childH
}
if child.isDense() {
if w.heights[child.GridH()] > 0 {
w.heights[child.GridH()] = 1
if dense {
if w.heights[child.node.State.AtH] > 0 {
w.heights[child.node.State.AtH] = 1
} else {
w.heights[child.GridH()] = 0
w.heights[child.node.State.AtH] = 0
}
}
// child.showWidgetPlacement("grid: ")
log.Log(INFO, "placeGrid:", child.String(), "child()", childW, childH, "At()", child.GridW(), child.GridH())
log.Log(INFO, "placeGrid:", child.String(), "child()", childW, childH, "At()", child.node.State.AtW, child.node.State.AtH)
}
var maxW int = 0
@ -236,12 +224,12 @@ func (w *guiWidget) placeGrid(startW int, startH int) (int, int) {
var totalW, totalH int
for i, w := range w.widths {
if i < child.GridW() {
if i < child.node.State.AtW {
totalW += w
}
}
for i, h := range w.heights {
if i < child.GridH() {
if i < child.node.State.AtH {
totalH += h
}
}
@ -257,7 +245,7 @@ func (w *guiWidget) placeGrid(startW int, startH int) (int, int) {
maxH = totalH
}
log.Log(INFO, "placeGrid:", child.String(), "new()", newW, newH, "At()", child.GridW(), child.GridH())
log.Log(INFO, "placeGrid:", child.String(), "new()", newW, newH, "At()", child.node.State.AtW, child.node.State.AtH)
child.placeWidgets(newW, newH)
// child.showWidgetPlacement("grid2:")
}
@ -326,8 +314,8 @@ func textSize(n *tree.Node) (int, int) {
*/
func (tk *guiWidget) gocuiSetWH(sizeW, sizeH int) {
w := len(tk.GetLabel())
lines := strings.Split(tk.GetLabel(), "\n")
w := len(tk.node.GetLabel())
lines := strings.Split(tk.node.GetLabel(), "\n")
h := len(lines)
if tk.Hidden() {

170
plugin.go
View File

@ -4,7 +4,8 @@
package main
import (
"github.com/awesome-gocui/gocui"
// if you include more than just this import
// then your plugin might be doing something un-ideal (just a guess from 2023/02/27)
"go.wit.com/log"
"go.wit.com/toolkits/tree"
"go.wit.com/widget"
@ -16,7 +17,7 @@ func newAdd(n *tree.Node) {
return
}
if n.TK != nil {
log.Log(INFO, "Tree Add() sent a widget we aleady seem to have")
log.Warn("Tree Add() sent a widget we aleady seem to have")
// this is done to protect the plugin being 'refreshed' with the
// widget binary tree. TODO: find a way to keep them in sync
return
@ -34,26 +35,24 @@ func newAdd(n *tree.Node) {
w = n.TK.(*guiWidget)
}
*/
// w.setColor(&colorDisabled)
w := n.TK.(*guiWidget)
w.Show()
me.refresh = true // testing code to see if refresh can work
}
// for gocui as a GUI plugin, SetTitle & SetLabel are identical to SetText
func setTitle(n *tree.Node, s string) {
setText(n, s)
me.refresh = true // testing code to see if refresh can work
func newSetTitle(n *tree.Node, s string) {
newSetText(n, s)
}
func setLabel(n *tree.Node, s string) {
setText(n, s)
me.refresh = true // testing code to see if refresh can work
func newSetLabel(n *tree.Node, s string) {
newSetText(n, s)
}
// setText() and addText() are simple. They take the event sent
// newSetText() and newAddText() are simple. They take the event sent
// to the GO plugin from the application and lookup the plugin structure
// then pass that event to gocui. This is the transfer point
func setText(n *tree.Node, s string) {
func newSetText(n *tree.Node, s string) {
if n == nil {
log.Warn("Tree Error: Add() sent n == nil")
return
@ -64,10 +63,9 @@ func setText(n *tree.Node, s string) {
}
w := n.TK.(*guiWidget)
w.SetText(s)
me.refresh = true // testing code to see if refresh can work
}
func addText(n *tree.Node, s string) {
func newAddText(n *tree.Node, s string) {
if n == nil {
log.Warn("Tree Error: Add() sent n == nil")
return
@ -78,7 +76,61 @@ func addText(n *tree.Node, s string) {
}
w := n.TK.(*guiWidget)
w.AddText(s)
me.refresh = true // testing code to see if refresh can work
}
func newaction(n *tree.Node, atype widget.ActionType) {
log.Log(INFO, "newaction() START", atype)
if !me.ok {
log.Log(INFO, "newaction() START NOT OKAY", atype)
log.Log(INFO, "newaction() START NOT OKAY", atype)
log.Log(INFO, "newaction() START NOT OKAY", atype)
waitOK()
}
if n == nil {
log.Warn("Tree Error: Add() sent n == nil")
return
}
if n.TK == nil {
log.Warn("Tree sent an action on a widget we didn't seem to have.")
// do this init here again? Probably something
// went wrong and we should reset the our while gocui.View tree
n.TK = initWidget(n)
}
w := n.TK.(*guiWidget)
switch atype {
case widget.Show:
w.Show()
case widget.Hide:
if n.Hidden() {
// already hidden
} else {
log.Log(NOW, "attempt to hide() =", atype, n.WidgetId, n.WidgetType, n.ProgName())
w.node.State.Hidden = true
w.Hide()
}
case widget.Move:
log.Log(NOW, "attempt to move() =", atype, n.WidgetType, n.ProgName())
case widget.ToolkitClose:
log.Log(NOW, "attempting to close the plugin and release stdout and stderr")
standardClose()
case widget.Enable:
w.enable = true
w.enableColor()
case widget.Disable:
w.enable = false
w.disableColor()
case widget.Delete:
if w == nil {
return
} else {
w.hideWidgets()
w.deleteNode()
}
n.DeleteNode()
default:
log.Log(ERROR, "newaction() UNHANDLED Action Type =", atype, "WidgetType =", n.WidgetType, "Name =", n.ProgName())
}
log.Log(INFO, "newaction() END", atype, n.String())
}
func (w *guiWidget) deleteGocuiViews() {
@ -116,7 +168,7 @@ func (w *guiWidget) AddText(text string) {
}
w.vals = append(w.vals, text)
for i, s := range w.vals {
log.Log(INFO, "AddText()", w.String(), i, s)
log.Log(NOW, "AddText()", w.String(), i, s)
}
w.SetText(text)
}
@ -156,92 +208,8 @@ func (tk *guiWidget) GetText() string {
// return gocui.view name?
return tk.cuiName
}
if tk.GetLabel() != "" {
return tk.GetLabel()
if tk.node.State.Label != "" {
return tk.node.State.Label
}
return ""
}
// hack. use "textbox widget" to "disable" user events
func hideDisable() {
if me.textbox.tk == nil {
initTextbox()
}
me.textbox.tk.Hide()
me.textbox.tk.enable = false
me.textbox.tk.node.State.Enable = false
me.textbox.active = false
me.baseGui.SetCurrentView("help")
// me.baseGui.DeleteView(me.textbox.tk.cuiName)
// me.baseGui.DeleteView(me.textbox.tk.v.Name())
}
// hack. use "textbox widget" to "disable" user events
func showDisable() {
if me.textbox.tk == nil {
initTextbox()
me.textbox.tk.prepTextbox()
}
r := new(rectType)
r.w0 = 2
r.h0 = 1
r.w1 = r.w0 + 24
r.h1 = r.h0 + 2
me.textbox.tk.forceSizes(r)
me.textbox.tk.Show() // actually makes the gocui view. TODO: redo this
// log.Info("textbox should be shown")
// showTextbox("Running...")
// me.textbox.tk.dumpWidget("shown?")
me.textbox.tk.setColorModal()
me.textbox.tk.v.Clear()
me.textbox.tk.v.WriteString("Running...")
me.textbox.tk.v.Editable = true
me.textbox.tk.v.Wrap = true
me.textbox.tk.SetViewRect(r)
me.baseGui.SetCurrentView(me.textbox.tk.v.Name())
// bind the enter key to a function so we can close the textbox
me.baseGui.SetKeybinding(me.textbox.tk.v.Name(), gocui.KeyEnter, gocui.ModNone, theCloseTheTextbox)
me.textbox.active = true
}
func (tk *guiWidget) Disable() {
if tk == nil {
log.Log(NOW, "widget is nil")
return
}
switch tk.WidgetType() {
case widget.Box:
showDisable()
return
case widget.Button:
tk.setColorDisable()
return
default:
tk.dumpWidget("fixme: disable")
}
}
func (tk *guiWidget) Enable() {
if tk == nil {
log.Log(NOW, "widget is nil")
return
}
switch tk.WidgetType() {
case widget.Box:
hideDisable()
return
case widget.Button:
tk.restoreEnableColor()
return
default:
tk.dumpWidget("fixme: enable")
}
}

45
size.go
View File

@ -9,6 +9,19 @@ import (
"go.wit.com/widget"
)
func (tk *guiWidget) Hidden() bool {
if tk.parent == nil {
return tk.node.Hidden()
}
if tk.parent.node.WidgetId == 0 {
return tk.node.Hidden()
}
if tk.parent.Hidden() {
return true
}
return tk.node.Hidden()
}
func (tk *guiWidget) Size() (int, int) {
if tk == nil {
return 0, 0
@ -22,7 +35,7 @@ func (tk *guiWidget) Size() (int, int) {
return 0, 0
}
switch tk.WidgetType() {
switch tk.node.WidgetType {
case widget.Window:
var maxH int = 0
var maxW int = 0
@ -63,11 +76,11 @@ func (tk *guiWidget) Size() (int, int) {
case widget.Label:
return len(tk.String()) + 2, 1
case widget.Textbox:
return len(tk.String()) + 10, 3 // TODO: compute this based on 'window dense'
return len(tk.String()) + 2, 3 // TODO: compute this based on 'window dense'
case widget.Checkbox:
return len(tk.String()) + 2, 3 // TODO: compute this based on 'window dense'
case widget.Button:
if tk.isDense() {
if tk.isWindowDense() {
return len(tk.String()) + 2, 0
}
return len(tk.String()) + 2, 3 // TODO: compute this based on 'window dense'
@ -91,11 +104,11 @@ func (w *guiWidget) sizeGrid() (int, int) {
sizeW, sizeH := child.Size()
// set the child's realWidth, and grid offset
if w.widths[child.GridW()] < sizeW {
w.widths[child.GridW()] = sizeW
if w.widths[child.node.State.AtW] < sizeW {
w.widths[child.node.State.AtW] = sizeW
}
if w.heights[child.GridH()] < sizeH {
w.heights[child.GridH()] = sizeH
if w.heights[child.node.State.AtH] < sizeH {
w.heights[child.node.State.AtH] = sizeH
}
}
@ -112,7 +125,7 @@ func (w *guiWidget) sizeGrid() (int, int) {
}
func (w *guiWidget) sizeBox() (int, int) {
if w.WidgetType() != widget.Box {
if w.node.WidgetType != widget.Box {
return 0, 0
}
if w.Hidden() {
@ -126,7 +139,7 @@ func (w *guiWidget) sizeBox() (int, int) {
continue
}
sizeW, sizeH := child.Size()
if child.Direction() == widget.Vertical {
if child.node.State.Direction == widget.Vertical {
maxW += sizeW
if sizeH > maxH {
maxH = sizeH
@ -241,10 +254,10 @@ func (tk *guiWidget) setFullSize() bool {
tk.full.h1 = r.h1
changed = true
}
if tk.WidgetType() == widget.Button {
if tk.node.WidgetType == widget.Button {
tk.full.h1 = tk.full.h0 + 1
}
if tk.isDense() && tk.isInGrid() {
if tk.isWindowDense() && tk.isInGrid() {
tk.full.h1 = tk.full.h0
}
if changed {
@ -309,7 +322,7 @@ func (tk *guiWidget) buttonFullSize() rectType {
tk.full.h1 = r.h1
// total hack. fix this somewhere eventually correctly
if tk.isDense() { // total hack. fix this somewhere eventually correctly
if tk.isWindowDense() { // total hack. fix this somewhere eventually correctly
tk.full.h0 += 1 // total hack. fix this somewhere eventually correctly
tk.full.h1 = tk.full.h0 // total hack. fix this somewhere eventually correctly
}
@ -337,13 +350,13 @@ func (tk *guiWidget) getFullSize() rectType {
return r
}
if tk.WidgetType() == widget.Grid {
if tk.node.WidgetType == widget.Grid {
return tk.gridFullSize()
}
// these are 'simple' widgets
// the full size is exactly what gocui uses
switch tk.WidgetType() {
switch tk.node.WidgetType {
case widget.Label:
r := tk.buttonFullSize()
r.w1 += 5
@ -355,9 +368,7 @@ func (tk *guiWidget) getFullSize() rectType {
case widget.Checkbox:
return tk.buttonFullSize()
case widget.Dropdown:
r := tk.buttonFullSize()
r.w1 += 7 // TODO: fix this to be real
return r
return tk.buttonFullSize()
default:
}

View File

@ -4,6 +4,7 @@
package main
import (
"errors"
"fmt"
"slices"
"strings"
@ -17,24 +18,21 @@ import (
func createStdout(g *gocui.Gui) bool {
if me.stdout.tk == nil {
makeOutputWidget(g, "this is a create before a mouse click")
// me.logStdout.v.Write([]byte(msg))
// this will show very early debugging output
// keep this code commented out but do not remove it. when it doubt, this will be the Light of Elendil
// NEVER REMOVE THIS CODE
msg := fmt.Sprintf("test out gocuiEvent() %d\n", me.ecount)
// me.logStdout.v.Write([]byte(msg))
me.stdout.tk.Write([]byte(msg))
log.Log(NOW, "logStdout test out")
}
return true
}
func coreStdout() {
if me.stdout.tk != nil {
return
func makeOutputWidget(g *gocui.Gui, stringFromMouseClick string) *gocui.View {
if me.treeRoot == nil {
// keep skipping this until the binary tree is initialized
return nil
}
if me.stdout.tk == nil {
a := new(widget.Action)
a.ProgName = "2stdout2"
a.WidgetType = widget.Stdout
@ -45,37 +43,38 @@ func coreStdout() {
me.stdout.tk = initWidget(n)
tk := me.stdout.tk
tk.cuiName = "msg"
tk.gocuiSize.w0 = me.stdout.lastW
tk.gocuiSize.h0 = me.stdout.lastH
tk.gocuiSize.w1 = tk.gocuiSize.w0 + me.stdout.w
tk.gocuiSize.h1 = tk.gocuiSize.h0 + me.stdout.h
}
func makeOutputWidget(g *gocui.Gui, stringFromMouseClick string) *gocui.View {
if me.treeRoot == nil {
// keep skipping this until the binary tree is initialized
return nil
}
coreStdout()
if me.stdout.tk == nil {
return nil
}
me.stdout.tk.cuiName = "msg"
me.stdout.tk.SetView()
v, err := g.View("msg")
if v == nil {
// log.Log(NOW, "makeoutputwindow() this is supposed to happen. v == nil", err)
log.Log(NOW, "makeoutputwindow() this is supposed to happen. v == nil", err)
} else {
log.Log(NOW, "makeoutputwindow() msg != nil. WTF now? err =", err)
return v
}
v = me.stdout.tk.v
rect := me.stdout.tk.gocuiSize
v, err = g.SetView("msg", rect.w0, rect.h0, rect.w1, rect.h1, 0)
if errors.Is(err, gocui.ErrUnknownView) {
log.Log(NOW, "makeoutputwindow() this is supposed to happen?", err)
}
if err != nil {
log.Log(NOW, "makeoutputwindow() create output window failed", err)
return nil
}
if v == nil {
log.Log(NOW, "makeoutputwindow() msg == nil. WTF now? err =", err)
return nil
} else {
me.stdout.tk.v = v
}
v.Clear()
v.SelBgColor = gocui.ColorCyan
@ -84,8 +83,16 @@ func makeOutputWidget(g *gocui.Gui, stringFromMouseClick string) *gocui.View {
// g.SetViewOnBottom("msg")
// setBottomBG()
me.stdout.tk.v = v
me.stdout.tk.DrawAt(me.stdout.lastW, me.stdout.lastH)
relocateStdoutOffscreen()
/*
if me.stdout.outputOffscreen {
me.stdout.tk.relocateStdout(me.stdout.lastW, me.stdout.lastH)
} else {
relocateStdoutOffscreen()
}
*/
return v
}
@ -93,32 +100,14 @@ func relocateStdoutOffscreen() {
if me.stdout.tk == nil {
return
}
if !me.stdout.disable {
log.Info("Using gocui STDOUT")
log.CaptureMode(me.stdout.tk)
}
// log.Log(ERROR, "setting log.CaptureMode(tk.v) in relocateStdoutOffscreen()")
newW := 10
newH := 0 - me.stdout.h - 4
me.stdout.tk.relocateStdout(newW, newH)
}
func (tk *guiWidget) relocateStdout(w int, h int) {
if me.stdout.w < 8 {
me.stdout.w = 8
}
if me.stdout.h < 4 {
me.stdout.h = 4
}
if w+me.stdout.w < 2 {
w = 2
}
if h+me.stdout.h < 2 {
h = 2
}
w0 := w
h0 := h
w1 := w + me.stdout.w
@ -134,7 +123,8 @@ func (tk *guiWidget) relocateStdout(w int, h int) {
tk.full.h0 = h0
tk.full.h1 = h1
tk.SetView()
me.baseGui.SetView("msg", w0, h0, w1, h1, 0)
// me.baseGui.SetViewOnBottom("msg")
}
// from the gocui devs:
@ -143,40 +133,22 @@ func (tk *guiWidget) relocateStdout(w int, h int) {
// of functions like fmt.Fprintf, fmt.Fprintln, io.Copy, etc. Clear must
// be called to clear the view's buffer.
func (w stdout) Height() int {
if w.tk == nil {
return 40
}
return w.tk.gocuiSize.Height() - 2
}
func (w stdout) Write(p []byte) (n int, err error) {
me.writeMutex.Lock()
defer me.writeMutex.Unlock()
lines := strings.Split(strings.TrimSpace(string(p)), "\n")
me.stdout.outputS = append(me.stdout.outputS, lines...)
if me.outf != nil {
fmt.Fprint(me.outf, string(p))
}
return len(p), nil
}
func (w *guiWidget) Write(p []byte) (n int, err error) {
lines := strings.Split(strings.TrimSpace(string(p)), "\n")
if me.outf != nil {
fmt.Fprint(me.outf, string(p))
}
if w == nil {
me.stdout.outputS = append(me.stdout.outputS, lines...)
return len(p), nil
}
w.tainted = true
me.writeMutex.Lock()
defer me.writeMutex.Unlock()
lines := strings.Split(strings.TrimSpace(string(p)), "\n")
me.stdout.outputS = append(me.stdout.outputS, lines...)
tk := me.stdout.tk
@ -184,14 +156,43 @@ func (w *guiWidget) Write(p []byte) (n int, err error) {
return len(p), nil
}
if tk.v == nil {
// redo this old code
v, _ := me.baseGui.View("msg")
if v != nil {
// fmt.Fprintln(outf, "found msg")
tk.v = v
}
return len(p), nil
}
tk.refreshStdout()
/*
// optionally write the output to /tmp
s := fmt.Sprint(string(p))
s = strings.TrimSuffix(s, "\n")
fmt.Fprintln(outf, s)
v, _ := me.baseGui.View("msg")
if v != nil {
// fmt.Fprintln(outf, "found msg")
tk.v = v
}
} else {
// display the output in the gocui window
var cur []string
// chop off the last lines in the buffer
chop := len(me.stdout.outputS) - (me.stdout.h - 1)
if chop < 0 {
chop = 0
}
if len(me.stdout.outputS) > chop {
cur = append(cur, me.stdout.outputS[chop:]...)
} else {
cur = append(cur, me.stdout.outputS...)
}
slices.Reverse(cur)
tk.v.Clear()
fmt.Fprintln(tk.v, strings.Join(cur, "\n"))
}
*/
return len(p), nil
}
@ -199,11 +200,6 @@ func (w *guiWidget) Write(p []byte) (n int, err error) {
func (tk *guiWidget) refreshStdout() {
if len(me.stdout.outputS) < me.stdout.h+me.stdout.pager {
// log.Info(fmt.Sprintf("buffer too small=%d len(%d)", me.stdout.pager, len(me.stdout.outputS)))
var cur []string
cur = append(cur, me.stdout.outputS...)
slices.Reverse(cur)
tk.v.Clear()
fmt.Fprintln(tk.v, strings.Join(cur, "\n"))
return
}
@ -211,9 +207,7 @@ func (tk *guiWidget) refreshStdout() {
// chop off the last lines in the buffer
chop := len(me.stdout.outputS) - (me.stdout.pager + me.stdout.h)
cur = append(cur, me.stdout.outputS[chop:chop+me.stdout.h]...)
if me.stdout.reverse {
slices.Reverse(cur)
}
tk.v.Clear()
fmt.Fprintln(tk.v, strings.Join(cur, "\n"))
}

View File

@ -10,7 +10,6 @@ package main
import (
"fmt"
"os"
"reflect"
"strconv"
"sync"
@ -18,14 +17,10 @@ import (
"github.com/awesome-gocui/gocui"
"go.wit.com/lib/protobuf/guipb"
log "go.wit.com/log"
"go.wit.com/toolkits/tree"
"go.wit.com/widget"
)
var initOnce sync.Once // run initPlugin() only once
// It's probably a terrible idea to call this 'me'
// 2025 note: doesn't seem terrible to call this 'me' anymore. notsure.
var me config
@ -39,13 +34,9 @@ type config struct {
myTree *tree.TreeInfo // ?
currentWindow *guiWidget // this is the current tab or window to show
ok bool // if the user doesn't hit a key or move the mouse, gocui doesn't really start
firstWindowOk bool // allows the init to wait for the first window from the application
refresh bool // redraw everything?
ctrlDown *tree.Node // shown if you click the mouse when the ctrl key is pressed
helpLabel *gocui.View // ?
showHelp bool // toggle boolean for the help menu (deprecate?)
FirstWindowW int `default:"2"` // how far over to start window #1
FirstWindowH int `default:"0"` // how far down to start window #1
FramePadW int `default:"1" dense:"0"` // When the widget has a frame, like a button, it adds 2 lines runes on each side
FramePadH int `default:"1" dense:"0"` // When the widget has a frame, like a button, it adds 2 lines runes on each side
PadW int `default:"1" dense:"0"` // pad spacing
@ -62,7 +53,6 @@ type config struct {
RawW int `default:"1"` // the raw beginning of each window (or tab)
RawH int `default:"5"` // the raw beginning of each window (or tab)
FakeW int `default:"20"` // offset for the hidden widgets
DropdownId int `default:"-78"` // the widget id to use
padded bool // add space between things like buttons
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
@ -77,17 +67,11 @@ type config struct {
stdout stdout // information for the STDOUT window
dropdown dropdown // the dropdown menu
textbox dropdown // the textbox popup window
BG dropdown // the background widget
notify libnotify // emulates the desktop libnotify menu
clock dropdown // the textbox popup window
allwin []*guiWidget // for tracking which window is next
dark bool // use a 'dark' color palette
mouse mouse // mouse settings
showDebug bool // todo: move this into config struct
debug bool // todo: move this into config struct
starttime time.Time // checks how long it takes on startup
winchW int // used to detect SIGWINCH
winchH int // used to detect SIGWINCH
outf *os.File // hacks for capturing stdout
}
// stuff controlling how the mouse works
@ -113,14 +97,13 @@ type stdout struct {
outputOnTop bool // is the STDOUT window on top?
outputOffscreen bool // is the STDOUT window offscreen?
startOnscreen bool // start the output window onscreen?
disable bool // disable the stdout window. do not change os.Stdout & os.Stderr
lastW int // the last 'w' location (used to move from offscreen to onscreen)
lastH int // the last 'h' location (used to move from offscreen to onscreen)
// mouseOffsetW int // the current 'w' offset
// mouseOffsetH int // the current 'h' offset
init bool // moves the window offscreen on startup
outputS []string // the buffer of all the output
pager int // allows the user to page through the buffer
changed bool // indicates the user has changed stdout. gocui should remember the state here
reverse bool // flip the STDOUT upside down so new STDOUT lines are at the top
}
// settings for the dropdown window
@ -132,27 +115,8 @@ type dropdown struct {
h int // the height
active bool // is the dropdown menu currently in use?
init bool // moves the window offscreen on startup
// Id int `default:"-78"` // the widget id to use
wId int `default:"-78"` // the widget id to use
}
// settings for the dropdown window
type internalTK struct {
once sync.Once // for init
tk *guiWidget // where to show STDOUT
callerTK *guiWidget // which widget called the dropdown menu
wId int // the widget id to use
active bool // is the internal widget currently in use?
offsetW int // width offset
offsetH int // height offset
}
// the desktop libnotify menu
type libnotify struct {
clock internalTK // widget for the clock
icon internalTK // libnotify menu icon
window internalTK // the libnotify menu
help internalTK // the help menu
// dtoggle bool // is a dropdown or combobox currently active?
}
// this is the gocui way
@ -190,12 +154,11 @@ type window struct {
currentTab bool // the visible tab
selectedTab *tree.Node // for a window, this is currently selected tab
active bool // means this window is the active one
isBG bool // means this is the background widget. There is only one of these
order int // what level the window is on
// resize bool // only set the title once
collapsed bool // only show the window title bar
dense bool // true if the window is dense
large bool // true if the window is huge
pager int // allows the user to page through the window
dense bool // true if the window is huge
}
type colorT struct {
@ -213,8 +176,6 @@ type guiWidget struct {
parent *guiWidget // mirrors the binary node tree
children []*guiWidget // mirrors the binary node tree
node *tree.Node // the pointer back to the tree
pb *guipb.Widget // the guipb Widget
wtype widget.WidgetType // used for Tables for now. todo: fix this correctly
windowFrame *guiWidget // this is the frame for a window widget
internal bool // indicates the widget is internal to gocui and should be treated differently
hasTabs bool // does the window have tabs?
@ -239,9 +200,8 @@ type guiWidget struct {
frame bool // ?
selectedTab *tree.Node // for a window, this is currently selected tab
color *colorT // what color to use
colorLast colorT // the last color the widget had
defaultColor *colorT // the default colors // TODO: make a function for this instead
isTable bool // is this a table?
isBG bool // means this is the background widget. There is only one of these
}
// THIS IS GO COMPILER MAGIC
@ -266,11 +226,12 @@ func Set(ptr interface{}, tag string) error {
}
func setField(field reflect.Value, defaultVal string, name string) error {
if !field.CanSet() {
// log("setField() Can't set value", field, defaultVal)
return fmt.Errorf("Can't set value\n")
} else {
// log.Log(NOW, "setField() Can set value", name, defaultVal)
log.Log(NOW, "setField() Can set value", name, defaultVal)
}
switch field.Kind() {

View File

@ -1,93 +0,0 @@
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
package main
import (
"fmt"
"slices"
"go.wit.com/lib/protobuf/guipb"
"go.wit.com/log"
"go.wit.com/toolkits/tree"
"go.wit.com/widget"
)
func initGridPB(pb *guipb.Widget) *guiWidget {
var w *guiWidget
w = new(guiWidget)
w.pb = pb
w.wtype = widget.Grid
w.cuiName = fmt.Sprintf("%d %s", pb.Id, "TK")
w.labelN = pb.Name
w.isTable = true
return w
}
func showTable(t *guipb.Table) {
log.Info("gocui: should show table here")
if t == nil {
return
}
log.Info("gocui: table.Title", t.Title)
// log.Info("gocui: need to add window here id =", t.Window.Id, t.Window.Name)
if t.Grid == nil {
log.Info("gocui: missing grid widget. tree plugin error")
return
}
root := me.treeRoot.TK.(*guiWidget)
parent := root.findWidgetById(int(t.Parent.Id))
if parent == nil {
log.Info("gocui: show table error. parent.Id not found", t.Parent.Id)
return
}
log.Info("gocui: need to add grid here id =", t.Grid.Id)
grid := initGridPB(t.Grid)
grid.parent = parent
}
func enableWidget(n *tree.Node) {
tk := n.TK.(*guiWidget)
tk.Enable()
}
func disableWidget(n *tree.Node) {
tk := n.TK.(*guiWidget)
tk.Disable()
}
func showWidget(n *tree.Node) {
tk := n.TK.(*guiWidget)
tk.Show()
}
func hideWidget(n *tree.Node) {
tk := n.TK.(*guiWidget)
if n.WidgetType == widget.Window {
tk.windowFrame.Hide()
tk.hideWidgets()
}
tk.Hide()
tk.deleteWidget()
}
func (tk *guiWidget) deleteWidget() {
log.Log(INFO, "gocui deleteWidget() looking for child to delete:", tk.cuiName)
p := tk.parent
for i, child := range p.children {
if tk == child {
log.Log(INFO, "deleteWidget() found parent with child to delete:", i, child.cuiName, child.WidgetId())
p.children = slices.Delete(p.children, i, i+1)
}
}
tk.deleteTree()
}
func (tk *guiWidget) deleteTree() {
for _, child := range tk.children {
child.deleteTree()
}
tk.Hide()
}

View File

@ -7,7 +7,6 @@ package main
import (
"strings"
"time"
"github.com/awesome-gocui/gocui"
log "go.wit.com/log"
@ -30,21 +29,18 @@ func (tk *guiWidget) forceSizes(r *rectType) {
tk.force.h1 = r.h1
}
func initTextbox() {
func (callertk *guiWidget) showTextbox() {
if me.textbox.tk == nil {
// should only happen once
me.textbox.tk = makeNewFlagWidget(me.textbox.wId)
// me.textbox.tk.dumpWidget("init() textbox")
me.textbox.tk.dumpWidget("init() textbox")
}
}
func (callertk *guiWidget) prepTextbox() {
initTextbox()
if me.textbox.tk == nil {
log.Log(WARN, "prepTextbox() Is Broken")
log.Log(GOCUI, "showTextbox() Is Broken")
return
}
tk := me.textbox.tk
r := new(rectType)
// startW, startH := tk.Position()
r.w0 = callertk.gocuiSize.w0 + 4
@ -54,56 +50,28 @@ func (callertk *guiWidget) prepTextbox() {
me.textbox.tk.forceSizes(r)
me.textbox.tk.dumpWidget("after sizes")
me.textbox.callerTK = callertk
if me.textbox.tk.v != nil {
log.Log(WARN, "WARNING textbox DeleteView()")
log.Log(WARN, "WARNING textbox DeleteView()")
log.Log(WARN, "WARNING textbox DeleteView()")
me.baseGui.DeleteView(me.textbox.tk.cuiName)
time.Sleep(time.Second)
}
if err := me.textbox.tk.SetViewRect(r); err != nil {
log.Log(WARN, "textbox SetViewRect() failed", err, "view name =", me.textbox.tk.cuiName)
return
}
// me.textbox.tk.Show() // actually makes the gocui view. TODO: redo this?
showTextbox(callertk.String())
}
func showTextbox(callers string) {
// tk := me.textbox.tk
// me.textbox.tk.dumpWidget("after sizes")
log.Log(WARN, "showTextbox() caller string =", callers)
// me.textbox.tk.Show() // actually makes the gocui view. TODO: redo this
me.textbox.tk.Show() // actually makes the gocui view. TODO: redo this
if me.textbox.tk.v == nil {
log.Log(WARN, "textbox.tk.v == nil showTextbox() is broken")
log.Info("wtf went wrong")
return
}
me.textbox.tk.setColorModal()
me.textbox.tk.v.Clear()
cur := strings.TrimSpace(callers)
// log.Info("setting textbox string to:", cur)
me.textbox.tk.v.WriteString(cur)
me.textbox.tk.v.Editable = true
me.textbox.tk.v.Wrap = true
me.textbox.tk.SetView()
me.baseGui.SetView(me.textbox.tk.cuiName, r.w0, r.h0, r.w1, r.h1, 0)
me.baseGui.SetCurrentView(me.textbox.tk.v.Name())
// bind the enter key to a function so we can close the textbox
me.baseGui.SetKeybinding(me.textbox.tk.v.Name(), gocui.KeyEnter, gocui.ModNone, theCloseTheTextbox)
me.textbox.active = true
me.textbox.callerTK = callertk
me.baseGui.SetViewOnTop(me.textbox.tk.v.Name())
me.textbox.tk.dumpWidget("showTextbox()")
tk.dumpWidget("showTextbox()")
}
func theCloseTheTextbox(g *gocui.Gui, v *gocui.View) error {
@ -114,7 +82,7 @@ func theCloseTheTextbox(g *gocui.Gui, v *gocui.View) error {
// updates the text and sends an event back to the application
func textboxClosed() {
// get the text the user entered
var newtext string
newtext := "testing"
if me.textbox.tk.v == nil {
newtext = ""
} else {
@ -123,9 +91,9 @@ func textboxClosed() {
newtext = strings.TrimSpace(newtext)
me.textbox.active = false
me.textbox.tk.Hide()
// log.Info("textbox closed with text:", newtext, me.textbox.callerTK.cuiName)
log.Info("textbox closed", newtext)
if me.notify.clock.tk.v != nil {
if me.clock.tk.v != nil {
me.baseGui.SetCurrentView("help")
} else {
me.baseGui.SetCurrentView("msg")
@ -140,12 +108,12 @@ func textboxClosed() {
win := me.textbox.callerTK.findParentWindow()
if win != nil {
// win.dumpWidget("redraw this!!!")
win.dumpWidget("redraw this!!!")
tk := me.textbox.callerTK
// me.textbox.callerTK.dumpWidget("resize this!!!")
me.textbox.callerTK.dumpWidget("resize this!!!")
me.textbox.callerTK.Size()
me.textbox.callerTK.placeWidgets(tk.gocuiSize.w0-4, tk.gocuiSize.h0-4)
// tk.dumpWidget("resize:" + tk.String())
win.makeWindowActive()
tk.dumpWidget("resize:" + tk.String())
win.redrawWindow(win.gocuiSize.w0, win.gocuiSize.h0)
}
}

View File

@ -28,7 +28,7 @@ func setFake(n *tree.Node) {
}
}
// mostly just sets the colors of things
// func (n *node) addWidget(n *tree.Node) {
func addWidget(n *tree.Node) {
if !me.ok {
log.Log(INFO, "addWidget() START NOT OKAY")
@ -36,36 +36,38 @@ func addWidget(n *tree.Node) {
log.Log(INFO, "addWidget() START NOT OKAY")
waitOK()
}
tk := n.TK.(*guiWidget)
var tk *guiWidget
tk = n.TK.(*guiWidget)
log.Log(INFO, "setStartWH() w.id =", n.WidgetId, "n.name", n.String())
switch n.WidgetType {
case widget.Root:
log.Log(INFO, "setStartWH() rootNode w.id =", n.WidgetId, "w.name", n.String())
tk.color = &colorRoot
setFake(n)
return
case widget.Flag:
tk.color = &colorFlag
setFake(n)
return
case widget.Window:
tk.frame = false
tk.labelN = tk.GetText() + " X"
tk.setColor(&colorWindow)
me.newWindowTrigger <- tk
redoWindows(0, 0)
hideHelp()
showHelp()
return
case widget.Stdout:
tk.labelN = "moreSTDOUT"
n.State.ProgName = "moreSTDOUT"
n.State.Label = "moreSTDOUT"
tk.isFake = true
return
case widget.Tab:
tk.color = &colorTab
return
case widget.Button:
tk.setColorButton()
if tk.IsEnabled() {
} else {
tk.setColorDisable()
}
return
case widget.Checkbox:
tk.setColorInput()
@ -75,18 +77,20 @@ func addWidget(n *tree.Node) {
tk.setColorInput()
return
case widget.Textbox:
n.State.Label = ""
tk.labelN = " "
tk.setColorInput()
n.State.Label = "TEXTBOX"
tk.labelN = " " + n.State.Label
tk.color = &colorDropdown
return
case widget.Combobox:
tk.setColorInput()
tk.color = &colorCombobox
return
case widget.Box:
// tk.color = &colorBox
tk.isFake = true
setFake(n)
return
case widget.Grid:
// tk.color = &colorGrid
tk.isFake = true
setFake(n)
return
@ -95,17 +99,7 @@ func addWidget(n *tree.Node) {
tk.frame = false
return
case widget.Label:
if tk.node.InTable() {
if tk.node.State.AtH == 0 {
// this is the table header
tk.setColorLabelTable()
} else {
// todo: highlight the whole table row
tk.setColorLabel()
}
} else {
tk.setColorLabel()
}
tk.frame = false
return
default:

32
treeCallback.go Normal file
View File

@ -0,0 +1,32 @@
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
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 (
"go.wit.com/widget"
)
// Other goroutines must use this to access the GUI
//
// You can not acess / process the GUI thread directly from
// other goroutines. This is due to the nature of how
// Linux, MacOS and Windows work (they all work differently. suprise. surprise.)
//
// this sets the channel to send user events back from the plugin
func Callback(guiCallback chan widget.Action) {
me.myTree.Callback(guiCallback)
}
func PluginChannel() chan widget.Action {
return me.myTree.PluginChannel()
}

View File

@ -13,74 +13,11 @@ import (
"go.wit.com/widget"
)
// don't draw widgets that are too far down the window
func (tk *guiWidget) doNotDraw() bool {
var check bool
switch tk.WidgetType() {
case widget.Button:
check = true
case widget.Label:
check = true
default:
}
if !check {
return false
}
win := tk.findParentWindow()
if win == nil {
// don't draw anything if you can't find the parent window
return true
}
h := tk.gocuiSize.h0 - win.gocuiSize.h0
if h > 20 {
return true
}
return false
}
// page widgets in the window
func (tk *guiWidget) pageWidget() *rectType {
r := new(rectType)
var check bool
switch tk.WidgetType() {
case widget.Button:
check = true
case widget.Label:
check = true
default:
}
if !check {
return nil
}
win := tk.findParentWindow()
if win == nil {
// don't draw anything if you can't find the parent window
return nil
}
r.w0 = tk.gocuiSize.w0
r.h0 = tk.gocuiSize.h0
r.w1 = tk.gocuiSize.w1
r.h1 = tk.gocuiSize.h1
// r.h0 = tk.gocuiSize.h0 - win.gocuiSize.h0
if r.h0 > 20 {
return r
}
return r
}
// display's the text of the widget in gocui
// deletes the old view if it exists and recreates it
func (tk *guiWidget) drawView() {
var err error
log.Log(INFO, "drawView() START", tk.WidgetType(), tk.String())
log.Log(INFO, "drawView() START", tk.node.WidgetType, tk.String())
if me.baseGui == nil {
log.Log(ERROR, "drawView() ERROR: me.baseGui == nil", tk)
return
@ -88,7 +25,7 @@ func (tk *guiWidget) drawView() {
if tk.cuiName == "" {
log.Log(ERROR, "drawView() tk.cuiName was not set for widget", tk)
tk.cuiName = strconv.Itoa(tk.WidgetId()) + " TK"
tk.cuiName = strconv.Itoa(tk.node.WidgetId) + " TK"
}
log.Log(INFO, "drawView() labelN =", tk.labelN)
@ -101,40 +38,8 @@ func (tk *guiWidget) drawView() {
c := tk.gocuiSize.w1
d := tk.gocuiSize.h1
/*
// testing code for paging large windows
if tk.doNotDraw() {
return
}
if tk.window.pager != 0 {
if r := tk.pageWidget(); r == nil {
// if nil, draw whatever it is anyway
} else {
if r.Width() == 0 && r.Height() == 0 {
// don't draw empty stuff
return
}
a = r.w0
b = r.h0
c = r.w1
d = r.h1
}
}
if tk.WidgetType() == widget.Window || tk.WidgetType() == widget.Flag {
if tk.window.pager != 0 {
if tk.gocuiSize.Height() > 40 {
tk.window.large = true
tk.gocuiSize.h1 = tk.gocuiSize.h0 + 40
d = tk.gocuiSize.h1
}
}
}
*/
// this is all terrible. This sets the title. kinda
if tk.WidgetType() == widget.Window {
if tk.node.WidgetType == widget.Window {
tk.textResize()
tk.full.w0 = tk.force.w0
tk.full.h0 = tk.force.h0
@ -154,6 +59,7 @@ func (tk *guiWidget) drawView() {
b = tk.gocuiSize.h0
c = tk.gocuiSize.w1
d = tk.gocuiSize.h1
}
tk.v, err = me.baseGui.SetView(tk.cuiName, a, b, c, d, 0)
@ -162,55 +68,18 @@ func (tk *guiWidget) drawView() {
log.Log(ERROR, "drawView() internal plugin error err = nil")
return
}
if !errors.Is(err, gocui.ErrUnknownView) {
tk.dumpWidget("drawView() err")
log.Log(ERROR, "drawView() internal plugin error error.IS()", err)
return
}
if tk.v == nil {
log.Info("MUTEX FAIL. tk.v == nil here in drawView()")
log.Info("MUTEX FAIL. tk.v == nil here in drawView()")
log.Info("MUTEX FAIL. tk.v == nil here in drawView()")
return
}
// this actually sends the text to display to gocui
tk.v.Wrap = true
tk.v.Frame = tk.frame
tk.v.Clear()
fmt.Fprint(tk.v, tk.labelN)
// tmp hack to disable buttons on window open
if tk.WidgetType() == widget.Button {
if tk.IsEnabled() {
} else {
tk.setColorDisable()
}
}
switch tk.WidgetType() {
case widget.Button:
if tk.IsEnabled() {
if tk.isDense() && tk.isInGrid() {
tk.setColorButtonDense()
} else {
tk.setColorButton()
}
} else {
tk.setColorDisable()
}
default:
}
if tk.v == nil {
log.Info("MUTEX FAIL 2. tk.v was deleted somehow tk.v == nil here in drawView()")
log.Info("MUTEX FAIL 2. tk.v == nil here in drawView()")
log.Info("MUTEX FAIL 2. tk.v == nil here in drawView()")
return
}
// if you don't do this here, it will be black & white only
if tk.color != nil {
tk.v.FrameColor = tk.color.frame
@ -219,16 +88,20 @@ func (tk *guiWidget) drawView() {
tk.v.SelFgColor = tk.color.selFg
tk.v.SelBgColor = tk.color.selBg
}
log.Log(INFO, "drawView() END")
}
// redraw the widget tree starting at this location
func (w *guiWidget) DrawAt(offsetW, offsetH int) {
w.setColor(&colorActiveW)
w.placeWidgets(offsetW, offsetH) // compute the sizes & places for each widget
// w.dumpWidget(fmt.Sprintf("DrawAt(%d,%d)", offsetW, offsetH))
}
func (w *guiWidget) simpleDrawAt(offsetW, offsetH int) {
w.setColor(&colorActiveW)
w.dumpWidget("simpleDrawAt()")
}
// display the widgets in the binary tree
func (w *guiWidget) drawTree(draw bool) {
if w == nil {
@ -258,9 +131,6 @@ func (w *guiWidget) Show() {
// never show hidden widgets
return
}
if me.debug {
w.dumpWidget("drawView()")
}
w.drawView()
}

View File

@ -1,90 +0,0 @@
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
/*
DO NOT EDIT THIS FILE
this file is the same for every GUI toolkit plugin
when you are making a new GUI toolkit plugin for
a specific toolkit, you just need to define these
functions.
for example, in the "gocui" toolkit, the functions
below are what triggers the "gocui" GO package
to draw labels, buttons, windows, etc
If you are starting out trying to make a new GUI toolkit,
all you have to do is copy this file over. Then
work on making these functions. addWidget(), setText(), etc.
That's it!
*/
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 (
"time"
log "go.wit.com/log"
"go.wit.com/toolkits/tree"
"go.wit.com/widget"
)
// Other goroutines must use this to access the GUI
//
// You can not acess / process the GUI thread directly from
// other goroutines. This is due to the nature of how
// Linux, MacOS and Windows work (they all work differently. suprise. surprise.)
//
// this sets the channel to send user events back from the plugin
func Callback(guiCallback chan widget.Action) {
me.myTree.Callback(guiCallback)
}
func PluginChannel() chan widget.Action {
initOnce.Do(initPlugin)
for {
if me.myTree != nil {
break
}
log.Info("me.myTree == nil")
time.Sleep(300 * time.Millisecond)
}
return me.myTree.PluginChannel()
}
func FrozenChannel() chan widget.Action {
return me.myTree.FrozenChannel()
}
func initTree() *tree.TreeInfo {
t := tree.New()
t.PluginName = PLUGIN
t.Add = newAdd
t.SetTitle = setTitle
t.SetLabel = setLabel
t.SetText = setText
t.AddText = addText
t.Enable = enableWidget
t.Disable = disableWidget
t.Show = showWidget
t.Hide = hideWidget
t.SetChecked = setChecked
t.ToolkitInit = toolkitInit
t.ToolkitClose = toolkitClose
t.ShowTable = showTable
return t
}

View File

@ -7,6 +7,7 @@ import (
"strconv"
"strings"
"github.com/awesome-gocui/gocui"
"go.wit.com/log"
"go.wit.com/toolkits/tree"
"go.wit.com/widget"
@ -17,8 +18,8 @@ func initWidget(n *tree.Node) *guiWidget {
w = new(guiWidget)
w.node = n
w.cuiName = strconv.Itoa(w.WidgetId()) + " TK"
// w.WidgetType() = n.WidgetType
w.cuiName = strconv.Itoa(w.node.WidgetId) + " TK"
// w.node.WidgetType = n.WidgetType
w.labelN = n.State.Label
if w.labelN == "" {
// remove this debugging hack once things are stable and fixed
@ -38,15 +39,11 @@ func initWidget(n *tree.Node) *guiWidget {
p := n.Parent
if p == nil {
log.Log(ERROR, "parent == nil", w.String(), n.WidgetId, w.WidgetType())
log.Log(ERROR, "parent == nil", w.String(), n.WidgetId, w.node.WidgetType)
return w
}
if p.TK == nil {
if n.WidgetId == 0 {
// this is a normal init condition
} else {
log.Log(ERROR, "parent.TK == nil", w.String(), n.WidgetId, w.WidgetType())
}
log.Log(ERROR, "parent.TK == nil", w.String(), n.WidgetId, w.node.WidgetType)
return w
}
@ -72,22 +69,13 @@ func setupCtrlDownWidget() {
func (w *guiWidget) deleteView() {
// make sure the view isn't really there
// log.Log(GOCUI, "deleteView()", w.cuiName, w.WidgetType(), w.WidgetId())
// log.Log(GOCUI, "deleteView()", w.cuiName, w.node.WidgetType, w.node.WidgetId)
me.baseGui.DeleteView(w.cuiName)
w.v = nil
}
func (tk *guiWidget) String() string {
// deprecate this?
curval := strings.TrimSpace(tk.labelN)
if curval != "" {
return curval
}
curval = strings.TrimSpace(tk.GetLabel())
if curval != "" {
return curval
}
curval = tk.GetText()
curval := strings.TrimSpace(tk.node.GetLabel())
if curval != "" {
return curval
}
@ -99,6 +87,11 @@ func (tk *guiWidget) String() string {
if curval != "" {
return curval
}
// deprecate this?
curval = strings.TrimSpace(tk.labelN)
if curval != "" {
return curval
}
return ""
}
@ -124,3 +117,34 @@ func (tk *guiWidget) SetVisible(b bool) {
tk.Hide()
}
}
func (tk *guiWidget) findWidgetByName(name string) *guiWidget {
if tk.cuiName == name {
return tk
}
for _, child := range tk.children {
found := child.findWidgetByName(name)
if found != nil {
return found
}
}
return nil
}
func (tk *guiWidget) findWidgetByView(v *gocui.View) *guiWidget {
if tk.v == v {
return tk
}
if tk.cuiName == v.Name() {
log.Log(NOW, "findWidget() error. names are mismatched or out of sync", tk.cuiName)
log.Log(NOW, "findWidget() or maybe the view has been deleted")
// return tk
}
for _, child := range tk.children {
found := child.findWidgetByView(v)
if found != nil {
return found
}
}
return nil
}

View File

@ -23,13 +23,6 @@ func (tk *guiWidget) textResize() {
h += 1
}
// todo: fix all this old code
if tk.WidgetType() == widget.Textbox {
if w < 5 {
w = 5
}
}
// this is old code. now move this somewhere smarter
tk.gocuiSize.w1 = tk.gocuiSize.w0 + w + me.FramePadW // TODO: move this FramePadW out of here
tk.gocuiSize.h1 = tk.gocuiSize.h0 + h + me.FramePadH // TODO: fix this size computation
@ -50,7 +43,7 @@ func (w *guiWidget) hideWidgets() {
if w == nil {
return
}
switch w.WidgetType() {
switch w.node.WidgetType {
case widget.Root:
case widget.Flag:
case widget.Window:

115
window.go
View File

@ -7,32 +7,31 @@ import (
"fmt"
"strings"
log "go.wit.com/log"
"go.wit.com/toolkits/tree"
"go.wit.com/widget"
)
func (tk *guiWidget) setTitle(s string) {
if tk.WidgetType() != widget.Window {
if tk.node.WidgetType != widget.Window {
return
}
if tk.v == nil {
return
}
tk.setColorWindowTitleActive()
rect := tk.gocuiSize
rect.w1 = rect.w0 + tk.full.Width() + 1
// rect.h1 = rect.h0 + 1
me.baseGui.SetView(tk.v.Name(), rect.w0-1, rect.h0, rect.w1+1, rect.h1, 0)
me.baseGui.SetView(tk.v.Name(), rect.w0, rect.h0, rect.w1, rect.h1, 0)
tk.v.Clear()
f := " %-" + fmt.Sprintf("%d", tk.full.Width()-3) + "s %s"
tmp := tk.GetLabel()
labelN := fmt.Sprintf(f, tmp, "X")
f := "%-" + fmt.Sprintf("%d", tk.full.Width()-3) + "s %s"
// tmp := tk.node.GetLabel() + " " + tk.v.Name() + " " + f
tmp := tk.node.GetLabel()
labelN := fmt.Sprintf(f, tmp, "XX")
tk.v.WriteString(labelN)
}
func (tk *guiWidget) redrawWindow(w int, h int) {
if tk.WidgetType() != widget.Window {
if tk.node.WidgetType != widget.Window {
return
}
// tk.dumpWidget(fmt.Sprintf("redrawWindow(%d,%d)", w, h))
@ -42,8 +41,8 @@ func (tk *guiWidget) redrawWindow(w int, h int) {
// pin the window to (w,h)
tk.gocuiSize.w0 = w
tk.gocuiSize.h0 = h
tk.gocuiSize.w1 = w + len(tk.GetLabel())
tk.labelN = tk.GetLabel() // could set XX here also but don't have final size of window yet
tk.gocuiSize.w1 = w + len(tk.node.GetLabel())
tk.labelN = tk.node.GetLabel() // could set XX here also but don't have final size of window yet
tk.force.w0 = w
tk.force.w1 = w
tk.force.h0 = h
@ -55,8 +54,7 @@ func (tk *guiWidget) redrawWindow(w int, h int) {
tk.hasTabs = false
tk.DrawAt(w, h)
// tk.setColor(&colorActiveW) // sets the window to Green BG
tk.setColorWindowTitleActive()
tk.setColor(&colorActiveW) // sets the window to Green BG
if tk.window.collapsed {
// don't show anything but the title bar
@ -70,18 +68,26 @@ func (tk *guiWidget) redrawWindow(w int, h int) {
tk.full.h0 = tk.force.h0
tk.setFullSize()
tk.Show()
if tk.v == nil {
log.Info("redrawWindow on tk.v == nil")
standardExit()
/*
v, err := me.baseGui.SetView(tk.cuiName, tk.gocuiSize.w0, tk.gocuiSize.h0, tk.gocuiSize.w1, tk.gocuiSize.h1, 0)
if err != nil {
log.Info("crap. got an err", err)
}
if tk.v != v {
log.Info("crap. got another problem v != tk.v")
}
*/
tk.Show()
tk.v.Clear()
fmt.Fprint(tk.v, "ZZZ"+tk.GetText())
tk.showWidgets()
// RE-VERIFY THIS CAN'T BE DONE IN A BETTER WAY. However, for now, this works finally so I am leaving it alone
if tk.windowFrame == nil {
tk.addWindowFrameTK(0 - tk.WidgetId())
tk.windowFrame.makeTK([]string{""})
tk.addWindowFrameTK(0 - tk.node.WidgetId)
tk.windowFrame.node.State.Label = " ZZzzzFrame" // temporary name. blank out when ready for release
tk.windowFrame.makeTK([]string{" ZZzzzFrame"})
}
// this seems to correctly create the window frame
@ -100,7 +106,6 @@ func (tk *guiWidget) redrawWindow(w int, h int) {
// set the window frame below the window widget, but this resizes the window widget it seems
me.baseGui.SetViewBeneath(tk.windowFrame.cuiName, tk.cuiName, 1)
// so now we have to resize the window frame, but this moves it to the top?
me.baseGui.SetView(tk.windowFrame.cuiName, tk.windowFrame.full.w0, tk.windowFrame.full.h0, tk.windowFrame.full.w1, tk.windowFrame.full.h1, 0)
@ -109,7 +114,7 @@ func (tk *guiWidget) redrawWindow(w int, h int) {
tk.showWidgets()
// draw the window title
tk.setTitle(tk.GetLabel())
tk.setTitle(tk.node.GetLabel() + " jwc")
}
// re-draws the buttons for each of the windows
@ -118,7 +123,8 @@ func redoWindows(nextW int, nextH int) {
// tk.dumpWidget(fmt.Sprintf("redoWindowsS (%d,%d)", nextW, nextH))
if tk.window.wasDragged {
// don't move windows around the user has dragged to a certain location
tk.makeWindowActive()
tk.redrawWindow(tk.gocuiSize.w0, tk.gocuiSize.h0)
setThingsOnTop() // sets help, Stdout, etc on the top after windows have been redrawn
} else {
w, _ := me.baseGui.Size()
if nextW > w-20 {
@ -157,11 +163,13 @@ func (win *guiWidget) addWindowFrame(wId int) *tree.Node {
if tk.node.Parent == nil {
tk.node.Parent = me.treeRoot
}
// copy the data from the action message
tk.node.State.Label = "windowFrame"
// set the name used by gocui to the id
tk.cuiName = fmt.Sprintf("%d DR", wId)
// tk.color = &colorGroup
tk.color = &colorGroup
// add this new widget on the binary tree
tk.parent = win
@ -175,41 +183,29 @@ func (win *guiWidget) addWindowFrame(wId int) *tree.Node {
return n
}
func (tk *guiWidget) isWindowActive() bool {
if !(tk.WidgetType() == widget.Window || tk.WidgetType() == widget.Stdout) {
// only allow Window or the Stdout widgets to be made active
return false
}
return tk.window.active
}
// always redraws at the corner of the gocuiSize box
func (tk *guiWidget) makeWindowActive() {
if !(tk.WidgetType() == widget.Window || tk.WidgetType() == widget.Stdout) {
if !(tk.node.WidgetType == widget.Window || tk.node.WidgetType == widget.Stdout) {
// only allow Window or the Stdout widgets to be made active
return
}
if tk.WidgetType() == widget.Stdout {
me.stdout.outputOnTop = true
} else {
// me.stdout.outputOnTop = false // ?
}
// disable and increment all the windows
for _, tk := range me.allwin {
tk.window.order += 1
tk.window.active = false
// tk.setColor(&colorWindow) // color for inactive windows
tk.setColorWindowTitle()
tk.setColor(&colorWindow) // color for inactive windows
}
// set this window as the active one
tk.window.active = true
tk.window.order = 0
tk.redrawWindow(tk.gocuiSize.w0, tk.gocuiSize.h0)
setThingsOnTop() // sets help, Stdout, etc on the top after windows have been redrawn
/*
// print out the window list
for _, tk := range me.allwin {
log.Info("makeWindowActive() Window", tk.labelN, tk.window.active, tk.window.order)
}
*/
}
func (tk *guiWidget) makeTK(ddItems []string) {
@ -220,21 +216,24 @@ func (tk *guiWidget) makeTK(ddItems []string) {
tk.gocuiSize.w1 = 120
tk.gocuiSize.h0 = 15
tk.gocuiSize.h1 = 18
/*
var err error
tk.v, err = me.baseGui.SetView(tk.cuiName,
tk.gocuiSize.w0,
tk.gocuiSize.h0,
tk.gocuiSize.w1,
tk.gocuiSize.h1, 0)
if err != nil {
log.Info("makeTK() err", err)
return
}
if tk.v == nil {
return
}
tk.v.Wrap = true
tk.v.Frame = true
tk.v.Clear()
fmt.Fprint(tk.v, items)
*/
tk.Show()
}
func (win *guiWidget) checkWindowClose(w int, h int) bool {
s := fmt.Sprintf("mouse(%d,%d) ", w, h)
offW := win.full.w1 - w
offH := h - win.full.h0
s += fmt.Sprintf("offset(%d,%d)", offW, offH)
if (offW < 2) && (offH < 2) {
log.Info("attempting close on ", s, win.cuiName)
me.myTree.SendWindowCloseEvent(win.node)
// store the stdout corner for computing the drag size
return true
}
// log.Info("not attempting close on ", s, win.cuiName)
return false
}