code moved to the cloudflare package

use the cloudflare package
    add a protobuf attempt
    better change detection, but formatting is broken
    don't redraw widgets if they are not visible
    create new dns entry worked
    attempting a DNS RR create
    attempt a create API call
    use cloudflare recommended ENV vars
    turn off debugging

Signed-off-by: Jeff Carr <jcarr@wit.com>
This commit is contained in:
Jeff Carr 2023-12-20 05:58:33 -06:00
parent f67e03db16
commit 2d147a9115
19 changed files with 407 additions and 156 deletions

3
.gitignore vendored
View File

@ -11,6 +11,9 @@ examples/textbox/textbox
examples/cloudflare/cloudflare
examples/*/helloconsole
# protobuf compiled files
protobuf/*.pb.go
# temporary files when building debian packages
/*.deb
/files

View File

@ -170,6 +170,13 @@ func (n *Node) Unpad() *Node {
return n
}
func (n *Node) Expand() *Node {
a := newAction(n, toolkit.Pad)
a.Expand = true
sendAction(a)
return n
}
// is this better?
// yes, this is better. it allows Internationalization very easily
// me.window = myGui.New2().Window("DNS and IPv6 Control Panel").Standard()
@ -182,8 +189,9 @@ func (n *Node) Window(title string) *Node {
// This should not really do anything. as per the docs, the "Standard()" way
// should be the default way
/*
func (n *Node) Standard() *Node {
log(debugError, "Standard() not implemented yet")
log(debugInfo, "Standard() not implemented yet")
return n
}
@ -191,3 +199,4 @@ func (n *Node) SetMargin() *Node {
log(debugError, "DoMargin() not implemented yet")
return n
}
*/

View File

@ -4,10 +4,11 @@ package main
import (
"os"
"log"
"fmt"
"encoding/json"
"io/ioutil"
"net/http"
"strconv"
// "strconv"
"bytes"
"github.com/davecgh/go-spew/spew"
@ -19,7 +20,17 @@ func doChange(dnsRow *RRT) {
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)
stuff, result := httpPut(dnsRow)
if (dnsRow.curlNode != nil) {
pretty, _ := formatJSON(stuff)
log.Println("http PUT curl =", pretty)
dnsRow.curlNode.SetText(pretty)
}
if (dnsRow.resultNode != nil) {
pretty, _ := formatJSON(result)
log.Println("http PUT result =", pretty)
dnsRow.resultNode.SetText(pretty)
}
}
dnsRow.saveNode.Disable()
}
@ -73,24 +84,26 @@ func getZonefile(c *configT) *DNSRecords {
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")
func httpPut(dnsRow *RRT) (string, string) {
var url string = cloudflareURL + os.Getenv("CF_API_ZONEID") + "/dns_records/" + dnsRow.ID
var authKey string = os.Getenv("CF_API_KEY")
var email string = os.Getenv("CF_API_EMAIL")
// make a json record to send on port 90 to cloudflare
// make a json record to send on port 80 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+= `"ttl": "` + "1" + `", `
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)
// log.Println("http PUT data =", data)
// spew.Dump(data)
pretty, _ := formatJSON(string(data))
log.Println("http PUT data =", pretty)
req, err := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(data))
@ -103,19 +116,19 @@ func httpPut(dnsRow *RRT) {
resp, err := client.Do(req)
if err != nil {
log.Println(err)
return
return tmp, fmt.Sprintf("blah err =", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println(err)
return
return tmp, fmt.Sprintf("blah err =", err)
}
log.Println("http PUT body =", body)
spew.Dump(body)
// log.Println("http PUT body =", body)
// spew.Dump(body)
return
return tmp, string(body)
}
// https://api.cloudflare.com/client/v4/zones
@ -185,3 +198,22 @@ func getZones(auth, email string) *DNSRecords {
return &records
}
// formatJSON takes an unformatted JSON string and returns a formatted version.
func formatJSON(unformattedJSON string) (string, error) {
var jsonData interface{}
// Decode the JSON string into an interface
err := json.Unmarshal([]byte(unformattedJSON), &jsonData)
if err != nil {
return "", err
}
// Re-encode the JSON with indentation for formatting
formattedJSON, err := json.MarshalIndent(jsonData, "", " ")
if err != nil {
return "", err
}
return string(formattedJSON), nil
}

31
examples/cloudflare/curl.sh Normal file → Executable file
View File

@ -1,3 +1,28 @@
curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
-H "Authorization: Bearer AAAPutYourTokenInHereSoYouCanTestItL5Cl3" \
-H "Content-Type:application/json"
#curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
# -H "Authorization: Bearer AAAPutYourTokenInHereSoYouCanTestItL5Cl3" \
# -H "Content-Type:application/json"
# https://api.cloudflare.com/client/v4/zones/27b900d9e05cfb9f3a64fecff2497f90/dns_records
#
# {
# "comment": "WIT DNS Control Panel",
# "content": "2001:4860:4860::8888",
# "name": "www",
# "proxied": false,
# "ttl": 3600,
# "type": "AAAA"
#}
curl --request POST \
--url https://api.cloudflare.com/client/v4/zones/27b900d9e05cfb9f3a64fecff2497f90/dns_records \
--header 'Content-Type: application/json' \
--header 'X-Auth-Key: e08806ad85ef97aebaacd2d7fa462a7d417a7x' \
--header 'X-Auth-Email: basilarchia@gmail.com' \
--data '{
"comment": "WIT DNS Control Panel",
"content": "2001:4860:4860::5555",
"name": "www5",
"proxied": false,
"ttl": 3600,
"type": "AAAA"
}'

View File

@ -4,6 +4,8 @@ package main
import (
"log"
"strconv"
"git.wit.org/jcarr/control-panel-dns/cloudflare"
)
func loadDNS(c *configT) {
@ -11,7 +13,8 @@ func loadDNS(c *configT) {
log.Println("adding DNS record", hostname)
newt := mainWindow.NewTab(hostname)
newg := newt.NewGroup("more")
vb := newt.NewBox("vBox", false)
newg := vb.NewGroup("more zoneID = " + c.zoneID)
// make a grid 6 things wide
grid := newg.NewGrid("gridnuts", 6, gridH)
@ -19,41 +22,22 @@ func loadDNS(c *configT) {
// 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.NewLabel("RR type")
grid.NewLabel("hostname")
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()
grid.NewLabel("Proxy")
grid.NewLabel("TTL")
grid.NewLabel("Value")
grid.NewLabel("Save")
masterSave = newt.NewButton("Master Save", func () {
masterSave = vb.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
var rr cloudflare.RRT // dns zonefile resource record
// copy all the JSON values into the row record.
rr.ID = record.ID
@ -62,59 +46,34 @@ func loadDNS(c *configT) {
rr.Content = record.Content
rr.Proxied = record.Proxied
rr.Proxiable = record.Proxiable
rr.TTL = record.TTL
// rr.Ttl = record.TTL
rr.typeNode = grid.NewLabel(record.Type)
rr.nameNode = grid.NewEntryLine(record.Name)
rr.nameNode.SetText(record.Name)
rr.nameNode.Disable()
grid.NewLabel(record.Type)
grid.NewLabel(record.Name)
// set proxy or unproxied
rr.proxyNode = grid.NewDropdown("proxy")
proxy := grid.NewLabel("proxy")
if (record.Proxied) {
rr.proxyNode.AddText("Proxied")
rr.proxyNode.AddText("DNS")
proxy.SetText("On")
} 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()
proxy.SetText("Off")
}
var ttl, short string
var ttl 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
}
grid.NewLabel(ttl)
rr.valueNode = grid.NewEntryLine(short)
rr.valueNode.SetText(record.Content)
val := grid.NewLabel("Value")
val.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 () {
load := grid.NewButton("Load", nil)
load.Custom = func () {
name := "save stuff to cloudflare for " + rr.ID
log.Println(name)
doChange(&rr)
// doChange(&rr)
}
}

View File

@ -7,7 +7,9 @@ import (
"log"
"bufio"
"strings"
"git.wit.org/wit/gui"
"git.wit.org/jcarr/control-panel-dns/cloudflare"
)
var title string = "Cloudflare DNS Control Panel"
@ -44,7 +46,8 @@ func makeCloudflareWindow() {
makeConfigTab(mainWindow)
t = mainWindow.NewTab("Zones")
g1 := t.NewGroup("zones")
vb := t.NewBox("vBox", false)
g1 := vb.NewGroup("zones")
// make dropdown list of zones
zonedrop = g1.NewDropdown("zone")
@ -52,6 +55,7 @@ func makeCloudflareWindow() {
for d, _ := range config {
zonedrop.AddText(d)
}
zonedrop.AddText("stablesid.org")
zonedrop.Custom = func () {
domain := zonedrop.S
@ -82,18 +86,18 @@ func makeConfigTab(window *gui.Node) {
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")
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 $CF_API_KEY \n env $CF_API_EMAIL\n")
// make grid to display credentials
grid := g1.NewGrid("credsGrid", 2, 4) // width = 2
grid.NewLabel("Auth Key")
aw := grid.NewEntryLine("CLOUDFLARE_AUTHKEY")
aw.SetText(os.Getenv("CLOUDFLARE_AUTHKEY"))
aw := grid.NewEntryLine("CF_API_KEY")
aw.SetText(os.Getenv("CF_API_KEY"))
grid.NewLabel("Email")
ew := grid.NewEntryLine("CLOUDFLARE_EMAIL")
ew.SetText(os.Getenv("CLOUDFLARE_EMAIL"))
ew := grid.NewEntryLine("CF_API_EMAIL")
ew.SetText(os.Getenv("CF_API_EMAIL"))
var url string = "https://api.cloudflare.com/client/v4/zones/"
grid.NewLabel("Cloudflare API")
@ -106,6 +110,10 @@ func makeConfigTab(window *gui.Node) {
getZones(aw.S, ew.S)
})
vb.NewButton("cloudflare wit.com", func () {
cloudflare.CreateRR(myGui, "wit.com", "3777302ac4a78cd7fa4f6d3f72086d06")
})
t.Pad()
t.Margin()
vb.Pad()
@ -144,16 +152,16 @@ func showCloudflareCredentials(box *gui.Node) {
grid := box.NewGrid("credsGrid", 2, 4) // width = 2
grid.NewLabel("Domain")
domainWidget = grid.NewEntryLine("CLOUDFLARE_DOMAIN")
domainWidget = grid.NewEntryLine("CF_API_DOMAIN")
grid.NewLabel("Zone ID")
zoneWidget = grid.NewEntryLine("CLOUDFLARE_ZONEID")
zoneWidget = grid.NewEntryLine("CF_API_ZONEID")
grid.NewLabel("Auth Key")
authWidget = grid.NewEntryLine("CLOUDFLARE_AUTHKEY")
authWidget = grid.NewEntryLine("CF_API_KEY")
grid.NewLabel("Email")
emailWidget = grid.NewEntryLine("CLOUDFLARE_EMAIL")
emailWidget = grid.NewEntryLine("CF_API_EMAIL")
var url string = "https://api.cloudflare.com/client/v4/zones/"
grid.NewLabel("Cloudflare API")
@ -161,10 +169,6 @@ func showCloudflareCredentials(box *gui.Node) {
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

View File

@ -34,20 +34,23 @@ 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
typeNode *gui.Node // CNAME, A, AAAA, ...
nameNode *gui.Node // www, mail, ...
proxyNode *gui.Node // If cloudflare is a port 80 & 443 proxy
ttlNode *gui.Node // just set to 1 which means automatic to cloudflare
valueNode *gui.Node // 4.2.2.2, "dkim stuff", etc
curlNode *gui.Node // shows you what you could run via curl
resultNode *gui.Node // what the cloudflare API returned
saveNode *gui.Node // button to send it to cloudflare
ID string
Type string
Name string
Content string
ProxyS string
Proxied bool
Proxiable bool
TTL int
Ttl string
}
/*

30
main.go
View File

@ -37,17 +37,17 @@ func init() {
func watchCallback() {
log(logInfo, "watchCallback() START")
for {
log(logNow, "watchCallback() restarted select for toolkit user events")
log(logInfo, "watchCallback() restarted select for toolkit user events")
select {
case a := <-me.guiChan:
if (a.ActionType == toolkit.UserQuit) {
log(logNow, "doUserEvent() User sent Quit()")
log(logInfo, "doUserEvent() User sent Quit()")
me.rootNode.doCustom()
exit("wit/gui toolkit.UserQuit")
break
}
if (a.ActionType == toolkit.EnableDebug) {
log(logNow, "doUserEvent() Enable Debugging Window")
log(logInfo, "doUserEvent() Enable Debugging Window")
DebugWindow()
break
}
@ -56,7 +56,7 @@ func watchCallback() {
if (n == nil) {
log(logError, "watchCallback() UNKNOWN widget id =", a.WidgetId, a.Name)
} else {
log(logNow, "watchCallback() FOUND widget id =", n.id, n.Name)
log(logInfo, "watchCallback() FOUND widget id =", n.id, n.Name)
n.doUserEvent(a)
}
// this maybe a good idea?
@ -67,7 +67,7 @@ func watchCallback() {
}
func (n *Node) doCustom() {
log(logNow, "doUserEvent() widget =", n.id, n.Name, n.WidgetType, n.B)
log(logInfo, "doUserEvent() widget =", n.id, n.Name, n.WidgetType, n.B)
if (n.Custom == nil) {
log(debugError, "Custom() = nil. SKIPPING")
return
@ -76,40 +76,40 @@ func (n *Node) doCustom() {
}
func (n *Node) doUserEvent(a toolkit.Action) {
log(logNow, "doUserEvent() node =", n.id, n.Name)
log(logInfo, "doUserEvent() node =", n.id, n.Name)
switch n.WidgetType {
case toolkit.Checkbox:
n.B = a.B
log(logNow, "doUserEvent() node =", n.id, n.Name, "set to:", n.B)
log(logInfo, "doUserEvent() node =", n.id, n.Name, "set to:", n.B)
n.doCustom()
case toolkit.Button:
log(logNow, "doUserEvent() node =", n.id, n.Name, "button clicked")
log(logInfo, "doUserEvent() node =", n.id, n.Name, "button clicked")
n.doCustom()
case toolkit.Combobox:
n.S = a.S
log(logNow, "doUserEvent() node =", n.id, n.Name, "set to:", n.S)
log(logInfo, "doUserEvent() node =", n.id, n.Name, "set to:", n.S)
n.doCustom()
case toolkit.Dropdown:
n.S = a.S
log(logNow, "doUserEvent() node =", n.id, n.Name, "set to:", n.S)
log(logInfo, "doUserEvent() node =", n.id, n.Name, "set to:", n.S)
n.doCustom()
case toolkit.Textbox:
n.S = a.S
log(logNow, "doUserEvent() node =", n.id, n.Name, "set to:", n.S)
log(logInfo, "doUserEvent() node =", n.id, n.Name, "set to:", n.S)
n.doCustom()
case toolkit.Spinner:
n.I = a.I
log(logNow, "doUserEvent() node =", n.id, n.Name, "set to:", n.I)
log(logInfo, "doUserEvent() node =", n.id, n.Name, "set to:", n.I)
n.doCustom()
case toolkit.Slider:
n.I = a.I
log(logNow, "doUserEvent() node =", n.id, n.Name, "set to:", n.I)
log(logInfo, "doUserEvent() node =", n.id, n.Name, "set to:", n.I)
n.doCustom()
case toolkit.Window:
log(logNow, "doUserEvent() node =", n.id, n.Name, "window closed")
log(logInfo, "doUserEvent() node =", n.id, n.Name, "window closed")
n.doCustom()
default:
log(logNow, "doUserEvent() type =", n.WidgetType)
log(logInfo, "doUserEvent() type =", n.WidgetType)
}
}

34
protobuf/Makefile Normal file
View File

@ -0,0 +1,34 @@
all:
# You must use the current protoc-gen-go
# protoc --version 3.6++ does not mean that protoc will generate version3 .go files
#
# apt remove golang-goprotobuf-dev
# apt install protobuf-compiler
#
# Then:
# go get -u github.com/golang/protobuf/protoc-gen-go
# cd ~/go/src/github.com/golang/protobuf/protoc-gen-go
# go install
#
# Then:
protoc --version
make widget.pb.go
clean:
rm -f *.pb.go
widget.pb.go: widget.proto
protoc --go_out=. widget.proto
compile:
protoc --go_out=. *.proto
deps:
apt install golang-goprotobuf-dev
apt install protobuf-compiler
push:
git pull
git add --all
git commit -a -s
git push

117
protobuf/widget.proto Normal file
View File

@ -0,0 +1,117 @@
syntax = "proto3";
package guiProtobuf;
message Action {
WidgetType widgetType = 1;
ActionType actionType = 2;
int64 widgetId = 3;
int64 parentId = 4;
string text = 5; // what is visable to the user
string name = 6; // a name useful for programming
// This is how the values are passed back and forth
// values from things like checkboxes & dropdown's
bool b = 7;
int64 i = 8;
string s = 9;
// This is used for things like a slider(0,100)
int64 x = 10;
int64 y = 11;
// This is for the grid size & widget position
int64 w = 12;
int64 h = 13;
int64 atw = 14;
int64 ath = 15;
bool margin = 16; // Put space around elements to improve look & feel
bool expand = 17; // Make widgets fill up the space available
repeated Response results = 18;
repeated Network networks = 19;
repeated VM vms = 20;
enum WidgetType {
Unknown = 0;
Root = 1; // the master 'root' node of the binary tree
Flag = 2; // used to send configuration values to plugins
Window = 3; // in certain gui's (ncurses), these are tabs
Tab = 4; // internally, this is a window
Frame = 5; // deprecate?
Grid = 6; // like drawers in a chest
Group = 7; // like the 'Appetizers' section on a menu
Box = 8; // a vertical or horizontal stack of widgets
Button = 9;
Checkbox = 10; // select 'on' or 'off'
Dropdown = 11;
Combobox = 12; // dropdown with edit=true
Label = 13;
Textbox = 14; // is this a Label with edit=true
Slider = 15; // like a progress bar
Spinner = 16; // like setting the oven temperature
Separator = 17; // TODO
Image = 18; // TODO
Area = 19; // TODO
Form = 20; // TODO
Font = 21; // TODO
Color = 22; // TODO
Dialog = 23; // TODO
Stdout = 24; // can be used to capture and display log output
}
enum ActionType {
Health = 0;
Add = 1;
Delete = 2;
Get = 3;
Set = 4;
GetText = 5;
SetText = 6;
AddText = 7;
Show = 8;
Hide = 9;
Enable = 10;
Disable = 11;
Margin = 12;
Unmargin = 13;
Pad = 14;
Unpad = 15;
Append = 16;
Move = 17;
Dump = 18;
User = 19; // the user did something (mouse, keyboard, etc)
InitToolkit = 20; // initializes the toolkit
CloseToolkit = 21; // closes the toolkit
UserQuit = 22; // the user closed the GUI
EnableDebug = 23; // open the debugging window
}
message Response {
// ActionType type = 1;
int64 id = 2;
string name = 3;
string error = 4;
repeated string snippets = 5;
}
message Network {
int64 id = 1;
string name = 2;
int64 total_cpu = 3;
int64 total_mem = 4;
string login_url = 5;
}
message VM {
int64 id = 1;
string name = 2;
string hostname = 3;
int64 cpus = 4;
int64 memory = 5;
int64 disk = 6;
string IPv6 = 7;
string role = 8;
string baseImage = 9;
}
}

View File

@ -38,11 +38,11 @@ func (n *node) enable(b bool) {
}
func (n *node) pad(at toolkit.ActionType) {
log(debugError, "pad()")
log(logInfo, "pad() on WidgetId =", n.WidgetId)
t := n.tk
if (t == nil) {
log(debugError, "pad() toolkit struct == nil. for", n.WidgetId)
log(logError, "pad() toolkit struct == nil. for", n.WidgetId)
return
}

View File

@ -127,15 +127,16 @@ func (p *node) place(n *node) bool {
return true
case toolkit.Tab:
if (p.tk.uiTab == nil) {
log(logError, "p.tk.uiTab == nil", p.tk)
log(logError, "p.tk.uiTab == nil for n.WidgetId =", n.WidgetId, "p.tk =", p.tk)
panic("p.tk.uiTab == nil")
}
if (n.tk.uiControl == nil) {
log(logError, "n.tk.uiControl == nil", n.tk)
log(logError, "n.tk.uiControl == nil for n.WidgetId =", n.WidgetId, "n.tk =", 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)
log(logError, "CHECK LOGIC ON THIS. APPENDING directly into a window without a tab")
// 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

View File

@ -14,12 +14,12 @@ var stretchy bool // expand things like buttons to the maximum size
var padded bool // add space between things like buttons
var margin bool // add space around the frames of windows
var debugToolkit bool = true
var debugChange bool = true
var debugPlugin bool = true
var debugAction bool = true
var debugFlags bool = true
var debugGrid bool = true
var debugToolkit bool = false
var debugChange bool = false
var debugPlugin bool = false
var debugAction bool = false
var debugFlags bool = false
var debugGrid bool = false
var debugNow bool = true
var debugError bool = true

View File

@ -40,13 +40,18 @@ func init() {
// log(debugToolkit, "init() Setting defaultBehavior = true")
setDefaultBehavior(true)
// TODO: this is messed up. run ui.Main() from the first add? Initialize it with an empty thing first?
// fake out the OS toolkit by making a fake window. This is probably needed for macos & windows
// actually, this probably breaks the macos build
go ui.Main(func() {
demoUI()
})
// andlabs = make(map[int]*andlabsT)
pluginChan = make(chan toolkit.Action, 1)
log(logNow, "Init() start channel reciever")
go ui.Main(func() {
demoUI()
})
go catchActionChannel()
log(logNow, "Init() END")
}

View File

@ -86,7 +86,8 @@ func demoUI() {
messageLabel.SetText("")
})
mainWindow.Show()
// this is messed up.
// mainWindow.Show()
}
/*

View File

@ -45,7 +45,8 @@ func (n *node) showWidgetPlacement(b bool, s string) {
s1 += fmt.Sprintf("At(%2d,%2d) ", n.AtW, n.AtH)
}
}
log(b, s1, s, n.WidgetType, ",", n.Name) // , "text=", w.text)
tmp := "." + n.Name + "."
log(b, s1, s, n.WidgetType, ",", tmp) // , "text=", w.text)
}
func (n *node) dumpWidget(pad string) {

View File

@ -43,7 +43,7 @@ func catchActionChannel() {
log(logError,"ERROR: console did not initialize")
continue
}
log(logNow, "catchActionChannel()", a.WidgetId, a.ActionType, a.WidgetType, a.Name)
log(logInfo, "catchActionChannel()", a.WidgetId, a.ActionType, a.WidgetType, a.Name)
action(&a)
}
}

View File

@ -51,8 +51,22 @@ func action(a *toolkit.Action) {
case toolkit.CloseToolkit:
log(logNow, "attempting to close the plugin and release stdout and stderr")
standardExit()
case toolkit.Enable:
if n.Visible() {
// widget was already shown
} else {
log(logInfo, "Setting Visable to true", a.Name)
n.SetVisible(true)
}
case toolkit.Disable:
if n.Visible() {
log(logInfo, "Setting Visable to false", a.Name)
n.SetVisible(false)
} else {
// widget was already hidden
}
default:
log(logError, "action() Unknown =", a.ActionType, a.WidgetType, a.Name)
log(logError, "action() ActionType =", a.ActionType, "WidgetType =", a.WidgetType, "Name =", a.Name)
}
log(logInfo, "action() END")
}
@ -70,16 +84,28 @@ func (n *node) AddText(text string) {
}
func (n *node) SetText(text string) {
var changed bool = false
if (n == nil) {
log(logNow, "widget is nil")
return
}
n.S = text
n.Text = text
if (n.Text != text) {
n.Text = text
changed = true
}
if (n.S != text) {
n.S = text
changed = true
}
if (! changed) {
return
}
n.textResize()
n.deleteView()
n.showView()
if (n.Visible()) {
n.textResize()
n.deleteView()
n.showView()
}
}
func (n *node) Set(val any) {

View File

@ -20,20 +20,30 @@ func splitLines(s string) []string {
return lines
}
func (n *node) textResize() {
func (n *node) textResize() bool {
w := n.tk
var width, height int = 0, 0
var changed bool = false
for i, s := range splitLines(n.Text) {
log(logNow, "textResize() len =", len(s), i, s)
log(logInfo, "textResize() len =", len(s), i, s)
if (width < len(s)) {
width = len(s)
}
height += 1
}
w.gocuiSize.w1 = w.gocuiSize.w0 + width + me.FramePadW
w.gocuiSize.h1 = w.gocuiSize.h0 + height + me.FramePadH
n.showWidgetPlacement(logNow, "textResize()")
if (w.gocuiSize.w1 != w.gocuiSize.w0 + width + me.FramePadW) {
w.gocuiSize.w1 = w.gocuiSize.w0 + width + me.FramePadW
changed = true
}
if (w.gocuiSize.h1 != w.gocuiSize.h0 + height + me.FramePadH) {
w.gocuiSize.h1 = w.gocuiSize.h0 + height + me.FramePadH
changed = true
}
if (changed) {
n.showWidgetPlacement(logNow, "textResize() changed")
}
return changed
}
func (n *node) hideView() {
@ -58,17 +68,38 @@ func (n *node) showView() {
x0, y0, x1, y1, err := me.baseGui.ViewPosition(w.cuiName)
log(logInfo, "showView() w.v already defined for widget", n.Name, err)
// n.smartGocuiSize()
changed := n.textResize()
if (changed) {
log(logNow, "showView() textResize() changed. Should recreateView here wId =", w.cuiName)
} else {
log(logNow, "showView() Clear() and Fprint() here wId =", w.cuiName)
w.v.Clear()
fmt.Fprint(w.v, n.Text)
n.SetVisible(false)
n.SetVisible(true)
return
}
// 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)
if (x0 != w.gocuiSize.w0) {
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)
if (y0 != w.gocuiSize.h0) {
log(logError, "showView() start hight mismatch id=", w.cuiName, "gocui h vs computed h =", w.gocuiSize.h0, y0)
n.recreateView()
return
}
if (x1 != w.gocuiSize.w1) {
log(logError, "showView() too wide", w.cuiName, "w,w", w.gocuiSize.w1, x1)
n.recreateView()
return
}
if (y1 != w.gocuiSize.h1) {
log(logError, "showView() too high", w.cuiName, "h,h", w.gocuiSize.h1, y1)
n.recreateView()
return
}