Compare commits

..

No commits in common. "guimaster" and "v0.22.7" have entirely different histories.

13 changed files with 158 additions and 734 deletions

View File

@ -1,4 +1,6 @@
redo: proto goimports vet
all: goimports vet
redo: clean proto goimports vet
vet:
@GO111MODULE=off go vet
@ -12,11 +14,9 @@ redomod: goimports
goimports:
goimports -w *.go
proto: toolkitConfig.pb.go
toolkitConfig.pb.go: toolkitConfig.proto
proto:
autogenpb --proto widget.proto
autogenpb --proto toolkitConfig.proto
clean:
rm -f go.* *.pb.go
go-mod-clean --purge

166
action.go
View File

@ -1,166 +0,0 @@
// Although most code from WIT.COM Inc is under the GPL
// This code is more generic because it must be able
// to be used in any GUI plugin
package tree
import (
"go.wit.com/lib/protobuf/guipb"
"go.wit.com/log"
"go.wit.com/widget"
)
// everything from the application goes through here
func (me *TreeInfo) doAction(a widget.Action) {
if a.ActionType == widget.ToolkitInit {
log.Log(TREE, "tree.doAction() trapped ToolkitInit finally!")
a.WidgetType = widget.Root
n := addNode(&a)
me.Add(n)
log.Log(TREE, "tree.doAction() init() me.treeRoot")
if me.ToolkitInit == nil {
log.Log(TREE, "tree.doAction() ToolkitInit() was called before plugin had a chance to initialize")
log.Log(TREE, "tree.doAction() TODO: fix channel to pause")
return
}
log.Log(TREE, "tree.doAction() doing ToolkitInit()")
me.ToolkitInit()
return
}
if a.TablePB != nil {
log.Log(TREE, "tree: got a TablePB")
me.doTable(a)
return
}
if a.WidgetId == 0 {
if treeRoot == nil {
log.Log(TREE, "tree.doAction() yes, treeRoot is nil. add here")
}
}
n := treeRoot.FindWidgetId(a.WidgetId)
switch a.ActionType {
case widget.Add:
if n == nil {
n := me.AddNode(&a)
me.Add(n)
return
}
if a.WidgetId == 0 {
// this is ok. This is the binary tree base and it's already initialized. This happens on startup
return
}
// this shouldn't really happen. It's good to print a warning so the plugin code can be debugged
log.Log(TREEWARN, "attempting to re-add widget", a.WidgetId, a.WidgetType, a.ActionType)
return
}
if n == nil {
// log.Log(TREEWARN, "tree.FindWidgetId() n == nil", a.WidgetId, a.WidgetType, a.ActionType)
// log.Log(TREEWARN, "tree.FindWidgetId() n == nil", a.State.CurrentS)
// log.Log(TREEWARN, "tree.FindWidgetId() n == nil. A bug in your application?")
log.Log(TREEWARN, "tree.doAction() bug in gui. trying to do action", a.ActionType, "before widget init() wId =", a.WidgetId)
if a.WidgetId == 0 {
log.Log(TREEWARN, "tree.doAction() bug in gui. on wId zero. is treeRoot nil?")
if treeRoot == nil {
log.Log(TREEWARN, "tree.doAction() yes, treeRoot is nil")
}
}
return
}
switch a.ActionType {
case widget.SetText:
log.Log(TREE, "tree.SetText() a.State.CurrentS =", a.State.CurrentS)
log.Log(TREE, "tree.SetText() a.State.DefaultS =", a.State.DefaultS)
log.Log(TREE, "tree.SetText() a.State.NewString =", a.State.NewString)
switch n.WidgetType {
case widget.Dropdown:
me.SetText(n, a.State.NewString)
case widget.Combobox:
me.SetText(n, a.State.NewString)
case widget.Textbox:
me.SetText(n, a.State.NewString)
case widget.Window:
me.SetTitle(n, a.State.Label)
default:
// buttons, checkboxes, groups, etc
me.SetLabel(n, a.State.Label)
}
case widget.AddText:
switch n.WidgetType {
case widget.Dropdown:
n.ddStrings = append(n.ddStrings, a.State.NewString)
me.AddText(n, a.State.NewString)
case widget.Combobox:
n.ddStrings = append(n.ddStrings, a.State.NewString)
me.AddText(n, a.State.NewString)
default:
log.Log(TREEWARN, "AddText() not supported on widget", n.WidgetType, n.String())
}
case widget.Checked:
switch n.WidgetType {
case widget.Checkbox:
if me.SetChecked == nil {
log.Log(TREEWARN, "SetChecked() == nil in toolkit", me.PluginName)
} else {
me.SetChecked(n, a.State.Checked)
}
default:
log.Log(TREEWARN, "SetChecked() not supported on widget", n.WidgetType, n.String())
}
case widget.Show:
if n.WidgetType == widget.Table {
t, err := loadTable(&a)
if err != nil {
log.Info("unmarshal data failed", err)
return
}
if t == nil {
log.Info("unmarshal data failed table == nil")
} else {
me.ShowTable(nil)
}
} else {
n.State.Hidden = false
me.Show(n)
}
case widget.Hide:
n.State.Hidden = true
me.Hide(n)
log.Info("tree: doing hide here on", a.WidgetId, n.WidgetType)
case widget.Enable:
n.State.Enable = true
me.Enable(n)
case widget.Disable:
n.State.Enable = false
me.Disable(n)
case widget.Delete:
if me.Hide == nil {
log.Info("toolkit doesn't know how to Hide() widgets")
} else {
me.Hide(n)
}
me.DeleteNode(n)
// now remove the child from the parent
default:
log.Log(TREEWARN, "tree.Action() unknown action", a.ActionType, "on wId", a.WidgetId)
// me.NodeAction(n, a.ActionType)
}
}
func loadTable(a *widget.Action) (*guipb.Tables, error) {
var t *guipb.Tables
err := t.Unmarshal(a.TablePB)
/*
test := NewRepos()
if test.Uuid != all.Uuid {
log.Log(WARN, "uuids do not match", test.Uuid, all.Uuid)
deleteProtobufFile(cfgname)
}
if test.Version != all.Version {
log.Log(WARN, "versions do not match", test.Version, all.Version)
deleteProtobufFile(cfgname)
}
*/
// log.Log(INFO, cfgname, "protobuf versions and uuid match", all.Uuid, all.Version)
return t, err
}

View File

@ -5,23 +5,14 @@ import (
"go.wit.com/widget"
)
// this is in common.go, do not move it
func (me *TreeInfo) AddNode(a *widget.Action) *Node {
if me.TryLock() {
defer me.Unlock()
} else {
log.Log(TREE, "mutex lock was already held before AddNode()")
}
return addNode(a)
}
func addNode(a *widget.Action) *Node {
n := new(Node)
n.WidgetType = a.WidgetType
n.WidgetId = a.WidgetId
n.ParentId = a.ParentId
n.State = a.State
n.State.Enable = a.State.Enable
// n.Strings = make(map[string]int)
// slices.Reverse(lines)
// dropdown strings
@ -38,9 +29,9 @@ func addNode(a *widget.Action) *Node {
}
if treeRoot.FindWidgetId(a.WidgetId) != nil {
// ignore these errors for now
log.Log(TREE, "AddNode() WidgetId already exists", a.WidgetId)
log.Log(TREE, "TODO: figure out what to do here probably this is a Show() / Hide() issue")
log.Log(TREEWARN, "AddNode() WidgetId already exists", a.WidgetId)
log.Log(TREEWARN, "probably this is a Show() / Hide() issue")
log.Log(TREEWARN, "TODO: figure out what to do here")
return treeRoot.FindWidgetId(a.WidgetId)
}
@ -59,15 +50,8 @@ func addNode(a *widget.Action) *Node {
return n
}
func (me *TreeInfo) DeleteNode(n *Node) {
log.Log(TREE, "DeleteNode() before lock n =", n.WidgetId, n.GetProgName())
if me.TryLock() {
defer me.Unlock()
} else {
log.Info("TREE: mutex lock was already held before DeleteNode()")
}
func (n *Node) DeleteNode() {
p := n.Parent
log.Log(TREE, "DeleteNode() parent =", p.WidgetId, p.GetProgName())
for i, child := range p.children {
log.Log(TREE, "parent has child:", i, child.WidgetId, child.GetProgName())
if n == child {

View File

@ -67,10 +67,6 @@ func (n *Node) Hidden() bool {
return n.State.Hidden
}
func (n *Node) IsEnabled() bool {
return n.State.Enable
}
/* avoid this function name as confusing
func (n *Node) GetText() string { // BAD
return widget.GetString(n.State.Value)

39
date.go
View File

@ -1,39 +0,0 @@
package tree
import (
"time"
)
// TODO; let the user choose the date format
func MakeDatestamp(t time.Time) string {
/*
// Get system locale from the environment
locale := os.Getenv("LANG")
if locale == "" {
locale = "en_US" // Default to English (US) if not set
}
// Parse the language tag
tag, err := language.Parse(locale)
if err != nil {
log.Fatalf("Invalid locale: %v", err)
}
// Create a date formatter
formatter := date.NewFormatter(date.OrderDefault, catalog.NewBuilder())
// Get the current timestamp
now := time.Now()
// Format the date based on the locale
p := message.NewPrinter(tag)
formattedDate := formatter.Format(tag, now)
// Print the formatted date
fmt.Println("Formatted Date:", formattedDate)
// Alternative: Use predefined time formats
fmt.Println("Localized Date (fallback):", p.Sprintf("%v", now.Format(time.RFC1123)))
*/
return t.Format(time.RFC1123)
}

63
find.go
View File

@ -1,63 +0,0 @@
package tree
import "log"
// find things in the tree
// also verify parent <-> child mappings aren't a lie
// searches the binary tree for a WidgetId
func FindWidgetId(id int) *Node {
return treeRoot.FindWidgetId(id)
}
func FindWidgetById(id int) *Node {
return treeRoot.FindWidgetId(id)
}
// searches the binary tree for a WidgetId
func (n *Node) FindWidgetId(id int) *Node {
if n == nil {
return nil
}
if n.WidgetId == id {
return n
}
for _, child := range n.children {
newN := child.FindWidgetId(id)
if newN != nil {
return newN
}
}
return nil
}
// used for debugging the 'gui' package
// to make sure things are valid
// fixes any errors along the way
func (me *Node) VerifyParentId() bool {
return me.verifyParentId(0)
}
func (n *Node) verifyParentId(parentId int) bool {
if n == nil {
return false
}
var ok bool = true
if n.ParentId != parentId {
log.Printf("fixed widgetId %d from %d to %d", n.WidgetId, n.ParentId, parentId)
n.ParentId = parentId
ok = false
}
for _, child := range n.children {
if child.verifyParentId(n.WidgetId) {
// everything is ok
} else {
ok = false
}
}
return ok
}

97
init.go
View File

@ -16,6 +16,71 @@ import (
var muAction sync.Mutex
// TODO: add checks for nil function pointers
func (me *TreeInfo) newAction(a widget.Action) {
n := treeRoot.FindWidgetId(a.WidgetId)
switch a.ActionType {
case widget.Add:
if n == nil {
n := me.AddNode(&a)
me.Add(n)
return
}
log.Log(TREEWARN, "attempting to re-add widget", a.WidgetId, a.WidgetType, a.ActionType)
return
}
if n == nil {
log.Log(TREEWARN, "tree.FindWidgetId() n == nil", a.WidgetId, a.WidgetType, a.ActionType)
log.Log(TREEWARN, "tree.FindWidgetId() n == nil", a.State.CurrentS)
log.Log(TREEWARN, "tree.FindWidgetId() n == nil. This should not happen. Bug in gui or tree package?")
log.Log(TREEWARN, "tree.FindWidgetId() n == nil. A bug in your application?")
return
}
switch a.ActionType {
case widget.SetText:
log.Log(TREE, "tree.SetText() a.State.CurrentS =", a.State.CurrentS)
log.Log(TREE, "tree.SetText() a.State.DefaultS =", a.State.DefaultS)
log.Log(TREE, "tree.SetText() a.State.NewString =", a.State.NewString)
switch n.WidgetType {
case widget.Dropdown:
me.SetText(n, a.State.NewString)
case widget.Combobox:
me.SetText(n, a.State.NewString)
case widget.Textbox:
me.SetText(n, a.State.NewString)
case widget.Window:
me.SetTitle(n, a.State.Label)
default:
// buttons, checkboxes, groups, etc
me.SetLabel(n, a.State.Label)
}
case widget.AddText:
switch n.WidgetType {
case widget.Dropdown:
n.ddStrings = append(n.ddStrings, a.State.NewString)
me.AddText(n, a.State.NewString)
case widget.Combobox:
n.ddStrings = append(n.ddStrings, a.State.NewString)
me.AddText(n, a.State.NewString)
default:
log.Log(TREEWARN, "AddText() not supported on widget", n.WidgetType, n.String())
}
case widget.Checked:
switch n.WidgetType {
case widget.Checkbox:
if me.SetChecked == nil {
log.Log(TREEWARN, "SetChecked() == nil in toolkit", me.PluginName)
} else {
me.SetChecked(n, a.State.Checked)
}
default:
log.Log(TREEWARN, "SetChecked() not supported on widget", n.WidgetType, n.String())
}
default:
me.NodeAction(n, a.ActionType)
}
}
func (me *TreeInfo) catchActionChannel() {
defer func() {
if r := recover(); r != nil {
@ -36,11 +101,7 @@ func (me *TreeInfo) catchActionChannel() {
case a := <-me.pluginChan:
log.Verbose("catchActionChannel() on ", a.WidgetId, a.WidgetType, a.ProgName)
muAction.Lock()
me.WaitOK()
// time.Sleep(10 * time.Millisecond)
me.Lock()
me.doAction(a)
me.Unlock()
me.newAction(a)
muAction.Unlock()
}
}
@ -49,7 +110,6 @@ func (me *TreeInfo) catchActionChannel() {
func New() *TreeInfo {
me := new(TreeInfo)
me.pluginChan = make(chan widget.Action, 1)
me.frozenChan = make(chan widget.Action, 1)
me.config = configLoad()
log.Log(TREE, "Init() start channel reciever")
@ -68,30 +128,7 @@ func (t *TreeInfo) ConfigFind(n string) (string, error) {
if n == r.Name {
return r.Value, nil
}
// log.Info("toolkit config no-match on", r.Plugin, r.Name, r.Value, n)
log.Info("toolkit config", r.Plugin, r.Name, r.Value, n)
}
return "", fmt.Errorf("toolkit config %s not found", n)
}
func (t *TreeInfo) ConfigSave(o *ToolkitConfig) {
t.configInsert(o)
t.config.configSave()
}
// update the config option value (or append if new record)
func (t *TreeInfo) configInsert(newr *ToolkitConfig) {
all := t.config.All() // get the list of repos
for all.Scan() {
r := all.Next()
if t.PluginName != r.Plugin {
// option isn't for this plugin
continue
}
if newr.Name == r.Name {
// found the record!
r.Value = newr.Value
return
}
}
t.config.Append(newr)
}

View File

@ -6,35 +6,37 @@ package tree
There are some helper functions that are probably going to be
the same everywhere. Mostly due to handling the binary tree structure
and the channel communication
For now, it's just a symlink to the 'master' version in
./toolkit/nocui/common.go
*/
import (
"os"
"time"
"go.wit.com/log"
"go.wit.com/widget"
)
func (me *TreeInfo) InitOK() {
me.ok = true
// searches the binary tree for a WidgetId
func FindWidgetId(id int) *Node {
return treeRoot.FindWidgetId(id)
}
// this hack is to wait for the application to send something
// before trying to do anything. todo: rethink this someday
func (me *TreeInfo) WaitOK() {
for {
if me == nil {
log.Info("WaitOK lied. me == nil but returned anyway")
log.Info("WaitOK lied. me == nil but returned anyway")
log.Info("WaitOK lied. me == nil but returned anyway")
os.Exit(-1)
}
if me.ok {
return
}
time.Sleep(10 * time.Millisecond)
// searches the binary tree for a WidgetId
func (n *Node) FindWidgetId(id int) *Node {
if n == nil {
return nil
}
if n.WidgetId == id {
return n
}
for _, child := range n.children {
newN := child.FindWidgetId(id)
if newN != nil {
return newN
}
}
return nil
}
// Other goroutines must use this to access the GUI
@ -48,13 +50,6 @@ func (me *TreeInfo) Callback(guiCallback chan widget.Action) {
me.callback = guiCallback
}
// this is the function that receives things from the application
func (me *TreeInfo) PluginChannel() chan widget.Action {
me.WaitOK()
return me.pluginChan
}
// this is the function that receives things from the application
func (me *TreeInfo) FrozenChannel() chan widget.Action {
return me.frozenChan
}

View File

@ -7,9 +7,6 @@ package tree
*/
import (
"sync"
"go.wit.com/lib/protobuf/guipb"
"go.wit.com/widget"
)
@ -20,28 +17,27 @@ import (
var treeRoot *Node
type TreeInfo struct {
sync.Mutex // a lock around the tree to serialize access
ok bool // indicates the plugin actually initialized
PluginName string // used to identify the plugin
config *ToolkitConfigs // protobuf of plugin settings
callback chan widget.Action // mouse clicks or keyboard events back to the program
pluginChan chan widget.Action // this is the channel we get requests to make widgets
frozenChan chan widget.Action // expirement to get fyne to work
Add func(*Node) // add a new widget
AddText func(*Node, string) // add a string to a dropdown widget
SetText func(*Node, string) // set the text of a widget
SetTitle func(*Node, string) // update the title of a window or tab
SetLabel func(*Node, string) // update the "label" (aka "Name") for a widget
SetChecked func(*Node, bool) // set the state of a checkbox
ToolkitInit func() // init the plugin
ToolkitClose func() // shutdown and unload the plugin
Show func(*Node) // show a widget
Hide func(*Node) // hide a widget
Enable func(*Node) // enable a widget
Disable func(*Node) // disable a widget
ShowTable func(*guipb.Table) // attempt at sending a whole table
currentTables []*guipb.Table // track the list of tables?
Root *guipb.Tree // this is the future of this system
PluginName string
config *ToolkitConfigs
// this is the channel we send user events like
// mouse clicks or keyboard events back to the program
callback chan widget.Action
// this is the channel we get requests to make widgets
pluginChan chan widget.Action
// NodeI interface{}
// ActionFromChannel func(widget.Action)
NodeAction func(*Node, widget.ActionType)
Add func(*Node)
AddText func(*Node, string)
SetText func(*Node, string)
SetTitle func(*Node, string)
SetLabel func(*Node, string)
SetChecked func(*Node, bool)
ToolkitClose func()
}
type Node struct {

352
table.go
View File

@ -1,352 +0,0 @@
// Although most code from WIT.COM Inc is under the GPL
// This code is more generic because it must be able
// to be used in any GUI plugin
package tree
import (
"fmt"
"time"
"go.wit.com/lib/gui/shell"
"go.wit.com/lib/protobuf/guipb"
"go.wit.com/log"
"go.wit.com/widget"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/timestamppb"
)
func (me *TreeInfo) doTable(a widget.Action) {
if a.TablePB == nil {
log.Log(TREE, "tree: action didn't have a Table PB")
return
}
pb := guipb.NewTables()
if err := pb.Unmarshal(a.TablePB); err != nil {
log.Info("unmarshal error", err, "data len =", len(a.TablePB))
return
}
log.Info("tree.doTables() start. # of tables:", len(pb.Tables))
for t := range pb.IterAll() {
// for i, o := range t.Order {
// log.Info("got order:", t.Title, i, o)
// }
// dumpTable(t)
// me.ShowTable(t)
// log.Info("TREE FOUND TABLE UUID", t.Uuid)
for i, ot := range me.currentTables {
// log.Info("TREE already has UUID", i, ot.Uuid)
if t.Uuid == ot.Uuid {
log.Log(TREE, "TREE found UUID! update table here", i, ot.Uuid)
if ot.Grid == nil {
log.Log(TREE, "TREE found UUID! ot.grid.Id = nil. need to find grid id here")
return
} else {
log.Log(TREE, "TREE found UUID! grid.Id =", ot.Grid.Id)
t.Grid = ot.Grid
}
if t.Grid == nil {
log.Log(TREE, "TREE found UUID! grid.Id = nil. need to find grid id here")
return
}
log.Log(TREE, "TREE found UUID! update table here", i, ot.Uuid, "grid.Id =", t.Grid.Id)
me.updateTable(t)
return
}
}
me.currentTables = append(me.currentTables, t)
if t.Grid == nil {
log.Log(TREEWARN, "new table error: grid.Id = nil need to set grid id here")
} else {
// log.Info("NEW TREE: grid.Id =", t.Grid.Id)
}
me.makeTable(t)
}
}
func (grid *Node) makeGridLabel(pb *guipb.Widget, w int, h int) *Node {
a := new(widget.Action)
a.WidgetType = widget.Label
a.WidgetId = int(pb.Id)
a.ParentId = grid.WidgetId
a.State.Enable = true
a.State.Label = pb.Name
a.State.AtW = w
a.State.AtH = h
a.State.GridOffset.X = w
a.State.GridOffset.Y = h
// log.Info("makeGridLabel()", a.State)
return addNode(a)
}
func (grid *Node) makeGridButton(pb *guipb.Widget, w int, h int) *Node {
a := new(widget.Action)
a.WidgetType = widget.Button
a.WidgetId = int(pb.Id)
a.ParentId = grid.WidgetId
a.State.Enable = true
a.State.Label = pb.Name
a.State.AtW = w
a.State.AtH = h
a.State.GridOffset.X = w
a.State.GridOffset.Y = h
// log.Info("makeGridLabel()", a.State)
return addNode(a)
}
func (me *TreeInfo) updateTable(t *guipb.Table) {
grid := FindWidgetId(int(t.Grid.Id))
if grid == nil {
log.Info("tree: updateTable() failed to make grid")
return
}
// delete the existing table
me.DeleteNode(grid)
// remake the table
me.Add(grid)
var h int = 0
var w int = 0
for _, name := range t.Order {
// log.Info("got order:", t.Title, name)
if me.addTableRow(t, grid, name, w) {
// log.Info("tree:row() COLUMN GOOD", t.Title, name, w, h)
} else {
log.Info("tree:row() COLOMN FAIL", t.Title, name, w, h)
}
w += 1
}
}
/*
func (me *TreeInfo) updateRow(t *guipb.Table, name string) {
for _, r := range t.StringRows {
if name == r.Header.Name {
// debugging code
// id := r.Header.Id
// n := treeRoot.FindWidgetId(int(id))
// if n == nil {
// log.Info("could not find widget id", id)
// }
log.Info("tree.updateRow(string)", r.Header, "len =", len(r.Widgets))
// if r.Header.Name == "Hostname" {
// }
// log.Info("tree.updateRow() found Hostnames", r.Vals)
for i, v := range r.Vals {
// log.Info("tree: Hostname Widget", i, v, w.Name)
w := r.Widgets[i]
if v != w.Name {
log.Info("tree: need to update:", i, v, "vs", w.Name, w.Id)
n := treeRoot.FindWidgetId(int(w.Id))
if n == nil {
log.Info("tree.TableUpdate() err n == nil ", w.Id, w.Name)
continue
}
me.SetText(n, v)
}
if r.Header.Name == "CurrentBranchName" {
log.Info("tree: check:", i, v, "vs", w.Name, w.Id)
}
}
return
}
}
for _, r := range t.TimeRows {
if name != r.Header.Name {
continue
}
log.Info("tree.updateRow(time)", r.Header, "len =", len(r.Widgets))
for i, _ := range r.Vals {
// log.Info("tree: Hostname Widget", i, v, w.Name)
w := r.Widgets[i]
n := treeRoot.FindWidgetId(int(w.Id))
if n == nil {
log.Info("tree.TableUpdate() err n == nil ", w.Id, w.Name)
continue
}
msg, err := anypb.UnmarshalNew(w.Val, proto.UnmarshalOptions{})
if err != nil {
log.Fatalf("failed to unmarshal: %v", err)
}
switch v := msg.(type) {
case *timestamppb.Timestamp:
me.SetText(n, shell.FormatDuration(time.Since(v.AsTime())))
default:
me.SetText(n, fmt.Sprintf("%v", v))
}
}
return
}
}
*/
func (me *TreeInfo) makeTable(t *guipb.Table) {
var grid *Node
if t.Parent != nil {
a := new(widget.Action)
a.WidgetType = widget.Grid
a.WidgetId = int(t.Grid.Id)
a.ParentId = int(t.Parent.Id)
a.State.Enable = true
grid = addNode(a)
}
if grid == nil {
log.Log(TREEWARN, "tree: makeTable() failed to make grid")
return
}
me.Add(grid)
grid.State.ProgName = "TableGridPB"
// log.Info("tree: makeTable() finished add win & grid")
var h int = 0
var w int = 0
for _, name := range t.Order {
// log.Info("got order:", t.Title, name)
if me.addTableRow(t, grid, name, w) {
// log.Info("tree:row() COLUMN GOOD", t.Title, name, w, h)
} else {
log.Log(TREEWARN, "tree:row() COLOMN FAIL", t.Title, name, w, h)
}
w += 1
}
}
func (me *TreeInfo) addTableRow(t *guipb.Table, grid *Node, name string, w int) bool {
var h int = 0
for _, r := range t.StringRows {
if name != r.Header.Name {
// log.Info("skip string row:", r.Header.Name, "!=", name)
continue
}
// log.Info("tree: Add()ing to grid here", r.Header.Id, r.Header.Name, w, h)
head := grid.makeGridLabel(r.Header, w, h)
me.Add(head)
h += 1
for _, v := range r.Widgets {
// log.Info("tree: Add()ing to grid here", v.Id, v.Name, w, h)
lab := grid.makeGridLabel(v, w, h)
me.Add(lab)
h += 1
}
return true
}
for _, r := range t.ButtonRows {
if name != r.Header.Name {
// log.Info("skip string row:", r.Header.Name, "!=", name)
continue
}
// log.Info("tree: Add()ing to grid here", r.Header.Id, r.Header.Name, w, h)
head := grid.makeGridLabel(r.Header, w, h)
me.Add(head)
h += 1
for _, v := range r.Widgets {
// log.Info("tree: Add()ing to grid here", v.Id, v.Name, w, h)
lab := grid.makeGridButton(v, w, h)
me.Add(lab)
h += 1
}
return true
}
for _, r := range t.IntRows {
if name != r.Header.Name {
// log.Info("skip sint row:", r.Header.Name, "!=", name)
continue
}
// log.Info("tree: Add()ing to grid here", r.Header.Id, r.Header.Name, w, h)
head := grid.makeGridLabel(r.Header, w, h)
me.Add(head)
h += 1
for _, v := range r.Widgets {
v.Name = fmt.Sprintf("%d", v.Size)
// log.Info("tree: Add()ing to grid here", v.Id, v.Name, w, h)
lab := grid.makeGridLabel(v, w, h)
me.Add(lab)
h += 1
}
return true
}
for _, r := range t.TimeRows {
if name != r.Header.Name {
// log.Info("skip sint row:", r.Header.Name, "!=", name)
continue
}
// log.Info("tree: Add()ing to grid here", r.Header.Id, r.Header.Name, w, h)
head := grid.makeGridLabel(r.Header, w, h)
me.Add(head)
h += 1
for _, widg := range r.Widgets {
msg, err := anypb.UnmarshalNew(widg.Val, proto.UnmarshalOptions{})
if err != nil {
log.Fatalf("failed to unmarshal: %v", err)
}
switch v := msg.(type) {
case *timestamppb.Timestamp:
// fmt.Println("Unpacked Timestamp:", shell.FormatDuration(time.Since(v.AsTime())))
widg.Name = shell.FormatDuration(time.Since(v.AsTime()))
default:
fmt.Println("Unknown type:", v)
widg.Name = fmt.Sprintf("%v", v)
}
// log.Info("tree: Add()ing to grid here", widg.Id, widg.Name, w, h)
lab := grid.makeGridLabel(widg, w, h)
me.Add(lab)
h += 1
}
return true
}
return false
}
// returns true if widget is in a table
func (n *Node) InTable() bool {
// log.Info("InTable() parent id =", n.ParentId)
grid := FindWidgetById(int(n.ParentId))
if grid != nil {
if grid.WidgetType == widget.Grid {
if grid.State.ProgName == "TableGridPB" {
// this is a protobuf table
return true
}
}
}
return false
}
func dumpTable(t *guipb.Table) {
for i, o := range t.Order {
log.Info("got order:", t.Title, i, o)
}
for i, r := range t.StringRows {
log.Info("got string row:", t.Title, i, r.Header.Name, r.Vals)
for _, v := range r.Widgets {
log.Info("tree: got string widget:", v.Id, v.Name)
}
}
for i, r := range t.IntRows {
log.Info("got int row:", t.Title, i, r.Header.Name, r.Vals)
for _, v := range r.Widgets {
log.Info("tree: got int widget:", v.Id, v.Size)
}
}
}
type TreeTable struct {
PB *guipb.Table
/*
hostnames []string
columns []*gui.NodeColumn
order []*gui.NodeColumn
*/
}

View File

@ -7,8 +7,8 @@ package forgepb;
import "google/protobuf/timestamp.proto"; // Import the well-known type for Timestamp
message ToolkitConfig { //
string plugin = 1; // 'gocui', 'andlabs', etc `autogenpb:unique`
string name = 2; // variable name 'fullscreen' `autogenpb:unique`
string plugin = 1; // 'gocui', 'andlabs', etc
string name = 2; // variable name 'fullscreen'
string value = 3; // value "true"
}

36
widget.proto Normal file
View File

@ -0,0 +1,36 @@
syntax = "proto3";
// playing around with ideas here
package main;
import "google/protobuf/timestamp.proto"; // Import the well-known type for Timestamp
message Size {
int64 width = 1;
int64 height = 2;
}
message Location {
int64 x = 1;
int64 y = 2;
}
message Tree {
Widget parent = 1;
repeated Widget children = 2;
}
message Widget {
int64 id = 1;
string name = 2;
Size size = 3;
Location location = 4;
string color = 5;
}
message Widgets {
string uuid = 1; // `autogenpb:uuid:0331fcd7-3c8c-43e4-be1b-77db6a6bc58c`
string version = 2; // `autogenpb:version:v1`
repeated Widget Widgets = 3;
}