tabs, windows + gocui dropdown menu (almost)
dropdown menu figures out what text was clicked dropdown menu movement changes line colors dropdown menus force user to select a response accidentally committed a binary tab selection works tab and window views almost working tabs and windows almost working window widgets selection works better color handling using gocui view.Visable flag removal of old color setting code still need an artificial delay for andlabs SetText() catching more 'nil' errors fixed the stupid duplicate tab problem in andlabs figured out how andlabs had a tab/box mess works on more than one domain builds and runs again debugging double tabs in andlabs gui GO111MODULE compile notes code reorg further improvements example cloudflare app does first successful dns update add NewEntryLine() for single line entry boxes Signed-off-by: Jeff Carr <jcarr@wit.com>
This commit is contained in:
parent
eab47f738d
commit
de771dbe98
|
@ -3,7 +3,7 @@
|
|||
# ignore compiled plugins
|
||||
*.so
|
||||
|
||||
examples/buttonplugin/buttonplugin
|
||||
examples/buttons/buttons
|
||||
examples/console-ui-helloworld/console-ui-helloworld
|
||||
examples/debug/debug
|
||||
examples/helloworld/helloworld
|
||||
|
|
38
Makefile
38
Makefile
|
@ -8,7 +8,19 @@ all: README.md
|
|||
@echo
|
||||
@echo This Requires working IPv6
|
||||
@echo
|
||||
@sleep 1
|
||||
ifeq ($(GO111MODULE),)
|
||||
@echo
|
||||
@echo If you are compiling this here, you probably want to set GO111MODULE
|
||||
@echo
|
||||
@echo Setting GO111MODULE means that the version you are compiling has plugins
|
||||
@echo that get compiled against this current running version of the code
|
||||
@echo Otherwise, the GO language plugins can complain about being compiled against
|
||||
@echo mis-matched versions
|
||||
@echo
|
||||
@echo export GO111MODULE=off
|
||||
@echo
|
||||
sleep 3
|
||||
endif
|
||||
ifeq (,$(wildcard go.mod))
|
||||
go mod init gui
|
||||
go mod tidy
|
||||
|
@ -35,8 +47,11 @@ examples: \
|
|||
examples-helloworld \
|
||||
examples-buttons \
|
||||
examples-console-ui-helloworld \
|
||||
examples-textbox \
|
||||
examples-debug
|
||||
examples-cloudflare
|
||||
|
||||
# this is the most basic one. This syntax should always work
|
||||
examples-helloworld:
|
||||
make -C examples/helloworld
|
||||
|
||||
examples-buttons:
|
||||
make -C examples/buttons
|
||||
|
@ -44,18 +59,8 @@ examples-buttons:
|
|||
examples-console-ui-helloworld:
|
||||
make -C examples/console-ui-helloworld
|
||||
|
||||
# this is the most basic one. This syntax should always work
|
||||
examples-helloworld:
|
||||
make -C examples/helloworld
|
||||
|
||||
examples-debug:
|
||||
-make -C examples/debug
|
||||
|
||||
examples-textbox:
|
||||
make -C examples/textbox
|
||||
|
||||
examples-helloconsole:
|
||||
make -C examples/plugin-consoleonly
|
||||
examples-cloudflare:
|
||||
-make -C examples/cloudflare
|
||||
|
||||
# sync repo to the github backup
|
||||
# git remote add github git@github.com:witorg/gui.git
|
||||
|
@ -102,3 +107,6 @@ objdump:
|
|||
log:
|
||||
reset
|
||||
tail -f /tmp/witgui.* /tmp/guilogfile
|
||||
|
||||
submit-to-docs:
|
||||
GOPROXY=https://proxy.golang.org GO111MODULE=on go get go.wit.com/gui@v1.0.0
|
||||
|
|
17
button.go
17
button.go
|
@ -11,22 +11,6 @@ func (parent *Node) NewButton(name string, custom func()) *Node {
|
|||
return newNode
|
||||
}
|
||||
|
||||
/*
|
||||
// deprecate this once andlabs is refactored
|
||||
func callback(i int) bool {
|
||||
log(debugError, "callback() for widget id =", i)
|
||||
n := me.rootNode.FindId(i)
|
||||
log(debugError, "callback() found node =", n)
|
||||
// running custom here means the button get's clicked twice
|
||||
if (n.Custom == nil) {
|
||||
log(debugError, "callback() = nil. SKIPPING")
|
||||
return false
|
||||
}
|
||||
n.Custom()
|
||||
return true
|
||||
}
|
||||
*/
|
||||
|
||||
// find widget by number
|
||||
func (n *Node) FindId(i int) (*Node) {
|
||||
if (n == nil) {
|
||||
|
@ -45,4 +29,3 @@ func (n *Node) FindId(i int) (*Node) {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
2
chan.go
2
chan.go
|
@ -14,6 +14,8 @@ import (
|
|||
"github.com/sourcegraph/conc/panics"
|
||||
)
|
||||
|
||||
// this should never exit
|
||||
// TODO: clean up all this poorly named code
|
||||
func makeConc() {
|
||||
var wg conc.WaitGroup
|
||||
defer wg.Wait()
|
||||
|
|
5
debug.go
5
debug.go
|
@ -140,9 +140,8 @@ func (n *Node) dumpWidget(b bool) string {
|
|||
for i := 0; i < listChildrenDepth; i++ {
|
||||
tabs = tabs + defaultPadding
|
||||
}
|
||||
d = tabs + d
|
||||
logindent(b, listChildrenDepth, defaultPadding, n.id, info)
|
||||
return d
|
||||
logindent(b, listChildrenDepth, defaultPadding, d)
|
||||
return tabs + d
|
||||
}
|
||||
|
||||
// func (n *Node) ListChildren(dump bool, dropdown *Node, mapNodes map[string]*Node) {
|
||||
|
|
|
@ -16,3 +16,6 @@ update:
|
|||
log:
|
||||
reset
|
||||
tail -f /tmp/witgui.* /tmp/guilogfile
|
||||
|
||||
gocui: build
|
||||
./cloudflare -gui gocui >/tmp/witgui.log.stderr 2>&1
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
// This is a simple example
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"log"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"bytes"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
func doChange(dnsRow *RRT) {
|
||||
log.Println("Look for changes in row", dnsRow.ID)
|
||||
log.Println("Proxy", dnsRow.Proxied, "vs", dnsRow.proxyNode.S)
|
||||
log.Println("Content", dnsRow.Content, "vs", dnsRow.valueNode.S)
|
||||
if (dnsRow.Content != dnsRow.valueNode.S) {
|
||||
log.Println("UPDATE VALUE", dnsRow.nameNode.Name, dnsRow.typeNode.Name, "to", dnsRow.valueNode.S)
|
||||
httpPut(dnsRow)
|
||||
}
|
||||
dnsRow.saveNode.Disable()
|
||||
}
|
||||
|
||||
func getZonefile(c *configT) *DNSRecords {
|
||||
var url = cloudflareURL + c.zoneID + "/dns_records/"
|
||||
log.Println("getZonefile()", c.domain, url)
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
log.Println("http.NewRequest error:", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set headers
|
||||
req.Header.Set("X-Auth-Key", c.auth)
|
||||
req.Header.Set("X-Auth-Email", c.email)
|
||||
|
||||
log.Println("getZonefile() auth, email", c.auth, c.email)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Println("http.Client error:", err)
|
||||
return nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Println("ioutil.ReadAll() error", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
var records DNSRecords
|
||||
if err := json.Unmarshal(body, &records); err != nil {
|
||||
log.Println("json.Unmarshal() error", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Println("getZonefile() worked", records)
|
||||
return &records
|
||||
}
|
||||
|
||||
/*
|
||||
pass in a DNS Resource Records (the stuff in a zonefile)
|
||||
|
||||
This will talk to the cloudflare API and generate a resource record in the zonefile:
|
||||
|
||||
For example:
|
||||
gitea.wit.com. 3600 IN CNAME git.wit.org.
|
||||
go.wit.com. 3600 IN A 1.1.1.9
|
||||
test.wit.com. 3600 IN NS ns1.wit.com.
|
||||
*/
|
||||
func httpPut(dnsRow *RRT) {
|
||||
var url string = cloudflareURL + os.Getenv("CLOUDFLARE_ZONEID") + "/dns_records/" + dnsRow.ID
|
||||
var authKey string = os.Getenv("CLOUDFLARE_AUTHKEY")
|
||||
var email string = os.Getenv("CLOUDFLARE_EMAIL")
|
||||
|
||||
// make a json record to send on port 90 to cloudflare
|
||||
var tmp string
|
||||
tmp = `{"content": "` + dnsRow.valueNode.S + `", `
|
||||
tmp += `"name": "` + dnsRow.Name + `", `
|
||||
tmp += `"type": "` + dnsRow.Type + `", `
|
||||
tmp+= `"ttl": "` + strconv.Itoa(dnsRow.TTL) + `", `
|
||||
tmp += `"comment": "WIT DNS Control Panel"`
|
||||
tmp += `}`
|
||||
data := []byte(tmp)
|
||||
|
||||
log.Println("http PUT url =", url)
|
||||
log.Println("http PUT data =", data)
|
||||
spew.Dump(data)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(data))
|
||||
|
||||
// Set headers
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
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 {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
log.Println("http PUT body =", body)
|
||||
spew.Dump(body)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// https://api.cloudflare.com/client/v4/zones
|
||||
func getZones(auth, email string) *DNSRecords {
|
||||
var url = "https://api.cloudflare.com/client/v4/zones"
|
||||
log.Println("getZones()", url)
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
log.Println("http.NewRequest error:", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set headers
|
||||
req.Header.Set("X-Auth-Key", auth)
|
||||
req.Header.Set("X-Auth-Email", email)
|
||||
|
||||
log.Println("getZones() auth, email", auth, email)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Println("getZones() http.Client error:", err)
|
||||
return nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Println("getZones() ioutil.ReadAll() error", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
var records DNSRecords
|
||||
if err := json.Unmarshal(body, &records); err != nil {
|
||||
log.Println("getZones() json.Unmarshal() error", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
/* Cloudflare API returns struct[] of:
|
||||
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\"" }
|
||||
*/
|
||||
|
||||
// log.Println("getZones() worked", records)
|
||||
// log.Println("spew dump:")
|
||||
spew.Dump(records)
|
||||
for _, record := range records.Result {
|
||||
log.Println("spew record:", record)
|
||||
log.Println("record:", record.Name, record.ID)
|
||||
|
||||
var newc *configT
|
||||
newc = new(configT)
|
||||
|
||||
newc.domain = record.Name
|
||||
newc.zoneID = record.ID
|
||||
newc.auth = auth
|
||||
newc.email = email
|
||||
|
||||
config[record.Name] = newc
|
||||
zonedrop.AddText(record.Name)
|
||||
log.Println("zonedrop.AddText:", record.Name, record.ID)
|
||||
}
|
||||
for d, _ := range config {
|
||||
log.Println("config entry:", d)
|
||||
}
|
||||
|
||||
return &records
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
|
||||
-H "Authorization: Bearer AAAPutYourTokenInHereSoYouCanTestItL5Cl3" \
|
||||
-H "Content-Type:application/json"
|
|
@ -1,132 +0,0 @@
|
|||
// 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")
|
||||
|
||||
newt := mainWindow.NewTab(hostname)
|
||||
newg := newt.NewGroup("more")
|
||||
grid := newg.NewGrid("gridnuts", 5, gridH)
|
||||
|
||||
// grid.NewButton("Type", func () {
|
||||
// log.Println("sort by Type")
|
||||
// })
|
||||
typedrop := grid.NewDropdown("type")
|
||||
typedrop.AddText("A")
|
||||
typedrop.AddText("AAAA")
|
||||
typedrop.AddText("CNAME")
|
||||
typedrop.Custom = func () {
|
||||
log.Println("custom dropdown() a =", typedrop.Name, typedrop.S)
|
||||
}
|
||||
grid.NewButton("Name", func () {
|
||||
log.Println("sort by Name")
|
||||
})
|
||||
grid.NewButton("Protection", func () {
|
||||
log.Println("sort proxied")
|
||||
})
|
||||
grid.NewButton("TTL", func () {
|
||||
log.Println("sort by TTL")
|
||||
})
|
||||
grid.NewButton("Value", func () {
|
||||
log.Println("sort by Value")
|
||||
})
|
||||
|
||||
newt.NewButton("Save", func () {
|
||||
log.Println("save stuff to cloudflare")
|
||||
})
|
||||
|
||||
records := getRecords()
|
||||
for _, record := range records.Result {
|
||||
grid.NewLabel(record.Type)
|
||||
textbox := grid.NewTextbox(record.Name)
|
||||
textbox.SetText(record.Name)
|
||||
if (record.Proxied) {
|
||||
grid.NewLabel("Proxied")
|
||||
} else {
|
||||
grid.NewLabel("DNS")
|
||||
}
|
||||
var ttl, short string
|
||||
if (record.TTL == 1) {
|
||||
ttl = "Auto"
|
||||
} else {
|
||||
ttl = strconv.Itoa(record.TTL)
|
||||
}
|
||||
grid.NewLabel(ttl)
|
||||
// short = fmt.Sprintf("%80s", record.Content)
|
||||
short = record.Content
|
||||
if len(short) > 40 {
|
||||
short = short[:40] // Slice the first 20 characters
|
||||
}
|
||||
|
||||
namebox := grid.NewTextbox(short)
|
||||
namebox.SetText(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
|
||||
}
|
||||
|
||||
return &records
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
// This is a simple example
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func loadDNS(c *configT) {
|
||||
hostname := c.domain
|
||||
log.Println("adding DNS record", hostname)
|
||||
|
||||
newt := mainWindow.NewTab(hostname)
|
||||
newg := newt.NewGroup("more")
|
||||
|
||||
// make a grid 6 things wide
|
||||
grid := newg.NewGrid("gridnuts", 6, gridH)
|
||||
|
||||
// grid.NewButton("Type", func () {
|
||||
// log.Println("sort by Type")
|
||||
// })
|
||||
typedrop := grid.NewDropdown("type")
|
||||
typedrop.AddText("A")
|
||||
typedrop.AddText("AAAA")
|
||||
typedrop.AddText("CNAME")
|
||||
typedrop.Custom = func () {
|
||||
log.Println("custom dropdown() a =", typedrop.Name, typedrop.S)
|
||||
}
|
||||
nb := grid.NewButton("Name", func () {
|
||||
log.Println("sort by Name")
|
||||
})
|
||||
nb.Disable()
|
||||
|
||||
grid.NewButton("Protection", func () {
|
||||
log.Println("sort proxied")
|
||||
})
|
||||
grid.NewButton("TTL", func () {
|
||||
log.Println("sort by TTL")
|
||||
})
|
||||
nb = grid.NewButton("Value", func () {
|
||||
log.Println("sort by Value")
|
||||
})
|
||||
nb.Disable()
|
||||
nb = grid.NewButton("Save", func () {
|
||||
log.Println("click below to save")
|
||||
})
|
||||
nb.Disable()
|
||||
|
||||
masterSave = newt.NewButton("Master Save", func () {
|
||||
log.Println("save stuff to cloudflare")
|
||||
})
|
||||
masterSave.Disable()
|
||||
|
||||
records := getZonefile(c)
|
||||
for _, record := range records.Result {
|
||||
var rr RRT // dns zonefile resource record
|
||||
|
||||
// copy all the JSON values into the row record.
|
||||
rr.ID = record.ID
|
||||
rr.Type = record.Type
|
||||
rr.Name = record.Name
|
||||
rr.Content = record.Content
|
||||
rr.Proxied = record.Proxied
|
||||
rr.Proxiable = record.Proxiable
|
||||
rr.TTL = record.TTL
|
||||
|
||||
rr.typeNode = grid.NewLabel(record.Type)
|
||||
rr.nameNode = grid.NewEntryLine(record.Name)
|
||||
rr.nameNode.SetText(record.Name)
|
||||
rr.nameNode.Disable()
|
||||
|
||||
// set proxy or unproxied
|
||||
rr.proxyNode = grid.NewDropdown("proxy")
|
||||
if (record.Proxied) {
|
||||
rr.proxyNode.AddText("Proxied")
|
||||
rr.proxyNode.AddText("DNS")
|
||||
} else {
|
||||
rr.proxyNode.AddText("DNS")
|
||||
rr.proxyNode.AddText("Proxied")
|
||||
}
|
||||
rr.proxyNode.Custom = func () {
|
||||
log.Println("proxy dropdown() a =", rr.proxyNode.Name, rr.proxyNode.S, rr.ID)
|
||||
rr.saveNode.Enable()
|
||||
masterSave.Enable()
|
||||
}
|
||||
|
||||
var ttl, short string
|
||||
if (record.TTL == 1) {
|
||||
ttl = "Auto"
|
||||
} else {
|
||||
ttl = strconv.Itoa(record.TTL)
|
||||
}
|
||||
rr.ttlNode = grid.NewLabel(ttl)
|
||||
// short = fmt.Sprintf("%80s", record.Content)
|
||||
short = record.Content
|
||||
if len(short) > 40 {
|
||||
short = short[:40] // Slice the first 20 characters
|
||||
}
|
||||
|
||||
rr.valueNode = grid.NewEntryLine(short)
|
||||
rr.valueNode.SetText(record.Content)
|
||||
|
||||
rr.valueNode.Custom = func () {
|
||||
log.Println("value changed =", rr.valueNode.Name, rr.proxyNode.S, rr.ID)
|
||||
rr.saveNode.Enable()
|
||||
masterSave.Enable()
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
rr.saveNode = grid.NewButton("Save", nil)
|
||||
rr.saveNode.Disable()
|
||||
rr.saveNode.Custom = func () {
|
||||
name := "save stuff to cloudflare for " + rr.ID
|
||||
log.Println(name)
|
||||
doChange(&rr)
|
||||
}
|
||||
}
|
||||
|
||||
grid.Pad()
|
||||
}
|
|
@ -5,11 +5,14 @@ import (
|
|||
"os"
|
||||
"fmt"
|
||||
"log"
|
||||
"bufio"
|
||||
"strings"
|
||||
"git.wit.org/wit/gui"
|
||||
)
|
||||
|
||||
var title string = "Cloudflare DNS Control Panel"
|
||||
var outfile string = "/tmp/guilogfile"
|
||||
var configfile string = ".config/wit/cloudflare"
|
||||
var myGui *gui.Node
|
||||
|
||||
var buttonCounter int = 5
|
||||
|
@ -19,8 +22,10 @@ var gridH int = 3
|
|||
var mainWindow, more, more2 *gui.Node
|
||||
|
||||
func main() {
|
||||
config = make(map[string]*configT)
|
||||
readConfig()
|
||||
myGui = gui.New().Default()
|
||||
buttonWindow()
|
||||
makeCloudflareWindow()
|
||||
|
||||
// This is just a optional goroutine to watch that things are alive
|
||||
gui.Watchdog()
|
||||
|
@ -28,30 +33,90 @@ func main() {
|
|||
}
|
||||
|
||||
// This creates a window
|
||||
func buttonWindow() {
|
||||
var t, g *gui.Node
|
||||
func makeCloudflareWindow() {
|
||||
var t *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)
|
||||
// this tab has the master cloudflare API credentials
|
||||
makeConfigTab(mainWindow)
|
||||
|
||||
// more2 = g1.NewGrid("gridnuts", gridW, gridH)
|
||||
t = mainWindow.NewTab("Zones")
|
||||
g1 := t.NewGroup("zones")
|
||||
|
||||
var domain string = os.Getenv("CLOUDFLARE_DOMAIN")
|
||||
if (domain == "") {
|
||||
domain = "example.org"
|
||||
// make dropdown list of zones
|
||||
zonedrop = g1.NewDropdown("zone")
|
||||
zonedrop.AddText("example.org")
|
||||
for d, _ := range config {
|
||||
zonedrop.AddText(d)
|
||||
}
|
||||
|
||||
g.NewButton("Load " + domain + " DNS", func () {
|
||||
loadDNS(domain)
|
||||
zonedrop.Custom = func () {
|
||||
domain := zonedrop.S
|
||||
log.Println("custom dropdown() zone (domain name) =", zonedrop.Name, domain)
|
||||
if (config[domain] == nil) {
|
||||
log.Println("custom dropdown() config[domain] = nil for domain =", domain)
|
||||
domainWidget.SetText(domain)
|
||||
zoneWidget.SetText("")
|
||||
authWidget.SetText("")
|
||||
emailWidget.SetText("")
|
||||
} else {
|
||||
log.Println("custom dropdown() a =", domain, config[domain].zoneID, config[domain].auth, config[domain].email)
|
||||
domainWidget.SetText(config[domain].domain)
|
||||
zoneWidget.SetText(config[domain].zoneID)
|
||||
authWidget.SetText(config[domain].auth)
|
||||
emailWidget.SetText(config[domain].email)
|
||||
}
|
||||
}
|
||||
|
||||
more = g1.NewGroup("data")
|
||||
showCloudflareCredentials(more)
|
||||
|
||||
makeDebugTab(mainWindow)
|
||||
}
|
||||
|
||||
func makeConfigTab(window *gui.Node) {
|
||||
t := window.NewTab("Get Zones")
|
||||
vb := t.NewBox("vBox", false)
|
||||
g1 := vb.NewGroup("Cloudflare API Config")
|
||||
|
||||
g1.NewLabel("If you have an API key with access to list all of /n your zone files, enter it here. \n \n Alternatively, you can set the enviroment variables: \n env $CLOUDFLARE_AUTHKEY \n env $CLOUDFLARE_EMAIL \n env $CLOUDFLARE_URL \n")
|
||||
|
||||
// make grid to display credentials
|
||||
grid := g1.NewGrid("credsGrid", 2, 4) // width = 2
|
||||
|
||||
grid.NewLabel("Auth Key")
|
||||
aw := grid.NewEntryLine(os.Getenv("CLOUDFLARE_AUTHKEY"))
|
||||
aw.SetText(os.Getenv("CLOUDFLARE_AUTHKEY"))
|
||||
|
||||
grid.NewLabel("Email")
|
||||
ew := grid.NewEntryLine(os.Getenv("CLOUDFLARE_EMAIL"))
|
||||
ew.SetText(os.Getenv("CLOUDFLARE_EMAIL"))
|
||||
|
||||
var url string = "https://api.cloudflare.com/client/v4/zones/"
|
||||
grid.NewLabel("Cloudflare API")
|
||||
grid.NewLabel(url)
|
||||
|
||||
grid.Pad()
|
||||
|
||||
vb.NewButton("getZones()", func () {
|
||||
log.Println("getZones()")
|
||||
getZones(aw.S, ew.S)
|
||||
})
|
||||
|
||||
t.Pad()
|
||||
t.Margin()
|
||||
vb.Pad()
|
||||
vb.Margin()
|
||||
g1.Pad()
|
||||
g1.Margin()
|
||||
}
|
||||
|
||||
func makeDebugTab(window *gui.Node) {
|
||||
t2 := window.NewTab("debug")
|
||||
g := t2.NewGroup("debug")
|
||||
g.NewButton("Load 'gocui'", func () {
|
||||
// this set the xterm and mate-terminal window title. maybe works generally?
|
||||
fmt.Println("\033]0;" + title + "blah \007")
|
||||
|
@ -65,20 +130,103 @@ func buttonWindow() {
|
|||
g.NewButton("gui.DebugWindow()", func () {
|
||||
gui.DebugWindow()
|
||||
})
|
||||
|
||||
g.NewButton("List all Widgets", func () {
|
||||
myGui.ListChildren(true)
|
||||
})
|
||||
g.NewButton("Dump all Widgets", func () {
|
||||
myGui.Dump()
|
||||
})
|
||||
}
|
||||
|
||||
func showCloudflareCredentials(box *gui.Node) {
|
||||
// make grid to display credentials
|
||||
grid := box.NewGrid("credsGrid", 2, 4) // width = 2
|
||||
|
||||
grid.NewLabel("Domain")
|
||||
grid.NewLabel(os.Getenv("CLOUDFLARE_DOMAIN"))
|
||||
domainWidget = grid.NewEntryLine(os.Getenv("CLOUDFLARE_DOMAIN"))
|
||||
|
||||
grid.NewLabel("Zone ID")
|
||||
zoneWidget = grid.NewEntryLine(os.Getenv("CLOUDFLARE_ZONEID"))
|
||||
|
||||
grid.NewLabel("Auth Key")
|
||||
grid.NewLabel(os.Getenv("CLOUDFLARE_AUTHKEY"))
|
||||
authWidget = grid.NewEntryLine(os.Getenv("CLOUDFLARE_AUTHKEY"))
|
||||
|
||||
grid.NewLabel("Email")
|
||||
grid.NewLabel(os.Getenv("CLOUDFLARE_EMAIL"))
|
||||
emailWidget = grid.NewEntryLine(os.Getenv("CLOUDFLARE_EMAIL"))
|
||||
|
||||
grid.NewLabel("URL")
|
||||
grid.NewLabel(os.Getenv("CLOUDFLARE_URL"))
|
||||
var url string = "https://api.cloudflare.com/client/v4/zones/"
|
||||
grid.NewLabel("Cloudflare API")
|
||||
grid.NewLabel(url)
|
||||
|
||||
grid.Pad()
|
||||
|
||||
saveButton = box.NewButton("Save to config", func () {
|
||||
})
|
||||
saveButton.Disable()
|
||||
|
||||
loadButton = box.NewButton("Load Cloudflare DNS zonefile", func () {
|
||||
var domain configT
|
||||
domain.domain = domainWidget.S
|
||||
domain.zoneID = zoneWidget.S
|
||||
domain.auth = authWidget.S
|
||||
domain.email = emailWidget.S
|
||||
loadDNS(&domain)
|
||||
})
|
||||
}
|
||||
|
||||
func readConfig() {
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
log.Println("searchPaths() error. exiting here?")
|
||||
}
|
||||
filename := homeDir + "/" + configfile
|
||||
log.Println("filename =", filename)
|
||||
|
||||
readFileLineByLine(filename)
|
||||
// os.Exit(0)
|
||||
}
|
||||
|
||||
// readFileLineByLine opens a file and reads through each line.
|
||||
func readFileLineByLine(filename string) error {
|
||||
// Open the file.
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
log.Println("readFileLineByLine() =", filename)
|
||||
|
||||
// Create a new Scanner for the file.
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
// Read through each line using scanner.
|
||||
for scanner.Scan() {
|
||||
var newc *configT
|
||||
newc = new(configT)
|
||||
|
||||
line := scanner.Text()
|
||||
parts := strings.Fields(line)
|
||||
|
||||
if (len(parts) < 4) {
|
||||
log.Println("readFileLineByLine() SKIP =", parts)
|
||||
continue
|
||||
}
|
||||
|
||||
newc.domain = parts[0]
|
||||
newc.zoneID = parts[1]
|
||||
newc.auth = parts[2]
|
||||
newc.email = parts[3]
|
||||
|
||||
config[parts[0]] = newc
|
||||
log.Println("readFileLineByLine() =", newc.domain, newc.zoneID, newc.auth, newc.email)
|
||||
}
|
||||
|
||||
// Check for errors during Scan.
|
||||
if err := scanner.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
// This is a simple example
|
||||
package main
|
||||
|
||||
import (
|
||||
"git.wit.org/wit/gui"
|
||||
)
|
||||
|
||||
var cloudflareURL string = "https://api.cloudflare.com/client/v4/zones/"
|
||||
|
||||
// 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 masterSave *gui.Node
|
||||
|
||||
var domainWidget *gui.Node
|
||||
var zoneWidget *gui.Node
|
||||
var authWidget *gui.Node
|
||||
var emailWidget *gui.Node
|
||||
|
||||
var loadButton *gui.Node
|
||||
var saveButton *gui.Node
|
||||
var zonedrop *gui.Node
|
||||
|
||||
// Resource Record (used in a DNS zonefile)
|
||||
type RRT struct {
|
||||
typeNode *gui.Node
|
||||
nameNode *gui.Node
|
||||
proxyNode *gui.Node
|
||||
ttlNode *gui.Node
|
||||
valueNode *gui.Node
|
||||
saveNode *gui.Node
|
||||
|
||||
ID string
|
||||
Type string
|
||||
Name string
|
||||
Content string
|
||||
Proxied bool
|
||||
Proxiable bool
|
||||
TTL int
|
||||
}
|
||||
|
||||
/*
|
||||
This is a structure of all the RR's (Resource Records)
|
||||
in the DNS zonefiile for a hostname. For example:
|
||||
|
||||
For the host test.wit.com:
|
||||
|
||||
test.wit.com A 127.0.0.1
|
||||
test.wit.com AAAA
|
||||
test.wit.com TXT email test@wit.com
|
||||
test.wit.com TXT phone 212-555-1212
|
||||
test.wit.com CNAME real.wit.com
|
||||
*/
|
||||
type hostT struct {
|
||||
hostname string
|
||||
RRs []configT
|
||||
}
|
||||
|
||||
type configT struct {
|
||||
domain string
|
||||
zoneID string
|
||||
auth string
|
||||
email string
|
||||
}
|
||||
|
||||
var config map[string]*configT
|
2
main.go
2
main.go
|
@ -61,7 +61,7 @@ func watchCallback() {
|
|||
}
|
||||
// this maybe a good idea?
|
||||
// TODO: Throttle user events somehow
|
||||
sleep(.01)
|
||||
// sleep(.01) // hack that throttles user events
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,7 +132,6 @@ func searchPaths(name string) *aplug {
|
|||
log(logError, filename, "was not embedded in the binary. Error:", err)
|
||||
}
|
||||
|
||||
log(logError, "fuck off")
|
||||
// attempt to write out the file from the internal resource
|
||||
filename = "toolkit/" + name + ".so"
|
||||
p := initToolkit(name, filename)
|
||||
|
@ -254,7 +253,7 @@ func sendAction(a *toolkit.Action) {
|
|||
log(logInfo, "Action() SEND to pluginChan", aplug.name)
|
||||
aplug.pluginChan <- *a
|
||||
// added during debugging. might be a good idea in general for a tactile experience
|
||||
sleep(.02)
|
||||
sleep(.02) // this delay makes it so SetText() works on initial widget creation
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -303,7 +302,7 @@ func (n *Node) LoadToolkit(name string) *Node {
|
|||
var a toolkit.Action
|
||||
a.ActionType = toolkit.InitToolkit
|
||||
plug.pluginChan <- a
|
||||
sleep(.5) // temp hack until chan communication is setup
|
||||
// sleep(.5) // temp hack until chan communication is setup
|
||||
|
||||
// TODO: find a new way to do this that is locking, safe and accurate
|
||||
me.rootNode.redraw(plug)
|
||||
|
@ -320,7 +319,7 @@ func (n *Node) CloseToolkit(name string) bool {
|
|||
var a toolkit.Action
|
||||
a.ActionType = toolkit.CloseToolkit
|
||||
plug.pluginChan <- a
|
||||
sleep(.5)
|
||||
// sleep(.5) // is this needed? TODO: properly close channel
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
3
tab.go
3
tab.go
|
@ -10,7 +10,6 @@ import (
|
|||
func (n *Node) NewTab(text string) *Node {
|
||||
// check to make sure n is actually a window
|
||||
|
||||
|
||||
if (n.WidgetType != toolkit.Window) {
|
||||
// figure out what the actual window is
|
||||
log(logError, "NewTab() is being requested on something that isn't a Window. node =", n)
|
||||
|
@ -35,7 +34,7 @@ func (n *Node) NewTab(text string) *Node {
|
|||
|
||||
// by default, create a box inside the tab
|
||||
// TODO: allow this to be configurable
|
||||
newBox := newNode.NewBox(text, true)
|
||||
newBox := newNode.NewBox(text + " box", true)
|
||||
|
||||
return newBox
|
||||
}
|
||||
|
|
14
textbox.go
14
textbox.go
|
@ -15,3 +15,17 @@ func (parent *Node) NewTextbox(name string) *Node {
|
|||
sendAction(a)
|
||||
return newNode
|
||||
}
|
||||
|
||||
func (parent *Node) NewEntryLine(name string) *Node {
|
||||
newNode := parent.newNode(name, toolkit.Textbox)
|
||||
|
||||
newNode.X = 1
|
||||
|
||||
newNode.Custom = func() {
|
||||
log(debugGui, "NewTextbox changed =", name)
|
||||
}
|
||||
|
||||
a := newAction(newNode, toolkit.Add)
|
||||
sendAction(a)
|
||||
return newNode
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"github.com/andlabs/ui"
|
||||
"git.wit.org/wit/gui/toolkit"
|
||||
)
|
||||
|
@ -20,6 +21,9 @@ func (n *node) show(b bool) {
|
|||
}
|
||||
|
||||
func (n *node) enable(b bool) {
|
||||
if n == nil {
|
||||
panic("WHAT? enable was passed nil. How does this even happen?")
|
||||
}
|
||||
if n.tk == nil {
|
||||
return
|
||||
}
|
||||
|
@ -193,12 +197,32 @@ func rawAction(a toolkit.Action) {
|
|||
|
||||
n := rootNode.findWidgetId(a.WidgetId)
|
||||
|
||||
switch a.ActionType {
|
||||
case toolkit.Add:
|
||||
if (a.ActionType == toolkit.Add) {
|
||||
ui.QueueMain(func() {
|
||||
add(a)
|
||||
})
|
||||
sleep(.05)
|
||||
// TODO: remove this artificial delay
|
||||
// sleep(.001)
|
||||
return
|
||||
}
|
||||
|
||||
if (a.ActionType == toolkit.Dump) {
|
||||
log(debugNow, "rawAction() Dump =", a.ActionType, a.WidgetType, n.Name)
|
||||
rootNode.listChildren(true)
|
||||
return
|
||||
}
|
||||
|
||||
if (n == nil) {
|
||||
rootNode.listChildren(true)
|
||||
log(true, "rawAction() ERROR findWidgetId found nil", a.ActionType, a.WidgetType)
|
||||
log(true, "rawAction() ERROR findWidgetId found nil for id =", a.WidgetId)
|
||||
log(true, "rawAction() ERROR findWidgetId found nil", a.ActionType, a.WidgetType)
|
||||
log(true, "rawAction() ERROR findWidgetId found nil for id =", a.WidgetId)
|
||||
return
|
||||
panic("findWidgetId found nil for id = " + strconv.Itoa(a.WidgetId))
|
||||
}
|
||||
|
||||
switch a.ActionType {
|
||||
case toolkit.Show:
|
||||
n.show(true)
|
||||
case toolkit.Hide:
|
||||
|
|
|
@ -134,6 +134,9 @@ func (p *node) place(n *node) bool {
|
|||
log(logError, "n.tk.uiControl == nil", n.tk)
|
||||
panic("n.tk.uiControl == nil")
|
||||
}
|
||||
log(logError, "THIS SHOULD NEVER HAPPEN ??????? trying to place() node=", n.WidgetId, n.Name, n.Text, n.WidgetType)
|
||||
log(logError, "THIS SHOULD NEVER HAPPEN ??????? trying to place() on parent=", p.WidgetId, p.Name, p.Text, p.WidgetType)
|
||||
// panic("n.tk.uiControl == nil")
|
||||
p.tk.uiTab.Append(n.Text, n.tk.uiControl)
|
||||
p.tk.boxC += 1
|
||||
return true
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
)
|
||||
|
||||
func (p *node) newButton(n *node) {
|
||||
log(debugToolkit, "newButton()", n.Name)
|
||||
log(debugToolkit, "newButton() START", n.Name)
|
||||
|
||||
t := p.tk
|
||||
if (t == nil) {
|
||||
|
@ -27,4 +27,5 @@ func (p *node) newButton(n *node) {
|
|||
|
||||
n.tk = newt
|
||||
p.place(n)
|
||||
log(debugToolkit, "newButton() END", n.Name)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package main
|
||||
|
||||
import "git.wit.org/wit/gui/toolkit"
|
||||
import (
|
||||
"strconv"
|
||||
"git.wit.org/wit/gui/toolkit"
|
||||
)
|
||||
|
||||
var defaultBehavior bool = true
|
||||
|
||||
|
@ -126,3 +129,40 @@ func flag(a *toolkit.Action) {
|
|||
log(debugError, "Can't set unknown flag", a.S)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *node) dumpWidget(b bool) {
|
||||
var info, d string
|
||||
|
||||
if (n == nil) {
|
||||
log(debugError, "dumpWidget() node == nil")
|
||||
return
|
||||
}
|
||||
info = n.WidgetType.String()
|
||||
|
||||
d = strconv.Itoa(n.WidgetId) + " " + info + " " + n.Name
|
||||
|
||||
var tabs string
|
||||
for i := 0; i < listChildrenDepth; i++ {
|
||||
tabs = tabs + defaultPadding
|
||||
}
|
||||
log(b, tabs + d)
|
||||
}
|
||||
|
||||
var defaultPadding string = " "
|
||||
var listChildrenDepth int = 0
|
||||
|
||||
func (n *node) listChildren(dump bool) {
|
||||
if (n == nil) {
|
||||
return
|
||||
}
|
||||
|
||||
n.dumpWidget(dump)
|
||||
if len(n.children) == 0 {
|
||||
return
|
||||
}
|
||||
for _, child := range n.children {
|
||||
listChildrenDepth += 1
|
||||
child.listChildren(dump)
|
||||
listChildrenDepth -= 1
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,8 @@ func catchActionChannel() {
|
|||
muAction.Lock()
|
||||
// TODO ui.QueueMain(f)
|
||||
// TODO ui.QueueMain( func() {rawAction(a)} )
|
||||
rawAction(a)
|
||||
ui.QueueMain( func() {rawAction(a)} )
|
||||
// rawAction(a)
|
||||
muAction.Unlock()
|
||||
log(logInfo, "catchActionChannel() STUFF END", a.WidgetId, a.ActionType, a.WidgetType)
|
||||
}
|
||||
|
@ -57,7 +58,7 @@ func init() {
|
|||
log(logNow, "Init() START")
|
||||
log(debugToolkit, "Init()")
|
||||
// Can you pass values to a plugin init() ? Otherwise, there is no way to safely print
|
||||
// log(debugToolkit, "gui/toolkit init() Setting defaultBehavior = true")
|
||||
// log(debugToolkit, "init() Setting defaultBehavior = true")
|
||||
setDefaultBehavior(true)
|
||||
|
||||
// andlabs = make(map[int]*andlabsT)
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
)
|
||||
|
||||
func (n *node) setText(a *toolkit.Action) {
|
||||
log(debugChange, "setText() START with a.S =", a.S)
|
||||
t := n.tk
|
||||
if (t == nil) {
|
||||
log(debugError, "setText error. tk == nil", n.Name, n.WidgetId)
|
||||
|
@ -34,9 +35,19 @@ func (n *node) setText(a *toolkit.Action) {
|
|||
case toolkit.Textbox:
|
||||
switch a.ActionType {
|
||||
case toolkit.Set:
|
||||
t.uiMultilineEntry.SetText(a.S)
|
||||
if (t.uiEntry != nil) {
|
||||
t.uiEntry.SetText(a.S)
|
||||
}
|
||||
if (t.uiMultilineEntry != nil) {
|
||||
t.uiMultilineEntry.SetText(a.S)
|
||||
}
|
||||
case toolkit.SetText:
|
||||
t.uiMultilineEntry.SetText(a.S)
|
||||
if (t.uiEntry != nil) {
|
||||
t.uiEntry.SetText(a.S)
|
||||
}
|
||||
if (t.uiMultilineEntry != nil) {
|
||||
t.uiMultilineEntry.SetText(a.S)
|
||||
}
|
||||
default:
|
||||
log(debugError, "setText() unknown", a.ActionType, "on checkbox", n.Name)
|
||||
}
|
||||
|
@ -113,4 +124,5 @@ func (n *node) setText(a *toolkit.Action) {
|
|||
default:
|
||||
log(debugError, "plugin Send() Don't know how to setText on", n.WidgetType, "yet", a.ActionType)
|
||||
}
|
||||
log(debugChange, "setText() END with a.S =", a.S)
|
||||
}
|
||||
|
|
|
@ -51,6 +51,9 @@ type andlabsT struct {
|
|||
parent *andlabsT
|
||||
children []*andlabsT
|
||||
|
||||
// used to track if a tab has a child widget yet
|
||||
child bool
|
||||
|
||||
uiControl ui.Control
|
||||
|
||||
uiBox *ui.Box
|
||||
|
|
|
@ -23,7 +23,7 @@ func (p *node) newTab(n *node) {
|
|||
var newt *andlabsT
|
||||
|
||||
if (p.WidgetType != toolkit.Window) {
|
||||
log(debugToolkit, "newTab() uiWindow == nil. I can't add a toolbar without window", n.WidgetId, n.ParentId)
|
||||
log(debugError, "newTab() uiWindow == nil. I can't add a toolbar without window", n.WidgetId, n.ParentId)
|
||||
return
|
||||
}
|
||||
t := p.tk
|
||||
|
@ -38,7 +38,15 @@ func (p *node) newTab(n *node) {
|
|||
} else {
|
||||
// this means you have to append a tab
|
||||
log(debugToolkit, "newTab() GOOD. This should be an additional tab:", n.WidgetId, n.ParentId)
|
||||
newt = t.appendTab(n.Text)
|
||||
if (n.WidgetType == toolkit.Tab) {
|
||||
// andlabs doesn't have multiple tab widgets so make a fake one?
|
||||
// this makes a andlabsT internal structure with the parent values
|
||||
newt = new(andlabsT)
|
||||
newt.uiWindow = t.uiWindow
|
||||
newt.uiTab = t.uiTab
|
||||
} else {
|
||||
newt = t.appendTab(n.Text)
|
||||
}
|
||||
}
|
||||
|
||||
n.tk = newt
|
||||
|
@ -63,7 +71,7 @@ func rawTab(w *ui.Window, name string) *andlabsT {
|
|||
log(debugError, "UiWindow == nil. I can't add a tab without a window")
|
||||
log(debugError, "UiWindow == nil. I can't add a tab without a window")
|
||||
log(debugError, "UiWindow == nil. I can't add a tab without a window")
|
||||
sleep(1)
|
||||
// sleep(1)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -77,13 +85,13 @@ func rawTab(w *ui.Window, name string) *andlabsT {
|
|||
|
||||
func (t *andlabsT) appendTab(name string) *andlabsT {
|
||||
var newT andlabsT
|
||||
log(debugToolkit, "gui.toolkit.NewTab() ADD", name)
|
||||
log(debugToolkit, "appendTab() ADD", name)
|
||||
|
||||
if (t.uiTab == nil) {
|
||||
log(debugToolkit, "gui.Toolkit.UiWindow == nil. I can't add a widget without a place to put it")
|
||||
log(debugToolkit, "UiWindow == nil. I can't add a widget without a place to put it")
|
||||
panic("should never have happened. wit/gui/toolkit has ui.Tab == nil")
|
||||
}
|
||||
log(debugToolkit, "gui.toolkit.AddTab() START name =", name)
|
||||
log(debugToolkit, "appendTab() START name =", name)
|
||||
|
||||
var hbox *ui.Box
|
||||
if (defaultBehavior) {
|
||||
|
@ -103,12 +111,3 @@ func (t *andlabsT) appendTab(name string) *andlabsT {
|
|||
newT.uiBox = hbox
|
||||
return &newT
|
||||
}
|
||||
|
||||
/*
|
||||
func newTab(n *node) {
|
||||
log(logInfo, "newTab() add to parent id:", n.ParentId)
|
||||
|
||||
p := n.parent
|
||||
p.newTab(n)
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -8,14 +8,25 @@ import (
|
|||
func (p *node) newTextbox(n *node) {
|
||||
newt := new(andlabsT)
|
||||
|
||||
e := ui.NewNonWrappingMultilineEntry()
|
||||
newt.uiMultilineEntry = e
|
||||
newt.uiControl = e
|
||||
if (n.X == 1) {
|
||||
e := ui.NewEntry()
|
||||
newt.uiEntry = e
|
||||
newt.uiControl = e
|
||||
|
||||
e.OnChanged(func(spin *ui.MultilineEntry) {
|
||||
n.S = spin.Text()
|
||||
n.doUserEvent()
|
||||
})
|
||||
e.OnChanged(func(spin *ui.Entry) {
|
||||
n.S = spin.Text()
|
||||
n.doUserEvent()
|
||||
})
|
||||
} else {
|
||||
e := ui.NewNonWrappingMultilineEntry()
|
||||
newt.uiMultilineEntry = e
|
||||
newt.uiControl = e
|
||||
|
||||
e.OnChanged(func(spin *ui.MultilineEntry) {
|
||||
n.S = spin.Text()
|
||||
n.doUserEvent()
|
||||
})
|
||||
}
|
||||
n.tk = newt
|
||||
p.place(n)
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@ all: plugin
|
|||
ldd ../gocui.so
|
||||
|
||||
goget:
|
||||
GO111MODULE="off" go get -v -t -u
|
||||
go get -v -t -u
|
||||
|
||||
plugin:
|
||||
GO111MODULE="off" go build -v -x -buildmode=plugin -o ../gocui.so
|
||||
go build -v -x -buildmode=plugin -o ../gocui.so
|
||||
|
||||
objdump:
|
||||
objdump -t ../gocui.so |less
|
||||
|
|
|
@ -31,29 +31,40 @@ func (n *node) addWidget() {
|
|||
switch n.WidgetType {
|
||||
case toolkit.Root:
|
||||
log(logInfo, "setStartWH() rootNode w.id =", n.WidgetId, "w.name", n.Name)
|
||||
nw.color = &colorRoot
|
||||
n.setFake()
|
||||
return
|
||||
case toolkit.Flag:
|
||||
nw.color = &colorFlag
|
||||
n.setFake()
|
||||
return
|
||||
case toolkit.Window:
|
||||
nw.frame = false
|
||||
redoWindows(0,0)
|
||||
nw.color = &colorWindow
|
||||
// redoWindows(0,0)
|
||||
return
|
||||
case toolkit.Tab:
|
||||
nw.color = &colorTab
|
||||
// redoWindows(0,0)
|
||||
return
|
||||
case toolkit.Button:
|
||||
nw.color = &colorButton
|
||||
case toolkit.Box:
|
||||
nw.color = &colorBox
|
||||
nw.isFake = true
|
||||
n.setFake()
|
||||
return
|
||||
case toolkit.Grid:
|
||||
nw.color = &colorGrid
|
||||
nw.isFake = true
|
||||
n.setFake()
|
||||
return
|
||||
case toolkit.Group:
|
||||
nw.color = &colorGroup
|
||||
nw.frame = false
|
||||
return
|
||||
case toolkit.Label:
|
||||
nw.color = &colorLabel
|
||||
nw.frame = false
|
||||
return
|
||||
default:
|
||||
|
|
|
@ -1,17 +1,23 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/awesome-gocui/gocui"
|
||||
"git.wit.org/wit/gui/toolkit"
|
||||
)
|
||||
|
||||
// set isCurrent = false everywhere
|
||||
func UnsetCurrent(n *node) {
|
||||
func unsetCurrent(n *node) {
|
||||
w := n.tk
|
||||
w.isCurrent = false
|
||||
|
||||
if n.WidgetType == toolkit.Tab {
|
||||
// n.tk.color = &colorTab
|
||||
// n.setColor()
|
||||
}
|
||||
|
||||
for _, child := range n.children {
|
||||
UnsetCurrent(child)
|
||||
unsetCurrent(child)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,7 +28,14 @@ func (n *node) updateCurrent() {
|
|||
log("updateCurrent()", n.Name)
|
||||
if n.WidgetType == toolkit.Tab {
|
||||
if n.IsCurrent() {
|
||||
// n.tk.color = &colorActiveT
|
||||
n.setColor(&colorActiveT)
|
||||
n.hideView()
|
||||
n.showView()
|
||||
setCurrentTab(n)
|
||||
} else {
|
||||
// n.tk.color = &colorTab
|
||||
// n.setColor()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -47,7 +60,7 @@ func setCurrentWindow(n *node) {
|
|||
if n.WidgetType != toolkit.Window {
|
||||
return
|
||||
}
|
||||
UnsetCurrent(me.rootNode)
|
||||
unsetCurrent(me.rootNode)
|
||||
|
||||
if n.hasTabs {
|
||||
// set isCurrent = true on the first tab
|
||||
|
@ -66,7 +79,7 @@ func setCurrentTab(n *node) {
|
|||
if n.WidgetType != toolkit.Tab {
|
||||
return
|
||||
}
|
||||
UnsetCurrent(me.rootNode)
|
||||
unsetCurrent(me.rootNode)
|
||||
w.isCurrent = true
|
||||
p := n.parent.tk
|
||||
p.isCurrent = true
|
||||
|
@ -83,14 +96,51 @@ func (n *node) doWidgetClick() {
|
|||
// me.rootNode.redoColor(true)
|
||||
me.rootNode.dumpTree(true)
|
||||
case toolkit.Window:
|
||||
me.rootNode.hideWidgets()
|
||||
n.redoTabs(me.TabW, me.TabH)
|
||||
if ! n.hasTabs {
|
||||
setCurrentWindow(n)
|
||||
n.placeWidgets(me.RawW, me.RawH)
|
||||
n.showWidgets()
|
||||
if (me.currentWindow == n) {
|
||||
return
|
||||
}
|
||||
if (me.currentWindow != nil) {
|
||||
unsetCurrent(me.currentWindow)
|
||||
me.currentWindow.setColor(&colorWindow)
|
||||
me.currentWindow.hideWidgets()
|
||||
}
|
||||
n.hideWidgets()
|
||||
me.currentWindow = n
|
||||
// setCurrentWindow(n) // probably delete this
|
||||
n.setColor(&colorActiveW)
|
||||
n.redoTabs(me.TabW, me.TabH)
|
||||
for _, child := range n.children {
|
||||
if (child.currentTab == true) {
|
||||
log(true, "FOUND CURRENT TAB", child.Name)
|
||||
setCurrentTab(child)
|
||||
child.placeWidgets(me.RawW, me.RawH)
|
||||
child.showWidgets()
|
||||
return
|
||||
}
|
||||
}
|
||||
/* FIXME: redo this
|
||||
if ! n.hasTabs {
|
||||
}
|
||||
*/
|
||||
case toolkit.Tab:
|
||||
if (n.IsCurrent()) {
|
||||
return // do nothing if you reclick on the already selected tab
|
||||
}
|
||||
// find the window and disable the active tab
|
||||
p := n.parent
|
||||
if (p != nil) {
|
||||
p.hideWidgets()
|
||||
p.redoTabs(me.TabW, me.TabH)
|
||||
unsetCurrent(p)
|
||||
for _, child := range p.children {
|
||||
if child.WidgetType == toolkit.Tab {
|
||||
child.setColor(&colorTab)
|
||||
n.currentTab = false
|
||||
}
|
||||
}
|
||||
}
|
||||
n.currentTab = true
|
||||
n.setColor(&colorActiveT)
|
||||
setCurrentTab(n)
|
||||
n.placeWidgets(me.RawW, me.RawH)
|
||||
n.showWidgets()
|
||||
|
@ -118,6 +168,50 @@ func (n *node) doWidgetClick() {
|
|||
n.toggleTree()
|
||||
case toolkit.Button:
|
||||
n.doUserEvent()
|
||||
case toolkit.Dropdown:
|
||||
log(true, "do the dropdown here")
|
||||
if (me.ddview == nil) {
|
||||
me.ddview = addDropdown()
|
||||
tk := me.ddview.tk
|
||||
tk.gocuiSize.w0 = 20
|
||||
tk.gocuiSize.w1 = 40
|
||||
tk.gocuiSize.h0 = 10
|
||||
tk.gocuiSize.h1 = 25
|
||||
tk.v, _ = me.baseGui.SetView("ddview",
|
||||
tk.gocuiSize.w0,
|
||||
tk.gocuiSize.h0,
|
||||
tk.gocuiSize.w1,
|
||||
tk.gocuiSize.h1, 0)
|
||||
if (tk.v == nil) {
|
||||
return
|
||||
}
|
||||
tk.v.Wrap = true
|
||||
tk.v.Frame = true
|
||||
tk.v.Clear()
|
||||
fmt.Fprint(tk.v, "example.com\nwit.org\nwit.com")
|
||||
me.ddview.SetVisible(true)
|
||||
return
|
||||
}
|
||||
log(true, "doWidgetClick() visible =", me.ddview.Visible())
|
||||
if (me.ddview.Visible()) {
|
||||
me.ddview.SetVisible(false)
|
||||
me.baseGui.DeleteView("ddview")
|
||||
me.ddview.tk.v = nil
|
||||
} else {
|
||||
var dnsList string
|
||||
for i, s := range n.vals {
|
||||
log(logNow, "AddText()", n.Name, i, s)
|
||||
dnsList += s + "\n"
|
||||
}
|
||||
me.ddNode = n
|
||||
log(logNow, "new dns list should be set to:", dnsList)
|
||||
me.ddview.Text = dnsList
|
||||
me.ddview.SetText(dnsList)
|
||||
me.ddview.SetVisible(true)
|
||||
}
|
||||
for i, s := range n.vals {
|
||||
log(logNow, "AddText()", n.Name, i, s)
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
@ -162,26 +256,15 @@ func click(g *gocui.Gui, v *gocui.View) error {
|
|||
n := findUnderMouse()
|
||||
if (n != nil) {
|
||||
log(logNow, "click() Found widget =", n.WidgetId, n.Name, ",", n.Text)
|
||||
if (n.Name == "DropBox") {
|
||||
log(logNow, "click() this is the dropdown menu. set a flag here what did I click? where is the mouse?")
|
||||
log(logNow, "click() set a global dropdown clicked flag=true here")
|
||||
me.ddClicked = true
|
||||
}
|
||||
n.doWidgetClick()
|
||||
} else {
|
||||
log(logNow, "click() could not find node name =", v.Name())
|
||||
}
|
||||
/*
|
||||
i, err := strconv.Atoi(v.Name())
|
||||
if (err != nil) {
|
||||
log(logError, "click() Can't find widget. error =", err)
|
||||
} else {
|
||||
log(logVerbose, "click() ok v.Name() =", v.Name())
|
||||
n := me.rootNode.findWidgetId(i)
|
||||
if (n == nil) {
|
||||
log(logError, "click() CANT FIND VIEW in binary tree. v.Name =", v.Name())
|
||||
return nil
|
||||
}
|
||||
log(logNow, "click() Found widget =", n.WidgetId, n.Name, ",", n.Text)
|
||||
n.doWidgetClick()
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
|
||||
if _, err := g.SetCurrentView(v.Name()); err != nil {
|
||||
return err
|
||||
|
@ -207,6 +290,17 @@ func findUnderMouse() *node {
|
|||
found = n
|
||||
}
|
||||
}
|
||||
if (n == me.ddview) {
|
||||
log(true, "findUnderMouse() found ddview")
|
||||
if n.Visible() {
|
||||
log(true, "findUnderMouse() and ddview is visable. hide it here. TODO: find highlighted row")
|
||||
found = n
|
||||
// find the actual value here and set the dropdown widget
|
||||
me.baseGui.DeleteView("ddview")
|
||||
} else {
|
||||
log(true, "findUnderMouse() I was lying, actually it's not found")
|
||||
}
|
||||
}
|
||||
|
||||
for _, child := range n.children {
|
||||
f(child)
|
||||
|
@ -217,7 +311,7 @@ func findUnderMouse() *node {
|
|||
// TODO: pop up menu with a list of them
|
||||
for _, n := range widgets {
|
||||
//log(logNow, "ctrlDown() FOUND widget", widget.id, widget.name)
|
||||
n.showWidgetPlacement(logNow, "ctrlDown() FOUND")
|
||||
n.showWidgetPlacement(logNow, "findUnderMouse() FOUND")
|
||||
}
|
||||
return found
|
||||
}
|
||||
|
@ -228,27 +322,6 @@ func ctrlDown(g *gocui.Gui, v *gocui.View) error {
|
|||
// 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) {
|
||||
setupCtrlDownWidget()
|
||||
me.ctrlDown.Text = found.Name
|
||||
|
@ -266,9 +339,9 @@ func ctrlDown(g *gocui.Gui, v *gocui.View) error {
|
|||
cd.gocuiSize.w1 = newR.w1
|
||||
cd.gocuiSize.h1 = newR.h1
|
||||
if me.ctrlDown.Visible() {
|
||||
me.ctrlDown.deleteView()
|
||||
me.ctrlDown.hideView()
|
||||
} else {
|
||||
me.ctrlDown.updateView()
|
||||
me.ctrlDown.showView()
|
||||
}
|
||||
me.ctrlDown.showWidgetPlacement(logNow, "ctrlDown:")
|
||||
return nil
|
||||
|
|
|
@ -3,86 +3,85 @@ package main
|
|||
import (
|
||||
"math/rand"
|
||||
"github.com/awesome-gocui/gocui"
|
||||
"git.wit.org/wit/gui/toolkit"
|
||||
)
|
||||
|
||||
// ColorBlack ColorRed ColorGreen ColorYellow ColorBlue ColorMagenta ColorCyan ColorWhite
|
||||
// gocui.GetColor("#FFAA55") // Dark Purple
|
||||
func (n *node) setDefaultWidgetColor() {
|
||||
w := n.tk
|
||||
log(logInfo, "setDefaultWidgetColor() on", n.WidgetType, n.Name)
|
||||
v, _ := me.baseGui.View(w.cuiName)
|
||||
if (v == nil) {
|
||||
log(logError, "setDefaultWidgetColor() failed on view == nil")
|
||||
return
|
||||
}
|
||||
sleep(.05)
|
||||
// v.BgColor = gocui.GetColor("#FFAA55") // Dark Purple
|
||||
// v.BgColor = gocui.GetColor("#88AA55") // heavy purple
|
||||
// v.BgColor = gocui.GetColor("#111111") // crazy red
|
||||
// v.BgColor = gocui.GetColor("#FF9911") // heavy red
|
||||
// v.SelBgColor = gocui.GetColor("#FFEE11") // blood red
|
||||
//w.v.SelBgColor = gocui.ColorCyan
|
||||
//color.go: w.v.SelFgColor = gocui.ColorBlack
|
||||
//color.go: w.v.BgColor = gocui.ColorGreen
|
||||
|
||||
// v.BgColor = gocui.GetColor("#55AAFF") // super light grey
|
||||
// v.BgColor = gocui.GetColor("#FFC0CB") // 'w3c pink' yellow
|
||||
switch n.WidgetType {
|
||||
case toolkit.Root:
|
||||
v.FrameColor = gocui.ColorRed
|
||||
v.BgColor = gocui.GetColor("#B0E0E6") // w3c 'powerder blue'
|
||||
case toolkit.Flag:
|
||||
v.FrameColor = gocui.ColorRed
|
||||
v.BgColor = gocui.GetColor("#B0E0E6") // w3c 'powerder blue'
|
||||
case toolkit.Window:
|
||||
v.FgColor = gocui.ColorCyan
|
||||
v.SelBgColor = gocui.ColorBlue
|
||||
v.FrameColor = gocui.ColorBlue
|
||||
case toolkit.Tab:
|
||||
v.SelBgColor = gocui.ColorBlue
|
||||
v.FrameColor = gocui.ColorBlue
|
||||
case toolkit.Button:
|
||||
v.BgColor = gocui.ColorWhite
|
||||
v.FrameColor = gocui.ColorGreen
|
||||
v.SelBgColor = gocui.ColorBlack
|
||||
v.SelFgColor = gocui.ColorGreen
|
||||
case toolkit.Label:
|
||||
v.BgColor = gocui.GetColor("#55AAFF") // super light grey
|
||||
v.SelBgColor = gocui.GetColor("#55AAFF") // super light grey
|
||||
case toolkit.Box:
|
||||
v.FrameColor = gocui.ColorRed
|
||||
// v.BgColor = gocui.GetColor("#FFC0CB") // 'w3c pink' yellow
|
||||
v.BgColor = gocui.GetColor("#DDDDDD") // light purple
|
||||
case toolkit.Grid:
|
||||
// v.FgColor = gocui.ColorCyan
|
||||
// v.SelBgColor = gocui.ColorBlue
|
||||
// v.FrameColor = gocui.ColorBlue
|
||||
case toolkit.Group:
|
||||
v.BgColor = gocui.GetColor("#55AAFF") // super light grey
|
||||
default:
|
||||
}
|
||||
type colorT struct {
|
||||
frame gocui.Attribute
|
||||
fg gocui.Attribute
|
||||
bg gocui.Attribute
|
||||
selFg gocui.Attribute
|
||||
selBg gocui.Attribute
|
||||
name string
|
||||
}
|
||||
|
||||
// SetColor("#FFAA55") // purple
|
||||
func (w *cuiWidget) SetColor(c string) {
|
||||
if (w.v == nil) {
|
||||
log(logError, "SetColor() failed on view == nil")
|
||||
var none gocui.Attribute = gocui.AttrNone
|
||||
var lightPurple gocui.Attribute = gocui.GetColor("#DDDDDD") // light purple
|
||||
var darkPurple gocui.Attribute = gocui.GetColor("#FFAA55") // Dark Purple
|
||||
var heavyPurple gocui.Attribute = gocui.GetColor("#88AA55") // heavy purple
|
||||
var powdererBlue gocui.Attribute = gocui.GetColor("#B0E0E6") // w3c 'powerder blue'
|
||||
var superLightGrey gocui.Attribute = gocui.GetColor("#55AAFF") // super light grey
|
||||
|
||||
// Standard defined colors from gocui:
|
||||
// ColorBlack ColorRed ColorGreen ColorYellow ColorBlue ColorMagenta ColorCyan ColorWhite
|
||||
|
||||
// v.BgColor = gocui.GetColor("#111111") // crazy red
|
||||
// v.BgColor = gocui.GetColor("#FF9911") // heavy red
|
||||
// v.SelBgColor = gocui.GetColor("#FFEE11") // blood red
|
||||
|
||||
// v.BgColor = gocui.GetColor("#55AAFF") // super light grey
|
||||
// v.BgColor = gocui.GetColor("#FFC0CB") // 'w3c pink' yellow
|
||||
|
||||
// Normal Text On mouseover
|
||||
// Widget Frame Text background Text background
|
||||
var colorWindow colorT = colorT{ none , gocui.ColorBlue, none , none , powdererBlue , "normal window"}
|
||||
var colorActiveW colorT = colorT{ none , none , powdererBlue , none , powdererBlue , "active window"}
|
||||
|
||||
var colorTab colorT = colorT{gocui.ColorBlue, gocui.ColorBlue, none , none , powdererBlue , "normal tab"}
|
||||
var colorActiveT colorT = colorT{gocui.ColorBlue, none , powdererBlue , none , powdererBlue , "active tab"}
|
||||
|
||||
var colorButton colorT = colorT{gocui.ColorGreen, none , gocui.ColorWhite, gocui.ColorGreen, gocui.ColorBlack, "normal button"}
|
||||
var colorLabel colorT = colorT{ none , none , superLightGrey , none , superLightGrey , "normal label"}
|
||||
var colorGroup colorT = colorT{ none , none , superLightGrey , none , superLightGrey , "normal group"}
|
||||
|
||||
// widget debugging colors. these widgets aren't displayed unless you are debugging
|
||||
var colorRoot colorT = colorT{gocui.ColorRed , none , powdererBlue , none , gocui.ColorBlue, "debug root"}
|
||||
var colorFlag colorT = colorT{gocui.ColorRed , none , powdererBlue , none , gocui.ColorGreen, "debug flag"}
|
||||
var colorBox colorT = colorT{gocui.ColorRed , none , lightPurple , none , gocui.ColorCyan, "debug box"}
|
||||
var colorGrid colorT = colorT{gocui.ColorRed , none , lightPurple , none , gocui.ColorRed, "debug grid"}
|
||||
var colorNone colorT = colorT{ none , none , none , none , none , "debug none"}
|
||||
|
||||
// actually sets the colors for the gocui element
|
||||
// the user will see the colors change when this runs
|
||||
// TODO: add black/white only flag for ttyS0
|
||||
// TODO: or fix kvm/qemu serial console & SIGWINCH.
|
||||
// TODO: and minicom and uboot and 5 million other things.
|
||||
// TODO: maybe enough of us could actually do that if we made it a goal.
|
||||
// TODO: start with riscv boards and fix it universally there
|
||||
// TODO: so just a small little 'todo' item here
|
||||
func (n *node) setColor(newColor *colorT) {
|
||||
tk := n.tk
|
||||
if (tk.color == newColor) {
|
||||
// nothing to do since the colors have nto changed
|
||||
return
|
||||
}
|
||||
w.v.SelBgColor = gocui.ColorCyan
|
||||
w.v.SelFgColor = gocui.ColorBlack
|
||||
switch c {
|
||||
case "Green":
|
||||
w.v.BgColor = gocui.ColorGreen
|
||||
case "Purple":
|
||||
w.v.BgColor = gocui.GetColor("#FFAA55")
|
||||
case "Yellow":
|
||||
w.v.BgColor = gocui.ColorYellow
|
||||
case "Blue":
|
||||
w.v.BgColor = gocui.ColorBlue
|
||||
case "Red":
|
||||
w.v.BgColor = gocui.ColorRed
|
||||
default:
|
||||
w.v.BgColor = gocui.GetColor(c)
|
||||
tk.color = newColor
|
||||
if (tk.v == nil) {
|
||||
return
|
||||
}
|
||||
if (tk.color == nil) {
|
||||
log(true, "Set the node to color = nil")
|
||||
tk.color = &colorNone
|
||||
}
|
||||
log(true, "Set the node to color =", tk.color.name)
|
||||
n.recreateView()
|
||||
}
|
||||
|
||||
func (n *node) setDefaultWidgetColor() {
|
||||
n.showView()
|
||||
}
|
||||
|
||||
func (n *node) setDefaultHighlight() {
|
||||
|
|
|
@ -98,6 +98,46 @@ func (n *node) findWidgetName(name string) *node {
|
|||
return nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func addNode(a *toolkit.Action) *node {
|
||||
n := new(node)
|
||||
n.WidgetType = a.WidgetType
|
||||
|
@ -143,42 +183,29 @@ func addNode(a *toolkit.Action) *node {
|
|||
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 addDropdown() *node {
|
||||
n := new(node)
|
||||
n.WidgetType = toolkit.Flag
|
||||
n.WidgetId = -2
|
||||
n.ParentId = 0
|
||||
|
||||
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
|
||||
}
|
||||
// copy the data from the action message
|
||||
n.Name = "DropBox"
|
||||
n.Text = "DropBox text"
|
||||
|
||||
func (n *node) SetVisible(b bool) {
|
||||
if (n == nil) {
|
||||
return
|
||||
// store the internal toolkit information
|
||||
n.tk = new(cuiWidget)
|
||||
n.tk.frame = true
|
||||
|
||||
// set the name used by gocui to the id
|
||||
n.tk.cuiName = "-1 dropbox"
|
||||
|
||||
n.tk.color = &colorFlag
|
||||
|
||||
// add this new widget on the binary tree
|
||||
n.parent = me.rootNode
|
||||
if n.parent != nil {
|
||||
n.parent.children = append(n.parent.children, n)
|
||||
}
|
||||
if (n.tk == nil) {
|
||||
return
|
||||
}
|
||||
if (n.tk.v == nil) {
|
||||
return
|
||||
}
|
||||
n.tk.v.Visible = b
|
||||
return n
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ func dragOutputWindow() {
|
|||
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)
|
||||
v := SetView("global", 5, 10, 5, 10, 0) // x0, x1, y1, y2, overlap
|
||||
if (v == nil) {
|
||||
log(logError, "setFrame() global failed")
|
||||
}
|
||||
|
|
|
@ -14,7 +14,9 @@ import (
|
|||
|
||||
var helpText []string = []string{"KEYBINDINGS",
|
||||
"",
|
||||
"d: show/hide debugging",
|
||||
"?: toggle help",
|
||||
"d: toggle debugging",
|
||||
"r: redraw widgets",
|
||||
"s/h: show/hide all widgets",
|
||||
"L: list all widgets",
|
||||
"q: quit()",
|
||||
|
@ -27,6 +29,12 @@ var helpText []string = []string{"KEYBINDINGS",
|
|||
"",
|
||||
}
|
||||
|
||||
func hidehelplayout() {
|
||||
me.baseGui.DeleteView("help")
|
||||
// n.deleteView()
|
||||
// child.hideFake()
|
||||
}
|
||||
|
||||
func helplayout() error {
|
||||
g := me.baseGui
|
||||
var err error
|
||||
|
|
|
@ -22,6 +22,7 @@ func defaultKeybindings(g *gocui.Gui) error {
|
|||
if err := g.SetKeybinding("", gocui.MouseRelease, gocui.ModNone, mouseUp); err != nil {
|
||||
return err
|
||||
}
|
||||
// mouseDown() runs whenever you click on an unknown view (?)
|
||||
if err := g.SetKeybinding("", gocui.MouseLeft, gocui.ModNone, mouseDown); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -40,10 +41,8 @@ func defaultKeybindings(g *gocui.Gui) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
var showDebug bool = true
|
||||
|
||||
func addDebugKeys(g *gocui.Gui) {
|
||||
// dump all widget info to the log
|
||||
// show debugging buttons
|
||||
g.SetKeybinding("", 'd', gocui.ModNone,
|
||||
func(g *gocui.Gui, v *gocui.View) error {
|
||||
log(logNow, "gocui.SetKeyBinding() dumpTree() START")
|
||||
|
@ -63,9 +62,29 @@ func addDebugKeys(g *gocui.Gui) {
|
|||
// display the help menu
|
||||
g.SetKeybinding("", '?', gocui.ModNone,
|
||||
func(g *gocui.Gui, v *gocui.View) error {
|
||||
helplayout()
|
||||
if (showHelp) {
|
||||
helplayout()
|
||||
showHelp = false
|
||||
} else {
|
||||
me.baseGui.DeleteView("help")
|
||||
showHelp = true
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// redraw all the widgets
|
||||
g.SetKeybinding("", 'r', gocui.ModNone,
|
||||
func(g *gocui.Gui, v *gocui.View) error {
|
||||
if (redoWidgets) {
|
||||
redoWindows(0,0)
|
||||
redoWidgets = false
|
||||
} else {
|
||||
me.rootNode.hideWidgets()
|
||||
redoWidgets = true
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// hide all widgets
|
||||
g.SetKeybinding("", 'h', gocui.ModNone,
|
||||
func(g *gocui.Gui, v *gocui.View) error {
|
||||
|
|
|
@ -24,6 +24,7 @@ func mouseMove(g *gocui.Gui) {
|
|||
|
||||
func msgDown(g *gocui.Gui, v *gocui.View) error {
|
||||
initialMouseX, initialMouseY = g.MousePosition()
|
||||
log(true, "msgDown() X,Y", initialMouseX, initialMouseY)
|
||||
if vx, vy, _, _, err := g.ViewPosition("msg"); err == nil {
|
||||
xOffset = initialMouseX - vx
|
||||
yOffset = initialMouseY - vy
|
||||
|
@ -32,7 +33,58 @@ func msgDown(g *gocui.Gui, v *gocui.View) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func hideDDview() error {
|
||||
w, h := me.baseGui.MousePosition()
|
||||
log(true, "hide dropdown menu() view msgMouseDown (w,h) =", w, h)
|
||||
if (me.ddview == nil) {
|
||||
return gocui.ErrUnknownView
|
||||
}
|
||||
if (me.ddview.tk.v == nil) {
|
||||
return gocui.ErrUnknownView
|
||||
}
|
||||
me.ddview.SetVisible(false)
|
||||
return nil
|
||||
}
|
||||
|
||||
func showDDview() error {
|
||||
w, h := me.baseGui.MousePosition()
|
||||
log(true, "show dropdown menu() view msgMouseDown (w,h) =", w, h)
|
||||
if (me.ddview == nil) {
|
||||
return gocui.ErrUnknownView
|
||||
}
|
||||
if (me.ddview.tk.v == nil) {
|
||||
return gocui.ErrUnknownView
|
||||
}
|
||||
me.ddview.SetVisible(true)
|
||||
return nil
|
||||
}
|
||||
|
||||
func mouseUp(g *gocui.Gui, v *gocui.View) error {
|
||||
w, h := g.MousePosition()
|
||||
log(true, "mouseUp() view msgMouseDown (check here for dropdown menu click) (w,h) =", w, h)
|
||||
if (me.ddClicked) {
|
||||
log(true, "mouseUp() ddview is the thing that was clicked", w, h)
|
||||
log(true, "mouseUp() find out what the string is here", w, h, me.ddview.tk.gocuiSize.h1)
|
||||
|
||||
if (me.ddNode != nil) {
|
||||
value := h - me.ddview.tk.gocuiSize.h0 - 1
|
||||
log(true, "mouseUp() me.ddview.tk.gocuiSize.h1 =", me.ddview.tk.gocuiSize.h1)
|
||||
log(true, "mouseUp() me.ddNode.vals =", me.ddNode.vals)
|
||||
valsLen := len(me.ddNode.vals)
|
||||
log(true, "mouseUp() value =", value, "valsLen =", valsLen)
|
||||
log(true, "mouseUp() me.ddNode.vals =", me.ddNode.vals)
|
||||
if ((value >= 0) && (value < valsLen)) {
|
||||
str := me.ddNode.vals[value]
|
||||
log(true, "mouseUp() value =", value, "str =", str)
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
// if there is a drop down view active, treat it like a dialog box and close it
|
||||
if (hideDDview() == nil) {
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
if msgMouseDown {
|
||||
msgMouseDown = false
|
||||
if movingMsg {
|
||||
|
@ -57,13 +109,25 @@ func mouseDown(g *gocui.Gui, v *gocui.View) error {
|
|||
}
|
||||
globalMouseDown = true
|
||||
maxX, _ := g.Size()
|
||||
msg := fmt.Sprintf("Mouse really down at: %d,%d", mx, my) + "foo\n" + "bar\n"
|
||||
test := findUnderMouse()
|
||||
msg := fmt.Sprintf("Mouse really down at: %d,%d", mx, my) + "foobar"
|
||||
if (test == me.ddview) {
|
||||
if (me.ddview.Visible()) {
|
||||
log(true, "hide DDview() Mouse really down at:", mx, my)
|
||||
hideDDview()
|
||||
} else {
|
||||
log(true, "show DDview() Mouse really down at:", mx, my)
|
||||
showDDview()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
x := mx - len(msg)/2
|
||||
if x < 0 {
|
||||
x = 0
|
||||
} else if x+len(msg)+1 > maxX-1 {
|
||||
x = maxX - 1 - len(msg) - 1
|
||||
}
|
||||
log(true, "mouseDown() about to write out message to 'globalDown' view. msg =", msg)
|
||||
if v, err := g.SetView("globalDown", x, my-1, x+len(msg)+1, my+1, 0); err != nil {
|
||||
if !errors.Is(err, gocui.ErrUnknownView) {
|
||||
return err
|
||||
|
|
|
@ -24,6 +24,7 @@ func showMsg(g *gocui.Gui, v *gocui.View) error {
|
|||
var l string
|
||||
var err error
|
||||
|
||||
log(true, "showMsg() v.name =", v.Name())
|
||||
if _, err := g.SetCurrentView(v.Name()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -21,14 +21,24 @@ import (
|
|||
// It's probably a terrible idea to call this 'me'
|
||||
var me config
|
||||
|
||||
var showDebug bool = true
|
||||
var showHelp bool = true
|
||||
var redoWidgets bool = true
|
||||
|
||||
// This is the window that is currently active
|
||||
var currentWindow *node
|
||||
|
||||
type config struct {
|
||||
baseGui *gocui.Gui // the main gocui handle
|
||||
rootNode *node // the base of the binary tree. it should have id == 0
|
||||
|
||||
ctrlDown *node // shown if you click the mouse when the ctrl key is pressed
|
||||
// current *cuiWidget // this is the current tab or window to show
|
||||
currentWindow *node // this is the current tab or window to show
|
||||
logStdout *node // where to show STDOUT
|
||||
helpLabel *gocui.View
|
||||
ddview *node // the gocui view to select dropdrown lists
|
||||
ddClicked bool // the dropdown menu view was clicked
|
||||
ddNode *node // the dropdown menu is for this widget
|
||||
|
||||
// this is the channel we send user events like
|
||||
// mouse clicks or keyboard events back to the program
|
||||
|
@ -123,6 +133,7 @@ type node struct {
|
|||
horizontal bool `default:false`
|
||||
|
||||
hasTabs bool // does the window have tabs?
|
||||
currentTab bool // the visible tab
|
||||
|
||||
// the internal plugin toolkit structure
|
||||
tk *cuiWidget
|
||||
|
@ -152,7 +163,7 @@ type cuiWidget struct {
|
|||
size rectType
|
||||
|
||||
// the actual gocui display view of this widget
|
||||
// sometimes this isn't visable like with a Box or Grid
|
||||
// sometimes this isn't visible like with a Box or Grid
|
||||
gocuiSize rectType
|
||||
|
||||
isCurrent bool // is this the currently displayed Window or Tab?
|
||||
|
@ -164,6 +175,12 @@ type cuiWidget struct {
|
|||
|
||||
tainted bool
|
||||
frame bool
|
||||
|
||||
// for a window, this is currently selected tab
|
||||
selectedTab *node
|
||||
|
||||
// what color to use
|
||||
color *colorT
|
||||
}
|
||||
|
||||
// from the gocui devs:
|
||||
|
|
|
@ -103,6 +103,10 @@ func (p *node) redoTabs(nextW int, nextH int) {
|
|||
n.gocuiSetWH(nextW, nextH)
|
||||
n.deleteView()
|
||||
// setCurrentTab(n)
|
||||
// if (len(w.cuiName) < 4) {
|
||||
// w.cuiName = "abcd"
|
||||
// }
|
||||
|
||||
n.showView()
|
||||
|
||||
sizeW := w.Width() + me.TabPadW
|
||||
|
|
|
@ -36,7 +36,12 @@ func (n *node) textResize() {
|
|||
n.showWidgetPlacement(logNow, "textResize()")
|
||||
}
|
||||
|
||||
func (n *node) hideView() {
|
||||
n.SetVisible(false)
|
||||
}
|
||||
|
||||
// display's the text of the widget in gocui
|
||||
// will create a new gocui view if there isn't one or if it has been moved
|
||||
func (n *node) showView() {
|
||||
var err error
|
||||
w := n.tk
|
||||
|
@ -46,31 +51,34 @@ func (n *node) showView() {
|
|||
w.cuiName = strconv.Itoa(n.WidgetId)
|
||||
}
|
||||
|
||||
// if the gocui element doesn't exist, create it
|
||||
if (w.v == nil) {
|
||||
n.updateView()
|
||||
n.recreateView()
|
||||
}
|
||||
x0, y0, x1, y1, err := me.baseGui.ViewPosition(w.cuiName)
|
||||
log(logInfo, "showView() w.v already defined for widget", n.Name, err)
|
||||
|
||||
// if the gocui element has changed where it is supposed to be on the screen
|
||||
// recreate it
|
||||
if (x0 != w.gocuiSize.w0) || (y0 != w.gocuiSize.h0) {
|
||||
log(logError, "showView() w.v.w0 != x0", n.Name, w.gocuiSize.w0, x0)
|
||||
log(logError, "showView() w.v.h0 != y0", n.Name, w.gocuiSize.h0, y0)
|
||||
n.updateView()
|
||||
n.recreateView()
|
||||
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()
|
||||
n.recreateView()
|
||||
return
|
||||
}
|
||||
|
||||
if (w.v.Visible == false) {
|
||||
log(logInfo, "showView() w.v.Visible set to true ", n.Name)
|
||||
w.v.Visible = true
|
||||
}
|
||||
n.SetVisible(true)
|
||||
}
|
||||
|
||||
func (n *node) updateView() {
|
||||
// create or recreate the gocui widget visible
|
||||
// deletes the old view if it exists and recreates it
|
||||
func (n *node) recreateView() {
|
||||
var err error
|
||||
w := n.tk
|
||||
if (me.baseGui == nil) {
|
||||
|
@ -105,8 +113,14 @@ func (n *node) updateView() {
|
|||
fmt.Fprint(w.v, n.Text)
|
||||
n.showWidgetPlacement(logNow, "Window: " + n.Text)
|
||||
|
||||
n.setDefaultHighlight()
|
||||
n.setDefaultWidgetColor()
|
||||
// if you don't do this here, it will be black & white only
|
||||
if (w.color != nil) {
|
||||
w.v.FrameColor = w.color.frame
|
||||
w.v.FgColor = w.color.fg
|
||||
w.v.BgColor = w.color.bg
|
||||
w.v.SelFgColor = w.color.selFg
|
||||
w.v.SelBgColor = w.color.selBg
|
||||
}
|
||||
}
|
||||
|
||||
func (n *node) hideWidgets() {
|
||||
|
@ -119,7 +133,7 @@ func (n *node) hideWidgets() {
|
|||
case toolkit.Box:
|
||||
case toolkit.Grid:
|
||||
default:
|
||||
n.deleteView()
|
||||
n.hideView()
|
||||
}
|
||||
for _, child := range n.children {
|
||||
child.hideWidgets()
|
||||
|
@ -129,7 +143,7 @@ func (n *node) hideWidgets() {
|
|||
func (n *node) hideFake() {
|
||||
w := n.tk
|
||||
if (w.isFake) {
|
||||
n.deleteView()
|
||||
n.hideView()
|
||||
}
|
||||
for _, child := range n.children {
|
||||
child.hideFake()
|
||||
|
@ -153,13 +167,13 @@ func (n *node) showWidgets() {
|
|||
if (w.isFake) {
|
||||
// don't display by default
|
||||
} else {
|
||||
if n.IsCurrent() {
|
||||
// if n.IsCurrent() {
|
||||
n.showWidgetPlacement(logInfo, "current:")
|
||||
n.showView()
|
||||
} else {
|
||||
n.showWidgetPlacement(logInfo, "not:")
|
||||
// } else {
|
||||
// n.showWidgetPlacement(logInfo, "not:")
|
||||
// w.drawView()
|
||||
}
|
||||
// }
|
||||
}
|
||||
for _, child := range n.children {
|
||||
child.showWidgets()
|
||||
|
|
|
@ -69,6 +69,7 @@ const (
|
|||
Textbox // is this a Label with edit=true
|
||||
Slider // like a progress bar
|
||||
Spinner // like setting the oven temperature
|
||||
Separator // TODO
|
||||
Image // TODO
|
||||
Area // TODO
|
||||
Form // TODO
|
||||
|
@ -138,6 +139,8 @@ func (s WidgetType) String() string {
|
|||
return "Slider"
|
||||
case Spinner:
|
||||
return "Spinner"
|
||||
case Separator:
|
||||
return "Separator"
|
||||
case Image:
|
||||
return "Image"
|
||||
case Area:
|
||||
|
|
Loading…
Reference in New Issue