Compare commits
281 Commits
Author | SHA1 | Date |
---|---|---|
|
3acf473792 | |
|
6c3149c0fe | |
|
784eac740f | |
|
a88937c508 | |
|
96eac58cf5 | |
|
b8781b1b64 | |
|
126b9a30a2 | |
|
994449b1c2 | |
|
5ebb13a454 | |
|
6127fa1cbb | |
|
54bbe72aa8 | |
|
b373eab346 | |
|
e73cfaf490 | |
|
046e6b4d6c | |
|
efb5ede4b9 | |
|
5e6d7cffdf | |
|
76e15fa1df | |
|
75014f4b28 | |
|
9ef16c1bf2 | |
|
da54c0f039 | |
|
6d1dfed3db | |
|
65cf744a86 | |
|
caf7428ba3 | |
|
948d2af071 | |
|
ddd7709182 | |
|
9912c3eb82 | |
|
660d9e7e3a | |
|
0124d25c34 | |
|
ed3789c23f | |
|
6f739933b7 | |
|
4b79e862a7 | |
|
dc329ed18c | |
|
3e7287baea | |
|
04406b3561 | |
|
0638183356 | |
|
f24c509859 | |
|
a000c06987 | |
|
3b9e5beff6 | |
|
ad34230d67 | |
|
57b6efd831 | |
|
f36f9cfd0f | |
|
a5800917e8 | |
|
c64592f326 | |
|
377b08eeb6 | |
|
22e139e2e5 | |
|
6b7fafbde2 | |
|
3f09b2b6e4 | |
|
31324ad083 | |
|
ad299911f1 | |
|
3d1bb9680a | |
|
9cd1d582e2 | |
|
3ca1fff755 | |
|
5a9f3565aa | |
|
1f33979af9 | |
|
1e79d31a02 | |
|
08a5b198c7 | |
|
c215e3c2c4 | |
|
c5472a42a2 | |
|
fa9ec36dbb | |
|
8c459da9f7 | |
|
552bdeb1e6 | |
|
0a60272440 | |
|
a575a08bcc | |
|
57e5ff22dc | |
|
733c595c54 | |
|
535646335a | |
|
8d24366492 | |
|
6df064282c | |
|
6ea6ffaa3d | |
|
7d793c68db | |
|
b07d8bd8f7 | |
|
42758e1459 | |
|
f30489219b | |
|
bb2732b621 | |
|
00d1256eba | |
|
cf073e9aae | |
|
90a9f84f10 | |
|
c5cada3dc9 | |
|
87d31a3d94 | |
|
c5d9522c0b | |
|
4a009f79a2 | |
|
70452bdaac | |
|
36745e0492 | |
|
9540c01d83 | |
|
58eff2a9e2 | |
|
c00084bf3f | |
|
9a08b37be4 | |
|
955afcb1a9 | |
|
af3fec6f20 | |
|
5bac0308e5 | |
|
8d8fc22745 | |
|
eba5ea8cc0 | |
|
b8b8a409ea | |
|
010bd2a33f | |
|
ba629f1892 | |
|
bff0943dc5 | |
|
2c07da350a | |
|
82ed687460 | |
|
5a84456c7a | |
|
f8b7c603a1 | |
|
419f4aef6a | |
|
12d0e185cc | |
|
e80827d890 | |
|
42eafb87c7 | |
|
ea544e429e | |
|
58cb7f3d2d | |
|
53eb14ccbd | |
|
23dfd96a87 | |
|
5827b9ace2 | |
|
c4f9bac85e | |
|
90083d5bcb | |
|
77b4bcb94b | |
|
665d2289e2 | |
|
ed024aac70 | |
|
6045a205fd | |
|
227419c1ad | |
|
7b06b81ed3 | |
|
9d1a045a1f | |
|
1923f8df96 | |
|
b730ee9459 | |
|
a6c1864f43 | |
|
1010db44a6 | |
|
078a23e0e0 | |
|
44264df09d | |
|
0aa82f5ba5 | |
|
83b4d7142a | |
|
fefa99920b | |
|
8185d8bc1a | |
|
481fa11211 | |
|
a295aa420b | |
|
d8353f9b1a | |
|
b6b5df6a18 | |
|
13a194dca5 | |
|
6c522a4b27 | |
|
dd5232fa6b | |
|
6ac82df949 | |
|
0b67b198bd | |
|
7813fc126d | |
|
fb3c16707d | |
|
5668e6f081 | |
|
e96cb4375c | |
|
c2f8cac4a9 | |
|
7e47ca9843 | |
|
37723c2b9a | |
|
16886945ed | |
|
3d104d5b4a | |
|
0b265d2b72 | |
|
5d1a3b2578 | |
|
e39bcafb78 | |
|
176831d0f3 | |
|
2a5734892a | |
|
f5d465901d | |
|
e134ecb6a4 | |
|
5bae8b7e41 | |
|
93e87a05c7 | |
|
bc15e6c879 | |
|
1918dcbbde | |
|
5675307497 | |
|
88f33afbb7 | |
|
9fa974f6c4 | |
|
c4095ef7aa | |
|
c136ca2b4c | |
|
87141b8d99 | |
|
6d991fef63 | |
|
9c7b139e5a | |
|
d3b25092f8 | |
|
96cb52f3ef | |
|
9c548faeda | |
|
d2c3db7b58 | |
|
d0e35bb98f | |
|
8522d4671e | |
|
88e9594b93 | |
|
3faacd6c43 | |
|
31c130045d | |
|
70a742c98a | |
|
546a4e022b | |
|
efebe00640 | |
|
07f6b7842e | |
|
83e9787e75 | |
|
85eda6aeb8 | |
|
8dd0f88e7c | |
|
c328a755c6 | |
|
3fa508f786 | |
|
d75bfa639c | |
|
f1eefc9a06 | |
|
6a0fd773f4 | |
|
ec68f448af | |
|
ae339cc587 | |
|
38a08d66fc | |
|
fb8d1d0940 | |
|
12f3d5ac5c | |
|
a81e931b9a | |
|
6237bf89c3 | |
|
8ce9ca882a | |
|
bf8cbddf1a | |
|
4e5c6f2515 | |
|
3cf873439d | |
|
652cf2b73b | |
|
1867bae62c | |
|
012273d8d3 | |
|
9d5cd2c865 | |
|
acfb80a2e7 | |
|
a10582c846 | |
|
5a28806bdf | |
|
d2c681f573 | |
|
acb0e43945 | |
|
65622d01cd | |
|
d61e03b877 | |
|
f0d403e834 | |
|
e627e4e822 | |
|
c91733e10d | |
|
6370d87fc2 | |
|
c5e6c66338 | |
|
a5b3a934d2 | |
|
517d844b3c | |
|
4a8fb6ab22 | |
|
ac9c6617e3 | |
|
d5d0262013 | |
|
3125bbb258 | |
|
a069e6c984 | |
|
d6f2fd983e | |
|
e3c874cd69 | |
|
eccec3ef1a | |
|
666d5ca52d | |
|
0355f7c2fb | |
|
f79cf89170 | |
|
5a2097d080 | |
|
9a3f9d0991 | |
|
2062060dac | |
|
7557486b13 | |
|
4dad234532 | |
|
3d5ee3f89b | |
|
2e0465e44a | |
|
49f8e1c043 | |
|
4bc9fa41b7 | |
|
96fdfd1338 | |
|
8d007ec10d | |
|
fdca4d2601 | |
|
417b3e5225 | |
|
e4f0524bdf | |
|
ebb03139bb | |
|
4695ada409 | |
|
a78cd82dcd | |
|
a8a918655a | |
|
39e851c76c | |
|
bac14a675b | |
|
b7cd6d07fc | |
|
f76960c907 | |
|
5b39848b64 | |
|
bbdf7fefbd | |
|
73de9899a8 | |
|
c348940ca1 | |
|
8a4afa760d | |
|
4aef276b64 | |
|
1d32c5da2b | |
|
9f38585892 | |
|
1a1881aa4e | |
|
75a5c7bf72 | |
|
11465e4043 | |
|
57fbbc62ed | |
|
ce11f999f9 | |
|
a16b53c289 | |
|
b5fe1eb8ff | |
|
85f3a08238 | |
|
439c6e3b01 | |
|
19370790f8 | |
|
bab555aa4c | |
|
7e2d7f72ef | |
|
39eb2e5210 | |
|
bb3802857b | |
|
c02399708e | |
|
aea18d5b65 | |
|
820f27c0a2 | |
|
15666309ee | |
|
aae13f2b57 | |
|
2461df0153 | |
|
368c25107a | |
|
2ace17294c | |
|
6d3dded68b | |
|
32619e7dad | |
|
2ea283ea74 |
|
@ -1,4 +1,7 @@
|
|||
*.swp
|
||||
*.so
|
||||
*.pb.go
|
||||
*.patch
|
||||
go.mod
|
||||
go.sum
|
||||
gocui
|
||||
|
|
36
Makefile
36
Makefile
|
@ -1,11 +1,31 @@
|
|||
all: plugin
|
||||
ldd ../gocui.so
|
||||
VERSION = $(shell git describe --tags)
|
||||
BUILDTIME = $(shell date +%Y.%m.%d)
|
||||
|
||||
plugin:
|
||||
GO111MODULE=off go build -v -buildmode=plugin -o ../gocui.so
|
||||
all: clean goimports vet gocui
|
||||
@ldd gocui.so
|
||||
|
||||
pluginreal:
|
||||
go build -v -buildmode=plugin -o ~/go/lib/toolkits/gocui.so
|
||||
vet:
|
||||
@GO111MODULE=off go vet
|
||||
@echo this go plugin builds okay
|
||||
|
||||
gocui:
|
||||
GO111MODULE=off go build -v -x -buildmode=plugin -o gocui.so \
|
||||
-ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
|
||||
|
||||
install:
|
||||
go build -buildmode=plugin -o ~/go/lib/gocui-${VERSION}.so \
|
||||
-ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
|
||||
cd ~/go/lib && ln -f -s gocui-${VERSION}.so gocui.so
|
||||
|
||||
# for testing custom golang
|
||||
custom:
|
||||
# GO111MODULE=off go build -v
|
||||
GO111MODULE=off go build -v -work -buildmode=blah
|
||||
|
||||
clean:
|
||||
rm -f gocui *.so go.*
|
||||
rm -f *.pb.go *.patch
|
||||
go-mod-clean --purge
|
||||
|
||||
# Test the README.md & doc.go file
|
||||
# this runs pkgsite, the binary that does dev.go.dev
|
||||
|
@ -27,3 +47,7 @@ redomod:
|
|||
rm -f go.*
|
||||
GO111MODULE= go mod init
|
||||
GO111MODULE= go mod tidy
|
||||
|
||||
proto:
|
||||
autogenpb --proto gocuiView.proto
|
||||
make goimports
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
# a console toolkit around gocui
|
||||
|
||||
* to build, run 'make build'
|
||||
* TODO: make a way to trigger plugin builds. 'package plugin' maybe?
|
||||
|
||||
[terminals that support ture color](https://github.com/termstandard/colors#truecolor-support-in-output-devices)
|
||||
[more info about color](https://jvns.ca/blog/2024/10/01/terminal-colours/)
|
||||
|
|
94
add.go
94
add.go
|
@ -1,94 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
log "go.wit.com/log"
|
||||
"go.wit.com/toolkits/tree"
|
||||
"go.wit.com/widget"
|
||||
)
|
||||
|
||||
var fakeStartWidth int = me.FakeW
|
||||
var fakeStartHeight int = me.TabH + me.FramePadH
|
||||
|
||||
// setup fake labels for non-visible things off screen
|
||||
func setFake(n *tree.Node) {
|
||||
var w *guiWidget
|
||||
w = n.TK.(*guiWidget)
|
||||
w.isFake = true
|
||||
|
||||
w.gocuiSetWH(fakeStartWidth, fakeStartHeight)
|
||||
|
||||
fakeStartHeight += w.gocuiSize.Height()
|
||||
// TODO: use the actual max hight of the terminal window
|
||||
if fakeStartHeight > 24 {
|
||||
fakeStartHeight = me.TabH
|
||||
fakeStartWidth += me.FakeW
|
||||
}
|
||||
}
|
||||
|
||||
// set the widget start width & height
|
||||
// func (n *node) addWidget(n *tree.Node) {
|
||||
func addWidget(n *tree.Node) {
|
||||
var nw *guiWidget
|
||||
nw = 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())
|
||||
nw.color = &colorRoot
|
||||
setFake(n)
|
||||
return
|
||||
case widget.Flag:
|
||||
nw.color = &colorFlag
|
||||
setFake(n)
|
||||
return
|
||||
case widget.Window:
|
||||
nw.frame = false
|
||||
// nw.color = &colorWindow
|
||||
nw.setColor(&colorWindow)
|
||||
wRoot := me.treeRoot.TK.(*guiWidget)
|
||||
wRoot.redoWindows(0, 0)
|
||||
// TODO: record the first window here?
|
||||
// do initial setup of helper widgets here:
|
||||
if me.dropdownV == nil {
|
||||
me.dropdownV = makeDropdownView("addWidget() ddview")
|
||||
}
|
||||
return
|
||||
case widget.Tab:
|
||||
nw.color = &colorTab
|
||||
// redoWindows(0,0)
|
||||
return
|
||||
case widget.Button:
|
||||
nw.color = &colorButton
|
||||
case widget.Checkbox:
|
||||
nw.color = &colorCheckbox
|
||||
case widget.Dropdown:
|
||||
nw.color = &colorDropdown
|
||||
case widget.Combobox:
|
||||
nw.color = &colorCombobox
|
||||
case widget.Box:
|
||||
nw.color = &colorBox
|
||||
nw.isFake = true
|
||||
setFake(n)
|
||||
return
|
||||
case widget.Grid:
|
||||
nw.color = &colorGrid
|
||||
nw.isFake = true
|
||||
setFake(n)
|
||||
return
|
||||
case widget.Group:
|
||||
nw.color = &colorGroup
|
||||
nw.frame = false
|
||||
return
|
||||
case widget.Label:
|
||||
nw.color = &colorLabel
|
||||
nw.frame = false
|
||||
return
|
||||
default:
|
||||
/*
|
||||
if n.IsCurrent() {
|
||||
n.updateCurrent()
|
||||
}
|
||||
*/
|
||||
}
|
||||
nw.showWidgetPlacement("addWidget()")
|
||||
}
|
51
checkbox.go
51
checkbox.go
|
@ -1,3 +1,6 @@
|
|||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
|
@ -6,48 +9,32 @@ import (
|
|||
"go.wit.com/widget"
|
||||
)
|
||||
|
||||
// this comes from the application
|
||||
func setChecked(n *tree.Node, b bool) {
|
||||
if n.WidgetType != widget.Checkbox {
|
||||
}
|
||||
|
||||
n.State.Checked = b
|
||||
var tk *guiWidget
|
||||
tk = n.TK.(*guiWidget)
|
||||
|
||||
if tk.node.State.Label == "" {
|
||||
tk.node.State.Label = "BLANK"
|
||||
tk.setCheckbox()
|
||||
}
|
||||
|
||||
// redraw the checkbox
|
||||
func (tk *guiWidget) setCheckbox() {
|
||||
if tk.WidgetType() != widget.Checkbox {
|
||||
log.Log(WARN, "setCheckbox() being run on widget:", tk.WidgetType())
|
||||
return
|
||||
}
|
||||
if tk.node.State.Checked {
|
||||
log.Log(WARN, "setCheckbox() got true", tk.node.State.Checked)
|
||||
tk.labelN = "X " + tk.node.State.Label
|
||||
if tk.Checked() {
|
||||
log.Log(WARN, "setCheckbox() got true", tk.Checked())
|
||||
tk.labelN = "X " + tk.GetLabel()
|
||||
} else {
|
||||
log.Log(WARN, "setCheckbox() got false", tk.node.State.Checked)
|
||||
tk.labelN = " " + tk.node.State.Label
|
||||
log.Log(WARN, "setCheckbox() got false", tk.Checked())
|
||||
tk.labelN = "_ " + tk.GetLabel()
|
||||
}
|
||||
|
||||
tk.Hide()
|
||||
tk.Show()
|
||||
}
|
||||
|
||||
// redraw the checkbox
|
||||
func (w *guiWidget) setCheckbox() {
|
||||
if w.node.WidgetType != widget.Checkbox {
|
||||
log.Log(WARN, "setCheckbox() being run on widget:", w.node.WidgetType)
|
||||
return
|
||||
}
|
||||
if w.node.State.Label == "" {
|
||||
w.node.State.Label = "BLANK"
|
||||
}
|
||||
if w.node.State.Checked {
|
||||
log.Log(WARN, "setCheckbox() got true", w.node.State.Checked)
|
||||
w.labelN = "X " + w.node.State.Label
|
||||
// w.changed = true
|
||||
} else {
|
||||
log.Log(WARN, "setCheckbox() got false", w.node.State.Checked)
|
||||
w.labelN = " " + w.node.State.Label
|
||||
// w.changed = true
|
||||
}
|
||||
// t := len(w.labelN) + 3
|
||||
// w.gocuiSize.w1 = w.gocuiSize.w0 + t
|
||||
|
||||
w.Hide()
|
||||
w.Show()
|
||||
}
|
||||
|
|
229
click.go
229
click.go
|
@ -1,229 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
"go.wit.com/log"
|
||||
"go.wit.com/widget"
|
||||
)
|
||||
|
||||
func (w *guiWidget) doWidgetClick() {
|
||||
switch w.WidgetType {
|
||||
/*
|
||||
case widget.Root:
|
||||
// THIS IS THE BEGINING OF THE LAYOUT
|
||||
log.Log(GOCUI, "doWidgetClick()", w.String())
|
||||
wRoot := me.treeRoot.TK.(*guiWidget)
|
||||
wRoot.redoWindows(0, 0)
|
||||
case widget.Flag:
|
||||
log.Log(GOCUI, "doWidgetClick() FLAG widget name =", w.String())
|
||||
log.Log(GOCUI, "doWidgetClick() if this is the dropdown menu, handle it here?")
|
||||
*/
|
||||
case widget.Window:
|
||||
log.Log(GOCUI, "doWidgetClick() START on window", w.String())
|
||||
// if the user clicked on the current window, do nothing
|
||||
/* Ignore this for now and redraw the window anyway
|
||||
if me.currentWindow == w {
|
||||
if !w.active {
|
||||
return
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// if there is a current window, hide it
|
||||
if me.currentWindow != nil {
|
||||
me.currentWindow.setColor(&colorWindow)
|
||||
me.currentWindow.hideWidgets()
|
||||
me.currentWindow.isCurrent = false
|
||||
}
|
||||
|
||||
// now set this window as the current window
|
||||
me.currentWindow = w
|
||||
me.currentWindow.isCurrent = true
|
||||
|
||||
// draw the current window
|
||||
log.Log(GOCUI, "doWidgetClick() set currentWindow to", w.String())
|
||||
w.setColor(&colorActiveW)
|
||||
w.DrawAt(3, 2)
|
||||
w.placeWidgets(3, 2) // compute the sizes & places for each widget
|
||||
w.active = false
|
||||
w.showWidgets()
|
||||
/*
|
||||
hideFake()
|
||||
showDebug = true
|
||||
*/
|
||||
case widget.Group:
|
||||
if w.active {
|
||||
w.active = false
|
||||
w.placeWidgets(w.startW, w.startH)
|
||||
w.showWidgets()
|
||||
} else {
|
||||
w.active = true
|
||||
for _, child := range w.children {
|
||||
child.hideWidgets()
|
||||
}
|
||||
}
|
||||
// w.dumpTree("click end")
|
||||
case widget.Checkbox:
|
||||
if w.node.State.Checked {
|
||||
log.Log(WARN, "checkbox is being set to false")
|
||||
w.node.State.Checked = false
|
||||
w.setCheckbox()
|
||||
} else {
|
||||
log.Log(WARN, "checkbox is being set to true")
|
||||
w.node.State.Checked = true
|
||||
w.setCheckbox()
|
||||
}
|
||||
me.myTree.SendUserEvent(w.node)
|
||||
case widget.Grid:
|
||||
newR := w.realGocuiSize()
|
||||
|
||||
// w,h := n.logicalSize()
|
||||
// w := newR.w1 - newR.w0
|
||||
// h := newR.h1 - newR.h0
|
||||
|
||||
w.placeGrid(newR.w0, newR.h0)
|
||||
w.showWidgets()
|
||||
case widget.Box:
|
||||
// w.showWidgetPlacement(logNow, "drawTree()")
|
||||
if w.node.State.Direction == widget.Horizontal {
|
||||
log.Log(GOCUI, "BOX IS HORIZONTAL", w.String())
|
||||
} else {
|
||||
log.Log(GOCUI, "BOX IS VERTICAL", w.String())
|
||||
}
|
||||
w.placeWidgets(w.startW, w.startH)
|
||||
w.toggleTree()
|
||||
case widget.Button:
|
||||
// doUserEvent(n)
|
||||
me.myTree.SendFromUser(w.node)
|
||||
case widget.Combobox:
|
||||
log.Log(GOCUI, "do the combobox here")
|
||||
w.showDropdown()
|
||||
me.dropdownW = w
|
||||
case widget.Dropdown:
|
||||
log.Log(GOCUI, "do the dropdown here")
|
||||
w.showDropdown()
|
||||
me.dropdownW = w
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func click(g *gocui.Gui, v *gocui.View) error {
|
||||
mouseW, mouseH := me.baseGui.MousePosition()
|
||||
|
||||
log.Log(GOCUI, "click() START gocui name:", v.Name())
|
||||
w := findUnderMouse()
|
||||
|
||||
// if the dropdown view is visable, process it no matter what
|
||||
if me.dropdownV.Visible() {
|
||||
me.dropdownV.dropdownClicked(mouseW, mouseH)
|
||||
}
|
||||
if w == me.dropdownV {
|
||||
return nil
|
||||
}
|
||||
|
||||
if w == nil {
|
||||
log.Error(errors.New("click() could not find widget for view =" + v.Name()))
|
||||
} else {
|
||||
log.Log(GOCUI, "click() Found widget =", w.node.WidgetId, w.String(), ",", w.labelN)
|
||||
w.doWidgetClick()
|
||||
}
|
||||
|
||||
rootTK := me.treeRoot.TK.(*guiWidget)
|
||||
realTK := rootTK.findWidgetByView(v)
|
||||
if realTK == nil {
|
||||
log.Error(errors.New("toolkit click() out of reality with gocui. v.Name() not in binary tree " + v.Name()))
|
||||
log.Log(GOCUI, "click() END FAILURE ON gocui v.Name =", v.Name())
|
||||
// return nil // otherwise gocui exits
|
||||
}
|
||||
|
||||
// double check the widget view really still exists
|
||||
nameTK := rootTK.findWidgetByName(v.Name())
|
||||
if nameTK == nil {
|
||||
log.Error(errors.New("toolkit click() out of reality with gocui. v.Name() not in binary tree " + v.Name()))
|
||||
return nil
|
||||
}
|
||||
if nameTK.v == nil {
|
||||
log.Log(GOCUI, "click() maybe this widget has had it's view distroyed?", nameTK.cuiName, nameTK.WidgetType)
|
||||
log.Log(GOCUI, "yep. it's gone now")
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetCurrentView dies if it's sent an non-existent view
|
||||
if _, err := g.SetCurrentView(v.Name()); err != nil {
|
||||
log.Log(GOCUI, "click() END v.Name =", v.Name(), "err =", err)
|
||||
// return err // return causes gocui.MainLoop() to exit. Do we ever want that to happen here?
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Log(GOCUI, "click() END gocui name:", v.Name())
|
||||
return nil
|
||||
}
|
||||
|
||||
func findUnderMouse() *guiWidget {
|
||||
var widgets []*guiWidget
|
||||
var f func(w *guiWidget)
|
||||
w, h := me.baseGui.MousePosition()
|
||||
|
||||
// find buttons that are below where the mouse button click
|
||||
f = func(widget *guiWidget) {
|
||||
// ignore widgets that are not visible
|
||||
if widget.Visible() {
|
||||
if (widget.gocuiSize.w0 <= w) && (w <= widget.gocuiSize.w1) &&
|
||||
(widget.gocuiSize.h0 <= h) && (h <= widget.gocuiSize.h1) {
|
||||
widgets = append(widgets, widget)
|
||||
}
|
||||
}
|
||||
|
||||
for _, child := range widget.children {
|
||||
f(child)
|
||||
}
|
||||
}
|
||||
rootW := me.treeRoot.TK.(*guiWidget)
|
||||
f(rootW)
|
||||
|
||||
var found *guiWidget
|
||||
// widgets has everything that matches
|
||||
for _, w := range widgets {
|
||||
// prioritize window buttons. This means if some code covers
|
||||
// up the window widgets, then it will ignore everything else
|
||||
// and allow the user (hopefully) to redraw or switch windows
|
||||
// TODO: display the window widgets on top
|
||||
if w.WidgetType == widget.Window {
|
||||
return w
|
||||
}
|
||||
// w.showWidgetPlacement("findUnderMouse() FOUND")
|
||||
found = w
|
||||
}
|
||||
return found
|
||||
}
|
||||
|
||||
// find the widget under the mouse click
|
||||
func ctrlDown(g *gocui.Gui, v *gocui.View) error {
|
||||
var found *guiWidget
|
||||
// var widgets []*node
|
||||
// var f func (n *node)
|
||||
found = findUnderMouse()
|
||||
if me.ctrlDown == nil {
|
||||
setupCtrlDownWidget()
|
||||
|
||||
var tk *guiWidget
|
||||
tk = me.ctrlDown.TK.(*guiWidget)
|
||||
tk.labelN = found.String()
|
||||
tk.cuiName = "ctrlDown"
|
||||
// me.ctrlDown.parent = me.rootNode
|
||||
}
|
||||
var tk *guiWidget
|
||||
tk = me.ctrlDown.TK.(*guiWidget)
|
||||
if found == nil {
|
||||
found = me.treeRoot.TK.(*guiWidget)
|
||||
}
|
||||
tk.labelN = found.String()
|
||||
newR := found.realGocuiSize()
|
||||
tk.gocuiSize.w0 = newR.w0
|
||||
tk.gocuiSize.h0 = newR.h0
|
||||
tk.gocuiSize.w1 = newR.w1
|
||||
tk.gocuiSize.h1 = newR.h1
|
||||
return nil
|
||||
}
|
466
color.go
466
color.go
|
@ -1,181 +1,309 @@
|
|||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
|
||||
"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
|
||||
// simple colors for light and dark
|
||||
|
||||
type colorT struct {
|
||||
frame gocui.Attribute
|
||||
fg gocui.Attribute
|
||||
bg gocui.Attribute
|
||||
selFg gocui.Attribute
|
||||
selBg gocui.Attribute
|
||||
name string
|
||||
}
|
||||
// information about how terminfo works
|
||||
// https://jvns.ca/blog/2024/10/01/terminal-colours/
|
||||
|
||||
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: none,
|
||||
selBg: powdererBlue,
|
||||
name: "normal window",
|
||||
}
|
||||
var colorActiveW colorT = colorT{none, none, powdererBlue, none, powdererBlue, "active window"}
|
||||
|
||||
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 colorButton colorT = colorT{
|
||||
frame: gocui.ColorGreen,
|
||||
fg: none,
|
||||
bg: gocui.ColorWhite,
|
||||
selFg: gocui.ColorGreen,
|
||||
selBg: gocui.ColorBlack,
|
||||
name: "normal button",
|
||||
}
|
||||
|
||||
var colorDropdown colorT = colorT{
|
||||
frame: gocui.ColorYellow,
|
||||
fg: none,
|
||||
bg: gocui.ColorWhite,
|
||||
selFg: gocui.ColorYellow,
|
||||
selBg: gocui.ColorBlack,
|
||||
name: "normal button",
|
||||
}
|
||||
|
||||
var colorCombobox colorT = colorT{
|
||||
frame: gocui.ColorBlue,
|
||||
fg: none,
|
||||
bg: gocui.ColorWhite,
|
||||
selFg: gocui.ColorBlue,
|
||||
selBg: gocui.ColorBlack,
|
||||
name: "normal button",
|
||||
}
|
||||
|
||||
var colorCheckbox colorT = colorT{
|
||||
frame: gocui.ColorRed,
|
||||
fg: none,
|
||||
bg: gocui.ColorWhite,
|
||||
selFg: gocui.ColorRed,
|
||||
selBg: gocui.ColorBlack,
|
||||
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: move all this to a protobuf
|
||||
// TODO: add black/white only flag for ttyS0
|
||||
// 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
|
||||
// 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)
|
||||
}
|
||||
tk.color = newColor
|
||||
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() {
|
||||
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
|
||||
}
|
||||
|
||||
// saves the color and makes it active
|
||||
func (tk *guiWidget) updateColor() {
|
||||
if tk.v == 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()
|
||||
}
|
||||
|
||||
// Below are all the colors. TODO: move to protobuf and save in a config file
|
||||
|
||||
func (tk *guiWidget) setColorWindowFrame() {
|
||||
if tk.color == nil {
|
||||
log.Log(NOW, "Set the node to color = nil")
|
||||
tk.color = &colorNone
|
||||
tk.color = new(colorT)
|
||||
}
|
||||
log.Log(NOW, "Set the node to color =", tk.color.name)
|
||||
tk.Show()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
w.v.SelBgColor = gocui.ColorGreen
|
||||
w.v.SelFgColor = gocui.ColorBlack
|
||||
}
|
||||
|
||||
func randColor() gocui.Attribute {
|
||||
colors := []string{"Green", "#FFAA55", "Yellow", "Blue", "Red", "Black", "White"}
|
||||
i := rand.Intn(len(colors))
|
||||
log.Log(NOW, "randColor() i =", i)
|
||||
return gocui.GetColor(colors[i])
|
||||
}
|
||||
|
||||
func (w *guiWidget) redoColor(draw bool) {
|
||||
if w == nil {
|
||||
return
|
||||
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
|
||||
}
|
||||
|
||||
log.Sleep(.05)
|
||||
w.setDefaultHighlight()
|
||||
// w.setDefaultWidgetColor()
|
||||
w.Show()
|
||||
|
||||
for _, child := range w.children {
|
||||
child.redoColor(draw)
|
||||
}
|
||||
tk.updateColor()
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
tk.updateColor()
|
||||
}
|
||||
|
||||
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) 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 {
|
||||
|
@ -195,3 +323,29 @@ 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])
|
||||
}
|
||||
|
||||
var none gocui.Attribute = gocui.AttrNone
|
||||
var colorNone colorT = colorT{none, none, none, none, none, "debug none"}
|
||||
|
||||
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
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
def color(num, text):
|
||||
return f"\033[38;5;{num}m{text}\033[0m"
|
||||
|
||||
for i in range(300):
|
||||
print(color(i, f"number {i:02}"))
|
95
debug.go
95
debug.go
|
@ -1,53 +1,102 @@
|
|||
// 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"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
"go.wit.com/log"
|
||||
"go.wit.com/widget"
|
||||
)
|
||||
|
||||
func (w *guiWidget) dumpTree(s string) {
|
||||
// log.Log(ERROR, "dumpTree w", w.node.WidgetId, w.WidgetType, w.String())
|
||||
// log.Log(ERROR, "dump w", w.WidgetId(), w.WidgetType, w.String())
|
||||
if w == nil {
|
||||
log.Log(ERROR, "dumpTree w.TK == nil", w.node.WidgetId, w.WidgetType, w.String())
|
||||
log.Log(ERROR, "dump w.TK == nil", w.WidgetId(), w.WidgetType(), w.String())
|
||||
return
|
||||
}
|
||||
w.showWidgetPlacement("dumpTree() " + s)
|
||||
w.dumpWidget("dumpTree() " + s)
|
||||
|
||||
for _, child := range w.children {
|
||||
child.dumpTree(s)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *guiWidget) showWidgetPlacement(s string) {
|
||||
func (w *guiWidget) dumpWindows(s string) {
|
||||
// log.Log(ERROR, "dump w", w.WidgetId(), w.WidgetType, w.String())
|
||||
if w == nil {
|
||||
log.Log(ERROR, "dump w.TK == nil", w.WidgetId(), w.WidgetType(), w.String())
|
||||
return
|
||||
}
|
||||
if w.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
|
||||
// w.full.h0 = w.force.h0
|
||||
w.dumpWidget("dumpWindow() " + s)
|
||||
w.windowFrame.dumpWidget("dumpFrame() " + s)
|
||||
}
|
||||
|
||||
for _, child := range w.children {
|
||||
child.dumpWindows(s)
|
||||
}
|
||||
}
|
||||
|
||||
// a standard function to print out information about a widget
|
||||
func (tk *guiWidget) dumpWidget(s string) {
|
||||
var s1 string
|
||||
var pId int
|
||||
if w.node.Parent == nil {
|
||||
log.Log(INFO, "showWidgetPlacement() parent == nil", w.node.WidgetId, w.cuiName)
|
||||
// tk.verifyRect()
|
||||
if tk.parent == nil {
|
||||
log.Logf(WARN, "showWidgetPlacement() parent == nil wId=%d cuiName=%s", tk.WidgetId(), tk.cuiName)
|
||||
pId = 0
|
||||
} else {
|
||||
pId = w.node.Parent.WidgetId
|
||||
pId = tk.parent.WidgetId()
|
||||
}
|
||||
s1 = fmt.Sprintf("(wId,pId)=(%2d,%2d) ", w.node.WidgetId, pId)
|
||||
if w.Visible() {
|
||||
sizeW, sizeH := w.Size()
|
||||
s1 += fmt.Sprintf("size=(%2d,%2d)", sizeW, sizeH)
|
||||
s1 += fmt.Sprintf("gocui=(%2d,%2d,%2d,%2d)",
|
||||
w.gocuiSize.w0, w.gocuiSize.h0, w.gocuiSize.w1, w.gocuiSize.h1)
|
||||
s1 = fmt.Sprintf("(wId,pId)=(%4d,%4d) ", tk.WidgetId(), pId)
|
||||
sizeW, sizeH := tk.Size()
|
||||
hide := "S"
|
||||
if tk.Hidden() {
|
||||
hide = "H"
|
||||
}
|
||||
s1 += fmt.Sprintf("size=(%3d,%3d)%s)", sizeW, sizeH, hide)
|
||||
if tk.Visible() {
|
||||
s1 += fmt.Sprintf("gocui=(%3d,%3d,%3d,%3d)",
|
||||
tk.gocuiSize.w0, tk.gocuiSize.h0, tk.gocuiSize.w1, tk.gocuiSize.h1)
|
||||
} else {
|
||||
sizeW, sizeH := w.Size()
|
||||
s1 += fmt.Sprintf("size=(%2d,%2d)", sizeW, sizeH)
|
||||
s1 += fmt.Sprintf(" ")
|
||||
s1 += fmt.Sprintf(" %3s %3s %3s %3s ", "", "", "", "")
|
||||
}
|
||||
if w.node.Parent != nil {
|
||||
if w.node.Parent.WidgetType == widget.Grid {
|
||||
s1 += fmt.Sprintf("At(%2d,%2d) ", w.node.State.AtW, w.node.State.AtH)
|
||||
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()])
|
||||
} else {
|
||||
s1 += fmt.Sprintf(" %3s %3s ", "", "")
|
||||
s1 += fmt.Sprintf(" %3s %3s ", "", "")
|
||||
}
|
||||
} else {
|
||||
s1 += fmt.Sprintf(" %3s %3s ", "", "")
|
||||
}
|
||||
tmp := "." + w.String() + ". " + w.cuiName
|
||||
if w.node.WidgetType == widget.Box {
|
||||
tmp = "." + w.node.State.Direction.String() + ". " + w.cuiName
|
||||
var end string
|
||||
if tk.WidgetType() == widget.Box {
|
||||
end = fmt.Sprintf("%-8s %-8s %s %s", tk.WidgetType(), tk.cuiName, tk.Direction().String(), tk.String())
|
||||
} else {
|
||||
end = fmt.Sprintf("%-8s %-8s %s", tk.WidgetType(), tk.cuiName, tk.String())
|
||||
}
|
||||
log.Log(NOW, s1, s, w.node.WidgetType, ",", tmp) //
|
||||
log.Log(GOCUI, s1, s, end)
|
||||
}
|
||||
|
||||
func printWidgetTree(g *gocui.Gui, v *gocui.View) error {
|
||||
me.treeRoot.ListWidgets()
|
||||
return nil
|
||||
}
|
||||
|
||||
func printWidgetPlacements(g *gocui.Gui, v *gocui.View) error {
|
||||
w := me.treeRoot.TK.(*guiWidget)
|
||||
w.dumpTree("MM")
|
||||
w.dumpWindows("WW")
|
||||
return nil
|
||||
}
|
||||
|
|
112
draw.go
112
draw.go
|
@ -1,112 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
log "go.wit.com/log"
|
||||
)
|
||||
|
||||
var toggle bool = true
|
||||
|
||||
func (w *guiWidget) DrawAt(offsetW, offsetH int) {
|
||||
w.setColor(&colorActiveW)
|
||||
w.placeWidgets(offsetW, offsetH) // compute the sizes & places for each widget
|
||||
w.active = false
|
||||
w.showWidgets()
|
||||
}
|
||||
|
||||
func (w *guiWidget) toggleTree() {
|
||||
if toggle {
|
||||
w.drawTree(toggle)
|
||||
toggle = false
|
||||
} else {
|
||||
w.hideWidgets()
|
||||
toggle = true
|
||||
}
|
||||
}
|
||||
|
||||
// display the widgets in the binary tree
|
||||
func (w *guiWidget) drawTree(draw bool) {
|
||||
if w == nil {
|
||||
return
|
||||
}
|
||||
w.showWidgetPlacement("drawTree()")
|
||||
if draw {
|
||||
// w.textResize()
|
||||
w.Show()
|
||||
} else {
|
||||
w.Hide()
|
||||
}
|
||||
|
||||
for _, child := range w.children {
|
||||
child.drawTree(draw)
|
||||
}
|
||||
}
|
||||
|
||||
// display's the text of the widget in gocui
|
||||
// deletes the old view if it exists and recreates it
|
||||
func (w *guiWidget) drawView() {
|
||||
var err error
|
||||
log.Log(INFO, "drawView() START", w.WidgetType, w.String())
|
||||
if me.baseGui == nil {
|
||||
log.Log(ERROR, "drawView() ERROR: me.baseGui == nil", w)
|
||||
return
|
||||
}
|
||||
|
||||
if w.cuiName == "" {
|
||||
log.Log(ERROR, "drawView() w.cuiName was not set for widget", w)
|
||||
w.cuiName = strconv.Itoa(w.node.WidgetId) + " TK"
|
||||
}
|
||||
log.Log(INFO, "drawView() labelN =", w.labelN)
|
||||
|
||||
// this deletes the button from gocui
|
||||
me.baseGui.DeleteView(w.cuiName)
|
||||
w.v = nil
|
||||
|
||||
w.textResize()
|
||||
a := w.gocuiSize.w0
|
||||
b := w.gocuiSize.h0
|
||||
c := w.gocuiSize.w1
|
||||
d := w.gocuiSize.h1
|
||||
|
||||
w.v, err = me.baseGui.SetView(w.cuiName, a, b, c, d, 0)
|
||||
if err == nil {
|
||||
w.showWidgetPlacement("drawView()")
|
||||
log.Log(ERROR, "drawView() internal plugin error err = nil")
|
||||
return
|
||||
}
|
||||
if !errors.Is(err, gocui.ErrUnknownView) {
|
||||
w.showWidgetPlacement("drawView()")
|
||||
log.Log(ERROR, "drawView() internal plugin error error.IS()", err)
|
||||
return
|
||||
}
|
||||
|
||||
// this sets up the keybinding for the name of the window
|
||||
// does this really need to be done? I think we probably already
|
||||
// know everything about where all the widgets are so we could bypass
|
||||
// the gocui package and just handle all the mouse events internally here (?)
|
||||
// for now, the w.v.Name is a string "1", "2", "3", etc from the widgetId
|
||||
|
||||
// set the binding for this gocui view now that it has been created
|
||||
// gocui handles overlaps of views so it will run on the view that is clicked on
|
||||
me.baseGui.SetKeybinding(w.v.Name(), gocui.MouseLeft, gocui.ModNone, click)
|
||||
|
||||
// this actually sends the text to display to gocui
|
||||
w.v.Wrap = true
|
||||
w.v.Frame = w.frame
|
||||
w.v.Clear()
|
||||
fmt.Fprint(w.v, w.labelN)
|
||||
|
||||
// if you don't do this here, it will be black & white only
|
||||
if w.color != nil {
|
||||
w.v.FrameColor = w.color.frame
|
||||
w.v.FgColor = w.color.fg
|
||||
w.v.BgColor = w.color.bg
|
||||
w.v.SelFgColor = w.color.selFg
|
||||
w.v.SelBgColor = w.color.selBg
|
||||
}
|
||||
log.Log(INFO, "drawView() END")
|
||||
}
|
145
dropdown.go
145
dropdown.go
|
@ -1,156 +1,115 @@
|
|||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
package main
|
||||
|
||||
// simulates a dropdown menu in gocui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
log "go.wit.com/log"
|
||||
"go.wit.com/toolkits/tree"
|
||||
"go.wit.com/widget"
|
||||
)
|
||||
|
||||
func makeDropdownView(ddItems string) *guiWidget {
|
||||
newNode := addDropdown()
|
||||
tk := newNode.TK.(*guiWidget)
|
||||
tk.labelN = ddItems
|
||||
tk.SetText(ddItems)
|
||||
tk.gocuiSize.w0 = 100
|
||||
tk.gocuiSize.w1 = 120
|
||||
tk.gocuiSize.h0 = 15
|
||||
tk.gocuiSize.h1 = 18
|
||||
tk.v, _ = me.baseGui.SetView("ddview",
|
||||
tk.gocuiSize.w0,
|
||||
tk.gocuiSize.h0,
|
||||
tk.gocuiSize.w1,
|
||||
tk.gocuiSize.h1, 0)
|
||||
if tk.v == nil {
|
||||
return tk
|
||||
}
|
||||
tk.v.Wrap = true
|
||||
tk.v.Frame = true
|
||||
tk.v.Clear()
|
||||
fmt.Fprint(tk.v, ddItems)
|
||||
tk.Show()
|
||||
return tk
|
||||
}
|
||||
|
||||
func addDropdown() *tree.Node {
|
||||
// create a new widget in the binary tree
|
||||
func makeNewFlagWidget(wId int) *guiWidget {
|
||||
n := new(tree.Node)
|
||||
n.WidgetType = widget.Flag
|
||||
n.WidgetId = 2222
|
||||
n.WidgetId = wId
|
||||
n.ParentId = 0
|
||||
|
||||
// store the internal toolkit information
|
||||
tk := new(guiWidget)
|
||||
tk.frame = true
|
||||
tk.labelN = "DropBox text"
|
||||
|
||||
tk.node = n
|
||||
// copy the data from the action message
|
||||
tk.node.State.Label = "DropBox"
|
||||
if tk.node.Parent == nil {
|
||||
tk.node.Parent = me.treeRoot
|
||||
}
|
||||
|
||||
// set the name used by gocui to the id
|
||||
tk.cuiName = "-1 dropbox"
|
||||
tk.cuiName = fmt.Sprintf("%d DR", wId)
|
||||
|
||||
tk.color = &colorFlag
|
||||
tk.setColorInput()
|
||||
|
||||
// add this new widget on the binary tree
|
||||
tk.parent = me.treeRoot.TK.(*guiWidget)
|
||||
if tk.parent == nil {
|
||||
panic("addDropdown() didn't get treeRoot guiWidget")
|
||||
panic("makeNewFlagWidget() didn't get treeRoot guiWidget")
|
||||
} else {
|
||||
tk.parent.children = append(tk.parent.children, tk)
|
||||
}
|
||||
|
||||
n.TK = tk
|
||||
return n
|
||||
return tk
|
||||
}
|
||||
|
||||
func (tk *guiWidget) showDropdown() {
|
||||
var ddItems string
|
||||
if me.dropdown.tk == nil {
|
||||
// should only happen once
|
||||
me.dropdown.tk = makeNewFlagWidget(me.dropdown.wId)
|
||||
me.dropdown.tk.dumpWidget("init() dropdown")
|
||||
}
|
||||
if me.dropdown.tk == nil {
|
||||
log.Log(GOCUI, "showDropdown() Is Broken!")
|
||||
return
|
||||
}
|
||||
|
||||
// todo: fix this after switching to protobuf
|
||||
// var items []string
|
||||
// items = tk.node.State.Strings
|
||||
//for i, s := range items {
|
||||
me.dropdown.items = []string{} // zero out whatever was there before
|
||||
for i, s := range tk.node.Strings() {
|
||||
log.Log(GOCUI, "showDropdown()", tk.String(), i, s)
|
||||
ddItems += s + "\n"
|
||||
me.dropdown.items = append(me.dropdown.items, s)
|
||||
}
|
||||
log.Log(GOCUI, "new dropdown items should be set to:", me.dropdown.items)
|
||||
|
||||
log.Log(GOCUI, "new dropdown items should be set to:", ddItems)
|
||||
sizeW, sizeH := tk.Size()
|
||||
log.Log(GOCUI, "showDropdown() size W,H=", sizeW, sizeH)
|
||||
startW, startH := tk.Position()
|
||||
log.Log(GOCUI, "showDropdown() location W,H=", startW, startH)
|
||||
me.dropdownV.MoveToOffset(startW+3, startH+2)
|
||||
me.dropdownV.labelN = ddItems
|
||||
me.dropdownV.Show()
|
||||
}
|
||||
log.Log(GOCUI, "showDropdown() SHOWING AT W,H=", startW, startH)
|
||||
me.dropdown.tk.Hide()
|
||||
me.dropdown.tk.MoveToOffset(startW+3, startH+2)
|
||||
me.dropdown.tk.labelN = strings.Join(me.dropdown.items, "\n")
|
||||
me.dropdown.tk.Show()
|
||||
me.dropdown.active = true
|
||||
me.dropdown.callerTK = tk
|
||||
|
||||
func hideDDview() error {
|
||||
w, h := me.baseGui.MousePosition()
|
||||
log.Log(GOCUI, "hide dropdown menu() view msgMouseDown (w,h) =", w, h)
|
||||
if me.dropdownV == nil {
|
||||
return gocui.ErrUnknownView
|
||||
}
|
||||
if me.dropdownV.v == nil {
|
||||
return gocui.ErrUnknownView
|
||||
}
|
||||
me.dropdownV.SetVisible(false)
|
||||
return nil
|
||||
}
|
||||
r := me.dropdown.tk.gocuiSize // set the 'full' size so that mouse clicks are sent here
|
||||
me.dropdown.tk.full.w0 = r.w0
|
||||
me.dropdown.tk.full.w1 = r.w1
|
||||
me.dropdown.tk.full.h0 = r.h0
|
||||
me.dropdown.tk.full.h1 = r.h1
|
||||
|
||||
func showDDview() error {
|
||||
w, h := me.baseGui.MousePosition()
|
||||
log.Log(GOCUI, "show dropdown menu() view msgMouseDown (w,h) =", w, h)
|
||||
if me.dropdownV == nil {
|
||||
return gocui.ErrUnknownView
|
||||
}
|
||||
if me.dropdownV.v == nil {
|
||||
return gocui.ErrUnknownView
|
||||
}
|
||||
me.dropdownV.SetVisible(true)
|
||||
return nil
|
||||
me.dropdown.tk.dumpWidget("showDropdown()")
|
||||
}
|
||||
|
||||
// if there is a drop down view active, treat it like a dialog box and close it
|
||||
func (w *guiWidget) dropdownClicked(mouseW, mouseH int) string {
|
||||
w.Hide()
|
||||
me.dropdown.active = false
|
||||
|
||||
startW, startH := w.Position()
|
||||
log.Log(GOCUI, "dropdownClicked() start (w,h) =", startW, startH)
|
||||
log.Log(GOCUI, "dropdownClicked() at (w,h) =", mouseW, mouseH)
|
||||
// only need height to figure out what line in the dropdown menu the user clicked
|
||||
_, startH := w.Position()
|
||||
|
||||
itemNumber := mouseH - startH
|
||||
items := strings.Split(w.labelN, "\n")
|
||||
log.Log(GOCUI, "dropdownClicked() look for item", itemNumber, "len(items) =", len(items))
|
||||
items := me.dropdown.items
|
||||
// log.Log(GOCUI, "dropdownClicked() look for item", itemNumber, "len(items) =", len(items))
|
||||
if itemNumber < 1 {
|
||||
return ""
|
||||
}
|
||||
|
||||
if len(items) >= itemNumber {
|
||||
log.Log(GOCUI, "dropdownClicked() found", items[itemNumber-1])
|
||||
// log.Log(GOCUI, "dropdownClicked() found", items[itemNumber-1])
|
||||
if items[itemNumber-1] != "" {
|
||||
if me.dropdownW != nil {
|
||||
log.Log(GOCUI, "dropdownClicked() send event for", me.dropdownW.cuiName, me.dropdownW.WidgetType)
|
||||
me.dropdownW.SetText(items[itemNumber-1])
|
||||
me.dropdownW.node.SetCurrentS(items[itemNumber-1])
|
||||
me.myTree.SendUserEvent(me.dropdownW.node)
|
||||
if me.dropdown.tk != nil {
|
||||
// log.Log(GOCUI, "dropdownClicked() send event for", me.dropdownW.cuiName, me.dropdownW.node.WidgetType)
|
||||
me.dropdown.callerTK.SetText(items[itemNumber-1])
|
||||
me.dropdown.callerTK.node.SetCurrentS(items[itemNumber-1])
|
||||
me.myTree.SendUserEvent(me.dropdown.callerTK.node)
|
||||
}
|
||||
}
|
||||
return items[itemNumber-1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func dropdownUnclicked(mouseX, mouseH int) {
|
||||
if me.dropdownV == nil {
|
||||
log.Log(GOCUI, "mouseUp() dropdownV = nil", mouseX, mouseH)
|
||||
return
|
||||
}
|
||||
tk := me.dropdownV
|
||||
log.Log(GOCUI, "mouseUp() view msgMouseDown (check here for dropdown menu click) (w,h) =", mouseX, mouseH)
|
||||
log.Log(GOCUI, "mouseUp() ddview is the thing that was clicked", mouseX, mouseH)
|
||||
log.Log(GOCUI, "mouseUp() find out what the string is here", mouseX, mouseH, tk.gocuiSize.h1)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,234 @@
|
|||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
// register how the 'gocui' will work as a GO toolkit plugin
|
||||
// all applications will use these keys. they are universal.
|
||||
|
||||
// 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
|
||||
g.SetKeybinding("", gocui.MouseLeft, gocui.ModMouseCtrl, ctrlDown) // mouse with the ctrl key held down
|
||||
g.SetKeybinding("", gocui.MouseRelease, gocui.ModNone, mouseUp) // mouse button release
|
||||
g.SetKeybinding("", gocui.MouseWheelUp, gocui.ModNone, wheelsUp) // mouse button release
|
||||
g.SetKeybinding("", gocui.MouseWheelDown, gocui.ModNone, wheelsDown) // mouse button release
|
||||
|
||||
// Ctrl key handlers
|
||||
g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, doExit) // CTRL-C : exits the application
|
||||
g.SetKeybinding("", gocui.KeyCtrlV, gocui.ModNone, doPanic) // CTRL-V : force a panic()
|
||||
g.SetKeybinding("", gocui.KeyCtrlD, gocui.ModNone, openDebuggger) // CTRL-D : open the (D)ebugger
|
||||
keyForced, modForced := gocui.MustParse("ctrl+z") // setup ctrl+z
|
||||
g.SetKeybinding("", keyForced, modForced, handle_ctrl_z) // CTRL-Z :cleverly let's you background gocui (breaks cursor mouse on return)
|
||||
g.SetKeybinding("", gocui.KeyEsc, gocui.ModNone, doEsc) // escape key
|
||||
|
||||
// regular keys
|
||||
g.SetKeybinding("", 'H', gocui.ModNone, theHelp) // 'H' toggles on and off the help menu
|
||||
g.SetKeybinding("", 'O', gocui.ModNone, theStdout) // 'O' toggle the STDOUT window
|
||||
g.SetKeybinding("", 'D', gocui.ModNone, theDarkness) // 'D' toggles light/dark mode
|
||||
g.SetKeybinding("", 'q', gocui.ModNone, doExit) // 'q' exit
|
||||
g.SetKeybinding("", gocui.KeyTab, gocui.ModNone, tabCycleWindows) // '2' use this to test new ideas
|
||||
|
||||
// stdout keys
|
||||
g.SetKeybinding("", gocui.KeyPgup, gocui.ModNone, stdoutPgup) // Pgup scroll up the Stdout buffer
|
||||
g.SetKeybinding("", gocui.KeyPgdn, gocui.ModNone, stdoutPgdn) // Pgdn scroll down the Stdout buffer
|
||||
g.SetKeybinding("", gocui.KeyHome, gocui.ModNone, stdoutHome) // Pgdn scroll down the Stdout buffer
|
||||
g.SetKeybinding("", gocui.KeyArrowUp, gocui.ModNone, stdoutArrowUp) // Pgdn scroll down the Stdout buffer
|
||||
g.SetKeybinding("", gocui.KeyArrowDown, gocui.ModNone, stdoutArrowDown) // Pgdn scroll down the Stdout buffer
|
||||
|
||||
// debugging
|
||||
g.SetKeybinding("", '2', gocui.ModNone, theNotsure) // '2' use this to test new ideas
|
||||
g.SetKeybinding("", 'S', gocui.ModNone, theSuperMouse) // 'S' Super Mouse mode!
|
||||
g.SetKeybinding("", 'M', gocui.ModNone, printWidgetPlacements) // 'M' list all widgets with positions
|
||||
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("", 'q', gocui.ModNone, quit) // 'q' only exits gocui. plugin stays alive (?)
|
||||
}
|
||||
|
||||
// flips on 'super mouse' mode // this was awesome for debugging gocui. never remove this code.
|
||||
// while this is turned on, it will print out every widget found under the mouse
|
||||
func theSuperMouse(g *gocui.Gui, v *gocui.View) error {
|
||||
if me.supermouse {
|
||||
log.Log(GOCUI, "supermouse off")
|
||||
me.supermouse = false
|
||||
} else {
|
||||
me.supermouse = true
|
||||
log.Log(GOCUI, "supermouse on")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func theDarkness(g *gocui.Gui, v *gocui.View) error {
|
||||
if me.dark {
|
||||
me.dark = false
|
||||
log.Info("you have seen the light")
|
||||
} else {
|
||||
me.dark = true
|
||||
log.Info("you have entered into darkness")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func wheelsUp(g *gocui.Gui, v *gocui.View) error {
|
||||
// log.Info("private wheels up")
|
||||
me.stdout.pager -= 2
|
||||
if me.stdout.pager < 0 {
|
||||
me.stdout.pager = 0
|
||||
}
|
||||
me.stdout.tk.refreshStdout()
|
||||
return nil
|
||||
}
|
||||
|
||||
func wheelsDown(g *gocui.Gui, v *gocui.View) error {
|
||||
// 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()
|
||||
return nil
|
||||
}
|
||||
|
||||
func tabCycleWindows(g *gocui.Gui, v *gocui.View) error {
|
||||
// log.Info("try to switch windows here")
|
||||
if len(me.allwin) != len(findWindows()) {
|
||||
me.allwin = findWindows()
|
||||
}
|
||||
tk := findNextWindow()
|
||||
if tk == nil {
|
||||
log.Info("findNextWindow() err. returned nil")
|
||||
return nil
|
||||
}
|
||||
tk.makeWindowActive()
|
||||
return nil
|
||||
}
|
||||
|
||||
func doEsc(g *gocui.Gui, v *gocui.View) error {
|
||||
log.Info("got escape key")
|
||||
if me.dropdown.active {
|
||||
me.dropdown.tk.Hide()
|
||||
me.dropdown.active = false
|
||||
log.Info("escaped from dropdown")
|
||||
}
|
||||
if me.textbox.active {
|
||||
me.textbox.tk.Hide()
|
||||
me.textbox.active = false
|
||||
log.Info("escaped from textbox")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func theShow(g *gocui.Gui, v *gocui.View) error {
|
||||
var w *guiWidget
|
||||
w = me.treeRoot.TK.(*guiWidget)
|
||||
w.showWidgets()
|
||||
return nil
|
||||
}
|
||||
|
||||
func doExit(g *gocui.Gui, v *gocui.View) error {
|
||||
standardExit()
|
||||
return nil
|
||||
}
|
||||
|
||||
func doPanic(g *gocui.Gui, v *gocui.View) error {
|
||||
log.Log(GOCUI, "do panic() here")
|
||||
standardClose()
|
||||
panic("forced panic in gocui")
|
||||
}
|
||||
|
||||
func openDebuggger(g *gocui.Gui, v *gocui.View) error {
|
||||
me.myTree.SendEnableDebugger()
|
||||
return nil
|
||||
}
|
||||
|
||||
func theFind(g *gocui.Gui, v *gocui.View) error {
|
||||
w, h := g.MousePosition()
|
||||
for _, tk := range findByXY(w, h) {
|
||||
// tk.v.BgColor = gocui.ColorGreen
|
||||
tk.dumpWidget("theFind()")
|
||||
// tk.verifyRect()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// is run whenever anyone hits 'd' (in an open space)
|
||||
func theLetterD(g *gocui.Gui, v *gocui.View) error {
|
||||
// widgets that don't have physical existance in
|
||||
// a display toolkit are hidden. In the case
|
||||
// of gocui, they are set as not 'visible' and put offscreen
|
||||
// or have the size set to zero
|
||||
// (hopefully anyway) lots of things with the toolkit
|
||||
// still don't work
|
||||
|
||||
fakeStartWidth = me.FakeW
|
||||
fakeStartHeight = me.TabH + me.FramePadH
|
||||
if me.showDebug {
|
||||
showFake()
|
||||
me.showDebug = false
|
||||
} else {
|
||||
hideFake()
|
||||
me.showDebug = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func theHelp(g *gocui.Gui, v *gocui.View) error {
|
||||
if me.showHelp {
|
||||
log.Info("Show the help!")
|
||||
showHelp()
|
||||
} else {
|
||||
log.Info("Hide the help!")
|
||||
hideHelp()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// todo: find and give credit to the person that I found this patch in their forked repo
|
||||
// handle ctrl+z
|
||||
func handle_ctrl_z(g *gocui.Gui, v *gocui.View) error {
|
||||
gocui.Suspend()
|
||||
log.Info("got ctrl+z")
|
||||
syscall.Kill(syscall.Getpid(), syscall.SIGSTOP)
|
||||
log.Info("got ctrl+z syscall() done")
|
||||
gocui.Resume()
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
// 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"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
if me.stdout.outputOnTop {
|
||||
if me.stdout.outputOffscreen {
|
||||
me.stdout.outputOffscreen = false
|
||||
log.Info("stdout moved off screen", infos)
|
||||
me.stdout.lastW = me.stdout.tk.gocuiSize.w0
|
||||
me.stdout.lastH = me.stdout.tk.gocuiSize.h0
|
||||
relocateStdoutOffscreen()
|
||||
return nil
|
||||
} else {
|
||||
me.stdout.outputOffscreen = true
|
||||
log.Info("stdout moved on screen", infos)
|
||||
}
|
||||
// move the stdout window back onscreen
|
||||
me.stdout.tk.relocateStdout(me.stdout.lastW, me.stdout.lastH)
|
||||
me.stdout.outputOnTop = false
|
||||
setThingsOnTop()
|
||||
} else {
|
||||
me.stdout.outputOnTop = true
|
||||
setThingsOnTop()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func stdoutPgup(g *gocui.Gui, v *gocui.View) error {
|
||||
me.stdout.pager -= me.stdout.Height() - 2
|
||||
if me.stdout.pager < 0 {
|
||||
me.stdout.pager = 0
|
||||
}
|
||||
tk := me.stdout.tk
|
||||
tk.refreshStdout()
|
||||
return nil
|
||||
}
|
||||
|
||||
func stdoutHome(g *gocui.Gui, v *gocui.View) error {
|
||||
me.stdout.pager = 0
|
||||
me.stdout.tk.refreshStdout()
|
||||
return nil
|
||||
}
|
||||
|
||||
func stdoutArrowUp(g *gocui.Gui, v *gocui.View) error {
|
||||
me.stdout.pager += 1
|
||||
me.stdout.tk.refreshStdout()
|
||||
return nil
|
||||
}
|
||||
|
||||
func stdoutArrowDown(g *gocui.Gui, v *gocui.View) error {
|
||||
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
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
// 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.
|
||||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
package main
|
||||
|
||||
|
@ -8,7 +7,6 @@ import (
|
|||
"errors"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
|
@ -19,29 +17,11 @@ import (
|
|||
// complicated console handling, it sends events here in a clean way.
|
||||
// This is equivalent to the linux command xev (apt install x11-utils)
|
||||
func gocuiEvent(g *gocui.Gui) error {
|
||||
maxX, maxY := g.Size()
|
||||
mx, my := g.MousePosition()
|
||||
log.Verbose("handleEvent() START", maxX, maxY, mx, my, msgMouseDown)
|
||||
if _, err := g.View("msg"); msgMouseDown && err == nil {
|
||||
moveMsg(g)
|
||||
}
|
||||
if widgetView, _ := g.View("msg"); widgetView == nil {
|
||||
log.Log(NOW, "handleEvent() create output widget now", maxX, maxY, mx, my)
|
||||
makeOutputWidget(g, "this is a create before a mouse click")
|
||||
if me.logStdout != nil {
|
||||
// setOutput(me.logStdout)
|
||||
}
|
||||
} else {
|
||||
log.Verbose("output widget already exists", maxX, maxY, mx, my)
|
||||
}
|
||||
me.ecount += 1
|
||||
mouseMove(g)
|
||||
log.Verbose("handleEvent() END ", maxX, maxY, mx, my, msgMouseDown)
|
||||
return nil
|
||||
}
|
||||
|
||||
func dragOutputWindow() {
|
||||
}
|
||||
|
||||
// turns off the frame on the global window
|
||||
func setFrame(b bool) {
|
||||
// TODO: figure out what this might be useful for
|
||||
|
@ -53,6 +33,8 @@ func setFrame(b bool) {
|
|||
v.Frame = b
|
||||
}
|
||||
|
||||
// a test. exits gocui, but the application still runs
|
||||
// maybe can switch toolkits?
|
||||
func quit(g *gocui.Gui, v *gocui.View) error {
|
||||
return gocui.ErrQuit
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
// 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"
|
||||
"time"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
func mouseUp(g *gocui.Gui, v *gocui.View) error {
|
||||
// useful to debug everything that is being clicked on
|
||||
/*
|
||||
for _, tk := range findByXY(w, h) {
|
||||
tk.dumpWidget("mouseUp()")
|
||||
}
|
||||
*/
|
||||
|
||||
me.mouse.mouseUp = true
|
||||
me.mouse.currentDrag = nil
|
||||
|
||||
if me.mouse.double && (time.Since(me.mouse.down) < me.mouse.doubletime) {
|
||||
me.mouse.double = false
|
||||
doMouseDoubleClick(me.mouse.downW, me.mouse.downH)
|
||||
return nil
|
||||
}
|
||||
me.mouse.double = false
|
||||
|
||||
if time.Since(me.mouse.down) < me.mouse.clicktime {
|
||||
doMouseClick(me.mouse.downW, me.mouse.downH)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// this is where you have to figure out what
|
||||
// widget was underneath so you can active
|
||||
// the right response for the toolkit user's app
|
||||
func mouseDown(g *gocui.Gui, v *gocui.View) error {
|
||||
if me.mouse.mouseUp {
|
||||
if time.Since(me.mouse.down) < me.mouse.doubletime {
|
||||
me.mouse.double = true
|
||||
}
|
||||
me.mouse.mouseUp = false
|
||||
me.mouse.down = time.Now()
|
||||
w, h := g.MousePosition()
|
||||
me.mouse.downW = w
|
||||
me.mouse.downH = h
|
||||
|
||||
win := findWindowUnderMouse()
|
||||
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
|
||||
s += fmt.Sprintf("corner(%d,%d)", offW, offH)
|
||||
if (offW < 3) && (offH < 3) {
|
||||
log.Info("attempting resize on ", s, win.cuiName)
|
||||
me.mouse.resize = true
|
||||
// store the stdout corner for computing the drag size
|
||||
me.stdout.lastW = me.stdout.tk.gocuiSize.w0
|
||||
me.stdout.lastH = me.stdout.tk.gocuiSize.h0
|
||||
} else {
|
||||
// log.Info("mouse down resize off", s)
|
||||
me.mouse.resize = false
|
||||
}
|
||||
win.setAsDragging()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/awesome-gocui/gocui"
|
||||
"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)
|
||||
} else {
|
||||
log.Info("button is currently disabled by the application")
|
||||
// tk.dumpWidget("disabled()") // enable this to debug widget clicks
|
||||
}
|
||||
}
|
||||
|
||||
// handles a mouse click
|
||||
func doMouseClick(w int, h int) {
|
||||
// Flag widgets (dropdown menus, etc) are the highest priority. ALWAYS SEND MOUSE CLICKS THERE FIRST
|
||||
// handle an open dropdown menu or text entry window first
|
||||
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 dropdwon click", w, h, tk.cuiName)
|
||||
tk.dropdownClicked(w, h)
|
||||
return
|
||||
}
|
||||
if tk.WidgetId() == me.textbox.wId {
|
||||
log.Info("got textbox click", w, h, tk.cuiName)
|
||||
textboxClosed()
|
||||
return
|
||||
}
|
||||
}
|
||||
log.Info("a dropdown or textbox is active. you can't click anywhere else (otherwise hit ESC)", w, h)
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// look in this window for widgets
|
||||
// widgets have priority. send the click here first
|
||||
for _, tk := range win.findByXYreal(w, h) {
|
||||
switch tk.WidgetType() {
|
||||
case widget.Checkbox:
|
||||
if tk.Checked() {
|
||||
log.Log(WARN, "checkbox is being set to false")
|
||||
tk.SetChecked(false)
|
||||
tk.setCheckbox()
|
||||
} else {
|
||||
log.Log(WARN, "checkbox is being set to true")
|
||||
tk.SetChecked(true)
|
||||
tk.setCheckbox()
|
||||
}
|
||||
me.myTree.SendUserEvent(tk.node)
|
||||
return
|
||||
case widget.Button:
|
||||
tk.doButtonClick()
|
||||
return
|
||||
case widget.Combobox:
|
||||
tk.showDropdown()
|
||||
return
|
||||
case widget.Dropdown:
|
||||
tk.showDropdown()
|
||||
return
|
||||
case widget.Textbox:
|
||||
tk.prepTextbox()
|
||||
return
|
||||
default:
|
||||
// TODO: enable the GUI debugger in gocui
|
||||
// tk.dumpWidget("undef click()") // enable this to debug widget clicks
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// todo: use this?
|
||||
func ctrlDown(g *gocui.Gui, v *gocui.View) error {
|
||||
log.Info("todo: clicked with ctrlDown")
|
||||
return nil
|
||||
}
|
||||
|
||||
func doMouseDoubleClick(w int, h int) {
|
||||
me.mouse.double = false
|
||||
// log.Printf("actually a double click (%d,%d)", w, h)
|
||||
|
||||
if me.dropdown.active || me.textbox.active {
|
||||
// can't drag or do anything when dropdown or textbox are visible
|
||||
log.Info("can't double click. dropdown or textbox is active")
|
||||
return
|
||||
}
|
||||
|
||||
for _, tk := range findByXY(w, h) {
|
||||
if tk.WidgetType() == widget.Window {
|
||||
tk.makeWindowActive()
|
||||
return
|
||||
}
|
||||
|
||||
if tk.WidgetType() == widget.Stdout {
|
||||
if me.stdout.outputOnTop {
|
||||
me.stdout.outputOnTop = false
|
||||
setThingsOnTop()
|
||||
} else {
|
||||
me.stdout.outputOnTop = true
|
||||
setThingsOnTop()
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
// 2025 note by jcarr:
|
||||
// this is one of the coolest things ever worked with.
|
||||
// Personally, I've been working on making a gocui GO plugin
|
||||
// so I can use it as a generalized console GUI toolkit.
|
||||
//
|
||||
// Well done everyone that has contributed to this gocui project !!!
|
||||
// I am in your debt. Happy hacking & peace.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
log "go.wit.com/log"
|
||||
"go.wit.com/widget"
|
||||
)
|
||||
|
||||
// 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) {
|
||||
// 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
|
||||
if me.dropdown.active || me.textbox.active {
|
||||
if me.dropdown.tk != nil && me.dropdown.tk.v == v {
|
||||
v.Highlight = true
|
||||
}
|
||||
if me.textbox.tk != nil && me.textbox.tk.v == v {
|
||||
v.Highlight = true
|
||||
}
|
||||
} else {
|
||||
v.Highlight = true
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if createStdout(g) {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// END HIGHLIGHTING
|
||||
|
||||
// Super Mouse Mode. very useful for debugging in the past. also, just fun
|
||||
if me.supermouse {
|
||||
w, h := g.MousePosition()
|
||||
for _, tk := range findByXY(w, h) {
|
||||
s := fmt.Sprintf("SM (%3d,%3d)", w, h)
|
||||
tk.dumpWidget(s)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
return
|
||||
}
|
||||
|
||||
if me.dropdown.active || me.textbox.active {
|
||||
// can't drag
|
||||
return
|
||||
}
|
||||
|
||||
// drag whatever was set to drag
|
||||
if me.mouse.currentDrag != nil {
|
||||
// me.mouse.currentDrag.dumpWidget(fmt.Sprintf("MM (%3d,%3d)", w, h))
|
||||
me.mouse.currentDrag.moveNew()
|
||||
return
|
||||
}
|
||||
log.Info(fmt.Sprintf("gocui gui toolkit plugin error. nothing to drag at (%d,%d)", w, h))
|
||||
return
|
||||
}
|
||||
|
||||
func (tk *guiWidget) setAsDragging() {
|
||||
me.mouse.currentDrag = tk
|
||||
tk.lastW = tk.gocuiSize.w0
|
||||
tk.lastH = tk.gocuiSize.h0
|
||||
}
|
||||
|
||||
// this is how the window gets dragged around
|
||||
func (tk *guiWidget) moveNew() {
|
||||
w, h := me.baseGui.MousePosition()
|
||||
if tk.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()
|
||||
return
|
||||
}
|
||||
/*
|
||||
if tk.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.WidgetType() == widget.Stdout {
|
||||
if me.mouse.resize {
|
||||
newW := w - me.stdout.lastW
|
||||
newH := h - me.stdout.lastH
|
||||
me.stdout.w = newW
|
||||
me.stdout.h = newH
|
||||
// log.Info("Resize true", w, h, newW, newH)
|
||||
// me.stdout.lastW = w - me.stdout.mouseOffsetW
|
||||
// me.stdout.lastH = h - me.stdout.mouseOffsetH
|
||||
tk.relocateStdout(me.stdout.lastW, me.stdout.lastH)
|
||||
} else {
|
||||
// compute the new location based off how far the mouse has moved
|
||||
// since the mouse button was pressed down
|
||||
newW := tk.lastW + w - me.mouse.downW
|
||||
newH := tk.lastH + h - me.mouse.downH
|
||||
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
|
||||
}
|
||||
}
|
58
fakefile.go
58
fakefile.go
|
@ -1,58 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
type FakeFile struct {
|
||||
reader *bytes.Reader
|
||||
buffer *bytes.Buffer
|
||||
offset int64
|
||||
}
|
||||
|
||||
func (f *FakeFile) Read(p []byte) (n int, err error) {
|
||||
n, err = f.reader.ReadAt(p, f.offset)
|
||||
f.offset += int64(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (f *FakeFile) Write(p []byte) (n int, err error) {
|
||||
n, err = f.buffer.Write(p)
|
||||
f.offset += int64(n)
|
||||
f.reader.Reset(f.buffer.Bytes())
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (f *FakeFile) Seek(offset int64, whence int) (int64, error) {
|
||||
newOffset := f.offset
|
||||
|
||||
switch whence {
|
||||
case io.SeekStart:
|
||||
newOffset = offset
|
||||
case io.SeekCurrent:
|
||||
newOffset += offset
|
||||
case io.SeekEnd:
|
||||
newOffset = int64(f.buffer.Len()) + offset
|
||||
default:
|
||||
return 0, errors.New("Seek: whence not at start,current or end")
|
||||
}
|
||||
// never can get here right?
|
||||
|
||||
if newOffset < 0 {
|
||||
return 0, errors.New("Seek: offset < 0")
|
||||
}
|
||||
|
||||
f.offset = newOffset
|
||||
return f.offset, nil
|
||||
}
|
||||
|
||||
func NewFakeFile() *FakeFile {
|
||||
buf := &bytes.Buffer{}
|
||||
return &FakeFile{
|
||||
reader: bytes.NewReader(buf.Bytes()),
|
||||
buffer: buf,
|
||||
offset: 0,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,231 @@
|
|||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"slices"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
log "go.wit.com/log"
|
||||
"go.wit.com/widget"
|
||||
)
|
||||
|
||||
/*
|
||||
gocui defines the offset like this:
|
||||
|
||||
width -> increases to the right
|
||||
---------------------------------- hieght
|
||||
| H = 1 | increases
|
||||
| | |
|
||||
| W = 1 W = 18 | |
|
||||
| | v
|
||||
| H = 5 | downwards
|
||||
-------------------------------------
|
||||
*/
|
||||
|
||||
// change over to this name
|
||||
// returns all the widgets under (X,H) that are visible
|
||||
func findByXY(w int, h int) []*guiWidget {
|
||||
rootW := me.treeRoot.TK.(*guiWidget)
|
||||
|
||||
// this searches the binary tree recursively (function is right below)
|
||||
return rootW.findByXYreal(w, h)
|
||||
}
|
||||
|
||||
func (r rectType) inRect(w int, h int) bool {
|
||||
if (r.w0 <= w) && (w <= r.w1) && (r.h0 <= h) && (h <= r.h1) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// this checks a widget to see if it is under (W,H), then checks the widget's children
|
||||
// anything that matches is passed back as an array of widgets
|
||||
func (tk *guiWidget) findByXYreal(w int, h int) []*guiWidget {
|
||||
var widgets []*guiWidget
|
||||
|
||||
// if !tk.Visible() {
|
||||
// ignore widgets that are not visible
|
||||
// } else {
|
||||
|
||||
// check the location to see if this is under (W,H)
|
||||
// if it is, return this widget
|
||||
// if (tk.gocuiSize.w0 <= w) && (w <= tk.gocuiSize.w1) &&
|
||||
// (tk.gocuiSize.h0 <= h) && (h <= tk.gocuiSize.h1) {
|
||||
// if tk.gocuiSize.inRect(w, h) {
|
||||
// widgets = append(widgets, tk)
|
||||
// } else {
|
||||
// if (tk.full.w0 <= w) && (w <= tk.full.w1) &&
|
||||
// (tk.full.h0 <= h) && (h <= tk.full.h1) {
|
||||
if tk.full.inRect(w, h) {
|
||||
widgets = append(widgets, tk)
|
||||
}
|
||||
// log.Log(GOCUI, "findByXY() found", widget.WidgetType(), w, h)
|
||||
// }
|
||||
// }
|
||||
// tk.verifyRect()
|
||||
|
||||
// search through the children widgets in the binary tree
|
||||
for _, child := range tk.children {
|
||||
widgets = append(widgets, child.findByXYreal(w, h)...)
|
||||
}
|
||||
|
||||
return widgets
|
||||
}
|
||||
|
||||
// returns all the windows from the root of the binary tree
|
||||
func findWindows() []*guiWidget {
|
||||
rootW := me.treeRoot.TK.(*guiWidget)
|
||||
return rootW.findWindows()
|
||||
}
|
||||
|
||||
// walk the binary tree looking for WidgetType == Window
|
||||
func (tk *guiWidget) findWindows() []*guiWidget {
|
||||
var found []*guiWidget
|
||||
|
||||
if tk.WidgetType() == widget.Window {
|
||||
found = append(found, tk)
|
||||
}
|
||||
|
||||
for _, child := range tk.children {
|
||||
found = append(found, child.findWindows()...)
|
||||
}
|
||||
return found
|
||||
}
|
||||
|
||||
// used by gocui.TabKey to rotate through the windows
|
||||
func findNextWindow() *guiWidget {
|
||||
var found bool
|
||||
if len(me.allwin) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, tk := range me.allwin {
|
||||
if tk.window.active {
|
||||
found = true
|
||||
continue
|
||||
}
|
||||
if found {
|
||||
return tk
|
||||
}
|
||||
}
|
||||
// at the end, loop to the beginning
|
||||
return me.allwin[0]
|
||||
}
|
||||
|
||||
// find the window under the mouse and only the window under the mouse
|
||||
func findWindowUnderMouse() *guiWidget {
|
||||
w, h := me.baseGui.MousePosition()
|
||||
|
||||
if len(me.allwin) != len(findWindows()) {
|
||||
me.allwin = findWindows()
|
||||
}
|
||||
|
||||
// if the stdout window is on top, check it first
|
||||
if me.stdout.outputOnTop {
|
||||
if me.stdout.tk.full.inRect(w, h) {
|
||||
// log.Info(fmt.Sprintf("findWindowUnderMouse() found %s stdout on top (%dx%d)", me.stdout.tk.cuiName, w, h))
|
||||
return me.stdout.tk
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// 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 {
|
||||
if tk.full.inRect(w, h) {
|
||||
// log.Info(fmt.Sprintf("findWindowUnderMouse() found %s active window (%dx%d)", tk.cuiName, w, h))
|
||||
return tk
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// well, just find any window then
|
||||
// sorting by order might work?
|
||||
slices.SortFunc(me.allwin, func(a, b *guiWidget) int {
|
||||
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))
|
||||
return win
|
||||
}
|
||||
}
|
||||
|
||||
// okay, no window. maybe the stdout is there?
|
||||
if me.stdout.tk.full.inRect(w, h) {
|
||||
// log.Info(fmt.Sprintf("findWindowUnderMouse() found %s stdout (%dx%d)", me.stdout.tk.cuiName, w, h))
|
||||
return me.stdout.tk
|
||||
}
|
||||
|
||||
// geez. nothing! maybe auto return stdout?
|
||||
log.Info("findWindowUnderMouse() no window found at", w, h)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tk *guiWidget) findParentWindow() *guiWidget {
|
||||
if tk.WidgetType() == widget.Window {
|
||||
return tk
|
||||
}
|
||||
if tk.parent == nil {
|
||||
return nil
|
||||
}
|
||||
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
|
||||
}
|
80
help.go
80
help.go
|
@ -1,4 +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.
|
||||
|
||||
|
@ -10,32 +13,47 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
log "go.wit.com/log"
|
||||
)
|
||||
|
||||
var helpText []string = []string{"KEYBINDINGS",
|
||||
/*
|
||||
This in helpText doesn't print
|
||||
|
||||
"\x1b[0;32m \x1b[0m", // this was a test to see what might be
|
||||
// possible with gocui. it doesn't seem to work for me
|
||||
*/
|
||||
|
||||
var helpText []string = []string{"Help Menu",
|
||||
"",
|
||||
"?: toggle help",
|
||||
"d: toggle debugging",
|
||||
"r: redraw widgets",
|
||||
"s/h: show/hide all widgets",
|
||||
"L: list all widgets",
|
||||
"M: list all widgets positions",
|
||||
"\x1b[0;32m \x1b[0m",
|
||||
"q: quit()",
|
||||
"p: panic()",
|
||||
"o: show Stdout",
|
||||
"l: log to /tmp/witgui.log",
|
||||
"Ctrl-D: Toggle Debugging",
|
||||
"Ctrl-V: Toggle Verbose Debugging",
|
||||
"Ctrl-C: Exit",
|
||||
"Tab: toggle through windows",
|
||||
"O: toggle STDOUT",
|
||||
"H: toggle this gocui menu",
|
||||
"L: toggle light/dark mode",
|
||||
"CTRL-c: quit()",
|
||||
"",
|
||||
"Debugging:",
|
||||
"S: Supermouse mode",
|
||||
"M: list all widget positions",
|
||||
"L: list all widgets in tree",
|
||||
}
|
||||
|
||||
func hidehelplayout() {
|
||||
func hideHelp() {
|
||||
if me.showHelp {
|
||||
log.Info("help is already down")
|
||||
me.showHelp = true
|
||||
return
|
||||
}
|
||||
me.showHelp = true
|
||||
me.baseGui.DeleteView("help")
|
||||
}
|
||||
|
||||
func helplayout() error {
|
||||
func showHelp() error {
|
||||
if !me.showHelp {
|
||||
log.Info("help is already up")
|
||||
me.showHelp = false
|
||||
return nil
|
||||
}
|
||||
me.showHelp = false
|
||||
g := me.baseGui
|
||||
var err error
|
||||
maxX, _ := g.Size()
|
||||
|
@ -47,17 +65,18 @@ func helplayout() error {
|
|||
}
|
||||
}
|
||||
|
||||
help, err := g.SetView("help", maxX-(newW+me.FramePadW), 0, maxX-1, len(helpText)+me.FramePadH, 0)
|
||||
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)
|
||||
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"))
|
||||
|
||||
|
@ -65,6 +84,21 @@ func helplayout() error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
g.SetViewOnTop("help")
|
||||
me.helpLabel = help
|
||||
|
||||
/*
|
||||
if me.treeRoot == nil {
|
||||
log.Info("gogui makeClock() error. treeRoot == nil")
|
||||
return nil
|
||||
} else {
|
||||
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
|
||||
}
|
||||
|
|
|
@ -0,0 +1,425 @@
|
|||
// 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"
|
||||
"os"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"runtime/pprof"
|
||||
"time"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
// sent via -ldflags
|
||||
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()
|
||||
me.textbox.tk.prepTextbox()
|
||||
}
|
||||
// TEST TEXTBOX END
|
||||
}
|
||||
|
||||
func toolkitClose() {
|
||||
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()
|
||||
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}()
|
||||
|
||||
var err error
|
||||
|
||||
// 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("dark"); err == nil {
|
||||
if val == "true" {
|
||||
me.dark = true
|
||||
}
|
||||
} else {
|
||||
// macos iterm2 really only works with dark mode right now
|
||||
if runtime.GOOS == "macos" {
|
||||
me.dark = true
|
||||
}
|
||||
}
|
||||
// todo: make this a tmp file that goes away
|
||||
if !me.stdout.disable {
|
||||
log.Log(INFO, "stdout.disable == true. writing to /tmp/captureMode.log")
|
||||
me.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)
|
||||
}
|
||||
// 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
|
||||
|
||||
// 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.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")
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
// log(true, "standardExit() setOutput(os.Stdout)")
|
||||
// setOutput(os.Stdout)
|
||||
log.Log(NOW, "standardExit() send back Quit()")
|
||||
// go sendBackQuit() // don't stall here in case the
|
||||
// induces a delay in case the callback channel is broken
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
log.Log(NOW, "standardExit() exit()")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func standardClose() {
|
||||
log.Log(NOW, "standardExit() doing baseGui.Close()")
|
||||
me.baseGui.Close()
|
||||
log.Log(NOW, "standardExit() doing outf.Close()")
|
||||
me.outf.Close()
|
||||
// os.Stdin = os.Stdin
|
||||
// os.Stdout = os.Stdout
|
||||
// os.Stderr = os.Stderr
|
||||
log.Log(NOW, "standardExit() send back Quit()")
|
||||
}
|
||||
|
||||
func main() {
|
||||
}
|
||||
|
||||
// this hack is to wait for the application to send something
|
||||
// before trying to do anything. todo: rethink this someday
|
||||
func waitOK() {
|
||||
for {
|
||||
if me.ok {
|
||||
return
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
// 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")
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
// 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()
|
||||
} else {
|
||||
if time.Since(lastRefresh) > 3*time.Second {
|
||||
libNotifyUpdate()
|
||||
lastRefresh = time.Now()
|
||||
}
|
||||
}
|
||||
me.myTree.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set the widget start width & height
|
||||
|
||||
func newWindowTrigger() {
|
||||
// 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)
|
||||
waitOK()
|
||||
me.myTree.Lock()
|
||||
// time.Sleep(200 * time.Millisecond)
|
||||
redoWindows(me.FirstWindowW, me.FirstWindowH)
|
||||
me.firstWindowOk = true
|
||||
if !me.stdout.init {
|
||||
me.stdout.init = true
|
||||
relocateStdoutOffscreen()
|
||||
}
|
||||
if me.textbox.tk == nil {
|
||||
initTextbox()
|
||||
me.textbox.tk.prepTextbox()
|
||||
}
|
||||
tk.makeWindowActive()
|
||||
me.myTree.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
200
keybindings.go
200
keybindings.go
|
@ -1,200 +0,0 @@
|
|||
// Copyright 2014 The gocui Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
// handle ctrl+z
|
||||
func handle_ctrl_z(g *gocui.Gui, v *gocui.View) error {
|
||||
gocui.Suspend()
|
||||
log.Info("got ctrl+z")
|
||||
syscall.Kill(syscall.Getpid(), syscall.SIGSTOP)
|
||||
gocui.Resume()
|
||||
return nil
|
||||
}
|
||||
|
||||
func defaultKeybindings(g *gocui.Gui) error {
|
||||
if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
|
||||
return err
|
||||
}
|
||||
// setup ctrl+z
|
||||
keyForced, modForced := gocui.MustParse("ctrl+z")
|
||||
if err := g.SetKeybinding("", keyForced, modForced, handle_ctrl_z); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
for _, n := range []string{"but1", "but2", "help", "but3"} {
|
||||
if err := g.SetKeybinding(n, gocui.MouseLeft, gocui.ModNone, showMsg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := g.SetKeybinding("", gocui.MouseRelease, gocui.ModNone, mouseUp); err != nil {
|
||||
return err
|
||||
}
|
||||
// mouseDown() runs whenever you click on an unknown view (?)
|
||||
if err := g.SetKeybinding("", gocui.MouseLeft, gocui.ModNone, mouseDown); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding("", gocui.MouseLeft, gocui.ModMouseCtrl, ctrlDown); err != nil {
|
||||
return err
|
||||
}
|
||||
// if err := g.SetKeybinding(w.v.Name(), gocui.MouseLeft, gocui.ModNone, click); err != nil {
|
||||
// return err
|
||||
// }
|
||||
/*
|
||||
if err := g.SetKeybinding("", gocui.MouseLeft, gocui.ModNone, globalDown); err != nil {
|
||||
return err
|
||||
}
|
||||
*/
|
||||
if err := g.SetKeybinding("msg", gocui.MouseLeft, gocui.ModNone, msgDown); err != nil {
|
||||
return err
|
||||
}
|
||||
addDebugKeys(g)
|
||||
return nil
|
||||
}
|
||||
|
||||
func addDebugKeys(g *gocui.Gui) {
|
||||
// show debugging buttons
|
||||
g.SetKeybinding("", 'd', gocui.ModNone,
|
||||
func(g *gocui.Gui, v *gocui.View) error {
|
||||
fakeStartWidth = me.FakeW
|
||||
fakeStartHeight = me.TabH + me.FramePadH
|
||||
if showDebug {
|
||||
showFake()
|
||||
showDebug = false
|
||||
} else {
|
||||
hideFake()
|
||||
showDebug = true
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// display the help menu
|
||||
g.SetKeybinding("", '?', gocui.ModNone,
|
||||
func(g *gocui.Gui, v *gocui.View) error {
|
||||
if showHelp {
|
||||
helplayout()
|
||||
showHelp = false
|
||||
if me.dropdownV == nil {
|
||||
me.dropdownV = makeDropdownView("addWidget() ddview")
|
||||
}
|
||||
me.dropdownV.Show()
|
||||
} else {
|
||||
me.baseGui.DeleteView("help")
|
||||
showHelp = true
|
||||
me.dropdownV.Hide()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// redraw all the widgets
|
||||
g.SetKeybinding("", 'r', gocui.ModNone,
|
||||
func(g *gocui.Gui, v *gocui.View) error {
|
||||
var w *guiWidget
|
||||
w = me.treeRoot.TK.(*guiWidget)
|
||||
if redoWidgets {
|
||||
wRoot := me.treeRoot.TK.(*guiWidget)
|
||||
wRoot.redoWindows(0, 0)
|
||||
redoWidgets = false
|
||||
} else {
|
||||
w.hideWidgets()
|
||||
redoWidgets = true
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// hide all widgets
|
||||
g.SetKeybinding("", 'h', gocui.ModNone,
|
||||
func(g *gocui.Gui, v *gocui.View) error {
|
||||
var w *guiWidget
|
||||
w = me.treeRoot.TK.(*guiWidget)
|
||||
w.hideWidgets()
|
||||
return nil
|
||||
})
|
||||
|
||||
// show all widgets
|
||||
g.SetKeybinding("", 's', gocui.ModNone,
|
||||
func(g *gocui.Gui, v *gocui.View) error {
|
||||
var w *guiWidget
|
||||
w = me.treeRoot.TK.(*guiWidget)
|
||||
w.showWidgets()
|
||||
return nil
|
||||
})
|
||||
|
||||
// list all widgets
|
||||
g.SetKeybinding("", 'L', gocui.ModNone,
|
||||
func(g *gocui.Gui, v *gocui.View) error {
|
||||
me.treeRoot.ListWidgets()
|
||||
return nil
|
||||
})
|
||||
|
||||
// list all widgets with positions
|
||||
g.SetKeybinding("", 'M', gocui.ModNone,
|
||||
func(g *gocui.Gui, v *gocui.View) error {
|
||||
w := me.treeRoot.TK.(*guiWidget)
|
||||
w.dumpTree("M")
|
||||
return nil
|
||||
})
|
||||
|
||||
// redo windows
|
||||
g.SetKeybinding("", 'w', gocui.ModNone,
|
||||
func(g *gocui.Gui, v *gocui.View) error {
|
||||
wRoot := me.treeRoot.TK.(*guiWidget)
|
||||
wRoot.redoWindows(0, 0)
|
||||
return nil
|
||||
})
|
||||
|
||||
// log to output window
|
||||
g.SetKeybinding("", 'o', gocui.ModNone,
|
||||
func(g *gocui.Gui, v *gocui.View) error {
|
||||
log.Log(ERROR, "TODO: re-implement this")
|
||||
/*
|
||||
if me.logStdout.Visible() {
|
||||
me.logStdout.SetVisible(false)
|
||||
// setOutput(os.Stdout)
|
||||
} else {
|
||||
me.logStdout.SetVisible(true)
|
||||
// setOutput(me.logStdout.tk)
|
||||
}
|
||||
*/
|
||||
return nil
|
||||
})
|
||||
|
||||
// exit
|
||||
g.SetKeybinding("", 'q', gocui.ModNone,
|
||||
func(g *gocui.Gui, v *gocui.View) error {
|
||||
standardExit()
|
||||
return nil
|
||||
})
|
||||
g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone,
|
||||
func(g *gocui.Gui, v *gocui.View) error {
|
||||
standardExit()
|
||||
return nil
|
||||
})
|
||||
g.SetKeybinding("", gocui.KeyCtrlD, gocui.ModNone,
|
||||
func(g *gocui.Gui, v *gocui.View) error {
|
||||
if showDebug {
|
||||
me.myTree.SendEnableDebugger()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
g.SetKeybinding("", gocui.KeyCtrlV, gocui.ModNone,
|
||||
func(g *gocui.Gui, v *gocui.View) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
// panic
|
||||
g.SetKeybinding("", 'p', gocui.ModNone,
|
||||
func(g *gocui.Gui, v *gocui.View) error {
|
||||
standardClose()
|
||||
panic("forced panic in gocui")
|
||||
return nil
|
||||
})
|
||||
}
|
|
@ -0,0 +1,292 @@
|
|||
// 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)
|
||||
}
|
||||
|
||||
// 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()
|
||||
a := w
|
||||
b := h
|
||||
c := w + 8
|
||||
d := h + 4
|
||||
var err error
|
||||
tk.v, err = me.baseGui.SetView(tk.cuiName, a, b, c, d, 0)
|
||||
if err == nil {
|
||||
log.Info("hardDrawUnderMouse() err ok widget", tk.cuiName)
|
||||
tk.dumpWidget("hard draw err")
|
||||
}
|
||||
tk.v.Frame = false
|
||||
tk.v.Clear()
|
||||
tk.v.WriteString(tk.labelN + "\n" + name)
|
||||
}
|
||||
|
||||
func hardDrawAtgocuiSize(tk *guiWidget) {
|
||||
if tk.v != nil {
|
||||
tk.Hide()
|
||||
}
|
||||
a := tk.gocuiSize.w0
|
||||
b := tk.gocuiSize.h0
|
||||
c := tk.gocuiSize.w1
|
||||
d := tk.gocuiSize.h1
|
||||
var err error
|
||||
tk.v, err = me.baseGui.SetView(tk.cuiName, a, b, c, d, 0)
|
||||
if err == nil {
|
||||
log.Info("hardDrawAtgocuiSize() err ok widget", tk.cuiName)
|
||||
tk.dumpWidget("hard draw err")
|
||||
}
|
||||
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()
|
||||
a := -1
|
||||
b := -1
|
||||
c := w + 1
|
||||
d := h + 1
|
||||
var err error
|
||||
tk.v, err = me.baseGui.SetView(tk.cuiName, a, b, c, d, 0)
|
||||
if err == nil {
|
||||
if tk.v == nil {
|
||||
tk.dumpWidget("drawView() err")
|
||||
log.Log(ERROR, "drawView() internal plugin error err = nil")
|
||||
}
|
||||
return
|
||||
}
|
||||
log.Log(INFO, "background resized to", a, b, c, d)
|
||||
}
|
||||
|
||||
// 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()
|
||||
me.baseGui.SetView(tk.cuiName, -1, -1, w+1, h+1, 0)
|
||||
}
|
7
log.go
7
log.go
|
@ -1,3 +1,6 @@
|
|||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
package main
|
||||
|
||||
/*
|
||||
|
@ -8,8 +11,6 @@ import (
|
|||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
var outputS []string
|
||||
|
||||
var NOW *log.LogFlag
|
||||
var INFO *log.LogFlag
|
||||
var GOCUI *log.LogFlag
|
||||
|
@ -23,7 +24,7 @@ func init() {
|
|||
full := "go.wit.com/gui"
|
||||
short := "gocui"
|
||||
|
||||
GOCUI = log.NewFlag("GOCUI", false, full, short, "gocui internals")
|
||||
GOCUI = log.NewFlag("GOCUI", true, full, short, "gocui internals")
|
||||
|
||||
full = "go.wit.com/toolkits/gocui"
|
||||
short = "gocui"
|
||||
|
|
192
main.go
192
main.go
|
@ -1,192 +0,0 @@
|
|||
// Copyright 2014 The gocui Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
"go.wit.com/log"
|
||||
"go.wit.com/toolkits/tree"
|
||||
)
|
||||
|
||||
func queueToolkitClose() {
|
||||
me.baseGui.Close()
|
||||
}
|
||||
|
||||
func queueSetChecked(n *tree.Node, b bool) {
|
||||
setChecked(n, b)
|
||||
}
|
||||
|
||||
// sets defaults and establishes communication
|
||||
// to this toolkit from the wit/gui golang package
|
||||
func init() {
|
||||
log.Log(INFO, "Init() of awesome-gocui")
|
||||
|
||||
// init the config struct default values
|
||||
Set(&me, "default")
|
||||
|
||||
// Set(&me, "dense")
|
||||
|
||||
me.myTree = tree.New()
|
||||
me.myTree.PluginName = "gocui"
|
||||
|
||||
me.myTree.NodeAction = newaction
|
||||
me.myTree.Add = newAdd
|
||||
me.myTree.SetTitle = newSetTitle
|
||||
me.myTree.SetLabel = newSetLabel
|
||||
me.myTree.SetText = newSetText
|
||||
me.myTree.AddText = newAddText
|
||||
me.myTree.SetChecked = queueSetChecked
|
||||
me.myTree.ToolkitClose = queueToolkitClose
|
||||
|
||||
log.Log(NOW, "Init() start pluginChan")
|
||||
log.Sleep(.1) // probably not needed, but in here for now under development
|
||||
go mainGogui()
|
||||
log.Sleep(.1) // probably not needed, but in here for now under development
|
||||
}
|
||||
|
||||
func standardExit() {
|
||||
log.Log(NOW, "standardExit() doing baseGui.Close()")
|
||||
me.baseGui.Close()
|
||||
log.Log(NOW, "standardExit() doing outf.Close()")
|
||||
outf.Close()
|
||||
// log(true, "standardExit() setOutput(os.Stdout)")
|
||||
// setOutput(os.Stdout)
|
||||
log.Log(NOW, "standardExit() send back Quit()")
|
||||
// go sendBackQuit() // don't stall here in case the
|
||||
// induces a delay in case the callback channel is broken
|
||||
log.Sleep(1)
|
||||
log.Log(NOW, "standardExit() exit()")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func standardClose() {
|
||||
log.Log(NOW, "standardExit() doing baseGui.Close()")
|
||||
me.baseGui.Close()
|
||||
log.Log(NOW, "standardExit() doing outf.Close()")
|
||||
outf.Close()
|
||||
os.Stdin = os.Stdin
|
||||
os.Stdout = os.Stdout
|
||||
os.Stderr = os.Stderr
|
||||
log.Log(NOW, "standardExit() send back Quit()")
|
||||
}
|
||||
|
||||
var outf *os.File
|
||||
|
||||
func main() {
|
||||
}
|
||||
|
||||
var origStdout *os.File
|
||||
var origStderr *os.File
|
||||
|
||||
func mainGogui() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Warn("YAHOOOO Recovered in guiMain application:", r)
|
||||
log.Warn("Recovered from panic:", r)
|
||||
me.baseGui.Close()
|
||||
me.myTree.SendToolkitPanic()
|
||||
|
||||
// attempts to control STDOUT
|
||||
/*
|
||||
// allow gocui to close if possible, then print stack
|
||||
log.Sleep(1)
|
||||
me.myTree.SendToolkitLoad("nocui")
|
||||
log.Sleep(3)
|
||||
os.Stdout = origStdout
|
||||
os.Stderr = origStderr
|
||||
log.Warn("Stack trace:")
|
||||
debug.PrintStack()
|
||||
|
||||
// attempt to switch to the nocui toolkit
|
||||
log.Sleep(1)
|
||||
// panic("BUMMER")
|
||||
*/
|
||||
return
|
||||
}
|
||||
}()
|
||||
// attempts to control STDOUT
|
||||
/*
|
||||
var err error
|
||||
log.Log(INFO, "main() start Init()")
|
||||
|
||||
outf, err = os.OpenFile("/tmp/witgui.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
log.Error(err, "error opening file: %v")
|
||||
os.Exit(0)
|
||||
}
|
||||
origStdout = os.Stdout
|
||||
os.Stdout = outf
|
||||
defer outf.Close()
|
||||
|
||||
// setOutput(outf)
|
||||
// log("This is a test log entry")
|
||||
|
||||
ferr, _ := os.OpenFile("/tmp/witgui.err", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0664)
|
||||
origStderr = os.Stderr
|
||||
os.Stderr = ferr
|
||||
*/
|
||||
gocuiMain()
|
||||
}
|
||||
|
||||
// This initializes the gocui package
|
||||
// it runs SetManagerFunc which passes every input
|
||||
// event (keyboard, mouse, etc) to the function "gocuiEvent()"
|
||||
func gocuiMain() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Warn("YAHOOOO Recovered in gocuiMain()", r)
|
||||
log.Warn("Recovered from panic:", r)
|
||||
me.baseGui.Close()
|
||||
|
||||
// allow gocui to close if possible, then print stack
|
||||
log.Sleep(1)
|
||||
os.Stdout = origStdout
|
||||
os.Stderr = origStderr
|
||||
me.myTree.SendToolkitPanic()
|
||||
log.Warn("Stack trace:")
|
||||
debug.PrintStack()
|
||||
// panic("BUMMER 2")
|
||||
|
||||
// attempt to switch to the nocui toolkit
|
||||
log.Sleep(1)
|
||||
me.myTree.SendToolkitLoad("nocui")
|
||||
log.Sleep(3)
|
||||
me.myTree.SendToolkitLoad("nocui")
|
||||
// panic("BUMMER")
|
||||
return
|
||||
}
|
||||
}()
|
||||
g, err := gocui.NewGui(gocui.OutputNormal, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer g.Close()
|
||||
|
||||
me.baseGui = g
|
||||
|
||||
g.Cursor = true
|
||||
g.Mouse = true
|
||||
|
||||
// this sets the function that is run on every event. For example:
|
||||
// When you click the mouse, move the mouse, or press a key on the keyboard
|
||||
// This is equivalent to xev or similar to cat /dev/input on linux
|
||||
g.SetManagerFunc(gocuiEvent)
|
||||
|
||||
if err := defaultKeybindings(g); err != nil {
|
||||
// normally panic here
|
||||
log.Log(NOW, "defaultKeybindings(g) panic err =", err)
|
||||
panic("gocuiTKdefaultkeybindings OOPS")
|
||||
}
|
||||
|
||||
if err := g.MainLoop(); err != nil && !errors.Is(err, gocui.ErrQuit) {
|
||||
log.Log(NOW, "g.MainLoop() panic err =", err)
|
||||
// normally panic here
|
||||
panic("gocuiTKmainloop OOPS")
|
||||
}
|
||||
}
|
84
mouse.go
84
mouse.go
|
@ -1,84 +0,0 @@
|
|||
// Copyright 2014 The gocui Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
// this function uses the mouse position to highlight & unhighlight things
|
||||
// this is run every time the user moves the mouse over the terminal window
|
||||
func mouseMove(g *gocui.Gui) {
|
||||
mx, my := g.MousePosition()
|
||||
for _, view := range g.Views() {
|
||||
view.Highlight = false
|
||||
}
|
||||
if v, err := g.ViewByPosition(mx, my); err == nil {
|
||||
v.Highlight = true
|
||||
}
|
||||
}
|
||||
|
||||
func msgDown(g *gocui.Gui, v *gocui.View) error {
|
||||
initialMouseX, initialMouseY = g.MousePosition()
|
||||
log.Log(GOCUI, "msgDown() X,Y", initialMouseX, initialMouseY)
|
||||
if vx, vy, _, _, err := g.ViewPosition("msg"); err == nil {
|
||||
xOffset = initialMouseX - vx
|
||||
yOffset = initialMouseY - vy
|
||||
msgMouseDown = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func mouseUp(g *gocui.Gui, v *gocui.View) error {
|
||||
w, h := g.MousePosition()
|
||||
|
||||
dropdownUnclicked(w, h)
|
||||
if msgMouseDown {
|
||||
msgMouseDown = false
|
||||
if movingMsg {
|
||||
movingMsg = false
|
||||
return nil
|
||||
} else {
|
||||
g.DeleteView("msg")
|
||||
}
|
||||
} else if globalMouseDown {
|
||||
globalMouseDown = false
|
||||
g.DeleteView("globalDown")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func mouseDown(g *gocui.Gui, v *gocui.View) error {
|
||||
mx, my := g.MousePosition()
|
||||
if vx0, vy0, vx1, vy1, err := g.ViewPosition("msg"); err == nil {
|
||||
if mx >= vx0 && mx <= vx1 && my >= vy0 && my <= vy1 {
|
||||
return msgDown(g, v)
|
||||
}
|
||||
}
|
||||
globalMouseDown = true
|
||||
maxX, _ := g.Size()
|
||||
findUnderMouse()
|
||||
msg := fmt.Sprintf("mouseDown() Mouse really down at: %d,%d", mx, my)
|
||||
// dropdownClicked(mx, my)
|
||||
x := mx - len(msg)/2
|
||||
if x < 0 {
|
||||
x = 0
|
||||
} else if x+len(msg)+1 > maxX-1 {
|
||||
x = maxX - 1 - len(msg) - 1
|
||||
}
|
||||
log.Log(GOCUI, "mouseDown() about to write out message to 'globalDown' view. msg =", msg)
|
||||
if v, err := g.SetView("globalDown", x, my-1, x+len(msg)+1, my+1, 0); err != nil {
|
||||
if !errors.Is(err, gocui.ErrUnknownView) {
|
||||
return err
|
||||
}
|
||||
v.WriteString(msg)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
// 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
|
||||
}
|
208
place.go
208
place.go
|
@ -1,19 +1,45 @@
|
|||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"go.wit.com/log"
|
||||
"go.wit.com/toolkits/tree"
|
||||
"go.wit.com/widget"
|
||||
)
|
||||
|
||||
/*
|
||||
gocui defines the offset like this:
|
||||
|
||||
width -> increases to the right
|
||||
---------------------------------- hieght
|
||||
| H = 1 | increases
|
||||
| | |
|
||||
| W = 1 W = 18 | |
|
||||
| | v
|
||||
| H = 5 | downwards
|
||||
-------------------------------------
|
||||
*/
|
||||
|
||||
// moves the gocui view to the W and H offset on the screen
|
||||
func (tk *guiWidget) MoveToOffset(W, H int) {
|
||||
tk.gocuiSetWH(W, H)
|
||||
}
|
||||
|
||||
// returns where the corner of widget starts (upper left)
|
||||
func (tk *guiWidget) Position() (int, int) {
|
||||
return tk.gocuiSize.w0, tk.gocuiSize.h0
|
||||
}
|
||||
|
||||
func (w *guiWidget) placeBox(startW int, startH int) {
|
||||
if w.WidgetType != widget.Box {
|
||||
if w.WidgetType() != widget.Box {
|
||||
return
|
||||
}
|
||||
// tk.dumpTree("beforebox")
|
||||
|
||||
w.full.w0 = startW
|
||||
w.full.h0 = startH
|
||||
newW := startW
|
||||
newH := startH
|
||||
|
||||
|
@ -24,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.node.State.Direction == widget.Vertical {
|
||||
if w.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
|
||||
|
@ -35,7 +61,6 @@ func (w *guiWidget) placeBox(startW int, startH int) {
|
|||
}
|
||||
log.Log(INFO, "BOX END size(W,H) =", sizeW, sizeH, "new(W,H) =", newW, newH)
|
||||
}
|
||||
// tk.dumpTree("afterbox")
|
||||
}
|
||||
|
||||
func (tk *guiWidget) placeWidgets(startW int, startH int) (int, int) {
|
||||
|
@ -45,37 +70,57 @@ func (tk *guiWidget) placeWidgets(startW int, startH int) (int, int) {
|
|||
if me.treeRoot == nil {
|
||||
return 0, 0
|
||||
}
|
||||
if tk.Hidden() {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
tk.startW = startW
|
||||
tk.startH = startH
|
||||
|
||||
switch tk.WidgetType {
|
||||
switch tk.WidgetType() {
|
||||
case widget.Window:
|
||||
newW := startW
|
||||
newH := startH
|
||||
var maxH int = 0
|
||||
tk.full.w0 = startW
|
||||
tk.full.h0 = startH
|
||||
startW += -2
|
||||
startH += 3
|
||||
for _, child := range tk.children {
|
||||
child.placeWidgets(newW, newH)
|
||||
sizeW, sizeH := child.Size()
|
||||
if sizeW < 20 {
|
||||
sizeW = 20
|
||||
}
|
||||
newW += sizeW
|
||||
if sizeH > maxH {
|
||||
maxH = sizeH
|
||||
}
|
||||
child.placeWidgets(startW, startH)
|
||||
sizeW, _ := child.Size()
|
||||
startW += sizeW + 4 // add the width to move the next widget over
|
||||
|
||||
}
|
||||
return newW - startW, maxH
|
||||
return startW, startH
|
||||
case widget.Tab:
|
||||
case widget.Grid:
|
||||
return tk.placeGrid(startW, startH)
|
||||
// tk.dumpWidget(fmt.Sprintf("PlaceGridS(%d,%d)", startW, startH))
|
||||
// if you reset the values here, grid horizontal stacking doesn't work anymore
|
||||
// tk.widths = make(map[int]int) // how tall each row in the grid is
|
||||
// tk.heights = make(map[int]int) // how wide each column in the grid is
|
||||
newW, newH := tk.placeGrid(startW, startH)
|
||||
tk.full.w0 = newW
|
||||
tk.full.h0 = newH
|
||||
tk.full.w1 = newW
|
||||
tk.full.h1 = newH
|
||||
// tk.dumpWidget(fmt.Sprintf("PlaceGridE(%d,%d)", newW, newH))
|
||||
return newW, newH
|
||||
case widget.Box:
|
||||
tk.placeBox(startW, startH)
|
||||
tk.full.w0 = startW
|
||||
tk.full.h0 = startH
|
||||
tk.full.w1 = startW
|
||||
tk.full.h1 = startH
|
||||
// tk.dumpWidget(fmt.Sprintf("PlaceBox(%d,%d)", startW, startH))
|
||||
return 0, 0
|
||||
case widget.Stdout:
|
||||
tk.setStdoutWH(startW, startH)
|
||||
return tk.gocuiSize.Width(), tk.gocuiSize.Height()
|
||||
case widget.Group:
|
||||
// move the group to the parent's next location
|
||||
tk.gocuiSetWH(startW, startH)
|
||||
tk.full.w0 = startW
|
||||
tk.full.h0 = startH
|
||||
tk.full.w1 = startW
|
||||
tk.full.h1 = startH
|
||||
|
||||
newW := startW + me.GroupPadW
|
||||
newH := startH + 1 // normal hight of the group label
|
||||
|
@ -94,7 +139,27 @@ func (tk *guiWidget) placeWidgets(startW int, startH int) (int, int) {
|
|||
}
|
||||
log.Log(INFO, "REAL HEIGHT sizeW:", sizeW, "sizeH:", sizeH)
|
||||
}
|
||||
return maxW, newH - startH
|
||||
newH = newH - startH
|
||||
// tk.dumpWidget(fmt.Sprintf("PlaceGroup(%d,%d)", maxW, newH))
|
||||
return maxW, newH
|
||||
case widget.Button:
|
||||
if tk.isWindowDense() && tk.isInGrid() {
|
||||
tk.frame = false
|
||||
// tk.color = nil
|
||||
// tk.defaultColor = nil
|
||||
/*
|
||||
if tk.IsEnabled() {
|
||||
tk.setColorButtonDense()
|
||||
} else {
|
||||
tk.setColorDisable()
|
||||
}
|
||||
*/
|
||||
// if tk.full.Height() > 0 {
|
||||
tk.full.h1 = tk.full.h0
|
||||
// }
|
||||
}
|
||||
tk.gocuiSetWH(startW, startH)
|
||||
return tk.gocuiSize.Width(), tk.gocuiSize.Height()
|
||||
default:
|
||||
tk.gocuiSetWH(startW, startH)
|
||||
return tk.gocuiSize.Width(), tk.gocuiSize.Height()
|
||||
|
@ -102,25 +167,58 @@ func (tk *guiWidget) placeWidgets(startW int, startH int) (int, int) {
|
|||
return 0, 0
|
||||
}
|
||||
|
||||
func (tk *guiWidget) isWindowDense() bool {
|
||||
if tk.WidgetType() == widget.Window {
|
||||
return tk.window.dense
|
||||
}
|
||||
if tk.parent == nil {
|
||||
return true
|
||||
}
|
||||
return tk.parent.isWindowDense()
|
||||
}
|
||||
|
||||
func (tk *guiWidget) isInGrid() bool {
|
||||
if tk.WidgetType() == widget.Grid {
|
||||
return true
|
||||
}
|
||||
if tk.parent == nil {
|
||||
return true
|
||||
}
|
||||
return tk.parent.isInGrid()
|
||||
}
|
||||
|
||||
func (w *guiWidget) placeGrid(startW int, startH int) (int, int) {
|
||||
// w.showWidgetPlacement("grid0:")
|
||||
if w.WidgetType != widget.Grid {
|
||||
if w.WidgetType() != widget.Grid {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
dense := w.isWindowDense()
|
||||
|
||||
w.full.w0 = startW
|
||||
w.full.h0 = startH
|
||||
|
||||
// first compute the max sizes of the rows and columns
|
||||
for _, child := range w.children {
|
||||
childW, childH := child.placeWidgets(child.startW, child.startH)
|
||||
|
||||
// set the child's realWidth, and grid offset
|
||||
if w.widths[child.node.State.AtW] < childW {
|
||||
w.widths[child.node.State.AtW] = childW
|
||||
if w.widths[child.GridW()] < childW {
|
||||
w.widths[child.GridW()] = childW
|
||||
}
|
||||
if w.heights[child.node.State.AtH] < childH {
|
||||
w.heights[child.node.State.AtH] = childH
|
||||
if w.heights[child.GridH()] < childH {
|
||||
w.heights[child.GridH()] = childH
|
||||
}
|
||||
if dense {
|
||||
if w.heights[child.GridH()] > 0 {
|
||||
w.heights[child.GridH()] = 1
|
||||
} else {
|
||||
w.heights[child.GridH()] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// child.showWidgetPlacement("grid: ")
|
||||
log.Log(INFO, "placeGrid:", child.String(), "child()", childW, childH, "At()", child.node.State.AtW, child.node.State.AtH)
|
||||
log.Log(INFO, "placeGrid:", child.String(), "child()", childW, childH, "At()", child.GridW(), child.GridH())
|
||||
}
|
||||
|
||||
var maxW int = 0
|
||||
|
@ -132,12 +230,12 @@ func (w *guiWidget) placeGrid(startW int, startH int) (int, int) {
|
|||
|
||||
var totalW, totalH int
|
||||
for i, w := range w.widths {
|
||||
if i < child.node.State.AtW {
|
||||
if i < child.GridW() {
|
||||
totalW += w
|
||||
}
|
||||
}
|
||||
for i, h := range w.heights {
|
||||
if i < child.node.State.AtH {
|
||||
if i < child.GridH() {
|
||||
totalH += h
|
||||
}
|
||||
}
|
||||
|
@ -153,11 +251,13 @@ func (w *guiWidget) placeGrid(startW int, startH int) (int, int) {
|
|||
maxH = totalH
|
||||
}
|
||||
|
||||
log.Log(INFO, "placeGrid:", child.String(), "new()", newW, newH, "At()", child.node.State.AtW, child.node.State.AtH)
|
||||
log.Log(INFO, "placeGrid:", child.String(), "new()", newW, newH, "At()", child.GridW(), child.GridH())
|
||||
child.placeWidgets(newW, newH)
|
||||
// child.showWidgetPlacement("grid2:")
|
||||
}
|
||||
// w.showWidgetPlacement("grid3:")
|
||||
w.full.w1 = startW + maxW
|
||||
w.full.h1 = startH + maxH
|
||||
return maxW, maxH
|
||||
}
|
||||
|
||||
|
@ -165,9 +265,11 @@ func (w *guiWidget) placeGrid(startW int, startH int) (int, int) {
|
|||
func (w *guiWidget) realGocuiSize() *rectType {
|
||||
var f func(tk *guiWidget, r *rectType)
|
||||
newR := new(rectType)
|
||||
|
||||
outputW, outputH := w.Size()
|
||||
// initialize the values to opposite
|
||||
newR.w0 = 80
|
||||
newR.h0 = 24
|
||||
newR.w0 = outputW
|
||||
newR.h0 = outputH
|
||||
if me.baseGui != nil {
|
||||
maxW, maxH := me.baseGui.Size()
|
||||
newR.w0 = maxW
|
||||
|
@ -201,6 +303,7 @@ func (w *guiWidget) realGocuiSize() *rectType {
|
|||
return newR
|
||||
}
|
||||
|
||||
/*
|
||||
func textSize(n *tree.Node) (int, int) {
|
||||
var tk *guiWidget
|
||||
tk = n.TK.(*guiWidget)
|
||||
|
@ -214,35 +317,21 @@ func textSize(n *tree.Node) (int, int) {
|
|||
}
|
||||
return width, height
|
||||
}
|
||||
|
||||
// moves the gocui view the W and H offset on the screen
|
||||
/*
|
||||
gocui defines the offset like this:
|
||||
|
||||
width -> increases to the right
|
||||
---------------------------------- hieght
|
||||
| H = 1 | increases
|
||||
| | |
|
||||
| W = 1 W = 18 | |
|
||||
| | v
|
||||
| H = 5 | downwards
|
||||
-------------------------------------
|
||||
*/
|
||||
// change over to this name
|
||||
func (tk *guiWidget) MoveToOffset(W, H int) {
|
||||
tk.gocuiSetWH(W, H)
|
||||
}
|
||||
|
||||
// returns where the corner of widget starts (upper left)
|
||||
func (tk *guiWidget) Position() (int, int) {
|
||||
return tk.gocuiSize.w0, tk.gocuiSize.h0
|
||||
}
|
||||
|
||||
func (tk *guiWidget) gocuiSetWH(sizeW, sizeH int) {
|
||||
w := len(widget.GetString(tk.value))
|
||||
lines := strings.Split(widget.GetString(tk.value), "\n")
|
||||
w := len(tk.GetLabel())
|
||||
lines := strings.Split(tk.GetLabel(), "\n")
|
||||
h := len(lines)
|
||||
|
||||
if tk.Hidden() {
|
||||
tk.gocuiSize.w0 = 0
|
||||
tk.gocuiSize.h0 = 0
|
||||
tk.gocuiSize.w1 = 0
|
||||
tk.gocuiSize.h1 = 0
|
||||
return
|
||||
}
|
||||
|
||||
// tk := n.tk
|
||||
if tk.isFake {
|
||||
tk.gocuiSize.w0 = sizeW
|
||||
|
@ -264,3 +353,10 @@ func (tk *guiWidget) gocuiSetWH(sizeW, sizeH int) {
|
|||
tk.gocuiSize.h1 = tk.gocuiSize.h0 + h + 1
|
||||
}
|
||||
}
|
||||
|
||||
func (tk *guiWidget) setStdoutWH(sizeW, sizeH int) {
|
||||
tk.gocuiSize.w0 = sizeW
|
||||
tk.gocuiSize.h0 = sizeH
|
||||
tk.gocuiSize.w1 = tk.gocuiSize.w0 + me.stdout.w
|
||||
tk.gocuiSize.h1 = tk.gocuiSize.h0 + me.stdout.h
|
||||
}
|
||||
|
|
199
plugin.go
199
plugin.go
|
@ -1,8 +1,10 @@
|
|||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
// if you include more than just this import
|
||||
// then your plugin might be doing something un-ideal (just a guess from 2023/02/27)
|
||||
"github.com/awesome-gocui/gocui"
|
||||
"go.wit.com/log"
|
||||
"go.wit.com/toolkits/tree"
|
||||
"go.wit.com/widget"
|
||||
|
@ -32,20 +34,26 @@ 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
|
||||
}
|
||||
|
||||
func newSetTitle(n *tree.Node, s string) {
|
||||
newSetText(n, s)
|
||||
// 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 newSetLabel(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 newSetText(n *tree.Node, s string) {
|
||||
// setText() and addText() 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) {
|
||||
if n == nil {
|
||||
log.Warn("Tree Error: Add() sent n == nil")
|
||||
return
|
||||
|
@ -56,9 +64,10 @@ func newSetText(n *tree.Node, s string) {
|
|||
}
|
||||
w := n.TK.(*guiWidget)
|
||||
w.SetText(s)
|
||||
me.refresh = true // testing code to see if refresh can work
|
||||
}
|
||||
|
||||
func newAddText(n *tree.Node, s string) {
|
||||
func addText(n *tree.Node, s string) {
|
||||
if n == nil {
|
||||
log.Warn("Tree Error: Add() sent n == nil")
|
||||
return
|
||||
|
@ -69,51 +78,7 @@ func newAddText(n *tree.Node, s string) {
|
|||
}
|
||||
w := n.TK.(*guiWidget)
|
||||
w.AddText(s)
|
||||
}
|
||||
|
||||
func newaction(n *tree.Node, atype widget.ActionType) {
|
||||
log.Log(INFO, "newaction() START", atype)
|
||||
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:
|
||||
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()
|
||||
wRoot := me.treeRoot.TK.(*guiWidget)
|
||||
wRoot.redoWindows(0, 0)
|
||||
default:
|
||||
log.Log(ERROR, "newaction() UNHANDLED Action Type =", atype, "WidgetType =", n.WidgetType, "Name =", n.ProgName())
|
||||
}
|
||||
log.Log(INFO, "newaction() END", atype, n.String())
|
||||
me.refresh = true // testing code to see if refresh can work
|
||||
}
|
||||
|
||||
func (w *guiWidget) deleteGocuiViews() {
|
||||
|
@ -151,45 +116,131 @@ func (w *guiWidget) AddText(text string) {
|
|||
}
|
||||
w.vals = append(w.vals, text)
|
||||
for i, s := range w.vals {
|
||||
log.Log(NOW, "AddText()", w.String(), i, s)
|
||||
log.Log(INFO, "AddText()", w.String(), i, s)
|
||||
}
|
||||
w.SetText(text)
|
||||
}
|
||||
|
||||
func (w *guiWidget) SetText(text string) {
|
||||
func (tk *guiWidget) SetText(text string) {
|
||||
var changed bool = false
|
||||
if w == nil {
|
||||
if tk == nil {
|
||||
log.Log(NOW, "widget is nil")
|
||||
return
|
||||
}
|
||||
if w.labelN != text {
|
||||
w.labelN = text
|
||||
if tk.labelN != text {
|
||||
tk.labelN = text
|
||||
changed = true
|
||||
}
|
||||
tk.node.State.Label = text
|
||||
if !changed {
|
||||
return
|
||||
}
|
||||
|
||||
if w.Visible() {
|
||||
w.textResize()
|
||||
w.Hide()
|
||||
w.Show()
|
||||
if tk.Visible() {
|
||||
tk.textResize()
|
||||
tk.Hide()
|
||||
tk.Show()
|
||||
}
|
||||
}
|
||||
|
||||
func (w *guiWidget) Set(val any) {
|
||||
if w == nil {
|
||||
log.Log(WARN, "Set() w == nil. val =", val)
|
||||
func (tk *guiWidget) GetText() string {
|
||||
if tk == nil {
|
||||
log.Log(NOW, "widget is nil")
|
||||
return ""
|
||||
}
|
||||
// deprecate this
|
||||
if tk.labelN != "" {
|
||||
return tk.labelN
|
||||
}
|
||||
if tk.node == nil {
|
||||
// return gocui.view name?
|
||||
return tk.cuiName
|
||||
}
|
||||
if tk.GetLabel() != "" {
|
||||
return tk.GetLabel()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func hideDisable() {
|
||||
if me.textbox.tk == nil {
|
||||
initTextbox()
|
||||
me.textbox.tk.prepTextbox()
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
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.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
|
||||
}
|
||||
|
||||
func (tk *guiWidget) Disable() {
|
||||
if tk == nil {
|
||||
log.Log(NOW, "widget is nil")
|
||||
return
|
||||
}
|
||||
log.Log(INFO, "Set() value =", val)
|
||||
|
||||
w.value = val.(string)
|
||||
if w.node.WidgetType == widget.Checkbox {
|
||||
w.node.State.Checked = widget.GetBool(val)
|
||||
w.setCheckbox()
|
||||
}
|
||||
if w.node.WidgetType == widget.Label {
|
||||
w.labelN = widget.GetString(val)
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
|
117
showStdout.go
117
showStdout.go
|
@ -1,117 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
|
||||
"go.wit.com/log"
|
||||
"go.wit.com/widget"
|
||||
)
|
||||
|
||||
var outputW int = 180
|
||||
var outputH int = 24
|
||||
|
||||
func moveMsg(g *gocui.Gui) {
|
||||
mx, my := g.MousePosition()
|
||||
if !movingMsg && (mx != initialMouseX || my != initialMouseY) {
|
||||
movingMsg = true
|
||||
}
|
||||
g.SetView("msg", mx-xOffset, my-yOffset, mx-xOffset+outputW, my-yOffset+outputH+me.FramePadH, 0)
|
||||
me.startOutputW = mx - xOffset
|
||||
me.startOutputH = my - yOffset
|
||||
g.SetViewOnBottom("msg")
|
||||
}
|
||||
|
||||
func showMsg(g *gocui.Gui, v *gocui.View) error {
|
||||
var l string
|
||||
var err error
|
||||
|
||||
log.Log(NOW, "showMsg() v.name =", v.Name())
|
||||
if _, err := g.SetCurrentView(v.Name()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, cy := v.Cursor()
|
||||
if l, err = v.Line(cy); err != nil {
|
||||
l = ""
|
||||
}
|
||||
|
||||
makeOutputWidget(g, l)
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeOutputWidget(g *gocui.Gui, stringFromMouseClick string) *gocui.View {
|
||||
maxX, maxY := g.Size()
|
||||
|
||||
if me.treeRoot == nil {
|
||||
// keep skipping this until the binary tree is initialized
|
||||
return nil
|
||||
}
|
||||
|
||||
if me.logStdout == nil {
|
||||
a := new(widget.Action)
|
||||
a.ProgName = "stdout"
|
||||
a.WidgetType = widget.Stdout
|
||||
a.WidgetId = -3
|
||||
a.ParentId = 0
|
||||
// n := addNode(a)
|
||||
n := me.myTree.AddNode(a)
|
||||
n.TK = initWidget(n)
|
||||
me.logStdout = n
|
||||
|
||||
var tk *guiWidget
|
||||
tk = me.logStdout.TK.(*guiWidget)
|
||||
// tk.gocuiSize.w0 = maxX - 32
|
||||
// tk.gocuiSize.h0 = maxY / 2
|
||||
tk.gocuiSize.w0 = me.startOutputW
|
||||
tk.gocuiSize.h0 = me.startOutputH
|
||||
tk.gocuiSize.w1 = tk.gocuiSize.w0 + outputW
|
||||
tk.gocuiSize.h1 = tk.gocuiSize.h0 + outputH
|
||||
}
|
||||
v, err := g.View("msg")
|
||||
if v == nil {
|
||||
log.Log(NOW, "makeoutputwindow() this is supposed to happen. v == nil", err)
|
||||
} else {
|
||||
log.Log(NOW, "makeoutputwindow() msg != nil. WTF now? err =", err)
|
||||
}
|
||||
|
||||
// help, err := g.SetView("help", maxX-32, 0, maxX-1, 13, 0)
|
||||
// v, err = g.SetView("msg", 3, 3, 30, 30, 0)
|
||||
|
||||
if me.startOutputW == 0 {
|
||||
me.startOutputW = maxX - 32
|
||||
}
|
||||
if me.startOutputW == 0 {
|
||||
me.startOutputH = maxY / 2
|
||||
}
|
||||
|
||||
// v, err = g.SetView("msg", maxX-32, maxY/2, maxX/2+outputW, maxY/2+outputH, 0)
|
||||
v, err = g.SetView("msg", me.startOutputW, me.startOutputH, maxX/2+outputW, maxY/2+outputH, 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 {
|
||||
var tk *guiWidget
|
||||
tk = me.logStdout.TK.(*guiWidget)
|
||||
tk.v = v
|
||||
}
|
||||
|
||||
v.Clear()
|
||||
v.SelBgColor = gocui.ColorCyan
|
||||
v.SelFgColor = gocui.ColorBlack
|
||||
fmt.Fprintln(v, "figure out how to capture STDOUT to here\n"+stringFromMouseClick)
|
||||
g.SetViewOnBottom("msg")
|
||||
// g.SetViewOnBottom(v.Name())
|
||||
return v
|
||||
}
|
310
size.go
310
size.go
|
@ -1,6 +1,11 @@
|
|||
// 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"
|
||||
|
||||
"go.wit.com/widget"
|
||||
)
|
||||
|
||||
|
@ -13,16 +18,16 @@ func (tk *guiWidget) Size() (int, int) {
|
|||
}
|
||||
|
||||
// don't count hidden widgets in size calculations
|
||||
if tk.node.Hidden() {
|
||||
if tk.Hidden() {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
switch tk.WidgetType {
|
||||
switch tk.WidgetType() {
|
||||
case widget.Window:
|
||||
var maxH int = 0
|
||||
var maxW int = 0
|
||||
for _, child := range tk.children {
|
||||
if tk.node.Hidden() {
|
||||
if tk.Hidden() {
|
||||
continue
|
||||
}
|
||||
sizeW, sizeH := child.Size()
|
||||
|
@ -43,7 +48,7 @@ func (tk *guiWidget) Size() (int, int) {
|
|||
maxH := tk.gocuiSize.Height()
|
||||
|
||||
for _, child := range tk.children {
|
||||
if tk.node.Hidden() {
|
||||
if tk.Hidden() {
|
||||
continue
|
||||
}
|
||||
sizeW, sizeH := child.Size()
|
||||
|
@ -57,8 +62,15 @@ func (tk *guiWidget) Size() (int, int) {
|
|||
return maxW + me.GroupPadW + 3, maxH
|
||||
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'
|
||||
case widget.Checkbox:
|
||||
return len(tk.String()) + 2, 3
|
||||
return len(tk.String()) + 2, 3 // TODO: compute this based on 'window dense'
|
||||
case widget.Button:
|
||||
if tk.isWindowDense() {
|
||||
return len(tk.String()) + 2, 0
|
||||
}
|
||||
return len(tk.String()) + 2, 3 // TODO: compute this based on 'window dense'
|
||||
}
|
||||
if tk.isFake {
|
||||
return 0, 0
|
||||
|
@ -67,25 +79,23 @@ func (tk *guiWidget) Size() (int, int) {
|
|||
}
|
||||
|
||||
func (w *guiWidget) sizeGrid() (int, int) {
|
||||
if w.node.Hidden() {
|
||||
if w.Hidden() {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
// first compute the max sizes of the rows and columns
|
||||
for _, child := range w.children {
|
||||
if w.node.Hidden() {
|
||||
if w.Hidden() {
|
||||
continue
|
||||
}
|
||||
sizeW, sizeH := child.Size()
|
||||
|
||||
sizeW += 2
|
||||
|
||||
// set the child's realWidth, and grid offset
|
||||
if w.widths[child.node.State.AtW] < sizeW {
|
||||
w.widths[child.node.State.AtW] = sizeW
|
||||
if w.widths[child.GridW()] < sizeW {
|
||||
w.widths[child.GridW()] = sizeW
|
||||
}
|
||||
if w.heights[child.node.State.AtH] < sizeH {
|
||||
w.heights[child.node.State.AtH] = sizeH
|
||||
if w.heights[child.GridH()] < sizeH {
|
||||
w.heights[child.GridH()] = sizeH
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,21 +112,21 @@ func (w *guiWidget) sizeGrid() (int, int) {
|
|||
}
|
||||
|
||||
func (w *guiWidget) sizeBox() (int, int) {
|
||||
if w.WidgetType != widget.Box {
|
||||
if w.WidgetType() != widget.Box {
|
||||
return 0, 0
|
||||
}
|
||||
if w.node.Hidden() {
|
||||
if w.Hidden() {
|
||||
return 0, 0
|
||||
}
|
||||
var maxW int = 0
|
||||
var maxH int = 0
|
||||
|
||||
for _, child := range w.children {
|
||||
if w.node.Hidden() {
|
||||
if w.Hidden() {
|
||||
continue
|
||||
}
|
||||
sizeW, sizeH := child.Size()
|
||||
if child.node.State.Direction == widget.Vertical {
|
||||
if child.Direction() == widget.Vertical {
|
||||
maxW += sizeW
|
||||
if sizeH > maxH {
|
||||
maxH = sizeH
|
||||
|
@ -130,3 +140,269 @@ func (w *guiWidget) sizeBox() (int, int) {
|
|||
}
|
||||
return maxW + me.BoxPadW, maxH
|
||||
}
|
||||
|
||||
/*
|
||||
var wtf bool
|
||||
|
||||
func (tk *guiWidget) verifyRect() bool {
|
||||
if !tk.Visible() {
|
||||
// log.Info("verifyRect() tk is not visible", tk.cuiName)
|
||||
return false
|
||||
}
|
||||
vw0, vh0, vw1, vh1, err := me.baseGui.ViewPosition(tk.cuiName)
|
||||
if err != nil {
|
||||
// log.Printf("verifyRect() gocui err=%v cuiName=%s v.Name=%s", err, tk.cuiName, tk.v.Name())
|
||||
vw0, vh0, vw1, vh1, err = me.baseGui.ViewPosition(tk.v.Name())
|
||||
if err != nil {
|
||||
log.Printf("verifyRect() ACTUAL FAIL gocui err=%v cuiName=%s v.Name=%s", err, tk.cuiName, tk.v.Name())
|
||||
return false
|
||||
}
|
||||
// return false
|
||||
}
|
||||
var ok bool = true
|
||||
if vw0 != tk.full.w0 {
|
||||
// log.Info("verifyRect() FIXING w0", tk.cuiName, vw0, vw1, vh0, vh1, tk.gocuiSize.w0, "w0 =", vw0)
|
||||
tk.full.w0 = vw0
|
||||
ok = false
|
||||
}
|
||||
if vw1 != tk.full.w1 {
|
||||
// log.Info("verifyRect() FIXING w1", tk.cuiName, vw0, vw1, vh0, vh1, tk.gocuiSize.w1, "w1 =", vw1)
|
||||
tk.full.w1 = vw1
|
||||
ok = false
|
||||
}
|
||||
if vh0 != tk.full.h0 {
|
||||
// log.Info("verifyRect() FIXING h0", tk.cuiName, vw0, vw1, vh0, vh1, tk.gocuiSize.h0)
|
||||
tk.full.h0 = vh0
|
||||
ok = false
|
||||
}
|
||||
if vh1 != tk.full.h1 {
|
||||
// log.Info("verifyRect() FIXING h1", tk.cuiName, vw0, vw1, vh0, vh1, tk.gocuiSize.h1)
|
||||
tk.full.h1 = vh1
|
||||
ok = false
|
||||
}
|
||||
if !ok {
|
||||
// log.Info("verifyRect() NEED TO FIX RECT HERE", tk.cuiName)
|
||||
// tk.dumpWidget("verifyRect() FIXME")
|
||||
}
|
||||
// log.Printf("verifyRect() OK cuiName=%s v.Name=%s", tk.cuiName, tk.v.Name())
|
||||
return true
|
||||
}
|
||||
*/
|
||||
|
||||
func (tk *guiWidget) setFullSize() bool {
|
||||
r := tk.getFullSize()
|
||||
|
||||
if tk.Hidden() {
|
||||
p := tk.parent
|
||||
if p != nil {
|
||||
// tk.full.w0 = p.full.w0
|
||||
// tk.full.w1 = p.full.w1
|
||||
// tk.full.h0 = p.full.h0
|
||||
// tk.full.h1 = p.full.h1
|
||||
tk.full.w0 = 0
|
||||
tk.full.w1 = 0
|
||||
tk.full.h0 = 0
|
||||
tk.full.h1 = 0
|
||||
} else {
|
||||
tk.full.w0 = 0
|
||||
tk.full.w1 = 0
|
||||
tk.full.h0 = 0
|
||||
tk.full.h1 = 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var changed bool
|
||||
if tk.full.w0 != r.w0 {
|
||||
tk.full.w0 = r.w0
|
||||
changed = true
|
||||
}
|
||||
// widget might be forced to a certain location
|
||||
if tk.full.w0 < tk.force.w0 {
|
||||
tk.gocuiSize.w0 = tk.force.w0
|
||||
tk.full.w0 = tk.force.w0
|
||||
changed = false
|
||||
}
|
||||
if tk.full.w1 != r.w1 {
|
||||
tk.full.w1 = r.w1
|
||||
changed = true
|
||||
}
|
||||
if tk.full.h0 != r.h0 {
|
||||
tk.full.h0 = r.h0
|
||||
changed = true
|
||||
}
|
||||
// widget might be forced to a certain location
|
||||
if tk.full.h0 < tk.force.h0 {
|
||||
tk.gocuiSize.h0 = tk.force.h0
|
||||
tk.full.h0 = tk.force.h0
|
||||
changed = false
|
||||
}
|
||||
if tk.full.h1 != r.h1 {
|
||||
tk.full.h1 = r.h1
|
||||
changed = true
|
||||
}
|
||||
if tk.WidgetType() == widget.Button {
|
||||
tk.full.h1 = tk.full.h0 + 1
|
||||
}
|
||||
if tk.isWindowDense() && tk.isInGrid() {
|
||||
tk.full.h1 = tk.full.h0
|
||||
}
|
||||
if changed {
|
||||
tk.dumpWidget(fmt.Sprintf("setFullSize(changed)"))
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
func (tk *guiWidget) gridFullSize() rectType {
|
||||
var r rectType
|
||||
var first bool = true
|
||||
for _, child := range tk.children {
|
||||
cr := child.getFullSize()
|
||||
if cr.Width() == 0 && cr.Height() == 0 {
|
||||
// ignore widgets of zero size?
|
||||
continue
|
||||
}
|
||||
if first {
|
||||
// use the lowest width and hight from children widgets
|
||||
r.w0 = cr.w0
|
||||
r.h0 = cr.h0
|
||||
r.w1 = cr.w1
|
||||
r.h1 = cr.h1
|
||||
first = false
|
||||
// child.dumpWidget(fmt.Sprintf("grid(f)"))
|
||||
continue
|
||||
}
|
||||
// child.dumpWidget(fmt.Sprintf("grid()"))
|
||||
// use the lowest width and hight from children widgets
|
||||
if r.w0 > cr.w0 {
|
||||
r.w0 = cr.w0
|
||||
}
|
||||
if r.h0 > cr.h0 {
|
||||
r.h0 = cr.h0
|
||||
}
|
||||
// use the highest width and hight from children widgets
|
||||
if r.w1 < cr.w1 {
|
||||
r.w1 = cr.w1
|
||||
}
|
||||
if r.h1 < cr.h1 {
|
||||
r.h1 = cr.h1
|
||||
}
|
||||
}
|
||||
tk.full.w0 = r.w0
|
||||
tk.full.w1 = r.w1
|
||||
tk.full.h0 = r.h0
|
||||
tk.full.h1 = r.h1
|
||||
return r
|
||||
}
|
||||
|
||||
func (tk *guiWidget) buttonFullSize() rectType {
|
||||
var r rectType
|
||||
r.w0 = tk.gocuiSize.w0
|
||||
r.w1 = tk.gocuiSize.w1
|
||||
r.h0 = tk.gocuiSize.h0
|
||||
r.h1 = tk.gocuiSize.h1
|
||||
|
||||
// try setting the full values here ? is this right?
|
||||
tk.full.w0 = r.w0
|
||||
tk.full.w1 = r.w1
|
||||
tk.full.h0 = r.h0
|
||||
tk.full.h1 = r.h1
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// this checks a widget to see if it is under (W,H), then checks the widget's children
|
||||
// anything that matches is passed back as an array of widgets
|
||||
func (tk *guiWidget) getFullSize() rectType {
|
||||
var r rectType
|
||||
|
||||
if tk.Hidden() {
|
||||
/*
|
||||
p := tk.parent
|
||||
if p != nil {
|
||||
return p.full
|
||||
}
|
||||
*/
|
||||
var r rectType
|
||||
r.w0 = 0
|
||||
r.w1 = 0
|
||||
r.h0 = 0
|
||||
r.h1 = 0
|
||||
return r
|
||||
}
|
||||
|
||||
if tk.WidgetType() == widget.Grid {
|
||||
return tk.gridFullSize()
|
||||
}
|
||||
|
||||
// these are 'simple' widgets
|
||||
// the full size is exactly what gocui uses
|
||||
switch tk.WidgetType() {
|
||||
case widget.Label:
|
||||
r := tk.buttonFullSize()
|
||||
r.w1 += 5
|
||||
return r
|
||||
case widget.Button:
|
||||
r := tk.buttonFullSize()
|
||||
r.w1 += 5
|
||||
return r
|
||||
case widget.Checkbox:
|
||||
return tk.buttonFullSize()
|
||||
case widget.Dropdown:
|
||||
r := tk.buttonFullSize()
|
||||
r.w1 += 7 // TODO: fix this to be real
|
||||
return r
|
||||
default:
|
||||
}
|
||||
|
||||
if tk.v == nil {
|
||||
r.w0 = tk.full.w0
|
||||
r.w1 = tk.full.w1
|
||||
r.h0 = tk.full.h0
|
||||
r.h1 = tk.full.h1
|
||||
} else {
|
||||
r.w0 = tk.gocuiSize.w0
|
||||
r.w1 = tk.gocuiSize.w1
|
||||
r.h0 = tk.gocuiSize.h0
|
||||
r.h1 = tk.gocuiSize.h1
|
||||
}
|
||||
|
||||
// search through the children widgets in the binary tree
|
||||
for _, child := range tk.children {
|
||||
cr := child.getFullSize()
|
||||
/* this didn't make things work either
|
||||
if child.v == nil {
|
||||
continue
|
||||
}
|
||||
*/
|
||||
// use the lowest width and hight from children widgets
|
||||
if r.w0 > cr.w0 {
|
||||
r.w0 = cr.w0
|
||||
}
|
||||
if r.h0 > cr.h0 {
|
||||
r.h0 = cr.h0
|
||||
}
|
||||
// use the highest width and hight from children widgets
|
||||
if r.w1 < cr.w1 {
|
||||
r.w1 = cr.w1
|
||||
}
|
||||
if r.h1 < cr.h1 {
|
||||
r.h1 = cr.h1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// try setting the full values here ? is this right?
|
||||
tk.full.w0 = r.w0
|
||||
tk.full.w1 = r.w1
|
||||
tk.full.h0 = r.h0
|
||||
tk.full.h1 = r.h1
|
||||
|
||||
return r
|
||||
}
|
||||
|
|
|
@ -0,0 +1,227 @@
|
|||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
|
||||
"go.wit.com/log"
|
||||
"go.wit.com/widget"
|
||||
)
|
||||
|
||||
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.stdout.tk.Write([]byte(msg))
|
||||
|
||||
log.Log(NOW, "logStdout test out")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func coreStdout() {
|
||||
if me.stdout.tk != nil {
|
||||
return
|
||||
}
|
||||
a := new(widget.Action)
|
||||
a.ProgName = "2stdout2"
|
||||
a.WidgetType = widget.Stdout
|
||||
a.WidgetId = me.stdout.wId
|
||||
a.ParentId = 0
|
||||
// n := addNode(a)
|
||||
n := me.myTree.AddNode(a)
|
||||
me.stdout.tk = initWidget(n)
|
||||
|
||||
tk := me.stdout.tk
|
||||
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
|
||||
}
|
||||
|
||||
v, err := g.View("msg")
|
||||
if v == nil {
|
||||
// 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
|
||||
}
|
||||
|
||||
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 {
|
||||
if v == nil {
|
||||
log.Log(NOW, "makeoutputwindow() BAD: v == nil && err =", err)
|
||||
}
|
||||
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
|
||||
v.SelFgColor = gocui.ColorBlack
|
||||
fmt.Fprintln(v, "figure out how to capture STDOUT to here\n"+stringFromMouseClick)
|
||||
// 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
|
||||
}
|
||||
|
||||
func relocateStdoutOffscreen() {
|
||||
if me.stdout.tk == nil {
|
||||
return
|
||||
}
|
||||
if !me.stdout.disable {
|
||||
log.Info("Using gocui STDOUT")
|
||||
log.CaptureMode(me.stdout.tk)
|
||||
}
|
||||
newW := 10
|
||||
newH := 0 - me.stdout.h - 4
|
||||
me.stdout.tk.relocateStdout(newW, newH)
|
||||
}
|
||||
|
||||
func (tk *guiWidget) relocateStdout(w int, h int) {
|
||||
w0 := w
|
||||
h0 := h
|
||||
w1 := w + me.stdout.w
|
||||
h1 := h + me.stdout.h
|
||||
|
||||
tk.gocuiSize.w0 = w0
|
||||
tk.gocuiSize.w1 = w1
|
||||
tk.gocuiSize.h0 = h0
|
||||
tk.gocuiSize.h1 = h1
|
||||
|
||||
tk.full.w0 = w0
|
||||
tk.full.w1 = w1
|
||||
tk.full.h0 = h0
|
||||
tk.full.h1 = h1
|
||||
|
||||
me.baseGui.SetView("msg", w0, h0, w1, h1, 0)
|
||||
// me.baseGui.SetViewOnBottom("msg")
|
||||
}
|
||||
|
||||
// from the gocui devs:
|
||||
// Write appends a byte slice into the view's internal buffer. Because
|
||||
// View implements the io.Writer interface, it can be passed as parameter
|
||||
// of functions like fmt.Fprintf, fmt.Fprintln, io.Copy, etc. Clear must
|
||||
// be called to clear the view's buffer.
|
||||
|
||||
func (w 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()
|
||||
|
||||
me.stdout.outputS = append(me.stdout.outputS, lines...)
|
||||
|
||||
tk := me.stdout.tk
|
||||
if tk == nil {
|
||||
return len(p), nil
|
||||
}
|
||||
if tk.v == nil {
|
||||
// redo this old code
|
||||
v, _ := me.baseGui.View("msg")
|
||||
if v != nil {
|
||||
tk.v = v
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
tk.refreshStdout()
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// lets the user page up and down through the stdout buffer
|
||||
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
|
||||
}
|
||||
|
||||
var cur []string
|
||||
// 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]...)
|
||||
slices.Reverse(cur)
|
||||
tk.v.Clear()
|
||||
fmt.Fprintln(tk.v, strings.Join(cur, "\n"))
|
||||
}
|
392
structs.go
392
structs.go
|
@ -1,5 +1,5 @@
|
|||
// LICENSE: same as the go language itself
|
||||
// Copyright 2023 WIT.COM
|
||||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
// all structures and variables are local (aka lowercase)
|
||||
// since the plugin should be isolated to access only
|
||||
|
@ -10,102 +10,150 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
|
||||
"go.wit.com/log"
|
||||
"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
|
||||
|
||||
var showDebug bool = true
|
||||
var showHelp bool = true
|
||||
var redoWidgets bool = true
|
||||
|
||||
// This is the window that is currently active
|
||||
// var currentWindow *tree.Node
|
||||
|
||||
// todo: move all this to a protobuf. then, redo all this mess.
|
||||
// it got me here, but now it's time to clean it up for good
|
||||
// I can't get a GO plugins that use protobuf to load yet (versioning mismatch)
|
||||
type config struct {
|
||||
baseGui *gocui.Gui // the main gocui handle
|
||||
// rootNode *node // the base of the binary tree. it should have id == 0
|
||||
|
||||
treeRoot *tree.Node // the base of the binary tree. it should have id == 0
|
||||
myTree *tree.TreeInfo
|
||||
|
||||
ctrlDown *tree.Node // shown if you click the mouse when the ctrl key is pressed
|
||||
currentWindow *guiWidget // this is the current tab or window to show
|
||||
logStdout *tree.Node // where to show STDOUT
|
||||
startOutputW int
|
||||
startOutputH int
|
||||
helpLabel *gocui.View
|
||||
|
||||
// this is a floating widget that we show whenever the user clicks on a
|
||||
// dropdown menu or combobox
|
||||
// the dropdown widget to select dropdrown lists
|
||||
dropdownV *guiWidget
|
||||
dropdownW *guiWidget // grab the dropdown choices from this widget
|
||||
|
||||
// When the widget has a frame, like a button, it adds 2 lines runes on each side
|
||||
// so you need 3 char spacing in each direction to not have them overlap
|
||||
// the amount of padding when there is a frame
|
||||
FramePadW int `default:"1" dense:"0"`
|
||||
FramePadH int `default:"1" dense:"0"`
|
||||
|
||||
PadW int `default:"1" dense:"0"`
|
||||
PadH int `default:"1" dense:"0"`
|
||||
|
||||
// how far down to start Window or Tab headings
|
||||
WindowW int `default:"8" dense:"0"`
|
||||
WindowH int `default:"-1"`
|
||||
TabW int `default:"5" dense:"0"`
|
||||
TabH int `default:"1" dense:"0"`
|
||||
|
||||
// additional amount of space to put between window & tab widgets
|
||||
WindowPadW int `default:"8" dense:"0"`
|
||||
TabPadW int `default:"4" dense:"0"`
|
||||
|
||||
// additional amount of space to indent on a group
|
||||
GroupPadW int `default:"2" dense:"1"`
|
||||
|
||||
// additional amount of space to indent on a group
|
||||
BoxPadW int `default:"2" dense:"1"`
|
||||
|
||||
// additional amount of space to indent on a group
|
||||
GridPadW int `default:"2" dense:"1"`
|
||||
|
||||
// the raw beginning of each window (or tab)
|
||||
RawW int `default:"1"`
|
||||
RawH int `default:"5"`
|
||||
|
||||
// offset for the hidden widgets
|
||||
FakeW int `default:"20"`
|
||||
|
||||
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
|
||||
menubar bool // for windows
|
||||
stretchy bool // expand things like buttons to the maximum size
|
||||
margin bool // add space around the frames of windows
|
||||
|
||||
// writeMutex protects locks the write process
|
||||
writeMutex sync.Mutex
|
||||
|
||||
// used for listWidgets() debugging
|
||||
depth int
|
||||
baseGui *gocui.Gui // the main gocui handle
|
||||
treeRoot *tree.Node // the base of the binary tree. it should have id == 0
|
||||
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
|
||||
PadH int `default:"1" dense:"0"` // pad spacing
|
||||
WindowW int `default:"8" dense:"0"` // how far down to start Window or Tab headings
|
||||
WindowH int `default:"-1"` // how far down to start Window or Tab headings
|
||||
TabW int `default:"5" dense:"0"` // how far down to start Window or Tab headings
|
||||
TabH int `default:"1" dense:"0"` // how far down to start Window or Tab headings
|
||||
WindowPadW int `default:"8" dense:"0"` // additional amount of space to put between window & tab widgets
|
||||
TabPadW int `default:"4" dense:"0"` // additional amount of space to put between window & tab widgets
|
||||
GroupPadW int `default:"2" dense:"1"` // additional amount of space to indent on a group
|
||||
BoxPadW int `default:"2" dense:"1"` // additional amount of space to indent on a box
|
||||
GridPadW int `default:"2" dense:"1"` // additional amount of space to indent on a grid
|
||||
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
|
||||
menubar bool // for windows
|
||||
stretchy bool // expand things like buttons to the maximum size
|
||||
margin bool // add space around the frames of windows
|
||||
writeMutex sync.Mutex // writeMutex protects writes to *guiWidget (it's global right now maybe)
|
||||
ecount int // counts how many mouse and keyboard events have occurred
|
||||
supermouse bool // prints out every widget found while you move the mouse around
|
||||
depth int // used for listWidgets() debugging
|
||||
newWindowTrigger chan *guiWidget // work around hack to redraw windows a bit after NewWindow()
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
// deprecate these
|
||||
var (
|
||||
initialMouseX, initialMouseY, xOffset, yOffset int
|
||||
globalMouseDown, msgMouseDown, movingMsg bool
|
||||
)
|
||||
// stuff controlling how the mouse works
|
||||
type mouse struct {
|
||||
down time.Time // when the mouse was pressed down
|
||||
up time.Time // when the mouse was released. used to detect click vs drag
|
||||
clicktime time.Duration // how long is too long for a mouse click vs drag
|
||||
mouseUp bool // is the mouse up?
|
||||
double bool // user is double clicking
|
||||
doubletime time.Duration // how long is too long for double click
|
||||
resize bool // mouse is resizing something
|
||||
downW int // where the mouse was pressed down
|
||||
downH int // where the mouse was pressed down
|
||||
currentDrag *guiWidget // what widget is currently being moved around
|
||||
}
|
||||
|
||||
// settings for the stdout window
|
||||
type stdout struct {
|
||||
tk *guiWidget // where to show STDOUT
|
||||
wId int // the widget id
|
||||
w int // the width
|
||||
h int // the height
|
||||
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
|
||||
}
|
||||
|
||||
// settings for the dropdown window
|
||||
type dropdown struct {
|
||||
tk *guiWidget // where to show STDOUT
|
||||
callerTK *guiWidget // which widget called the dropdown menu
|
||||
items []string // what is currently in the menu
|
||||
w int // the width
|
||||
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
|
||||
}
|
||||
|
||||
// this is the gocui way
|
||||
// corner starts at in the upper left corner
|
||||
|
@ -118,115 +166,86 @@ func (r *rectType) Width() int {
|
|||
}
|
||||
|
||||
func (r *rectType) Height() int {
|
||||
if r.h0 == 0 && r.h1 == 0 {
|
||||
// edge case. only return 0 for these
|
||||
return 0
|
||||
}
|
||||
if r.h1 == r.h0 {
|
||||
// if they are equal, it's actually height = 1
|
||||
return 1
|
||||
}
|
||||
if r.h1-r.h0 < 1 {
|
||||
// can't have negatives. something is wrong. return 1 for now
|
||||
return 1
|
||||
}
|
||||
|
||||
return r.h1 - r.h0
|
||||
}
|
||||
|
||||
// settings that are window specific
|
||||
type window struct {
|
||||
windowFrame *guiWidget // this is the frame for a window widget
|
||||
wasDragged bool // indicates the window was dragged. This keeps it from being rearranged
|
||||
hasTabs bool // does the window have tabs?
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
type colorT struct {
|
||||
frame gocui.Attribute
|
||||
fg gocui.Attribute
|
||||
bg gocui.Attribute
|
||||
selFg gocui.Attribute
|
||||
selBg gocui.Attribute
|
||||
name string
|
||||
}
|
||||
|
||||
type guiWidget struct {
|
||||
// the gocui package variables
|
||||
v *gocui.View // this is nil if the widget is not displayed
|
||||
cuiName string // what gocui uses to reference the widget
|
||||
|
||||
WidgetType widget.WidgetType
|
||||
|
||||
// tw *toolkit.Widget
|
||||
parent *guiWidget
|
||||
children []*guiWidget
|
||||
|
||||
node *tree.Node
|
||||
|
||||
hasTabs bool // does the window have tabs?
|
||||
currentTab bool // the visible tab
|
||||
|
||||
value string
|
||||
checked bool
|
||||
|
||||
// the actual text to display in the console
|
||||
labelN string
|
||||
|
||||
vals []string // dropdown menu items
|
||||
|
||||
active bool
|
||||
|
||||
enable bool
|
||||
defaultColor *colorT // store the color to go back to
|
||||
|
||||
// hidden bool
|
||||
|
||||
// AtW int
|
||||
// AtH int
|
||||
|
||||
// direction widget.Orientation
|
||||
|
||||
// progname string
|
||||
|
||||
// the logical size of the widget
|
||||
// For example, 40x12 would be the center of a normal terminal
|
||||
// size rectType
|
||||
|
||||
// the actual gocui display view of this widget
|
||||
// sometimes this isn't visible like with a Box or Grid
|
||||
gocuiSize rectType
|
||||
|
||||
startW int
|
||||
startH int
|
||||
|
||||
isCurrent bool // is this the currently displayed Window or Tab?
|
||||
isFake bool // widget types like 'box' are 'false'
|
||||
|
||||
// used to track the size of grids
|
||||
widths map[int]int // how tall each row in the grid is
|
||||
heights map[int]int // how wide each column in the grid is
|
||||
|
||||
tainted bool
|
||||
frame bool
|
||||
|
||||
// for a window, this is currently selected tab
|
||||
selectedTab *tree.Node
|
||||
|
||||
// what color to use
|
||||
color *colorT
|
||||
}
|
||||
|
||||
// from the gocui devs:
|
||||
// Write appends a byte slice into the view's internal buffer. Because
|
||||
// View implements the io.Writer interface, it can be passed as parameter
|
||||
// of functions like fmt.Fprintf, fmt.Fprintln, io.Copy, etc. Clear must
|
||||
// be called to clear the view's buffer.
|
||||
|
||||
func (w *guiWidget) Write(p []byte) (n int, err error) {
|
||||
w.tainted = true
|
||||
me.writeMutex.Lock()
|
||||
defer me.writeMutex.Unlock()
|
||||
var tk *guiWidget
|
||||
tk = me.logStdout.TK.(*guiWidget)
|
||||
if tk.v == nil {
|
||||
// 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
|
||||
tk.v.Clear()
|
||||
|
||||
s := fmt.Sprint(string(p))
|
||||
s = strings.TrimSuffix(s, "\n")
|
||||
tmp := strings.Split(s, "\n")
|
||||
outputS = append(outputS, tmp...)
|
||||
if len(outputS) > outputH {
|
||||
l := len(outputS) - outputH
|
||||
outputS = outputS[l:]
|
||||
}
|
||||
fmt.Fprintln(tk.v, strings.Join(outputS, "\n"))
|
||||
}
|
||||
|
||||
return len(p), nil
|
||||
v *gocui.View // this is nil if the widget is not displayed
|
||||
cuiName string // what gocui uses to reference the widget (usually "TK <widgetId>"
|
||||
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?
|
||||
currentTab bool // the visible tab
|
||||
window window // holds information specific only to Window widgets
|
||||
value string // ?
|
||||
checked bool // ?
|
||||
labelN string // the actual text to display in the console
|
||||
vals []string // dropdown menu items
|
||||
enable bool // ?
|
||||
gocuiSize rectType // should mirror the real display size. todo: verify these are accurate. they are not yet
|
||||
full rectType // full size of children (used by widget.Window, etc)
|
||||
force rectType // force widget within these boundries (using this to debug window dragging)
|
||||
startW int // ?
|
||||
startH int // ?
|
||||
lastW int // used during mouse dragging
|
||||
lastH int // used during mouse dragging
|
||||
isFake bool // widget types like 'box' are 'false'
|
||||
widths map[int]int // how tall each row in the grid is
|
||||
heights map[int]int // how wide each column in the grid is
|
||||
tainted bool // ?
|
||||
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
|
||||
}
|
||||
|
||||
// THIS IS GO COMPILER MAGIC
|
||||
// this sets the `default` in the structs above on init()
|
||||
// this is cool code. thank the GO devs for this code and Alex Flint for explaining it to me
|
||||
func Set(ptr interface{}, tag string) error {
|
||||
if reflect.TypeOf(ptr).Kind() != reflect.Ptr {
|
||||
log.Log(ERROR, "Set() Not a pointer", ptr, "with tag =", tag)
|
||||
|
@ -246,12 +265,11 @@ 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() {
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
// 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.parent = me.treeRoot.TK.(*guiWidget)
|
||||
w.wtype = widget.Window
|
||||
w.cuiName = fmt.Sprintf("%d %s", pb.Id, "TK")
|
||||
w.labelN = pb.Name
|
||||
return w
|
||||
}
|
||||
*/
|
||||
|
||||
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
|
||||
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()
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
package main
|
||||
|
||||
// simulates a dropdown menu in gocui
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
log "go.wit.com/log"
|
||||
)
|
||||
|
||||
func (tk *guiWidget) forceSizes(r *rectType) {
|
||||
tk.gocuiSize.w0 = r.w0
|
||||
tk.gocuiSize.w1 = r.w1
|
||||
tk.gocuiSize.h0 = r.h0
|
||||
tk.gocuiSize.h1 = r.h1
|
||||
|
||||
tk.full.w0 = r.w0
|
||||
tk.full.w1 = r.w1
|
||||
tk.full.h0 = r.h0
|
||||
tk.full.h1 = r.h1
|
||||
|
||||
tk.force.w0 = r.w0
|
||||
tk.force.w1 = r.w1
|
||||
tk.force.h0 = r.h0
|
||||
tk.force.h1 = r.h1
|
||||
}
|
||||
|
||||
func initTextbox() {
|
||||
if me.textbox.tk == nil {
|
||||
// should only happen once
|
||||
me.textbox.tk = makeNewFlagWidget(me.textbox.wId)
|
||||
// me.textbox.tk.dumpWidget("init() textbox")
|
||||
}
|
||||
}
|
||||
|
||||
func (callertk *guiWidget) prepTextbox() {
|
||||
initTextbox()
|
||||
if me.textbox.tk == nil {
|
||||
log.Log(GOCUI, "prepTextbox() Is Broken")
|
||||
return
|
||||
}
|
||||
|
||||
r := new(rectType)
|
||||
// startW, startH := tk.Position()
|
||||
r.w0 = callertk.gocuiSize.w0 + 4
|
||||
r.h0 = callertk.gocuiSize.h0 + 3
|
||||
r.w1 = r.w0 + 24
|
||||
r.h1 = r.h0 + 2
|
||||
me.textbox.tk.forceSizes(r)
|
||||
// me.textbox.tk.dumpWidget("after sizes")
|
||||
|
||||
me.textbox.callerTK = callertk
|
||||
|
||||
// showTextbox(callertk.String())
|
||||
}
|
||||
|
||||
func showTextbox(callers string) {
|
||||
// tk := me.textbox.tk
|
||||
// me.textbox.tk.dumpWidget("after sizes")
|
||||
|
||||
// me.textbox.tk.Show() // actually makes the gocui view. TODO: redo this
|
||||
|
||||
if me.textbox.tk.v == nil {
|
||||
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
|
||||
|
||||
r := me.textbox.tk.gocuiSize
|
||||
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.dumpWidget("showTextbox()")
|
||||
}
|
||||
|
||||
func theCloseTheTextbox(g *gocui.Gui, v *gocui.View) error {
|
||||
textboxClosed()
|
||||
return nil
|
||||
}
|
||||
|
||||
// updates the text and sends an event back to the application
|
||||
func textboxClosed() {
|
||||
// get the text the user entered
|
||||
var newtext string
|
||||
if me.textbox.tk.v == nil {
|
||||
newtext = ""
|
||||
} else {
|
||||
newtext = me.textbox.tk.v.ViewBuffer()
|
||||
}
|
||||
newtext = strings.TrimSpace(newtext)
|
||||
me.textbox.active = false
|
||||
me.textbox.tk.Hide()
|
||||
// log.Info("textbox closed with text:", newtext, me.textbox.callerTK.cuiName)
|
||||
|
||||
if me.notify.clock.tk.v != nil {
|
||||
me.baseGui.SetCurrentView("help")
|
||||
} else {
|
||||
me.baseGui.SetCurrentView("msg")
|
||||
}
|
||||
|
||||
// change the text of the caller widget
|
||||
me.textbox.callerTK.SetText(newtext)
|
||||
me.textbox.callerTK.node.SetCurrentS(newtext)
|
||||
|
||||
// send an event from the plugin with the new string
|
||||
me.myTree.SendUserEvent(me.textbox.callerTK.node)
|
||||
|
||||
win := me.textbox.callerTK.findParentWindow()
|
||||
if win != nil {
|
||||
// win.dumpWidget("redraw this!!!")
|
||||
tk := me.textbox.callerTK
|
||||
// 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()
|
||||
}
|
||||
}
|
24
tree.go
24
tree.go
|
@ -1,24 +0,0 @@
|
|||
package main
|
||||
|
||||
/*
|
||||
This is reference code for toolkit developers
|
||||
*/
|
||||
|
||||
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()
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
log "go.wit.com/log"
|
||||
"go.wit.com/toolkits/tree"
|
||||
"go.wit.com/widget"
|
||||
)
|
||||
|
||||
var fakeStartWidth int = me.FakeW
|
||||
var fakeStartHeight int = me.TabH + me.FramePadH
|
||||
|
||||
// setup fake labels for non-visible things off screen
|
||||
func setFake(n *tree.Node) {
|
||||
var w *guiWidget
|
||||
w = n.TK.(*guiWidget)
|
||||
w.isFake = true
|
||||
|
||||
w.gocuiSetWH(fakeStartWidth, fakeStartHeight)
|
||||
|
||||
fakeStartHeight += w.gocuiSize.Height()
|
||||
// TODO: use the actual max hight of the terminal window
|
||||
if fakeStartHeight > 24 {
|
||||
fakeStartHeight = me.TabH
|
||||
fakeStartWidth += me.FakeW
|
||||
}
|
||||
}
|
||||
|
||||
// mostly just sets the colors of things
|
||||
func addWidget(n *tree.Node) {
|
||||
if !me.ok {
|
||||
log.Log(INFO, "addWidget() START NOT OKAY")
|
||||
log.Log(INFO, "addWidget() START NOT OKAY")
|
||||
log.Log(INFO, "addWidget() START NOT OKAY")
|
||||
waitOK()
|
||||
}
|
||||
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)
|
||||
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()
|
||||
tk.labelN = "X " + n.State.Label
|
||||
return
|
||||
case widget.Dropdown:
|
||||
tk.setColorInput()
|
||||
return
|
||||
case widget.Textbox:
|
||||
n.State.Label = ""
|
||||
tk.labelN = " "
|
||||
// tk.color = &colorDropdown
|
||||
tk.setColorInput()
|
||||
return
|
||||
case widget.Combobox:
|
||||
// tk.color = &colorCombobox
|
||||
tk.setColorInput()
|
||||
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
|
||||
case widget.Group:
|
||||
tk.setColorLabel()
|
||||
tk.frame = false
|
||||
return
|
||||
case widget.Label:
|
||||
tk.setColorLabel()
|
||||
tk.frame = false
|
||||
return
|
||||
default:
|
||||
/*
|
||||
if n.IsCurrent() {
|
||||
n.updateCurrent()
|
||||
}
|
||||
*/
|
||||
}
|
||||
tk.dumpWidget("addWidget()unknown")
|
||||
}
|
|
@ -0,0 +1,271 @@
|
|||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
log "go.wit.com/log"
|
||||
"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())
|
||||
if me.baseGui == nil {
|
||||
log.Log(ERROR, "drawView() ERROR: me.baseGui == nil", tk)
|
||||
return
|
||||
}
|
||||
|
||||
if tk.cuiName == "" {
|
||||
log.Log(ERROR, "drawView() tk.cuiName was not set for widget", tk)
|
||||
tk.cuiName = strconv.Itoa(tk.WidgetId()) + " TK"
|
||||
}
|
||||
log.Log(INFO, "drawView() labelN =", tk.labelN)
|
||||
|
||||
// this deletes the button from gocui
|
||||
me.baseGui.DeleteView(tk.cuiName)
|
||||
tk.v = nil
|
||||
|
||||
a := tk.gocuiSize.w0
|
||||
b := tk.gocuiSize.h0
|
||||
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 {
|
||||
tk.textResize()
|
||||
tk.full.w0 = tk.force.w0
|
||||
tk.full.h0 = tk.force.h0
|
||||
|
||||
// for windows, make it the full size
|
||||
a = tk.full.w0
|
||||
b = tk.full.h0
|
||||
c = tk.full.w0 + tk.gocuiSize.Width()
|
||||
d = tk.full.h0 + tk.gocuiSize.Height()
|
||||
} else {
|
||||
if tk.internal {
|
||||
// do nothing
|
||||
} else {
|
||||
tk.textResize() // resize gocui frame to the widget text
|
||||
}
|
||||
a = tk.gocuiSize.w0
|
||||
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)
|
||||
if err == nil {
|
||||
tk.dumpWidget("drawView() err")
|
||||
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.isWindowDense() && 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
|
||||
tk.v.FgColor = tk.color.fg
|
||||
tk.v.BgColor = tk.color.bg
|
||||
tk.v.SelFgColor = tk.color.selFg
|
||||
tk.v.SelBgColor = tk.color.selBg
|
||||
}
|
||||
|
||||
log.Log(INFO, "drawView() END")
|
||||
}
|
||||
|
||||
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 {
|
||||
return
|
||||
}
|
||||
w.dumpWidget("in drawTree()")
|
||||
if draw {
|
||||
// w.textResize()
|
||||
w.Show()
|
||||
} else {
|
||||
w.Hide()
|
||||
}
|
||||
|
||||
for _, child := range w.children {
|
||||
child.drawTree(draw)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *guiWidget) Show() {
|
||||
if w.isFake {
|
||||
// don't display fake widgets
|
||||
return
|
||||
}
|
||||
|
||||
if w.Hidden() {
|
||||
// recursively checks if the parent is hidden
|
||||
// never show hidden widgets
|
||||
return
|
||||
}
|
||||
if me.debug {
|
||||
w.dumpWidget("drawView()")
|
||||
}
|
||||
|
||||
w.drawView()
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
// 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
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"go.wit.com/log"
|
||||
"go.wit.com/toolkits/tree"
|
||||
"go.wit.com/widget"
|
||||
)
|
||||
|
||||
func initWidget(n *tree.Node) *guiWidget {
|
||||
var w *guiWidget
|
||||
w = new(guiWidget)
|
||||
|
||||
w.node = n
|
||||
w.cuiName = strconv.Itoa(w.WidgetId()) + " TK"
|
||||
// w.WidgetType() = n.WidgetType
|
||||
w.labelN = n.State.Label
|
||||
if w.labelN == "" {
|
||||
// remove this debugging hack once things are stable and fixed
|
||||
w.labelN = n.GetProgName()
|
||||
}
|
||||
w.frame = true
|
||||
w.enable = n.State.Enable
|
||||
|
||||
if n.WidgetType == widget.Root {
|
||||
log.Log(INFO, "setupWidget() FOUND ROOT w.id =", n.WidgetId)
|
||||
}
|
||||
|
||||
if n.WidgetType == widget.Grid {
|
||||
w.widths = make(map[int]int) // how tall each row in the grid is
|
||||
w.heights = make(map[int]int) // how wide each column in the grid is
|
||||
}
|
||||
|
||||
p := n.Parent
|
||||
if p == nil {
|
||||
log.Log(ERROR, "parent == nil", w.String(), n.WidgetId, w.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())
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
||||
// set the parent and append to parent children
|
||||
var ptk *guiWidget
|
||||
ptk = p.TK.(*guiWidget)
|
||||
w.parent = ptk
|
||||
ptk.children = append(ptk.children, w)
|
||||
return w
|
||||
}
|
||||
|
||||
func setupCtrlDownWidget() {
|
||||
a := new(widget.Action)
|
||||
a.ProgName = "ctrlDown"
|
||||
a.WidgetType = widget.Dialog
|
||||
a.WidgetId = -1
|
||||
a.ParentId = 0
|
||||
// n := addNode(a)
|
||||
n := me.myTree.AddNode(a)
|
||||
|
||||
me.ctrlDown = n
|
||||
}
|
||||
|
||||
func (w *guiWidget) deleteView() {
|
||||
// make sure the view isn't really there
|
||||
// log.Log(GOCUI, "deleteView()", w.cuiName, w.WidgetType(), w.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()
|
||||
if curval != "" {
|
||||
return curval
|
||||
}
|
||||
curval = tk.node.String()
|
||||
if curval != "" {
|
||||
return curval
|
||||
}
|
||||
curval = strings.TrimSpace(tk.node.ProgName())
|
||||
if curval != "" {
|
||||
return curval
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (tk *guiWidget) Visible() bool {
|
||||
if tk == nil {
|
||||
return false
|
||||
}
|
||||
if tk.v == nil {
|
||||
return false
|
||||
}
|
||||
tk.v.Visible = true
|
||||
return true
|
||||
}
|
||||
|
||||
func (tk *guiWidget) Hide() {
|
||||
tk.deleteView()
|
||||
}
|
||||
|
||||
func (tk *guiWidget) SetVisible(b bool) {
|
||||
if b {
|
||||
tk.Show()
|
||||
} else {
|
||||
tk.Hide()
|
||||
}
|
||||
}
|
68
view.go
68
view.go
|
@ -1,54 +1,56 @@
|
|||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"strings"
|
||||
|
||||
"go.wit.com/log"
|
||||
"go.wit.com/widget"
|
||||
)
|
||||
|
||||
func splitLines(s string) []string {
|
||||
var lines []string
|
||||
sc := bufio.NewScanner(strings.NewReader(s))
|
||||
for sc.Scan() {
|
||||
lines = append(lines, sc.Text())
|
||||
// expands the gocuiSize rectangle to fit
|
||||
// all the text in tk.labelN
|
||||
func (tk *guiWidget) textResize() {
|
||||
var w, h int = 0, 0
|
||||
|
||||
for _, s := range strings.Split(tk.labelN, "\n") {
|
||||
s = strings.TrimSpace(s)
|
||||
// log.Log(INFO, "textResize() len =", len(s), i, s)
|
||||
if w < len(s) {
|
||||
w = len(s)
|
||||
}
|
||||
h += 1
|
||||
}
|
||||
return lines
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func (w *guiWidget) textResize() bool {
|
||||
// w := n.tk
|
||||
var width, height int = 0, 0
|
||||
var changed bool = false
|
||||
|
||||
for i, s := range splitLines(w.labelN) {
|
||||
log.Log(INFO, "textResize() len =", len(s), i, s)
|
||||
if width < len(s) {
|
||||
width = len(s)
|
||||
}
|
||||
height += 1
|
||||
// deletes every view
|
||||
func (w *guiWidget) hideWindow() {
|
||||
if w == nil {
|
||||
return
|
||||
}
|
||||
if w.gocuiSize.w1 != w.gocuiSize.w0+width+me.FramePadW {
|
||||
w.gocuiSize.w1 = w.gocuiSize.w0 + width + me.FramePadW
|
||||
changed = true
|
||||
w.Hide()
|
||||
for _, child := range w.children {
|
||||
child.hideWindow()
|
||||
}
|
||||
if w.gocuiSize.h1 != w.gocuiSize.h0+height+me.FramePadH {
|
||||
w.gocuiSize.h1 = w.gocuiSize.h0 + height + me.FramePadH
|
||||
changed = true
|
||||
}
|
||||
if changed {
|
||||
// w.showWidgetPlacement("textResize() changed")
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
func (w *guiWidget) hideWidgets() {
|
||||
if w == nil {
|
||||
return
|
||||
}
|
||||
w.isCurrent = false
|
||||
switch w.node.WidgetType {
|
||||
switch w.WidgetType() {
|
||||
case widget.Root:
|
||||
case widget.Flag:
|
||||
case widget.Window:
|
||||
|
@ -88,7 +90,7 @@ func (w *guiWidget) hideFake() {
|
|||
func (w *guiWidget) showFake() {
|
||||
if w.isFake {
|
||||
w.drawView()
|
||||
w.showWidgetPlacement("showFake:")
|
||||
w.dumpWidget("in showFake()")
|
||||
}
|
||||
for _, child := range w.children {
|
||||
child.showFake()
|
||||
|
|
198
widget.go
198
widget.go
|
@ -1,198 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/awesome-gocui/gocui"
|
||||
"go.wit.com/log"
|
||||
"go.wit.com/toolkits/tree"
|
||||
"go.wit.com/widget"
|
||||
)
|
||||
|
||||
func initWidget(n *tree.Node) *guiWidget {
|
||||
var w *guiWidget
|
||||
w = new(guiWidget)
|
||||
|
||||
w.node = n
|
||||
w.cuiName = strconv.Itoa(w.node.WidgetId) + " TK"
|
||||
w.WidgetType = n.WidgetType
|
||||
w.labelN = n.State.Label
|
||||
if w.labelN == "" {
|
||||
// remove this debugging hack once things are stable and fixed
|
||||
w.labelN = n.GetProgName()
|
||||
}
|
||||
w.frame = true
|
||||
w.enable = n.State.Enable
|
||||
|
||||
if n.WidgetType == widget.Root {
|
||||
log.Log(INFO, "setupWidget() FOUND ROOT w.id =", n.WidgetId)
|
||||
}
|
||||
|
||||
if n.WidgetType == widget.Grid {
|
||||
w.widths = make(map[int]int) // how tall each row in the grid is
|
||||
w.heights = make(map[int]int) // how wide each column in the grid is
|
||||
}
|
||||
|
||||
p := n.Parent
|
||||
if p == nil {
|
||||
log.Log(ERROR, "parent == nil", w.String(), n.WidgetId, w.WidgetType)
|
||||
return w
|
||||
}
|
||||
if p.TK == nil {
|
||||
log.Log(ERROR, "parent.TK == nil", w.String(), n.WidgetId, w.WidgetType)
|
||||
return w
|
||||
}
|
||||
|
||||
// set the parent and append to parent children
|
||||
var ptk *guiWidget
|
||||
ptk = p.TK.(*guiWidget)
|
||||
w.parent = ptk
|
||||
ptk.children = append(ptk.children, w)
|
||||
return w
|
||||
}
|
||||
|
||||
func setupCtrlDownWidget() {
|
||||
a := new(widget.Action)
|
||||
a.ProgName = "ctrlDown"
|
||||
a.WidgetType = widget.Dialog
|
||||
a.WidgetId = -1
|
||||
a.ParentId = 0
|
||||
// n := addNode(a)
|
||||
n := me.myTree.AddNode(a)
|
||||
|
||||
me.ctrlDown = n
|
||||
}
|
||||
|
||||
func (w *guiWidget) deleteView() {
|
||||
// make sure the view isn't really there
|
||||
log.Log(GOCUI, "deleteView()", w.cuiName, w.WidgetType, w.node.WidgetId)
|
||||
me.baseGui.DeleteView(w.cuiName)
|
||||
w.v = nil
|
||||
}
|
||||
|
||||
func (w *guiWidget) IsCurrent() bool {
|
||||
if w.node.WidgetType == widget.Tab {
|
||||
return w.isCurrent
|
||||
}
|
||||
if w.node.WidgetType == widget.Window {
|
||||
log.Log(GOCUI, "IsCurrent() found current window", w.cuiName, w.String())
|
||||
log.Log(GOCUI, "IsCurrent() window w.isCurrent =", w.isCurrent)
|
||||
return w.isCurrent
|
||||
}
|
||||
if w.node.WidgetType == widget.Root {
|
||||
return false
|
||||
}
|
||||
return w.parent.IsCurrent()
|
||||
}
|
||||
|
||||
func (tk *guiWidget) String() string {
|
||||
return tk.node.String()
|
||||
}
|
||||
|
||||
func (tk *guiWidget) Visible() bool {
|
||||
if tk == nil {
|
||||
return false
|
||||
}
|
||||
if tk.v == nil {
|
||||
return false
|
||||
}
|
||||
tk.v.Visible = true
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *guiWidget) Show() {
|
||||
// always should the dropdown widget
|
||||
if w == me.dropdownV {
|
||||
me.dropdownV.drawView()
|
||||
return
|
||||
}
|
||||
|
||||
// don't display fake widgets
|
||||
if w.isFake {
|
||||
return
|
||||
}
|
||||
|
||||
// if this isn't in the binary tree
|
||||
// it's some internal widget so always display those
|
||||
if w.node == nil {
|
||||
w.drawView()
|
||||
return
|
||||
}
|
||||
|
||||
// always show window titles
|
||||
if w.node.WidgetType == widget.Window {
|
||||
w.drawView()
|
||||
return
|
||||
}
|
||||
|
||||
if w.node.WidgetType == widget.Dropdown {
|
||||
log.Log(NOW, "Show() dropdown", w.cuiName, w.String())
|
||||
log.Log(NOW, "Show() dropdown n.Strings() =", w.node.Strings())
|
||||
}
|
||||
if w.node.WidgetType == widget.Combobox {
|
||||
log.Log(NOW, "Show() dropdown", w.cuiName, w.String())
|
||||
log.Log(NOW, "Show() dropdown n.Strings() =", w.node.Strings())
|
||||
}
|
||||
|
||||
// if the widget is not in the current displayed windo
|
||||
// then ignore it
|
||||
log.Log(GOCUI, "Show() widget =", w.cuiName, w.String())
|
||||
log.Log(GOCUI, "Show() w.IsCurrent() returned", w.IsCurrent())
|
||||
if !w.IsCurrent() {
|
||||
log.Log(GOCUI, "Show() NOT drawing", w.cuiName, w.String())
|
||||
return
|
||||
}
|
||||
log.Log(GOCUI, "Show() drawing", w.cuiName, w.String())
|
||||
|
||||
// finally, check if the widget State is hidden or not
|
||||
if w.node.Hidden() {
|
||||
// don't display hidden widgets
|
||||
return
|
||||
}
|
||||
|
||||
// okay, if you made it this far, then display the widget
|
||||
w.drawView()
|
||||
}
|
||||
|
||||
func (tk *guiWidget) Hide() {
|
||||
tk.deleteView()
|
||||
}
|
||||
|
||||
func (tk *guiWidget) SetVisible(b bool) {
|
||||
if b {
|
||||
tk.Show()
|
||||
} else {
|
||||
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
|
||||
}
|
270
window.go
270
window.go
|
@ -1,28 +1,264 @@
|
|||
// 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"
|
||||
"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 {
|
||||
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)
|
||||
tk.v.Clear()
|
||||
f := " %-" + fmt.Sprintf("%d", tk.full.Width()-3) + "s %s"
|
||||
tmp := tk.GetLabel()
|
||||
labelN := fmt.Sprintf(f, tmp, "X")
|
||||
tk.v.WriteString(labelN)
|
||||
}
|
||||
|
||||
func (tk *guiWidget) redrawWindow(w int, h int) {
|
||||
if tk.WidgetType() != widget.Window {
|
||||
return
|
||||
}
|
||||
// tk.dumpWidget(fmt.Sprintf("redrawWindow(%d,%d)", w, h))
|
||||
if tk.full.Height() > 40 {
|
||||
tk.window.dense = true
|
||||
}
|
||||
// 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.force.w0 = w
|
||||
tk.force.w1 = w
|
||||
tk.force.h0 = h
|
||||
tk.force.h1 = h
|
||||
|
||||
tk.setFullSize() // might make the green box the right size
|
||||
|
||||
tk.frame = false
|
||||
tk.hasTabs = false
|
||||
|
||||
tk.DrawAt(w, h)
|
||||
// tk.setColor(&colorActiveW) // sets the window to Green BG
|
||||
tk.setColorWindowTitleActive()
|
||||
|
||||
if tk.window.collapsed {
|
||||
// don't show anything but the title bar
|
||||
tk.hideWindow()
|
||||
return
|
||||
}
|
||||
tk.placeWidgets(w, h) // compute the sizes & places for each widget
|
||||
|
||||
// this is a test. this should not be needed
|
||||
tk.full.w0 = tk.force.w0
|
||||
tk.full.h0 = tk.force.h0
|
||||
|
||||
tk.setFullSize()
|
||||
tk.Show()
|
||||
if tk.v == nil {
|
||||
log.Info("redrawWindow on tk.v == nil")
|
||||
standardExit()
|
||||
}
|
||||
tk.v.Clear()
|
||||
fmt.Fprint(tk.v, "ZZZ"+tk.GetText())
|
||||
tk.showWidgets()
|
||||
|
||||
if tk.windowFrame == nil {
|
||||
tk.addWindowFrameTK(0 - tk.WidgetId())
|
||||
tk.windowFrame.makeTK([]string{""})
|
||||
}
|
||||
|
||||
// this seems to correctly create the window frame
|
||||
r := tk.getFullSize()
|
||||
tk.windowFrame.gocuiSize.w0 = tk.force.w0
|
||||
tk.windowFrame.gocuiSize.w1 = r.w1 + 1
|
||||
tk.windowFrame.gocuiSize.h0 = tk.force.h0 + 2
|
||||
tk.windowFrame.gocuiSize.h1 = r.h1 + 1
|
||||
tk.windowFrame.full.w0 = tk.force.w0
|
||||
tk.windowFrame.full.w1 = r.w1 + 1
|
||||
tk.windowFrame.full.h0 = tk.force.h0 + 2
|
||||
tk.windowFrame.full.h1 = r.h1 + 1
|
||||
tk.windowFrame.setColorWindowFrame()
|
||||
tk.windowFrame.Hide()
|
||||
tk.windowFrame.Show()
|
||||
|
||||
// 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)
|
||||
|
||||
// so we have to redraw the widgets in the window anyway and then they will appear above he frame
|
||||
tk.hideWidgets()
|
||||
tk.showWidgets()
|
||||
|
||||
// draw the window title
|
||||
tk.setTitle(tk.GetLabel())
|
||||
}
|
||||
|
||||
// re-draws the buttons for each of the windows
|
||||
func (w *guiWidget) redoWindows(nextW int, nextH int) {
|
||||
var startW int = nextW
|
||||
var startH int = nextH
|
||||
|
||||
for _, child := range w.children {
|
||||
if child.node.WidgetType != widget.Window {
|
||||
continue
|
||||
func redoWindows(nextW int, nextH int) {
|
||||
for _, tk := range findWindows() {
|
||||
// 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()
|
||||
} else {
|
||||
w, _ := me.baseGui.Size()
|
||||
if nextW > w-20 {
|
||||
nextW = 0
|
||||
nextH += 4
|
||||
}
|
||||
// probably a new window?
|
||||
tk.redrawWindow(nextW, nextH)
|
||||
}
|
||||
// tk.dumpWidget(fmt.Sprintf("redoWindowsE (%d,%d)", nextW, nextH))
|
||||
|
||||
child.frame = false
|
||||
child.hasTabs = false
|
||||
|
||||
child.gocuiSetWH(nextW, nextH)
|
||||
child.Hide()
|
||||
|
||||
child.drawView()
|
||||
sizeW := child.gocuiSize.Width()
|
||||
nextW += sizeW + 4
|
||||
child.redoWindows(startW+3, startH+2)
|
||||
// increment the width for the next window
|
||||
nextW += tk.gocuiSize.Width() + 10
|
||||
// nextH += 10
|
||||
}
|
||||
}
|
||||
|
||||
func (tk *guiWidget) addWindowFrameTK(wId int) {
|
||||
n := tk.addWindowFrame(wId)
|
||||
tk.windowFrame = n.TK.(*guiWidget)
|
||||
}
|
||||
|
||||
func (win *guiWidget) addWindowFrame(wId int) *tree.Node {
|
||||
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.labelN = "windowFrame text"
|
||||
tk.internal = true
|
||||
|
||||
tk.node = n
|
||||
if tk.node.Parent == nil {
|
||||
tk.node.Parent = me.treeRoot
|
||||
}
|
||||
|
||||
// set the name used by gocui to the id
|
||||
tk.cuiName = fmt.Sprintf("%d DR", wId)
|
||||
|
||||
// tk.color = &colorGroup
|
||||
|
||||
// add this new widget on the binary tree
|
||||
tk.parent = win
|
||||
if tk.parent == nil {
|
||||
panic("addDropdown() didn't get treeRoot guiWidget")
|
||||
} else {
|
||||
tk.parent.children = append(tk.parent.children, tk)
|
||||
}
|
||||
|
||||
n.TK = tk
|
||||
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) {
|
||||
// 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()
|
||||
}
|
||||
|
||||
// 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) {
|
||||
items := strings.Join(ddItems, "\n")
|
||||
tk.labelN = items
|
||||
tk.SetText(items)
|
||||
tk.gocuiSize.w0 = 100
|
||||
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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue