gocui plugin refactor to a *node binary tree

rename arg '--gui <toolkit>'
    add a cloudflare example
    fixes since go v1.21 didn't compile anymore due to argv order
    more place() changes
    recursive size computation

    gocui: Major refactor to use the *node binary tree
    gocui: refactor place() and size()
    gocui: better place() and spacing (tab, buttons, etc)
    gocui: better mouse click handling
    gocui: switch to using tk.gocuiSize & tk.size
    gocui: event handling cleanups
    gocui: add window labels work
    gocui: struct cleanups
    gocui: duplicate binary tree structs removed
    gocui: deprecate old children

Signed-off-by: Jeff Carr <jcarr@wit.com>
This commit is contained in:
Jeff Carr 2023-12-02 19:02:51 -06:00
parent 603d5ba7de
commit fe6a8dd969
32 changed files with 1358 additions and 936 deletions

1
.gitignore vendored
View File

@ -8,6 +8,7 @@ cmds/console-ui-helloworld/console-ui-helloworld
cmds/debug/debug cmds/debug/debug
cmds/helloworld/helloworld cmds/helloworld/helloworld
cmds/textbox/textbox cmds/textbox/textbox
cmds/cloudflare/cloudflare
cmds/*/helloconsole cmds/*/helloconsole
# temporary files when building debian packages # temporary files when building debian packages

View File

@ -8,6 +8,7 @@ all: README.md
@echo @echo
make clean make clean
make plugins make plugins
make cmds-buttonplugin
build-dep: build-dep:
apt install -f libgtk-3-dev apt install -f libgtk-3-dev
@ -82,11 +83,11 @@ clean:
plugins: plugins-gocui plugins-andlabs plugins: plugins-gocui plugins-andlabs
plugins-gocui: plugins-gocui:
GO111MODULE="off" go build -v -x -C toolkit/gocui -buildmode=plugin -o ../gocui.so GO111MODULE="off" go build -C toolkit/gocui -v -buildmode=plugin -o ../gocui.so
GO111MODULE="off" go build -v -x -C toolkit/nocui -buildmode=plugin -o ../nocui.so GO111MODULE="off" go build -C toolkit/nocui -v -buildmode=plugin -o ../nocui.so
plugins-andlabs: plugins-andlabs:
GO111MODULE="off" go build -v -x -C toolkit/andlabs -buildmode=plugin -o ../andlabs.so GO111MODULE="off" go build -C toolkit/andlabs -v -buildmode=plugin -o ../andlabs.so
objdump: objdump:
objdump -t toolkit/andlabs.so |less objdump -t toolkit/andlabs.so |less

View File

@ -139,7 +139,7 @@ Creates a window helpful for debugging this package
`func ShowDebugValues()` `func ShowDebugValues()`
### func [StandardExit](/main.go#L149) ### func [StandardExit](/main.go#L153)
`func StandardExit()` `func StandardExit()`
@ -158,13 +158,19 @@ This goroutine can be used like a watchdog timer
## Types ## Types
### type [GuiArgs](/structs.go#L27) ### type [GuiArgs](/structs.go#L29)
`type GuiArgs struct { ... }` `type GuiArgs struct { ... }`
This struct can be used with the go-arg package This struct can be used with the go-arg package
### type [Node](/structs.go#L57) #### Variables
```golang
var GuiArg GuiArgs
```
### type [Node](/structs.go#L59)
`type Node struct { ... }` `type Node struct { ... }`

View File

@ -7,7 +7,7 @@
# #
run: build run: build
./buttonplugin --gui-toolkit gocui >/tmp/witgui.log.stderr 2>&1 ./buttonplugin --gui gocui >/tmp/witgui.log.stderr 2>&1
build-release: build-release:
go get -v -u -x . go get -v -u -x .

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
arg "github.com/alexflint/go-arg" arg "github.com/alexflint/go-arg"
"git.wit.org/wit/gui" "git.wit.org/wit/gui"
log "git.wit.org/wit/gui/log"
) )
@ -14,6 +15,7 @@ var args struct {
User string `arg:"env:USER"` User string `arg:"env:USER"`
Demo bool `help:"run a demo"` Demo bool `help:"run a demo"`
gui.GuiArgs gui.GuiArgs
log.LogArgs
} }
/* /*
@ -26,6 +28,11 @@ func init() {
arg.MustParse(&args) arg.MustParse(&args)
fmt.Println(args.Foo, args.Bar, args.User) fmt.Println(args.Foo, args.Bar, args.User)
if (args.Gui != "") {
gui.GuiArg.Gui = args.Gui
}
log.Log(true, "INIT() args.GuiArg.Gui =", gui.GuiArg.Gui)
/* /*
log.Println() log.Println()
log.Println("STDOUT is now at /tmp/guilogfile") log.Println("STDOUT is now at /tmp/guilogfile")

View File

@ -20,14 +20,7 @@ func main() {
// This will turn on all debugging // This will turn on all debugging
// gui.SetDebug(true) // gui.SetDebug(true)
// myGui = gui.New().LoadToolkit("gocui") myGui = gui.New().Default()
// myGui = gui.New().LoadToolkit("andlabs")
// myGui = gui.New().Default()
if (args.GuiToolkit == nil) {
myGui = gui.New().Default()
} else {
myGui = gui.New().LoadToolkit(args.GuiToolkit[0])
}
buttonWindow() buttonWindow()
// This is just a optional goroutine to watch that things are alive // This is just a optional goroutine to watch that things are alive

18
cmds/cloudflare/Makefile Normal file
View File

@ -0,0 +1,18 @@
run: build
./cloudflare
build-release:
go get -v -u -x .
go build
./cloudflare
build:
GO111MODULE="off" go get -v -x .
GO111MODULE="off" go build
update:
GO111MODULE="off" go get -v -u -x .
log:
reset
tail -f /tmp/witgui.* /tmp/guilogfile

30
cmds/cloudflare/argv.go Normal file
View File

@ -0,0 +1,30 @@
// This creates a simple hello world window
package main
import (
"fmt"
arg "github.com/alexflint/go-arg"
"git.wit.org/wit/gui"
log "git.wit.org/wit/gui/log"
)
var args struct {
Foo string
Bar bool
User string `arg:"env:USER"`
Demo bool `help:"run a demo"`
gui.GuiArgs
log.LogArgs
}
func init() {
arg.MustParse(&args)
fmt.Println(args.Foo, args.Bar, args.User)
if (args.Gui != "") {
gui.GuiArg.Gui = args.Gui
}
log.Log(true, "INIT() args.GuiArg.Gui =", gui.GuiArg.Gui)
}

115
cmds/cloudflare/dns.go Normal file
View File

@ -0,0 +1,115 @@
// This is a simple example
package main
import (
"os"
"log"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strconv"
)
// Define a struct to match the JSON structure of the response.
// This structure should be adjusted based on the actual format of the response.
type DNSRecords struct {
Result []struct {
ID string `json:"id"`
Type string `json:"type"`
Name string `json:"name"`
Content string `json:"content"`
Proxied bool `json:"proxied"`
Proxiable bool `json:"proxiable"`
TTL int `json:"ttl"`
} `json:"result"`
}
// var domain string = "wit.org"
// var os.Getenv("CLOUDFLARE_DOMAIN")
func loadDNS(hostname string) {
log.Println("adding DNS record")
// more2.NewButton(name, func () {
// log.Println(name, "ip =", ip)
// })
newt := mainWindow.NewTab(hostname)
newg := newt.NewGroup("more")
more2 := newg.NewGrid("gridnuts", 5, gridH)
records := getRecords()
for _, record := range records.Result {
more2.NewLabel(record.Type)
more2.NewLabel(record.Name)
if (record.Proxied) {
more2.NewLabel("Proxied")
} else {
more2.NewLabel("DNS")
}
var ttl, short string
if (record.TTL == 1) {
ttl = "Auto"
} else {
ttl = strconv.Itoa(record.TTL)
}
more2.NewLabel(ttl)
// short = fmt.Sprintf("%80s", record.Content)
short = record.Content
if len(short) > 40 {
short = short[:40] // Slice the first 20 characters
}
more2.NewLabel(short)
fmt.Printf("ID: %s, Type: %s, Name: %s, short Content: %s\n", record.ID, record.Type, record.Name, short)
fmt.Printf("\tproxied: %b, %b, string TTL: %i\n", record.Proxied, record.Proxiable, ttl)
}
}
func getRecords() *DNSRecords {
var url string = os.Getenv("CLOUDFLARE_URL")
req, err := http.NewRequest("GET", url, nil)
if err != nil {
fmt.Println(err)
return nil
}
var authKey string = os.Getenv("CLOUDFLARE_AUTHKEY")
var email string = os.Getenv("CLOUDFLARE_EMAIL")
// Set headers
req.Header.Set("X-Auth-Key", authKey)
req.Header.Set("X-Auth-Email", email)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println(err)
return nil
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
return nil
}
var records DNSRecords
if err := json.Unmarshal(body, &records); err != nil {
fmt.Println(err)
return nil
}
// Process the records as needed
/*
for _, record := range records.Result {
fmt.Printf("ID: %s, Type: %s, Name: %s, Content: %s\n", record.ID, record.Type, record.Name, record.Content)
fmt.Printf("\tproxied: %b, %b, TTL: %i\n", record.Proxied, record.Proxiable, record.TTL)
}
*/
return &records
}

122
cmds/cloudflare/main.go Normal file
View File

@ -0,0 +1,122 @@
// This is a simple example
package main
import (
"os"
"fmt"
"log"
"strconv"
"git.wit.org/wit/gui"
)
var title string = "Cloudflare DNS Control Panel"
var outfile string = "/tmp/guilogfile"
var myGui *gui.Node
var buttonCounter int = 5
var gridW int = 5
var gridH int = 3
var mainWindow, more, more2 *gui.Node
func main() {
myGui = gui.New().Default()
buttonWindow()
// This is just a optional goroutine to watch that things are alive
gui.Watchdog()
gui.StandardExit()
}
// This creates a window
func buttonWindow() {
var t, g *gui.Node
log.Println("buttonWindow() START")
mainWindow = myGui.NewWindow(title).SetText(title)
t = mainWindow.NewTab("Cloudflare")
g = t.NewGroup("buttons")
g1 := t.NewGroup("buttonGroup 2")
more = g1.NewGroup("more")
showCloudflareCredentials(more)
g1.NewButton("hello", func () {
log.Println("world")
})
more2 = g1.NewGrid("gridnuts", gridW, gridH)
var domain string = os.Getenv("CLOUDFLARE_DOMAIN")
if (domain == "") {
domain = "example.org"
}
g.NewButton("Load " + domain + " DNS", func () {
loadDNS(domain)
})
g.NewButton("Load 'gocui'", func () {
// this set the xterm and mate-terminal window title. maybe works generally?
fmt.Println("\033]0;" + title + "blah \007")
myGui.LoadToolkit("gocui")
})
g.NewButton("Load 'andlabs'", func () {
myGui.LoadToolkit("andlabs")
})
g.NewButton("NewButton(more)", func () {
name := "foobar " + strconv.Itoa(buttonCounter)
log.Println("NewButton(more) Adding button", name)
buttonCounter += 1
more.NewButton(name, func () {
log.Println("Got all the way to main() name =", name)
})
})
g.NewButton("NewButton(more2)", func () {
name := "foobar " + strconv.Itoa(buttonCounter)
log.Println("NewButton(more2) Adding button", name)
buttonCounter += 1
more2.NewButton(name, func () {
log.Println("Got all the way to main() name =", name)
})
})
g.NewButton("NewButton(more2 d)", func () {
name := "d" + strconv.Itoa(buttonCounter)
log.Println("NewButton(more2 d) Adding button", name)
buttonCounter += 1
more2.NewButton(name, func () {
log.Println("Got all the way to main() name =", name)
})
})
g.NewButton("NewGroup()", func () {
name := "neat " + strconv.Itoa(buttonCounter)
log.Println("NewGroup() Adding button", name)
buttonCounter += 1
more.NewGroup(name)
})
g.NewButton("gui.DebugWindow()", func () {
gui.DebugWindow()
})
}
func showCloudflareCredentials(box *gui.Node) {
grid := box.NewGrid("credsGrid", 2, 4) // width = 2
grid.NewLabel("Domain")
grid.NewLabel(os.Getenv("CLOUDFLARE_DOMAIN"))
grid.NewLabel("Auth Key")
grid.NewLabel(os.Getenv("CLOUDFLARE_AUTHKEY"))
grid.NewLabel("Email")
grid.NewLabel(os.Getenv("CLOUDFLARE_EMAIL"))
grid.NewLabel("URL")
grid.NewLabel(os.Getenv("CLOUDFLARE_URL"))
}

13
log/structs.go Normal file
View File

@ -0,0 +1,13 @@
package witlog
import (
)
//
// Attempt to switch logging to syslog on linux
//
// This struct can be used with the go-arg package
type LogArgs struct {
Log []string `arg:"--log" help:"Where to log [syslog,stdout]"`
}

View File

@ -123,6 +123,10 @@ func New() *Node {
// try to load andlabs, if that doesn't work, fall back to the console // try to load andlabs, if that doesn't work, fall back to the console
func (n *Node) Default() *Node { func (n *Node) Default() *Node {
if (GuiArg.Gui != "") {
log(logError, "New.Default() try toolkit =", GuiArg.Gui)
return n.LoadToolkit(GuiArg.Gui)
}
// if DISPLAY isn't set, return since gtk can't load // if DISPLAY isn't set, return since gtk can't load
// TODO: figure out how to check what to do in macos and mswindows // TODO: figure out how to check what to do in macos and mswindows
if (os.Getenv("DISPLAY") == "") { if (os.Getenv("DISPLAY") == "") {

View File

@ -119,8 +119,15 @@ func searchPaths(name string) *aplug {
filename = "plugins/" + name + ".so" filename = "plugins/" + name + ".so"
pfile, err = me.resFS.ReadFile(filename) pfile, err = me.resFS.ReadFile(filename)
if (err == nil) { if (err == nil) {
filename = "/tmp/" + name + ".so"
log(logError, "write out file here", name, filename, len(pfile)) log(logError, "write out file here", name, filename, len(pfile))
exit() f, _ := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE, 0600)
f.Write(pfile)
f.Close()
p := initToolkit(name, filename)
if (p != nil) {
return p
}
} else { } else {
log(logError, filename, "was not embedded. Error:", err) log(logError, filename, "was not embedded. Error:", err)
} }

View File

@ -23,9 +23,11 @@ import (
var me guiConfig var me guiConfig
var GuiArg GuiArgs
// This struct can be used with the go-arg package // This struct can be used with the go-arg package
type GuiArgs struct { type GuiArgs struct {
GuiToolkit []string `arg:"--gui-toolkit" help:"The order to attempt loading plugins [gocui,andlabs,gtk,qt]"` Gui string `arg:"--gui" help:"Use this gui toolkit [andlabs,gocui,nocui]"`
GuiDebug bool `arg:"--gui-debug" help:"open the GUI debugger"` GuiDebug bool `arg:"--gui-debug" help:"open the GUI debugger"`
GuiVerbose bool `arg:"--gui-verbose" help:"enable all logging"` GuiVerbose bool `arg:"--gui-verbose" help:"enable all logging"`
} }

View File

@ -1,88 +1,67 @@
package main package main
import ( import (
// "github.com/awesome-gocui/gocui"
"git.wit.org/wit/gui/toolkit" "git.wit.org/wit/gui/toolkit"
) )
// TODO: make these defaults in config struct definition var fakeStartWidth int = me.FakeW
var fakeStartWidth int = me.DevelOffsetW
var fakeStartHeight int = me.TabH + me.FramePadH var fakeStartHeight int = me.TabH + me.FramePadH
func (w *cuiWidget) setFake() { // setup fake labels for non-visible things off screen
func (n *node) setFake() {
w := n.tk
w.isFake = true w.isFake = true
t := len(w.name)
// setup fake labels for non-visable things off screen
w.gocuiSize.w0 = fakeStartWidth n.gocuiSetWH(fakeStartWidth, fakeStartHeight)
w.gocuiSize.h0 = fakeStartHeight
w.gocuiSize.w1 = w.gocuiSize.w0 + t + me.PadW
w.gocuiSize.h1 = w.gocuiSize.h0 + me.DefaultHeight + me.PadH
w.realWidth = w.gocuiSize.Width() + me.FramePadW fakeStartHeight += w.gocuiSize.Height()
w.realHeight = w.gocuiSize.Height() + me.FramePadH
fakeStartHeight += w.realHeight
// TODO: use the actual max hight of the terminal window // TODO: use the actual max hight of the terminal window
if (fakeStartHeight > 24) { if (fakeStartHeight > 24) {
fakeStartHeight = me.TabH + me.FramePadH fakeStartHeight = me.TabH
fakeStartWidth += me.DevelOffsetW fakeStartWidth += me.FakeW
} }
if (logInfo) { if (logInfo) {
w.showView() n.showView()
} }
} }
// set the widget start width & height // set the widget start width & height
func (w *cuiWidget) addWidget() { func (n *node) addWidget() {
log(logInfo, "setStartWH() w.id =", w.id, "w.name", w.name) nw := n.tk
switch w.widgetType { log(logInfo, "setStartWH() w.id =", n.WidgetId, "n.name", n.Name)
switch n.WidgetType {
case toolkit.Root: case toolkit.Root:
log(logInfo, "setStartWH() rootNode w.id =", w.id, "w.name", w.name) log(logInfo, "setStartWH() rootNode w.id =", n.WidgetId, "w.name", n.Name)
w.setFake() n.setFake()
return return
case toolkit.Flag: case toolkit.Flag:
w.setFake() n.setFake()
return return
case toolkit.Window: case toolkit.Window:
me.current = w nw.frame = false
updateCurrentTabs() redoWindows(0,0)
setCurrentWindow(w)
return return
case toolkit.Tab: case toolkit.Tab:
// if this is the first tab, set it to the current one and stay here
if (me.current != nil) {
// there is already a current tab. just redraw the tabs
updateCurrentTabs()
return
}
setCurrentTab(w)
return return
case toolkit.Box: case toolkit.Box:
w.isFake = true nw.isFake = true
w.setFake() n.setFake()
w.startW = w.parent.startW
w.startH = w.parent.startH
return return
case toolkit.Grid: case toolkit.Grid:
w.isFake = true nw.isFake = true
w.setFake() n.setFake()
w.startW = w.parent.startW
w.startH = w.parent.startH
return return
case toolkit.Group: case toolkit.Group:
w.startW = w.parent.startW + 4 nw.frame = false
w.startH = w.parent.startH + me.DefaultHeight + me.FramePadH return
case toolkit.Label:
t := len(w.text) nw.frame = false
w.gocuiSize.w1 = w.gocuiSize.w0 + t + me.FramePadW
w.gocuiSize.h1 = w.gocuiSize.h0 + me.DefaultHeight + me.FramePadH
return return
default: default:
w.startW = w.parent.startW /*
w.startH = w.parent.startH if n.IsCurrent() {
if w.IsCurrent() { n.updateCurrent()
w.updateCurrent()
} }
*/
} }
w.showWidgetPlacement(logInfo, "addWidget()") n.showWidgetPlacement(logInfo, "addWidget()")
} }

View File

@ -5,28 +5,29 @@ import (
"git.wit.org/wit/gui/toolkit" "git.wit.org/wit/gui/toolkit"
) )
func (w *cuiWidget) setCheckbox(b bool) { func (n *node) setCheckbox(b bool) {
if (w.widgetType != toolkit.Checkbox) { w := n.tk
if (n.WidgetType != toolkit.Checkbox) {
return return
} }
if (b) { if (b) {
w.b = b n.B = b
w.text = "X " + w.name n.Text = "X " + n.Name
} else { } else {
w.b = b n.B = b
w.text = " " + w.name n.Text = " " + n.Name
} }
t := len(w.text) + 1 t := len(n.Text) + 1
w.gocuiSize.w1 = w.gocuiSize.w0 + t w.gocuiSize.w1 = w.gocuiSize.w0 + t
w.realWidth = w.gocuiSize.Width() + me.PadW // w.realWidth = w.gocuiSize.Width() + me.PadW
w.realHeight = w.gocuiSize.Height() + me.PadH // w.realHeight = w.gocuiSize.Height() + me.PadH
if w.frame { // if w.frame {
w.realWidth += me.FramePadW // w.realWidth += me.FramePadW
w.realHeight += me.FramePadH // w.realHeight += me.FramePadH
} // }
w.deleteView() n.deleteView()
w.showView() n.showView()
} }

View File

@ -1,278 +1,275 @@
package main package main
import ( import (
// "fmt"
// "errors"
"strconv"
"strings"
"github.com/awesome-gocui/gocui" "github.com/awesome-gocui/gocui"
"git.wit.org/wit/gui/toolkit" "git.wit.org/wit/gui/toolkit"
) )
// set isCurrent = false everywhere // set isCurrent = false everywhere
func UnsetCurrent(w *cuiWidget) { func UnsetCurrent(n *node) {
w := n.tk
w.isCurrent = false w.isCurrent = false
for _, child := range w.children { for _, child := range n.children {
UnsetCurrent(child) UnsetCurrent(child)
} }
} }
func updateCurrentTabs() {
me.rootNode.nextW = 0
me.rootNode.nextH = 0
me.rootNode.redoTabs(true)
}
// when adding a new widget, this will update the display // when adding a new widget, this will update the display
// of the current widgets if that widget is supposed // of the current widgets if that widget is supposed
// to be in current display // to be in current display
func (w *cuiWidget) updateCurrent() { func (n *node) updateCurrent() {
if w.widgetType == toolkit.Tab { log("updateCurrent()", n.Name)
if w.IsCurrent() { if n.WidgetType == toolkit.Tab {
setCurrentTab(w) if n.IsCurrent() {
setCurrentTab(n)
} }
return return
} }
if w.widgetType == toolkit.Window { if n.WidgetType == toolkit.Window {
if w.IsCurrent() { if n.IsCurrent() {
setCurrentWindow(w) // setCurrentWindow(n)
} }
return return
} }
if w.widgetType == toolkit.Root { if n.WidgetType == toolkit.Root {
return return
} }
w.parent.updateCurrent() n.parent.updateCurrent()
} }
// shows the widgets in a window // shows the widgets in a window
func setCurrentWindow(w *cuiWidget) { func setCurrentWindow(n *node) {
if w.widgetType != toolkit.Window { if n.IsCurrent() {
return
}
w := n.tk
if n.WidgetType != toolkit.Window {
return return
} }
UnsetCurrent(me.rootNode) UnsetCurrent(me.rootNode)
me.rootNode.hideWidgets()
// THIS IS THE BEGINING OF THE LAYOUT if n.hasTabs {
me.rootNode.nextW = 0
me.rootNode.nextH = 0
w.isCurrent = true
if w.hasTabs {
// set isCurrent = true on the first tab // set isCurrent = true on the first tab
for _, child := range w.children { for _, child := range n.children {
child.isCurrent = true child.tk.isCurrent = true
break break
} }
} else {
w.isCurrent = true
} }
me.rootNode.redoTabs(true)
w.placeWidgets()
w.showWidgets()
} }
// shows the widgets in a tab // shows the widgets in a tab
func setCurrentTab(w *cuiWidget) { func setCurrentTab(n *node) {
if w.widgetType != toolkit.Tab { w := n.tk
if n.WidgetType != toolkit.Tab {
return return
} }
me.current = w
UnsetCurrent(me.rootNode) UnsetCurrent(me.rootNode)
me.rootNode.hideWidgets()
w.isCurrent = true w.isCurrent = true
w.parent.isCurrent = true p := n.parent.tk
updateCurrentTabs() p.isCurrent = true
w.placeWidgets() log("setCurrent()", n.Name)
w.showWidgets()
} }
func (w *cuiWidget) doWidgetClick() { func (n *node) doWidgetClick() {
switch w.widgetType { switch n.WidgetType {
case toolkit.Root: case toolkit.Root:
// THIS IS THE BEGINING OF THE LAYOUT // THIS IS THE BEGINING OF THE LAYOUT
me.rootNode.nextW = 0 log("doWidgetClick()", n.Name)
me.rootNode.nextH = 0 redoWindows(0,0)
me.rootNode.redoTabs(true)
case toolkit.Flag: case toolkit.Flag:
// me.rootNode.redoColor(true) // me.rootNode.redoColor(true)
me.rootNode.dumpTree(true) me.rootNode.dumpTree(true)
case toolkit.Window: case toolkit.Window:
setCurrentWindow(w)
case toolkit.Tab:
setCurrentTab(w)
case toolkit.Group:
w.placeWidgets()
w.toggleTree()
case toolkit.Checkbox:
if (w.b) {
w.setCheckbox(false)
} else {
w.setCheckbox(true)
}
w.doUserEvent()
case toolkit.Grid:
me.rootNode.hideWidgets() me.rootNode.hideWidgets()
w.placeGrid() n.redoTabs(me.TabW, me.TabH)
w.showWidgets() if ! n.hasTabs {
setCurrentWindow(n)
n.placeWidgets(me.RawW, me.RawH)
n.showWidgets()
}
case toolkit.Tab:
setCurrentTab(n)
n.placeWidgets(me.RawW, me.RawH)
n.showWidgets()
case toolkit.Group:
// n.placeWidgets(p.tk.startH, newH)
n.toggleTree()
case toolkit.Checkbox:
if (n.B) {
n.setCheckbox(false)
} else {
n.setCheckbox(true)
}
n.doUserEvent()
case toolkit.Grid:
n.placeGrid(n.tk.size.w0, n.tk.size.h0)
n.showWidgets()
case toolkit.Box: case toolkit.Box:
// w.showWidgetPlacement(logNow, "drawTree()") // w.showWidgetPlacement(logNow, "drawTree()")
if (w.horizontal) { if (n.horizontal) {
log("BOX IS HORIZONTAL", w.name) log("BOX IS HORIZONTAL", n.Name)
} else { } else {
log("BOX IS VERTICAL", w.name) log("BOX IS VERTICAL", n.Name)
} }
w.placeWidgets() // n.placeWidgets()
w.toggleTree() n.toggleTree()
case toolkit.Button: case toolkit.Button:
w.doUserEvent() n.doUserEvent()
default: default:
} }
} }
// this passes the user event back from the plugin
func (w *cuiWidget) doUserEvent() {
if (me.callback == nil) {
log(logError, "doUserEvent() no callback channel was configured")
return
}
var a toolkit.Action
a.WidgetId = w.id
a.Name = w.name
a.Text = w.text
a.B = w.b
a.ActionType = toolkit.User
me.callback <- a
log(logNow, "END: sent a button click callback()")
}
var toggle bool = true var toggle bool = true
func (w *cuiWidget) toggleTree() { func (n *node) toggleTree() {
if (toggle) { if (toggle) {
w.drawTree(toggle) n.drawTree(toggle)
toggle = false toggle = false
} else { } else {
w.hideWidgets() n.hideWidgets()
toggle = true toggle = true
} }
} }
// display the widgets in the binary tree // display the widgets in the binary tree
func (w *cuiWidget) drawTree(draw bool) { func (n *node) drawTree(draw bool) {
w := n.tk
if (w == nil) { if (w == nil) {
return return
} }
w.showWidgetPlacement(logNow, "drawTree()") n.showWidgetPlacement(logNow, "drawTree()")
if (draw) { if (draw) {
// w.textResize() // w.textResize()
w.showView() n.showView()
} else { } else {
w.deleteView() n.deleteView()
} }
for _, child := range w.children { for _, child := range n.children {
child.drawTree(draw) child.drawTree(draw)
} }
} }
func click(g *gocui.Gui, v *gocui.View) error { func click(g *gocui.Gui, v *gocui.View) error {
// var l string // var l string
var err error // var err error
log(logNow, "click() START", v.Name()) log(logVerbose, "click() START", v.Name())
// n := me.rootNode.findWidgetName(v.Name())
n := findUnderMouse()
if (n != nil) {
log(logNow, "click() Found widget =", n.WidgetId, n.Name, ",", n.Text)
n.doWidgetClick()
} else {
log(logNow, "click() could not find node name =", v.Name())
}
/*
i, err := strconv.Atoi(v.Name()) i, err := strconv.Atoi(v.Name())
if (err != nil) { if (err != nil) {
log(logNow, "click() Can't find widget. error =", err) log(logError, "click() Can't find widget. error =", err)
} else { } else {
log(logNow, "click() ok v.Name() =", v.Name()) log(logVerbose, "click() ok v.Name() =", v.Name())
w := findWidget(i, me.rootNode) n := me.rootNode.findWidgetId(i)
if (w == nil) { if (n == nil) {
log(logError, "click() CANT FIND VIEW in binary tree. v.Name =", v.Name()) log(logError, "click() CANT FIND VIEW in binary tree. v.Name =", v.Name())
return nil return nil
} }
log(logNow, "click() Found widget =", w.id, w.name, ",", w.text) log(logNow, "click() Found widget =", n.WidgetId, n.Name, ",", n.Text)
w.doWidgetClick() n.doWidgetClick()
return nil return nil
} }
*/
if _, err := g.SetCurrentView(v.Name()); err != nil { if _, err := g.SetCurrentView(v.Name()); err != nil {
return err return err
} }
/* log(logVerbose, "click() END")
_, cy := v.Cursor()
if l, err = v.Line(cy); err != nil {
l = ""
}
maxX, maxY := g.Size()
if v, err := g.SetView("msg", maxX/2-10, maxY/2, maxX/2+10, maxY/2+2, 0); err == nil || errors.Is(err, gocui.ErrUnknownView) {
v.Clear()
v.SelBgColor = gocui.ColorCyan
v.SelFgColor = gocui.ColorBlack
fmt.Fprintln(v, l)
}
*/
// this seems to delete the button(?)
// g.SetViewOnBottom(v.Name())
log(logNow, "click() END")
return nil return nil
} }
func findUnderMouse() *node {
// display the widgets in the binary tree var found *node
var widgets []*node
func ctrlDown(g *gocui.Gui, v *gocui.View) error { var f func (n *node)
var found *cuiWidget w, h := me.baseGui.MousePosition()
var widgets []*cuiWidget
var f func (widget *cuiWidget)
w, h := g.MousePosition()
// find buttons that are below where the mouse button click // find buttons that are below where the mouse button click
f = func(widget *cuiWidget) { f = func(n *node) {
// if ((widget.logicalSize.w0 < w) && (w < widget.logicalSize.w1)) { widget := n.tk
if ((widget.gocuiSize.w0 <= w) && (w <= widget.gocuiSize.w1) && // ignore widgets that are not visible
(widget.gocuiSize.h0 <= h) && (h <= widget.gocuiSize.h1)) { if n.Visible() {
widgets = append(widgets, widget) if ((widget.gocuiSize.w0 <= w) && (w <= widget.gocuiSize.w1) &&
found = widget (widget.gocuiSize.h0 <= h) && (h <= widget.gocuiSize.h1)) {
widgets = append(widgets, n)
found = n
}
} }
for _, child := range widget.children { for _, child := range n.children {
f(child) f(child)
} }
} }
f(me.rootNode) f(me.rootNode)
var t string // widgets has everything that matches
for _, widget := range widgets { // TODO: pop up menu with a list of them
// log(logNow, "ctrlDown() FOUND widget", widget.id, widget.name) for _, n := range widgets {
t += widget.cuiName + " " + widget.name + "\n" //log(logNow, "ctrlDown() FOUND widget", widget.id, widget.name)
widget.showWidgetPlacement(logNow, "ctrlDown() FOUND") n.showWidgetPlacement(logNow, "ctrlDown() FOUND")
} }
t = strings.TrimSpace(t) return found
}
// find the widget under the mouse click
func ctrlDown(g *gocui.Gui, v *gocui.View) error {
var found *node
// var widgets []*node
// var f func (n *node)
found = findUnderMouse()
/*
w, h := g.MousePosition()
// find buttons that are below where the mouse button click
f = func(n *node) {
widget := n.tk
// ignore widgets that are not visible
if n.Visible() {
if ((widget.gocuiSize.w0 <= w) && (w <= widget.gocuiSize.w1) &&
(widget.gocuiSize.h0 <= h) && (h <= widget.gocuiSize.h1)) {
widgets = append(widgets, n)
found = n
}
}
for _, child := range n.children {
f(child)
}
}
f(me.rootNode)
*/
if (me.ctrlDown == nil) { if (me.ctrlDown == nil) {
setupCtrlDownWidget() setupCtrlDownWidget()
me.ctrlDown.text = "ctrlDown" // t me.ctrlDown.Text = found.Name
me.ctrlDown.cuiName = "ctrlDown" me.ctrlDown.tk.cuiName = "ctrlDown"
me.ctrlDown.parent = me.rootNode // me.ctrlDown.parent = me.rootNode
} }
cd := me.ctrlDown.tk
if (found == nil) { if (found == nil) {
found = me.rootNode found = me.rootNode
} }
// ? TODO: found.setRealSize() me.ctrlDown.Text = found.Name
me.ctrlDown.gocuiSize.w0 = found.startW newR := found.realGocuiSize()
me.ctrlDown.gocuiSize.h0 = found.startH cd.gocuiSize.w0 = newR.w0
me.ctrlDown.gocuiSize.w1 = me.ctrlDown.gocuiSize.w0 + found.realWidth cd.gocuiSize.h0 = newR.h0
me.ctrlDown.gocuiSize.h1 = me.ctrlDown.gocuiSize.h0 + found.realHeight cd.gocuiSize.w1 = newR.w1
if (me.ctrlDown.v == nil) { cd.gocuiSize.h1 = newR.h1
me.ctrlDown.text = found.text if me.ctrlDown.Visible() {
me.ctrlDown.showWidgetPlacement(logNow, "ctrlDown:")
me.ctrlDown.showView()
} else {
me.ctrlDown.deleteView() me.ctrlDown.deleteView()
} else {
me.ctrlDown.updateView()
} }
me.ctrlDown.showWidgetPlacement(logNow, "ctrlDown:")
log(logNow, "ctrlDown()", w, h)
return nil return nil
} }

View File

@ -8,8 +8,9 @@ import (
// ColorBlack ColorRed ColorGreen ColorYellow ColorBlue ColorMagenta ColorCyan ColorWhite // ColorBlack ColorRed ColorGreen ColorYellow ColorBlue ColorMagenta ColorCyan ColorWhite
// gocui.GetColor("#FFAA55") // Dark Purple // gocui.GetColor("#FFAA55") // Dark Purple
func (w *cuiWidget) setDefaultWidgetColor() { func (n *node) setDefaultWidgetColor() {
log(logInfo, "setDefaultWidgetColor() on", w.widgetType, w.name) w := n.tk
log(logInfo, "setDefaultWidgetColor() on", n.WidgetType, n.Name)
v, _ := me.baseGui.View(w.cuiName) v, _ := me.baseGui.View(w.cuiName)
if (v == nil) { if (v == nil) {
log(logError, "setDefaultWidgetColor() failed on view == nil") log(logError, "setDefaultWidgetColor() failed on view == nil")
@ -24,7 +25,7 @@ func (w *cuiWidget) setDefaultWidgetColor() {
// v.BgColor = gocui.GetColor("#55AAFF") // super light grey // v.BgColor = gocui.GetColor("#55AAFF") // super light grey
// v.BgColor = gocui.GetColor("#FFC0CB") // 'w3c pink' yellow // v.BgColor = gocui.GetColor("#FFC0CB") // 'w3c pink' yellow
switch w.widgetType { switch n.WidgetType {
case toolkit.Root: case toolkit.Root:
v.FrameColor = gocui.ColorRed v.FrameColor = gocui.ColorRed
v.BgColor = gocui.GetColor("#B0E0E6") // w3c 'powerder blue' v.BgColor = gocui.GetColor("#B0E0E6") // w3c 'powerder blue'
@ -84,7 +85,8 @@ func (w *cuiWidget) SetColor(c string) {
} }
} }
func (w *cuiWidget) setDefaultHighlight() { func (n *node) setDefaultHighlight() {
w := n.tk
if (w.v == nil) { if (w.v == nil) {
log(logError, "SetColor() failed on view == nil") log(logError, "SetColor() failed on view == nil")
return return
@ -100,16 +102,17 @@ func randColor() gocui.Attribute {
return gocui.GetColor(colors[i]) return gocui.GetColor(colors[i])
} }
func (w *cuiWidget) redoColor(draw bool) { func (n *node) redoColor(draw bool) {
w := n.tk
if (w == nil) { if (w == nil) {
return return
} }
sleep(.05) sleep(.05)
w.setDefaultHighlight() n.setDefaultHighlight()
// w.setDefaultWidgetColor() n.setDefaultWidgetColor()
for _, child := range w.children { for _, child := range n.children {
child.redoColor(draw) child.redoColor(draw)
} }
} }

View File

@ -3,118 +3,182 @@ package main
import ( import (
"strconv" "strconv"
"git.wit.org/wit/gui/toolkit" "git.wit.org/wit/gui/toolkit"
// "github.com/awesome-gocui/gocui"
) )
func makeWidget(a *toolkit.Action) *cuiWidget { func makeWidget(n *node) *cuiWidget {
var w *cuiWidget var w *cuiWidget
w = new(cuiWidget) w = new(cuiWidget)
// Set(w, "default")
w.name = a.Name
w.text = a.Text
w.b = a.B
w.i = a.I
w.s = a.S
w.X = a.X
w.Y = a.Y
t := len(w.text)
w.gocuiSize.w1 = w.gocuiSize.w0 + t + me.PadW
w.gocuiSize.h1 = w.gocuiSize.h0 + me.DefaultHeight + me.PadH
w.realWidth = w.gocuiSize.Width()
w.realHeight = w.gocuiSize.Height()
// set the gocui view.Frame = true by default
w.frame = true w.frame = true
if (w.frame) {
w.realHeight += me.FramePadH
w.gocuiSize.height += me.FramePadH
}
w.widgetType = a.WidgetType
w.id = a.WidgetId
// set the name used by gocui to the id // set the name used by gocui to the id
w.cuiName = strconv.Itoa(w.id) w.cuiName = strconv.Itoa(n.WidgetId)
if w.widgetType == toolkit.Root { if n.WidgetType == toolkit.Root {
log(logInfo, "setupWidget() FOUND ROOT w.id =", w.id, "w.parent", w.parent, "ParentId =", a.ParentId) log(logInfo, "setupWidget() FOUND ROOT w.id =", n.WidgetId)
w.id = 0 n.WidgetId = 0
me.rootNode = w me.rootNode = n
return w return w
} }
w.parent = findWidget(a.ParentId, me.rootNode) if (n.WidgetType == toolkit.Box) {
log(logInfo, "setupWidget() w.id =", w.id, "w.parent", w.parent, "ParentId =", a.ParentId) if (n.B) {
if (w.parent == nil) { n.horizontal = true
log(logError, "setupWidget() ERROR: PARENT = NIL w.id =", w.id, "w.parent", w.parent, "ParentId =", a.ParentId)
// just use the rootNode (hopefully it's not nil)
w.parent = me.rootNode
// return w
}
// add this widget as a child for the parent
w.parent.Append(w)
if (a.WidgetType == toolkit.Box) {
if (a.B) {
w.horizontal = true
} else { } else {
w.horizontal = false n.horizontal = false
} }
} }
if (a.WidgetType == toolkit.Grid) {
if (n.WidgetType == toolkit.Grid) {
w.widths = make(map[int]int) // how tall each row in the grid is 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 w.heights = make(map[int]int) // how wide each column in the grid is
} }
return w return w
} }
func setupCtrlDownWidget() { func setupCtrlDownWidget() {
var w *cuiWidget a := new(toolkit.Action)
w = new(cuiWidget) a.Name = "ctrlDown"
a.WidgetType = toolkit.Dialog
a.WidgetId = -1
a.ParentId = 0
n := addNode(a)
w.name = "ctrlDown" me.ctrlDown = n
w.widgetType = toolkit.Flag
w.id = -1
me.ctrlDown = w
// me.rootNode.Append(w)
} }
func (w *cuiWidget) deleteView() { func (n *node) deleteView() {
w := n.tk
if (w.v != nil) { if (w.v != nil) {
me.baseGui.DeleteView(w.cuiName) w.v.Visible = false
return
} }
// make sure the view isn't really there
me.baseGui.DeleteView(w.cuiName)
w.v = nil w.v = nil
} }
func (n *cuiWidget) Append(child *cuiWidget) { // searches the binary tree for a WidgetId
n.children = append(n.children, child) func (n *node) findWidgetId(id int) *node {
// child.parent = n if (n == nil) {
}
// find widget by number
func findWidget(i int, w *cuiWidget) (*cuiWidget) {
if (w == nil) {
log(logVerbose, "findWidget() Trying to find i =", i, "currently checking against w.id = nil")
return nil return nil
} }
log(logVerbose, "findWidget() Trying to find i =", i, "currently checking against w.id =", w.id)
if (w.id == i) { if n.WidgetId == id {
log(logInfo, "findWidget() FOUND w.id ==", i, w.widgetType, w.name) return n
return w
} }
for _, child := range w.children { for _, child := range n.children {
newW := findWidget(i, child) newN := child.findWidgetId(id)
log(logVerbose, "findWidget() Trying to find i =", i, "currently checking against child.id =", child.id) if (newN != nil) {
if (newW != nil) { return newN
return newW
} }
} }
return nil return nil
} }
// searches the binary tree for a WidgetId
func (n *node) findWidgetName(name string) *node {
if (n == nil) {
return nil
}
if n.tk.cuiName == name {
return n
}
for _, child := range n.children {
newN := child.findWidgetName(name)
if (newN != nil) {
return newN
}
}
return nil
}
func addNode(a *toolkit.Action) *node {
n := new(node)
n.WidgetType = a.WidgetType
n.WidgetId = a.WidgetId
n.ParentId = a.ParentId
// copy the data from the action message
n.Name = a.Name
n.Text = a.Text
n.I = a.I
n.S = a.S
n.B = a.B
n.X = a.X
n.Y = a.Y
n.W = a.W
n.H = a.H
n.AtW = a.AtW
n.AtH = a.AtH
// store the internal toolkit information
n.tk = makeWidget(n)
if (a.WidgetType == toolkit.Root) {
log(logInfo, "addNode() Root")
return n
}
if (me.rootNode.findWidgetId(a.WidgetId) != nil) {
log(logError, "addNode() WidgetId already exists", a.WidgetId)
return me.rootNode.findWidgetId(a.WidgetId)
}
// add this new widget on the binary tree
n.parent = me.rootNode.findWidgetId(a.ParentId)
if n.parent != nil {
n.parent.children = append(n.parent.children, n)
//w := n.tk
//w.parent = n.parent.tk
//w.parent.children = append(w.parent.children, w)
}
return n
}
func (n *node) IsCurrent() bool {
w := n.tk
if (n.WidgetType == toolkit.Tab) {
return w.isCurrent
}
if (n.WidgetType == toolkit.Window) {
return w.isCurrent
}
if (n.WidgetType == toolkit.Root) {
return false
}
return n.parent.IsCurrent()
}
func (n *node) Visible() bool {
if (n == nil) {
return false
}
if (n.tk == nil) {
return false
}
if (n.tk.v == nil) {
return false
}
return n.tk.v.Visible
}
func (n *node) SetVisible(b bool) {
if (n == nil) {
return
}
if (n.tk == nil) {
return
}
if (n.tk.v == nil) {
return
}
n.tk.v.Visible = b
}

View File

@ -2,37 +2,72 @@ package main
import ( import (
"fmt" "fmt"
"git.wit.org/wit/gui/toolkit"
) )
func (w *cuiWidget) dumpTree(draw bool) { func (n *node) dumpTree(draw bool) {
w := n.tk
if (w == nil) { if (w == nil) {
return return
} }
w.showWidgetPlacement(logNow, "Tree:") n.showWidgetPlacement(logNow, "Tree:")
for _, child := range w.children { for _, child := range n.children {
child.dumpTree(draw) child.dumpTree(draw)
} }
} }
func (w *cuiWidget) showWidgetPlacement(b bool, s string) { func (n *node) showWidgetPlacement(b bool, s string) {
var s1 string if (n == nil) {
var pId int
if (w == nil) {
log(logError, "WTF w == nil") log(logError, "WTF w == nil")
return return
} }
if (w.parent == nil) { w := n.tk
log(logVerbose, "showWidgetPlacement() parent == nil", w.id, w.cuiName)
var s1 string
var pId int
if (n.parent == nil) {
log(logVerbose, "showWidgetPlacement() parent == nil", n.WidgetId, w.cuiName)
pId = 0 pId = 0
} else { } else {
pId = w.parent.id pId = n.parent.WidgetId
} }
s1 = fmt.Sprintf("(wId,pId)=(%2d,%2d) ", w.id, pId) s1 = fmt.Sprintf("(wId,pId)=(%2d,%2d) ", n.WidgetId, pId)
s1 += fmt.Sprintf("s/n (%2d,%2d) (%2d,%2d) ", w.startW, w.startH, w.nextW, w.nextH) s1 += fmt.Sprintf("size=(%2d,%2d)(%2d,%2d,%2d,%2d)",
s1 += fmt.Sprintf("size (%2d,%2d) ", w.realWidth, w.realHeight) w.size.Width(), w.size.Height(),
s1 += fmt.Sprintf("gocui=(%2d,%2d)(%2d,%2d,%2d,%2d)", w.size.w0, w.size.h0, w.size.w1, w.size.h1)
w.gocuiSize.Width(), w.gocuiSize.Height(), if n.Visible() {
w.gocuiSize.w0, w.gocuiSize.h0, w.gocuiSize.w1, w.gocuiSize.h1) s1 += fmt.Sprintf("gocui=(%2d,%2d)(%2d,%2d,%2d,%2d)",
log(b, s1, s, w.widgetType, ",", w.name) // , "text=", w.text) w.gocuiSize.Width(), w.gocuiSize.Height(),
w.gocuiSize.w0, w.gocuiSize.h0, w.gocuiSize.w1, w.gocuiSize.h1)
}
if (n.parent != nil) {
if (n.parent.WidgetType == toolkit.Grid) {
s1 += fmt.Sprintf("At(%2d,%2d) ", n.AtW, n.AtH)
}
}
log(b, s1, s, n.WidgetType, ",", n.Name) // , "text=", w.text)
}
func (n *node) dumpWidget(pad string) {
log(true, "node:", pad, n.WidgetId, "At(", n.AtW, n.AtH, ") ,", n.WidgetType, ",", n.Name)
}
func (n *node) listWidgets() {
if (n == nil) {
return
}
var pad string
for i := 0; i < me.depth; i++ {
pad = pad + " "
}
n.dumpWidget(pad)
for _, child := range n.children {
me.depth += 1
child.listWidgets()
me.depth -= 1
}
return
} }

View File

@ -1,37 +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"
)
func globalDown(g *gocui.Gui, v *gocui.View) error {
mx, my := g.MousePosition()
if vx0, vy0, vx1, vy1, err := g.ViewPosition("msg"); err == nil {
if mx >= vx0 && mx <= vx1 && my >= vy0 && my <= vy1 {
return msgDown(g, v)
}
}
globalMouseDown = true
maxX, _ := g.Size()
msg := fmt.Sprintf("Mouse really down at: %d,%d", mx, my) + "foo\n" + "bar\n"
x := mx - len(msg)/2
if x < 0 {
x = 0
} else if x+len(msg)+1 > maxX-1 {
x = maxX - 1 - len(msg) - 1
}
if v, err := g.SetView("globalDown", x, my-1, x+len(msg)+1, my+1, 0); err != nil {
if !errors.Is(err, gocui.ErrUnknownView) {
return err
}
v.WriteString(msg)
}
return nil
}

100
toolkit/gocui/gocui.go Normal file
View File

@ -0,0 +1,100 @@
// 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"
"github.com/awesome-gocui/gocui"
)
// This initializes the gocui package
// it runs SetManagerFunc which passes every input
// event (keyboard, mouse, etc) to the function "gocuiEvent()"
func gocuiMain() {
g, err := gocui.NewGui(gocui.OutputNormal, true)
if err != nil {
panic(err)
}
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 {
panic(err)
}
if err := g.MainLoop(); err != nil && !errors.Is(err, gocui.ErrQuit) {
panic(err)
}
}
// Thanks to the gocui developers -- your package kicks ass
// This function is called on every event. It is a callback function from the gocui package
// which has an excellent implementation. While gocui handles things like text highlighting
// and the layout of the text areas -- also things like handling SIGWINCH and lots of really
// 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(logVerbose, "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(logNow, "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(logInfo, "output widget already exists", maxX, maxY, mx, my)
}
mouseMove(g)
log(logVerbose, "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
// what is this do? I made it just 2 lines for now. Is this useful for something?
v := SetView("global", 15, 5, 80, 8, 10)
if (v == nil) {
log(logError, "setFrame() global failed")
}
v.Frame = b
}
func quit(g *gocui.Gui, v *gocui.View) error {
return gocui.ErrQuit
}
func SetView(name string, x0, y0, x1, y1 int, overlaps byte) *gocui.View {
if (me.baseGui == nil) {
log(logError, "SetView() ERROR: me.baseGui == nil")
return nil
}
v, err := me.baseGui.SetView(name, x0, y0, x1, y1, overlaps)
if err != nil {
if !errors.Is(err, gocui.ErrUnknownView) {
log(logError, "SetView() global failed on name =", name)
}
return nil
}
return v
}

View File

@ -12,25 +12,23 @@ import (
"github.com/awesome-gocui/gocui" "github.com/awesome-gocui/gocui"
) )
func addHelp() {
me.baseGui.SetManagerFunc(helplayout)
}
var helpText []string = []string{"KEYBINDINGS", var helpText []string = []string{"KEYBINDINGS",
"", "",
"d: show/hide debugging", "d: show/hide debugging",
"h: hide widgets", "s/h: show/hide all widgets",
"s: show all widgets", "L: list all widgets",
"q: quit()", "q: quit()",
"p: panic()", "p: panic()",
"o: show Stdout", "o: show Stdout",
"l: log to /tmp/witgui.log", "l: log to /tmp/witgui.log",
"Ctrl-D: Enable Debugging", "Ctrl-D: Toggle Debugging",
"Ctrl-V: Toggle Verbose Debugging",
"Ctrl-C: Exit", "Ctrl-C: Exit",
"", "",
} }
func helplayout(g *gocui.Gui) error { func helplayout() error {
g := me.baseGui
var err error var err error
maxX, _ := g.Size() maxX, _ := g.Size()

View File

@ -5,6 +5,7 @@
package main package main
import ( import (
"os"
"github.com/awesome-gocui/gocui" "github.com/awesome-gocui/gocui"
"git.wit.org/wit/gui/toolkit" "git.wit.org/wit/gui/toolkit"
) )
@ -21,7 +22,7 @@ func defaultKeybindings(g *gocui.Gui) error {
if err := g.SetKeybinding("", gocui.MouseRelease, gocui.ModNone, mouseUp); err != nil { if err := g.SetKeybinding("", gocui.MouseRelease, gocui.ModNone, mouseUp); err != nil {
return err return err
} }
if err := g.SetKeybinding("", gocui.MouseLeft, gocui.ModNone, globalDown); err != nil { if err := g.SetKeybinding("", gocui.MouseLeft, gocui.ModNone, mouseDown); err != nil {
return err return err
} }
if err := g.SetKeybinding("", gocui.MouseLeft, gocui.ModMouseCtrl, ctrlDown); err != nil { if err := g.SetKeybinding("", gocui.MouseLeft, gocui.ModMouseCtrl, ctrlDown); err != nil {
@ -47,7 +48,7 @@ func addDebugKeys(g *gocui.Gui) {
func(g *gocui.Gui, v *gocui.View) error { func(g *gocui.Gui, v *gocui.View) error {
log(logNow, "gocui.SetKeyBinding() dumpTree() START") log(logNow, "gocui.SetKeyBinding() dumpTree() START")
// me.rootNode.dumpTree(true) // me.rootNode.dumpTree(true)
fakeStartWidth = me.DevelOffsetW fakeStartWidth = me.FakeW
fakeStartHeight = me.TabH + me.FramePadH fakeStartHeight = me.TabH + me.FramePadH
if (showDebug) { if (showDebug) {
me.rootNode.showFake() me.rootNode.showFake()
@ -59,6 +60,12 @@ func addDebugKeys(g *gocui.Gui) {
return nil return nil
}) })
// display the help menu
g.SetKeybinding("", '?', gocui.ModNone,
func(g *gocui.Gui, v *gocui.View) error {
helplayout()
return nil
})
// hide all widgets // hide all widgets
g.SetKeybinding("", 'h', gocui.ModNone, g.SetKeybinding("", 'h', gocui.ModNone,
func(g *gocui.Gui, v *gocui.View) error { func(g *gocui.Gui, v *gocui.View) error {
@ -73,6 +80,26 @@ func addDebugKeys(g *gocui.Gui) {
return nil return nil
}) })
// list all widgets
g.SetKeybinding("", 'L', gocui.ModNone,
func(g *gocui.Gui, v *gocui.View) error {
me.rootNode.listWidgets()
return nil
})
// log to output window
g.SetKeybinding("", 'o', gocui.ModNone,
func(g *gocui.Gui, v *gocui.View) error {
if me.logStdout.Visible() {
me.logStdout.SetVisible(false)
setOutput(os.Stdout)
} else {
me.logStdout.SetVisible(true)
setOutput(me.logStdout.tk)
}
return nil
})
// exit // exit
g.SetKeybinding("", 'q', gocui.ModNone, g.SetKeybinding("", 'q', gocui.ModNone,
func(g *gocui.Gui, v *gocui.View) error { func(g *gocui.Gui, v *gocui.View) error {
@ -86,9 +113,28 @@ func addDebugKeys(g *gocui.Gui) {
}) })
g.SetKeybinding("", gocui.KeyCtrlD, gocui.ModNone, g.SetKeybinding("", gocui.KeyCtrlD, gocui.ModNone,
func(g *gocui.Gui, v *gocui.View) error { func(g *gocui.Gui, v *gocui.View) error {
var a toolkit.Action if (showDebug) {
a.ActionType = toolkit.EnableDebug var a toolkit.Action
me.callback <- a a.B = true
a.ActionType = toolkit.EnableDebug
me.callback <- a
logInfo = true
logVerbose = true
} else {
logInfo = false
logVerbose = false
}
return nil
})
g.SetKeybinding("", gocui.KeyCtrlV, gocui.ModNone,
func(g *gocui.Gui, v *gocui.View) error {
if (logVerbose) {
logInfo = false
logVerbose = false
} else {
logInfo = true
logVerbose = true
}
return nil return nil
}) })

View File

@ -96,7 +96,7 @@ func main() {
ferr, _ := os.OpenFile("/tmp/witgui.err", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0664) ferr, _ := os.OpenFile("/tmp/witgui.err", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0664)
os.Stderr = ferr os.Stderr = ferr
MouseMain() gocuiMain()
log(true, "MouseMain() closed") log(true, "MouseMain() closed")
standardExit() standardExit()

View File

@ -6,68 +6,13 @@ package main
import ( import (
"errors" "errors"
"fmt"
"github.com/awesome-gocui/gocui" "github.com/awesome-gocui/gocui"
) )
func MouseMain() { // this function uses the mouse position to highlight & unhighlight things
g, err := gocui.NewGui(gocui.OutputNormal, true) // this is run every time the user moves the mouse over the terminal window
if err != nil { func mouseMove(g *gocui.Gui) {
panic(err)
}
defer g.Close()
me.baseGui = g
g.Cursor = true
g.Mouse = true
g.SetManagerFunc(layout)
if err := defaultKeybindings(g); err != nil {
panic(err)
}
if err := g.MainLoop(); err != nil && !errors.Is(err, gocui.ErrQuit) {
panic(err)
}
}
func layout(g *gocui.Gui) error {
maxX, maxY := g.Size()
mx, my := g.MousePosition()
if _, err := g.View("msg"); msgMouseDown && err == nil {
moveMsg(g)
}
// TODO: figure out what this might be useful for
// what is this do? I made it just 2 lines for now. Is this useful for something?
if v, err := g.SetView("global", 15, 5, maxX, 8, 10); err != nil {
if !errors.Is(err, gocui.ErrUnknownView) {
log("global failed", maxX, maxY)
return err
}
v.Frame = false
}
helplayout(g)
if widgetView, _ := g.View("msg"); widgetView == nil {
log(logInfo, "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(logInfo, "output widget already exists", maxX, maxY, mx, my)
}
updateHighlightedView(g)
log(logInfo, "layout() END", maxX, maxY, mx, my)
return nil
}
func quit(g *gocui.Gui, v *gocui.View) error {
return gocui.ErrQuit
}
func updateHighlightedView(g *gocui.Gui) {
mx, my := g.MousePosition() mx, my := g.MousePosition()
for _, view := range g.Views() { for _, view := range g.Views() {
view.Highlight = false view.Highlight = false
@ -102,3 +47,28 @@ func mouseUp(g *gocui.Gui, v *gocui.View) error {
} }
return nil 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()
msg := fmt.Sprintf("Mouse really down at: %d,%d", mx, my) + "foo\n" + "bar\n"
x := mx - len(msg)/2
if x < 0 {
x = 0
} else if x+len(msg)+1 > maxX-1 {
x = maxX - 1 - len(msg) - 1
}
if v, err := g.SetView("globalDown", x, my-1, x+len(msg)+1, my+1, 0); err != nil {
if !errors.Is(err, gocui.ErrUnknownView) {
return err
}
v.WriteString(msg)
}
return nil
}

View File

@ -1,263 +1,196 @@
package main package main
import ( import (
"fmt" "strings"
// "github.com/awesome-gocui/gocui"
"git.wit.org/wit/gui/toolkit" "git.wit.org/wit/gui/toolkit"
) )
func (w *cuiWidget) placeBox() { func (n *node) placeBox(startW int, startH int) {
if (w.widgetType != toolkit.Box) { if (n.WidgetType != toolkit.Box) {
return return
} }
w.startW = w.parent.nextW n.tk.size.w0 = startW
w.startH = w.parent.nextH n.tk.size.h0 = startH
w.nextW = w.parent.nextW n.showWidgetPlacement(logNow, "boxS()")
w.nextH = w.parent.nextH
w.realWidth = 0
w.realHeight = 0
var maxW int newW := startW
var maxH int newH := startH
for _, child := range w.children { for _, child := range n.children {
w.showWidgetPlacement(logNow, "boxS()") child.placeWidgets(newW, newH)
child.placeWidgets() // n.showWidgetPlacement(logNow, "boxS()")
if (w.horizontal) { // w,h := child.logicalSize()
log(logVerbose, "BOX IS HORIZONTAL") newR := child.realGocuiSize()
w := newR.w1 - newR.w0
h := newR.h1 - newR.h0
if (n.horizontal) {
log(logNow, "BOX IS HORIZONTAL", n.Name, "newWH()", newW, newH, "child()", w, h, child.Name)
// expand based on the child width // expand based on the child width
w.nextW += child.realWidth newW += w
w.realWidth += child.realWidth
} else { } else {
log(logVerbose, "BOX IS VERTICAL") log(logNow, "BOX IS VERTICAL ", n.Name, "newWH()", newW, newH, "child()", w, h, child.Name)
// expand based on the child height // expand based on the child height
w.nextH += child.realHeight newH += h
w.realHeight += child.realHeight
}
if (maxW < child.realWidth) {
maxW = child.realWidth
}
if (maxH < child.realHeight) {
maxH = child.realHeight
} }
} }
if (w.horizontal) { // w,h := n.logicalSize()
w.realHeight = maxH newR := n.realGocuiSize()
} else { w := newR.w1 - newR.w0
w.realWidth = maxW h := newR.h1 - newR.h0
}
w.showWidgetPlacement(logNow, "boxE()") n.tk.size.w1 = n.tk.size.w0 + w
n.tk.size.h1 = n.tk.size.h0 + h
n.showWidgetPlacement(logNow, "boxE()")
} }
func (w *cuiWidget) placeWidgets() { func (n *node) placeWidgets(startW int, startH int) {
if (w == nil) { if (n == nil) {
return return
} }
if (me.rootNode == nil) { if (me.rootNode == nil) {
return return
} }
p := w.parent
if (p == nil) {
log(logInfo, "place()", w.id, "parent == nil")
return
}
switch w.widgetType { switch n.WidgetType {
case toolkit.Window: case toolkit.Window:
for _, child := range w.children { for _, child := range n.children {
w.startW = me.RawW child.placeWidgets(me.RawW, me.RawH)
w.startH = me.RawH return
w.nextW = me.RawW
w.nextH = me.RawH
w.showWidgetPlacement(logNow, "place()")
child.placeWidgets()
if (w.realWidth < child.realWidth) {
w.realWidth = child.realWidth
}
if (w.realHeight < child.realHeight) {
w.realHeight = child.realHeight
}
w.showWidgetPlacement(logNow, "place()")
} }
case toolkit.Tab: case toolkit.Tab:
for _, child := range w.children { for _, child := range n.children {
w.startW = me.RawW child.placeWidgets(me.RawW, me.RawH)
w.startH = me.RawH return
w.nextW = me.RawW
w.nextH = me.RawH
w.showWidgetPlacement(logNow, "place()")
child.placeWidgets()
if (w.realWidth < child.realWidth) {
w.realWidth = child.realWidth
}
if (w.realHeight < child.realHeight) {
w.realHeight = child.realHeight
}
w.showWidgetPlacement(logNow, "place()")
} }
case toolkit.Grid: case toolkit.Grid:
w.showWidgetPlacement(logNow, "placeGrid() START") n.placeGrid(startW, startH)
w.placeGrid()
w.showWidgetPlacement(logNow, "placeGrid() END")
case toolkit.Box: case toolkit.Box:
w.showWidgetPlacement(logNow, "placeBox() START") n.placeBox(startW, startH)
w.placeBox()
w.showWidgetPlacement(logNow, "placeBox() END")
case toolkit.Group: case toolkit.Group:
// move the group to the parent's next location // move the group to the parent's next location
w.startW = p.nextW n.gocuiSetWH(startW, startH)
w.startH = p.nextH n.showWidgetPlacement(logNow, "group()")
w.nextW = p.nextW
w.nextH = p.nextH
w.moveTo(p.nextW, p.nextH)
// initialize the real width to just the group gocui view newW := startW + me.GroupPadW
w.realWidth = w.gocuiSize.Width() + me.FramePadW newH := startH + 3 // normal hight of the group label
w.realHeight = w.gocuiSize.Height() + me.FramePadH // now move all the children aka: run place() on them
for _, child := range n.children {
// indent the widgets for a group child.placeWidgets(newW, newH)
w.nextW = p.nextW + me.GroupPadW // _,h := child.logicalSize()
w.nextH = p.nextH + w.realHeight newR := child.realGocuiSize()
w.showWidgetPlacement(logNow, "place()") // w := newR.w1 - newR.w0
h := newR.h1 - newR.h0
// mow move all the children aka: run place() on them
var maxW int
for _, child := range w.children {
child.showWidgetPlacement(logNow, "place()")
child.placeWidgets()
child.showWidgetPlacement(logNow, "place()")
// increment straight down // increment straight down
w.nextH += child.realHeight newH += h
w.realHeight += child.realHeight
// track largest width
if (maxW < child.realWidth) {
maxW = child.realWidth
}
} }
// add real width of largest child
w.realWidth += maxW
w.showWidgetPlacement(logNow, "place()")
default: default:
w.startW = p.nextW n.gocuiSetWH(startW, startH)
w.startH = p.nextH // n.moveTo(startW, startH)
w.nextW = p.nextW
w.nextH = p.nextH
newW := w.gocuiSize.Width()
newH := w.gocuiSize.Height()
w.gocuiSize.w0 = w.startW
w.gocuiSize.h0 = w.startH
w.gocuiSize.w1 = w.gocuiSize.w0 + newW
w.gocuiSize.h1 = w.gocuiSize.h0 + newH
// the realSize should not be smaller than the gocui view (?)
// this might not be a needed check? Maybe there are legit exceptions?
if (w.realWidth < newW) {
w.realWidth = newW
}
if (w.realHeight < newH) {
w.realHeight = newH
}
w.showWidgetPlacement(logNow, "place()")
} }
} }
/* func (n *node) placeGrid(startW int, startH int) {
func (w *cuiWidget) setWH() { w := n.tk
w.gocuiSize.w1 = w.gocuiSize.w0 + w.gocuiSize.width w.size.w0 = startW
w.gocuiSize.h1 = w.gocuiSize.h0 + w.gocuiSize.height w.size.h0 = startH
} n.showWidgetPlacement(logInfo, "grid0:")
*/ if (n.WidgetType != toolkit.Grid) {
func (w *cuiWidget) moveTo(leftW int, topH int) {
if (w.isFake) {
return return
} }
newW := w.gocuiSize.Width()
newH := w.gocuiSize.Height()
w.gocuiSize.w0 = leftW
w.gocuiSize.h0 = topH
w.gocuiSize.w1 = w.gocuiSize.w0 + newW
w.gocuiSize.h1 = w.gocuiSize.h0 + newH
w.showWidgetPlacement(logInfo, "moveTo()")
}
func (w *cuiWidget) placeGrid() { // first compute the max sizes of the rows and columns
w.showWidgetPlacement(logNow, "grid0:") for _, child := range n.children {
if (w.widgetType != toolkit.Grid) { // childW, childH := child.logicalSize()
return newR := child.realGocuiSize()
} childW := newR.w1 - newR.w0
w.startW = w.parent.nextW childH := newR.h1 - newR.h0
w.startH = w.parent.nextH
w.nextW = w.parent.nextW
w.nextH = w.parent.nextH
var wCount int = 0
var hCount int = 0
for _, child := range w.children {
// increment for the next child
w.nextW = w.startW + wCount * 20
w.nextH = w.startH + hCount * 2
// set the child's realWidth, and grid offset // set the child's realWidth, and grid offset
child.parentH = hCount if (w.widths[child.AtW] < childW) {
child.parentW = wCount w.widths[child.AtW] = childW
if (w.widths[wCount] < child.realWidth) {
w.widths[wCount] = child.realWidth
} }
if (w.heights[hCount] < child.realHeight) { if (w.heights[child.AtH] < childH) {
w.heights[hCount] = child.realHeight w.heights[child.AtH] = childH
}
log(logVerbose, "grid1: (w,h count)", wCount, hCount, "(X,Y)", w.X, w.Y, w.name)
child.showWidgetPlacement(logNow, "grid1: " + fmt.Sprintf("next()=(%2d,%2d)", w.nextW, w.nextH))
if ((wCount + 1) < w.X) {
wCount += 1
} else {
wCount = 0
hCount += 1
} }
// child.showWidgetPlacement(logInfo, "grid: ")
log(logVerbose, "placeGrid:", child.Name, "child()", childW, childH, "At()", child.AtW, child.AtH)
} }
// reset the size of the whole grid // find the width and height offset of the grid for AtW,AtH
w.realWidth = 0 for _, child := range n.children {
w.realHeight = 0 child.showWidgetPlacement(logInfo, "grid1:")
for _, val := range w.widths {
w.realWidth += val
}
for _, val := range w.heights {
w.realHeight += val
}
for _, child := range w.children {
child.showWidgetPlacement(logVerbose, "grid2:")
var totalW, totalH int var totalW, totalH int
for i, val := range w.widths { for i, w := range w.widths {
if (i < child.parentW) { if (i < child.AtW) {
log(logVerbose, "grid2: (w, widths[])", i, val) totalW += w
totalW += w.widths[i]
} }
} }
for i, h := range w.heights { for i, h := range w.heights {
if (i < child.parentH) { if (i < child.AtH) {
totalH += h totalH += h
} }
} }
// the new corner to move the child to // the new corner to move the child to
w.nextW = w.startW + totalW newW := startW + totalW
w.nextH = w.startH + totalH newH := startH + totalH
child.placeWidgets() log(logVerbose, "placeGrid:", child.Name, "new()", newW, newH, "At()", child.AtW, child.AtH)
child.placeWidgets(newW, newH)
child.showWidgetPlacement(logInfo, "grid2:") child.showWidgetPlacement(logInfo, "grid2:")
log(logInfo)
} }
// w.updateLogicalSizes() n.showWidgetPlacement(logInfo, "grid3:")
w.showWidgetPlacement(logNow, "grid3:")
} }
/* // computes the real, actual size of all the gocli objects in a widget
func (w *cuiWidget) setRealSize() { func (n *node) realGocuiSize() *rectType {
var f func (n *node, r *rectType)
newR := new(rectType)
// initialize the values to opposite
newR.w0 = 80
newR.h0 = 24
if me.baseGui != nil {
maxW, maxH := me.baseGui.Size()
newR.w0 = maxW
newR.h0 = maxH
}
newR.w1 = 0
newR.h1 = 0
// expand the rectangle to the biggest thing displayed
f = func(n *node, r *rectType) {
newR := n.tk.gocuiSize
if ! n.tk.isFake {
if r.w0 > newR.w0 {
r.w0 = newR.w0
}
if r.h0 > newR.h0 {
r.h0 = newR.h0
}
if r.w1 < newR.w1 {
r.w1 = newR.w1
}
if r.h1 < newR.h1 {
r.h1 = newR.h1
}
}
for _, child := range n.children {
f(child, r)
}
}
f(n, newR)
return newR
}
func (n *node) textSize() (int, int) {
var width, height int
for _, s := range strings.Split(n.Text, "\n") {
if (width < len(s)) {
width = len(s)
}
height += 1
}
return width, height
} }
*/

View File

@ -8,12 +8,17 @@ import (
func action(a *toolkit.Action) { func action(a *toolkit.Action) {
log(logInfo, "action() START", a.WidgetId, a.ActionType, a.WidgetType, a.Name) log(logInfo, "action() START", a.WidgetId, a.ActionType, a.WidgetType, a.Name)
w := findWidget(a.WidgetId, me.rootNode) n := me.rootNode.findWidgetId(a.WidgetId)
var w *cuiWidget
if (n != nil) {
w = n.tk
}
switch a.ActionType { switch a.ActionType {
case toolkit.Add: case toolkit.Add:
if (w == nil) { if (w == nil) {
w = makeWidget(a) n := addNode(a)
w.addWidget() // w = n.tk
n.addWidget()
} else { } else {
// this is done to protect the plugin being 'refreshed' with the // this is done to protect the plugin being 'refreshed' with the
// widget binary tree. TODO: find a way to keep them in sync // widget binary tree. TODO: find a way to keep them in sync
@ -22,16 +27,25 @@ func action(a *toolkit.Action) {
} }
case toolkit.Show: case toolkit.Show:
if (a.B) { if (a.B) {
w.showView() n.showView()
} else { } else {
w.hideWidgets() n.hideWidgets()
} }
case toolkit.Set: case toolkit.Set:
w.Set(a.A) if a.WidgetType == toolkit.Flag {
log(logNow, "TODO: set flag here", a.ActionType, a.WidgetType, a.Name)
log(logNow, "TODO: n.WidgetType =", n.WidgetType, "n.Name =", a.Name)
} else {
if (a.A == nil) {
log(logError, "TODO: Set here. a == nil", a.ActionType, "WidgetType =", a.WidgetType, "Name =", a.Name)
} else {
n.Set(a.A)
}
}
case toolkit.SetText: case toolkit.SetText:
w.SetText(a.S) n.SetText(a.S)
case toolkit.AddText: case toolkit.AddText:
w.AddText(a.S) n.AddText(a.S)
case toolkit.Move: case toolkit.Move:
log(logNow, "attempt to move() =", a.ActionType, a.WidgetType, a.Name) log(logNow, "attempt to move() =", a.ActionType, a.WidgetType, a.Name)
case toolkit.CloseToolkit: case toolkit.CloseToolkit:
@ -43,42 +57,61 @@ func action(a *toolkit.Action) {
log(logInfo, "action() END") log(logInfo, "action() END")
} }
func (w *cuiWidget) AddText(text string) { func (n *node) AddText(text string) {
if (w == nil) { if (n == nil) {
log(logNow, "widget is nil") log(logNow, "widget is nil")
return return
} }
w.vals = append(w.vals, text) n.vals = append(n.vals, text)
for i, s := range w.vals { for i, s := range n.vals {
log(logNow, "AddText()", w.name, i, s) log(logNow, "AddText()", n.Name, i, s)
} }
w.SetText(text) n.SetText(text)
} }
func (w *cuiWidget) SetText(text string) { func (n *node) SetText(text string) {
if (w == nil) { if (n == nil) {
log(logNow, "widget is nil") log(logNow, "widget is nil")
return return
} }
w.text = text n.S = text
w.s = text n.Text = text
w.textResize()
w.deleteView() n.textResize()
w.showView() n.deleteView()
n.showView()
} }
func (w *cuiWidget) Set(val any) { func (n *node) Set(val any) {
// w := n.tk
log(logInfo, "Set() value =", val) log(logInfo, "Set() value =", val)
switch v := val.(type) { switch v := val.(type) {
case bool: case bool:
w.b = val.(bool) n.B = val.(bool)
w.setCheckbox(val.(bool)) n.setCheckbox(val.(bool))
case string: case string:
w.SetText(val.(string)) n.SetText(val.(string))
case int: case int:
w.i = val.(int) n.I = val.(int)
default: default:
log(logError, "Set() unknown type =", val, v) log(logError, "Set() unknown type =", val, v)
} }
} }
// this passes the user event back from the plugin
func (n *node) doUserEvent() {
if (me.callback == nil) {
log(logError, "doUserEvent() no callback channel was configured")
return
}
var a toolkit.Action
a.WidgetId = n.WidgetId
a.Name = n.Name
a.Text = n.Text
a.B = n.B
a.ActionType = toolkit.User
log(logInfo, "doUserEvent() START: send a button click callback()", a.WidgetId, a.Name)
me.callback <- a
log(logInfo, "doUserEvent() END: sent a button click callback()", a.WidgetId, a.Name)
}

View File

@ -52,14 +52,12 @@ func makeOutputWidget(g *gocui.Gui, stringFromMouseClick string) *gocui.View {
a.WidgetType = toolkit.Stdout a.WidgetType = toolkit.Stdout
a.WidgetId = -3 a.WidgetId = -3
a.ParentId = 0 a.ParentId = 0
me.logStdout = makeWidget(a) n := addNode(a)
me.logStdout.gocuiSize.w0 = maxX - 32 me.logStdout = n
me.logStdout.gocuiSize.h0 = maxY/2 me.logStdout.tk.gocuiSize.w0 = maxX - 32
me.logStdout.gocuiSize.w1 = me.logStdout.gocuiSize.w0 + outputW me.logStdout.tk.gocuiSize.h0 = maxY/2
me.logStdout.gocuiSize.h1 = me.logStdout.gocuiSize.h0 + outputH me.logStdout.tk.gocuiSize.w1 = me.logStdout.tk.gocuiSize.w0 + outputW
me.logStdout.tk.gocuiSize.h1 = me.logStdout.tk.gocuiSize.h0 + outputH
me.logStdout.realWidth = me.logStdout.gocuiSize.Width()
me.logStdout.realHeight = me.logStdout.gocuiSize.Height()
} }
v, err := g.View("msg") v, err := g.View("msg")
if (v == nil) { if (v == nil) {
@ -78,19 +76,19 @@ func makeOutputWidget(g *gocui.Gui, stringFromMouseClick string) *gocui.View {
if (err != nil) { if (err != nil) {
log("create output window failed", err) log("create output window failed", err)
// return nil return nil
} }
if (v == nil) { if (v == nil) {
log("msg == nil. WTF now? err =", err) log("msg == nil. WTF now? err =", err)
return nil return nil
} else { } else {
me.logStdout.v = v me.logStdout.tk.v = v
} }
me.logStdout.v.Clear() v.Clear()
me.logStdout.v.SelBgColor = gocui.ColorCyan v.SelBgColor = gocui.ColorCyan
me.logStdout.v.SelFgColor = gocui.ColorBlack v.SelFgColor = gocui.ColorBlack
fmt.Fprintln(v, "figure out how to capture STDOUT to here\n" + stringFromMouseClick) fmt.Fprintln(v, "figure out how to capture STDOUT to here\n" + stringFromMouseClick)
g.SetViewOnBottom("msg") g.SetViewOnBottom("msg")
// g.SetViewOnBottom(v.Name()) // g.SetViewOnBottom(v.Name())

View File

@ -23,11 +23,12 @@ var me config
type config struct { type config struct {
baseGui *gocui.Gui // the main gocui handle baseGui *gocui.Gui // the main gocui handle
rootNode *cuiWidget // the base of the binary tree. it should have id == 0 rootNode *node // the base of the binary tree. it should have id == 0
ctrlDown *cuiWidget // shown if you click the mouse when the ctrl key is pressed
current *cuiWidget // this is the current tab or window to show ctrlDown *node // shown if you click the mouse when the ctrl key is pressed
logStdout *cuiWidget // where to show STDOUT // current *cuiWidget // this is the current tab or window to show
logStdoutV *gocui.View // where to show STDOUT logStdout *node // where to show STDOUT
helpLabel *gocui.View
// this is the channel we send user events like // this is the channel we send user events like
// mouse clicks or keyboard events back to the program // mouse clicks or keyboard events back to the program
@ -36,53 +37,47 @@ type config struct {
// this is the channel we get requests to make widgets // this is the channel we get requests to make widgets
pluginChan chan toolkit.Action pluginChan chan toolkit.Action
helpLabel *gocui.View
DefaultBehavior bool `default:"true"`
// Buttons, Group, Tabs, Windows, etc are by default assumed to be a single line
// as a default, we make buttons 8 chars wide
DefaultWidth int `default:"8"`
DefaultHeight int `default:"1"`
// When the widget has a frame, like a button, it adds 2 lines runes on each side // 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 // so you need 3 char spacing in each direction to not have them overlap
// the amount of padding when there is a frame // the amount of padding when there is a frame
FramePadW int `default:"4" dense:"0"` FramePadW int `default:"1" dense:"0"`
FramePadH int `default:"1" dense:"0"` FramePadH int `default:"1" dense:"0"`
PadW int `default:"1" dense:"0"` PadW int `default:"1" dense:"0"`
PadH int `default:"1" dense:"0"` PadH 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"`
// how far down to start Window or Tab headings // how far down to start Window or Tab headings
WindowW int `default:"8" dense:"0"` WindowW int `default:"8" dense:"0"`
WindowH int `default:"-1"` WindowH int `default:"-1"`
TabW int `default:"2" dense:"0"` TabW int `default:"5" dense:"0"`
TabH int `default:"1" 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 // additional amount of space to indent on a group
GroupPadW int `default:"6" dense:"2"` GroupPadW int `default:"6" dense:"2"`
// the raw beginning of each window (or tab) // the raw beginning of each window (or tab)
RawW int `default:"7"` RawW int `default:"1"`
RawH int `default:"3"` RawH int `default:"5"`
// offset for the hidden widgets // offset for the hidden widgets
DevelOffsetW int `default:"20"` 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? 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 canvas bool // if set to true, the windows are a raw canvas
menubar bool // for windows menubar bool // for windows
stretchy bool // expand things like buttons to the maximum size stretchy bool // expand things like buttons to the maximum size
padded bool // add space between things like buttons
margin bool // add space around the frames of windows margin bool // add space around the frames of windows
// writeMutex protects locks the write process // writeMutex protects locks the write process
writeMutex sync.Mutex writeMutex sync.Mutex
// used for listWidgets() debugging
depth int
} }
// deprecate these // deprecate these
@ -121,23 +116,21 @@ type node struct {
AtW int AtW int
AtH int AtH int
vals []string // dropdown menu items
// horizontal=true means layout widgets like books on a bookshelf
// horizontal=false means layout widgets like books in a stack
horizontal bool `default:false`
hasTabs bool // does the window have tabs?
// the internal plugin toolkit structure // the internal plugin toolkit structure
tk *cuiWidget tk *cuiWidget
} }
// the gocui way // this is the gocui way
// the logical size of the widget
// corner starts at in the upper left corner // corner starts at in the upper left corner
type rectType struct { type rectType struct {
// where the widget should calculate it's existance from
// startW int
// startH int
// the is a shortcut to access
// width int // this is always w1 - w0
height int // this is always h1 - h0
// this is the gocui way
w0, h0, w1, h1 int // left top right bottom w0, h0, w1, h1 int // left top right bottom
} }
@ -150,82 +143,27 @@ func (r *rectType) Height() int {
} }
type cuiWidget struct { type cuiWidget struct {
id int // widget ID // the gocui package variables
// parentId int v *gocui.View // this is nil if the widget is not displayed
widgetType toolkit.WidgetType
name string // a descriptive name of the widget
text string // the current text being displayed
cuiName string // what gocui uses to reference the widget cuiName string // what gocui uses to reference the widget
vals []string // dropdown menu options // 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 visable like with a Box or Grid
gocuiSize rectType
isCurrent bool // is this the currently displayed Window or Tab? isCurrent bool // is this the currently displayed Window or Tab?
hasTabs bool // does the window have tabs?
isFake bool // widget types like 'box' are 'false' isFake bool // widget types like 'box' are 'false'
// where the widget's real corner is
// should we always compute this?
startW int
startH int
// where the next child should be placed
nextW int
nextH int
// the widget size to reserve or things will overlap
realWidth int
realHeight int
gocuiSize rectType // the display size of this widget
// logicalSize rectType // the logical size. Includes all the child widgets
// used to track the size of grids // used to track the size of grids
widths map[int]int // how tall each row in the grid is widths map[int]int // how tall each row in the grid is
heights map[int]int // how wide each column in the grid is heights map[int]int // how wide each column in the grid is
// deprecate // where in the parent grid this widget should go
parentW int
parentH int
// things from toolkit/action
b bool
i int
s string
X int
Y int
width int
height int
// horizontal=true means layout widgets like books on a bookshelf
// horizontal=false means layout widgets like books in a stack
horizontal bool `default:false`
tainted bool tainted bool
v *gocui.View
frame bool frame bool
parent *cuiWidget
children []*cuiWidget
}
func (w *cuiWidget) IsCurrent() bool {
if (w.widgetType == toolkit.Tab) {
return w.isCurrent
}
if (w.widgetType == toolkit.Window) {
return w.isCurrent
}
if (w.widgetType == toolkit.Root) {
return false
}
return w.parent.IsCurrent()
}
func (w *cuiWidget) StartW() {
}
func (w *cuiWidget) StartH() {
} }
// from the gocui devs: // from the gocui devs:
@ -238,7 +176,7 @@ func (w *cuiWidget) Write(p []byte) (n int, err error) {
w.tainted = true w.tainted = true
me.writeMutex.Lock() me.writeMutex.Lock()
defer me.writeMutex.Unlock() defer me.writeMutex.Unlock()
if (me.logStdout.v == nil) { if (me.logStdout.tk.v == nil) {
// optionally write the output to /tmp // optionally write the output to /tmp
s := fmt.Sprint(string(p)) s := fmt.Sprint(string(p))
s = strings.TrimSuffix(s, "\n") s = strings.TrimSuffix(s, "\n")
@ -246,11 +184,11 @@ func (w *cuiWidget) Write(p []byte) (n int, err error) {
v, _ := me.baseGui.View("msg") v, _ := me.baseGui.View("msg")
if (v != nil) { if (v != nil) {
// fmt.Fprintln(outf, "found msg") // fmt.Fprintln(outf, "found msg")
me.logStdout.v = v me.logStdout.tk.v = v
} }
} else { } else {
// display the output in the gocui window // display the output in the gocui window
me.logStdout.v.Clear() me.logStdout.tk.v.Clear()
s := fmt.Sprint(string(p)) s := fmt.Sprint(string(p))
s = strings.TrimSuffix(s, "\n") s = strings.TrimSuffix(s, "\n")
@ -260,7 +198,7 @@ func (w *cuiWidget) Write(p []byte) (n int, err error) {
l := len(outputS) - outputH l := len(outputS) - outputH
outputS = outputS[l:] outputS = outputS[l:]
} }
fmt.Fprintln(me.logStdout.v, strings.Join(outputS, "\n")) fmt.Fprintln(me.logStdout.tk.v, strings.Join(outputS, "\n"))
} }
return len(p), nil return len(p), nil

View File

@ -3,136 +3,111 @@ package main
// implements widgets 'Window' and 'Tab' // implements widgets 'Window' and 'Tab'
import ( import (
"strings"
"git.wit.org/wit/gui/toolkit" "git.wit.org/wit/gui/toolkit"
// "github.com/awesome-gocui/gocui"
) )
func (w *cuiWidget) hideWidgets() { func (w *cuiWidget) Width() int {
w.isCurrent = false if w.frame {
switch w.widgetType { return w.gocuiSize.w1 - w.gocuiSize.w0
case toolkit.Root:
case toolkit.Flag:
case toolkit.Window:
// case toolkit.Tab:
case toolkit.Box:
case toolkit.Grid:
default:
w.deleteView()
}
for _, child := range w.children {
child.hideWidgets()
} }
return w.gocuiSize.w1 - w.gocuiSize.w0 - 1
} }
func (w *cuiWidget) hideFake() { func (w *cuiWidget) Height() int {
if (w.isFake) { if w.frame {
w.deleteView() return w.gocuiSize.h1 - w.gocuiSize.h0
}
for _, child := range w.children {
child.hideFake()
} }
return w.gocuiSize.h1 - w.gocuiSize.h0 - 1
} }
func (w *cuiWidget) showFake() { func (n *node) gocuiSetWH(sizeW, sizeH int) {
if (w.isFake) { w := len(n.Text)
w.setFake() lines := strings.Split(n.Text, "\n")
w.showWidgetPlacement(logNow, "showFake:") h := len(lines)
w.showView()
}
for _, child := range w.children {
child.showFake()
}
}
func (w *cuiWidget) showWidgets() { tk := n.tk
if (w.isFake) { if tk.isFake {
// don't display by default tk.gocuiSize.w0 = sizeW
tk.gocuiSize.h0 = sizeH
tk.gocuiSize.w1 = tk.gocuiSize.w0 + w + me.FramePadW
tk.gocuiSize.h1 = tk.gocuiSize.h0 + h + me.FramePadH
return
}
if tk.frame {
tk.size.w0 = sizeW
tk.size.h0 = sizeH
tk.gocuiSize.w0 = tk.size.w0
tk.gocuiSize.h0 = tk.size.h0
tk.gocuiSize.w1 = tk.gocuiSize.w0 + w + me.FramePadW
tk.gocuiSize.h1 = tk.gocuiSize.h0 + h + me.FramePadH
} else { } else {
if w.IsCurrent() { tk.size.w0 = sizeW - 1
w.showWidgetPlacement(logInfo, "current:") tk.size.h0 = sizeH - 1
w.showView() tk.gocuiSize.w0 = tk.size.w0
} else { tk.gocuiSize.h0 = tk.size.h0
w.showWidgetPlacement(logInfo, "not:") tk.gocuiSize.w1 = tk.gocuiSize.w0 + w + 1
// w.drawView() tk.gocuiSize.h1 = tk.gocuiSize.h0 + h + 1
}
}
func redoWindows(nextW int, nextH int) {
for _, n := range me.rootNode.children {
if n.WidgetType != toolkit.Window {
continue
} }
} w := n.tk
for _, child := range w.children { var tabs bool
child.showWidgets() for _, child := range n.children {
} if (child.WidgetType == toolkit.Tab) {
}
func (w *cuiWidget) setWindowWH() {
w.gocuiSize.w0 = me.rootNode.nextW
w.gocuiSize.h0 = me.WindowH
t := len(w.text)
w.gocuiSize.w1 = w.gocuiSize.w0 + t + me.PadW
w.gocuiSize.h1 = w.gocuiSize.h0 + me.DefaultHeight + me.PadH
w.realWidth = w.gocuiSize.Width()
w.realHeight = w.gocuiSize.Height()
// move the rootNode width over for the next window
me.rootNode.nextW += w.realWidth + me.WindowPadW
w.nextW = 4
w.nextH = 2
w.showWidgetPlacement(logNow, "setWindowWH:")
}
func (w *cuiWidget) setTabWH() {
// set the start and size of the tab gocui button
w.gocuiSize.w0 = w.parent.nextW
w.gocuiSize.h0 = me.TabH
t := len(w.text)
w.gocuiSize.w1 = w.gocuiSize.w0 + t + me.PadW
w.gocuiSize.h1 = w.gocuiSize.h0 + me.DefaultHeight + me.PadH
w.realWidth = w.gocuiSize.Width()
w.realHeight = w.gocuiSize.Height()
w.realWidth += me.FramePadW
w.realHeight += me.FramePadH
w.parent.nextW += w.realWidth + me.TabPadW
w.showWidgetPlacement(logNow, "setTabWH:")
}
func (w *cuiWidget) redoTabs(draw bool) {
if (w.widgetType == toolkit.Window) {
var tabs bool = false
// figure out if the window is just a bunch of tabs
for _, child := range w.children {
if (child.widgetType == toolkit.Tab) {
tabs = true tabs = true
} }
} }
if (tabs) { if (tabs) {
// window is tabs. Don't show it as a standard button // window is tabs. Don't show it as a standard button
w.frame = false w.frame = false
w.hasTabs = true n.hasTabs = true
} else { } else {
w.frame = true w.frame = false
w.hasTabs = false n.hasTabs = false
} }
w.setWindowWH()
w.deleteView()
w.showView()
}
if (w.widgetType == toolkit.Tab) {
w.setTabWH()
w.deleteView()
// show all the tabs for the current window
if w.parent.isCurrent {
w.showView()
}
}
for _, child := range w.children { w.size.w0 = nextW
child.redoTabs(draw) w.size.h0 = nextH
n.gocuiSetWH(nextW, nextH)
n.deleteView()
n.showView()
sizeW := w.Width() + me.WindowPadW
sizeH := w.Height()
nextW += sizeW
log(logNow, "redoWindows() start nextW,H =", nextW, nextH, "gocuiSize.W,H =", sizeW, sizeH, n.Name)
if n.hasTabs {
n.redoTabs(me.TabW, me.TabH)
}
}
}
func (p *node) redoTabs(nextW int, nextH int) {
for _, n := range p.children {
if n.WidgetType != toolkit.Tab {
continue
}
w := n.tk
w.frame = true
w.size.w0 = nextW
w.size.h0 = nextH
n.gocuiSetWH(nextW, nextH)
n.deleteView()
// setCurrentTab(n)
n.showView()
sizeW := w.Width() + me.TabPadW
sizeH := w.Height()
log(logNow, "redoTabs() start nextW,H =", nextW, nextH, "gocuiSize.W,H =", sizeW, sizeH, n.Name)
nextW += sizeW
} }
} }

View File

@ -20,10 +20,11 @@ func splitLines(s string) []string {
return lines return lines
} }
func (w *cuiWidget) textResize() { func (n *node) textResize() {
w := n.tk
var width, height int var width, height int
for i, s := range splitLines(w.text) { for i, s := range splitLines(n.Text) {
log(logNow, "textResize() len =", len(s), i, s) log(logNow, "textResize() len =", len(s), i, s)
if (width < len(s)) { if (width < len(s)) {
width = len(s) width = len(s)
@ -32,38 +33,52 @@ func (w *cuiWidget) textResize() {
} }
w.gocuiSize.w1 = w.gocuiSize.w0 + width + me.FramePadW w.gocuiSize.w1 = w.gocuiSize.w0 + width + me.FramePadW
w.gocuiSize.h1 = w.gocuiSize.h0 + height + me.FramePadH w.gocuiSize.h1 = w.gocuiSize.h0 + height + me.FramePadH
w.showWidgetPlacement(logNow, "textResize()") n.showWidgetPlacement(logNow, "textResize()")
} }
// display's the text of the widget in gocui // display's the text of the widget in gocui
func (w *cuiWidget) showView() { func (n *node) showView() {
var err error var err error
w := n.tk
if (w.cuiName == "") { if (w.cuiName == "") {
log(logError, "drawView() w.cuiName was not set for widget", w) log(logError, "showView() w.cuiName was not set for widget", w)
w.cuiName = strconv.Itoa(w.id) w.cuiName = strconv.Itoa(n.WidgetId)
} }
if (w.v != nil) { if (w.v == nil) {
log(logInfo, "drawView() w.v already defined for widget", w) n.updateView()
v, _ := me.baseGui.View(w.cuiName) }
if (v == nil) { x0, y0, x1, y1, err := me.baseGui.ViewPosition(w.cuiName)
log(logError, "drawView() ERROR view does not really exist", w) log(logInfo, "showView() w.v already defined for widget", n.Name, err)
w.v = nil if (x0 != w.gocuiSize.w0) || (y0 != w.gocuiSize.h0) {
} else { log(logError, "showView() w.v.w0 != x0", n.Name, w.gocuiSize.w0, x0)
return log(logError, "showView() w.v.h0 != y0", n.Name, w.gocuiSize.h0, y0)
} n.updateView()
return
}
if (x1 != w.gocuiSize.w1) || (y1 != w.gocuiSize.h1) {
log(logError, "showView() w.v.w1 != x1", n.Name, w.gocuiSize.w1, x1)
log(logError, "showView() w.v.h1 != y1", n.Name, w.gocuiSize.h1, y1)
n.updateView()
return
} }
if (w.v.Visible == false) {
log(logInfo, "showView() w.v.Visible set to true ", n.Name)
w.v.Visible = true
}
}
func (n *node) updateView() {
var err error
w := n.tk
if (me.baseGui == nil) { if (me.baseGui == nil) {
log(logError, "drawView() ERROR: me.baseGui == nil", w) log(logError, "showView() ERROR: me.baseGui == nil", w)
return
}
v, _ := me.baseGui.View(w.cuiName)
if (v != nil) {
log(logError, "drawView() already defined for name", w.cuiName)
w.v = v
return return
} }
me.baseGui.DeleteView(w.cuiName)
w.v = nil
a := w.gocuiSize.w0 a := w.gocuiSize.w0
b := w.gocuiSize.h0 b := w.gocuiSize.h0
@ -72,12 +87,12 @@ func (w *cuiWidget) showView() {
w.v, err = me.baseGui.SetView(w.cuiName, a, b, c, d, 0) w.v, err = me.baseGui.SetView(w.cuiName, a, b, c, d, 0)
if err == nil { if err == nil {
w.showWidgetPlacement(logError, "drawView()") n.showWidgetPlacement(logError, "drawView()")
log(logError, "drawView() internal plugin error err = nil") log(logError, "drawView() internal plugin error err = nil")
return return
} }
if !errors.Is(err, gocui.ErrUnknownView) { if !errors.Is(err, gocui.ErrUnknownView) {
w.showWidgetPlacement(logError, "drawView()") n.showWidgetPlacement(logError, "drawView()")
log(logError, "drawView() internal plugin error error.IS()", err) log(logError, "drawView() internal plugin error error.IS()", err)
return return
} }
@ -85,13 +100,68 @@ func (w *cuiWidget) showView() {
me.baseGui.SetKeybinding(w.v.Name(), gocui.MouseLeft, gocui.ModNone, click) me.baseGui.SetKeybinding(w.v.Name(), gocui.MouseLeft, gocui.ModNone, click)
w.v.Wrap = true w.v.Wrap = true
if (w.widgetType == toolkit.Window) { w.v.Frame = w.frame
w.v.Frame = w.frame w.v.Clear()
w.v.Clear() fmt.Fprint(w.v, n.Text)
fmt.Fprint(w.v, w.text) n.showWidgetPlacement(logNow, "Window: " + n.Text)
} else {
fmt.Fprintln(w.v, w.text)
}
w.setDefaultWidgetColor() n.setDefaultHighlight()
n.setDefaultWidgetColor()
}
func (n *node) hideWidgets() {
w := n.tk
w.isCurrent = false
switch n.WidgetType {
case toolkit.Root:
case toolkit.Flag:
case toolkit.Window:
case toolkit.Box:
case toolkit.Grid:
default:
n.deleteView()
}
for _, child := range n.children {
child.hideWidgets()
}
}
func (n *node) hideFake() {
w := n.tk
if (w.isFake) {
n.deleteView()
}
for _, child := range n.children {
child.hideFake()
}
}
func (n *node) showFake() {
w := n.tk
if (w.isFake) {
n.setFake()
n.showWidgetPlacement(logNow, "showFake:")
n.showView()
}
for _, child := range n.children {
child.showFake()
}
}
func (n *node) showWidgets() {
w := n.tk
if (w.isFake) {
// don't display by default
} else {
if n.IsCurrent() {
n.showWidgetPlacement(logInfo, "current:")
n.showView()
} else {
n.showWidgetPlacement(logInfo, "not:")
// w.drawView()
}
}
for _, child := range n.children {
child.showWidgets()
}
} }