1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
|
// 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
// by functions() to insure everything here is run
// inside a dedicated goroutine
package main
import (
"fmt"
"reflect"
"strconv"
"sync"
"github.com/awesome-gocui/gocui"
log "go.wit.com/log"
"go.wit.com/toolkits/tree"
)
// 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
// 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
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
helpLabel *gocui.View // ?
showHelp bool // toggle boolean for the help menu (deprecate?)
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
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
globalMouseDown bool // yep, mouse is pressed
newWindowTrigger chan *guiWidget // work around hack to redraw windows a bit after NewWindow()
stdout stdout // information for the STDOUT window
showDebug bool // todo: move this into config struct
dropdown dropdown // the dropdown menu
textbox dropdown // the textbox popup window
allwin []*guiWidget // for tracking which window is next
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
dark bool // use a 'dark' color palette
}
// settings for the stdout window
type stdout struct {
tk *guiWidget // where to show STDOUT
w int // the width
h int // the height
outputOnTop bool // is the STDOUT window on top?
outputOffscreen bool // is the STDOUT window offscreen?
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
resize bool // user is resizing the window
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
wId int // the widget id to use
// dtoggle bool // is a dropdown or combobox currently active?
}
// this is the gocui way
// corner starts at in the upper left corner
type rectType struct {
w0, h0, w1, h1 int // left top right bottom
}
func (r *rectType) Width() int {
return r.w1 - r.w0
}
func (r *rectType) Height() int {
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
dragW int // when dragging a window, this is the offset to the mouse position
dragH int // when dragging a window, this is the offset to the mouse position
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
isBG bool // means this is the background widget. There is only one of these
order int // what level the window is on
resize bool // only set the title once
collapsed bool // only show the window title bar
dense bool // true if the window is huge
}
type colorT struct {
frame gocui.Attribute
fg gocui.Attribute
bg gocui.Attribute
selFg gocui.Attribute
selBg gocui.Attribute
name string
}
type guiWidget struct {
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
windowFrame *guiWidget // this is the frame for a window widget
internal bool // indicates the widget is internal to gocui and should be treated differently
dragW int // when dragging a window, this is the offset to the mouse position
dragH int // when dragging a window, this is the offset to the mouse position
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 // ?
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
defaultColor *colorT // the default colors // TODO: make a function for this instead
isBG bool // means this is the background widget. There is only one of these
// resize bool // the window is currently being resized
}
// 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)
return fmt.Errorf("Not a pointer")
}
v := reflect.ValueOf(ptr).Elem()
t := v.Type()
for i := 0; i < t.NumField(); i++ {
defaultVal := t.Field(i).Tag.Get(tag)
name := t.Field(i).Name
// log("Set() try name =", name, "defaultVal =", defaultVal)
setField(v.Field(i), defaultVal, name)
}
return nil
}
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)
}
switch field.Kind() {
case reflect.Int:
val, _ := strconv.Atoi(defaultVal)
field.Set(reflect.ValueOf(int(val)).Convert(field.Type()))
case reflect.String:
field.Set(reflect.ValueOf(defaultVal).Convert(field.Type()))
case reflect.Bool:
if defaultVal == "true" {
field.Set(reflect.ValueOf(true))
} else {
field.Set(reflect.ValueOf(false))
}
}
return nil
}
|