Compare commits

...

29 Commits

Author SHA1 Message Date
Jeff Carr 25a074d02d still doesn't trap panic 2025-09-05 01:24:41 -05:00
Jeff Carr 9b1e7f102e rearrange output to see if it ever is showing up 2025-09-04 19:18:14 -05:00
Jeff Carr cb3047ab09 quiet output related to expected init() conditions 2025-03-10 04:37:21 -05:00
Jeff Carr bdb93a7b57 andlabs is unstable. need to switch to protobuf 2025-03-05 03:43:38 -06:00
Jeff Carr 8a71fc4012 maybe this will get fyne to work 2025-03-04 01:57:44 -06:00
Jeff Carr cd62709b64 work on tables 2025-02-24 11:00:23 -06:00
Jeff Carr 8ced00be79 build was wrong 2025-02-22 07:18:14 -06:00
Jeff Carr 3184badaec re-disable INFO flag 2025-02-21 18:31:42 -06:00
Jeff Carr 5b9eca7ac0 rm debugging printf 2025-02-21 16:55:26 -06:00
Jeff Carr 3e0b8c3df5 andlabs keeps panic'ing 2025-02-21 13:57:18 -06:00
Jeff Carr b64bf96606 debugging init() 2025-02-13 22:28:59 -06:00
Jeff Carr a264a7d121 add Disable() and Enable() 2025-02-13 21:04:25 -06:00
Jeff Carr 5530d2c6ad subbed in table() 2025-02-13 20:33:04 -06:00
Jeff Carr a16207bd1e stubbed in tables 2025-02-13 20:11:53 -06:00
Jeff Carr 514b39e382 better filename 2025-02-13 14:27:32 -06:00
Jeff Carr 0c0c42ecbb works again 2025-02-13 14:27:13 -06:00
Jeff Carr 9babe64e41 minor 2025-02-12 16:03:23 -06:00
Jeff Carr 17cff379fa clean was not complete 2025-01-09 21:16:04 -06:00
Jeff Carr 331e75e348 more correct build 2024-12-06 01:50:45 -06:00
Jeff Carr 6f08f22ca8 closer to purer plugin testing 2024-12-05 19:08:29 -06:00
Jeff Carr 9d965ee05a minor 2024-12-05 17:43:11 -06:00
Jeff Carr d14f8985e0 no .so 2024-12-03 00:47:13 -06:00
Jeff Carr 2246f8852a use this until 'package plugin' works 2024-12-02 05:16:42 -06:00
Jeff Carr ac6a348f54 add 'make install' for testing 2024-12-01 00:49:52 -06:00
Jeff Carr 03cc26d91f sets go list .Doc to 'plugin' 2024-11-28 22:58:26 -06:00
Jeff Carr c5ecf7ca32 avoid window in window crash. TODO: make it work
Signed-off-by: Jeff Carr <jcarr@wit.com>
2024-02-15 08:15:38 -06:00
Jeff Carr c6f9119c2e part of doc cleanups 2024-02-13 16:16:37 -06:00
Jeff Carr dac22688e2 ignore binary from autotypist automation
Signed-off-by: Jeff Carr <jcarr@wit.com>
2024-02-12 21:35:18 -06:00
Jeff Carr 142be47d3a more node state fixes
Signed-off-by: Jeff Carr <jcarr@wit.com>
2024-02-09 03:44:21 -06:00
17 changed files with 254 additions and 133 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
*.swp
*.so
go.mod
go.sum
andlabs

1
.plugin Normal file
View File

@ -0,0 +1 @@
// plugin

View File

@ -1,10 +1,19 @@
all: plugin
VERSION = $(shell git describe --tags)
BUILDTIME = $(shell date +%Y.%m.%d)
plugin:
GO111MODULE="off" go build -v -x -buildmode=plugin -o ../andlabs.so
all: clean goimports vet andlabs.so
pluginreal:
go build -v -x -buildmode=plugin -o ~/go/lib/andlabs.so
andlabs.so:
GO111MODULE=off go build -v -x -buildmode=plugin -o andlabs.so \
-ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
install: clean
go build -v -buildmode=plugin -o ~/go/lib/andlabs-${VERSION}.so \
-ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
cd ~/go/lib && ln -f -s andlabs-${VERSION}.so andlabs.so
clean:
rm -f andlabs andlabs.*so
goget:
GO111MODULE="off" go get -v -t -u
@ -12,6 +21,11 @@ goget:
goimports:
goimports -w *.go
vet:
@GO111MODULE=off go vet
@echo this go plugin builds okay
redomod:
rm -f go.*
goimports -w *.go

3
README.md Normal file
View File

@ -0,0 +1,3 @@
// TODO: make a fake 'plugin' channel of communication to andlabs for mswindows
// Windows doesn't support plugins. How can I keep andlabs and only compile it on windows?
// https://forum.heroiclabs.com/t/setting-up-goland-to-compile-plugins-on-windows/594/5

View File

@ -1,7 +1,6 @@
package main
import (
"go.wit.com/dev/andlabs/ui"
"go.wit.com/log"
"go.wit.com/toolkits/tree"
"go.wit.com/widget"
@ -81,7 +80,6 @@ func ready(n *tree.Node) bool {
func hide(n *tree.Node) {
show(n, false)
n.State.Hidden = true
}
func show(n *tree.Node, b bool) {
@ -105,7 +103,7 @@ func show(n *tree.Node, b bool) {
}
}
func enable(n *tree.Node, b bool) {
func realEnable(n *tree.Node, b bool) {
if !ready(n) {
return
}
@ -150,6 +148,15 @@ func pad(n *tree.Node, b bool) {
}
}
func showWidget(n *tree.Node) {
log.Info("not implemented in andlabs yet")
// widgetDelete(n)
}
func hideWidget(n *tree.Node) {
widgetDelete(n)
}
func widgetDelete(n *tree.Node) {
log.Log(ANDLABS, "widgetDelete()", n.WidgetId, n.WidgetType)
var tk *guiWidget
@ -162,7 +169,7 @@ func widgetDelete(n *tree.Node) {
tk.uiWindow.Destroy()
tk.uiWindow = nil
}
n.DeleteNode()
// n.DeleteNode()
} else {
log.Log(ANDLABS, "DESTROY can't destroy TODO:", n.WidgetId, n.WidgetType)
}
@ -182,7 +189,7 @@ func SetText(n *tree.Node, s string) {
return
}
if n.TK == nil {
log.Log(WARN, "Tree sent an action on a widget we didn't seem to have.")
log.Log(WARN, "SetText() Tree sent an action on a widget we didn't seem to have.", n.WidgetId)
return
}
setText(n, s)
@ -195,7 +202,7 @@ func AddText(n *tree.Node, s string) {
return
}
if n.TK == nil {
log.Log(WARN, "Tree sent an action on a widget we didn't seem to have.")
log.Log(WARN, "AddText() Tree sent an action on a widget we didn't seem to have.", n.WidgetId)
return
}
log.Log(ANDLABS, "AddText()", n.WidgetType, n.String())
@ -203,41 +210,3 @@ func AddText(n *tree.Node, s string) {
// w.AddText(s)
addText(n, s)
}
func newAction(n *tree.Node, atype widget.ActionType) {
log.Log(INFO, "newaction() START", atype)
if n == nil {
log.Log(WARN, "Tree Error: Add() sent n == nil")
return
}
if n.TK == nil {
log.Log(WARN, "Tree sent an action on a widget we didn't seem to have.")
// do this init here again? Probably something
// went wrong and we should reset the our while gocui.View tree
n.TK = initWidget(n)
}
// w := n.TK.(*guiWidget)
switch atype {
case widget.Show:
log.Log(ANDLABS, "Show() HERE. a.Hidden() was =", n.Hidden())
show(n, true)
case widget.Hide:
log.Log(ANDLABS, "Hide() HERE. a.State.Hidden was =", n.Hidden())
hide(n)
case widget.Move:
log.Log(ANDLABS, "attempt to move() =", atype, n.WidgetType, n.ProgName())
case widget.ToolkitClose:
log.Log(NOW, "attempting to Quit andlabs.ui")
// standardClose()
ui.Quit()
case widget.Enable:
enable(n, true)
case widget.Disable:
enable(n, false)
case widget.Delete:
widgetDelete(n)
default:
log.Log(ERROR, "newaction() UNHANDLED Action Type =", atype, "WidgetType =", n.WidgetType, "Name =", n.ProgName())
}
log.Log(INFO, "newaction() END", atype, n.String())
}

15
add.go
View File

@ -55,11 +55,18 @@ func newAdd(n *tree.Node) {
me.treeRoot = n
return
}
if me.treeRoot == nil {
panic("test")
}
add(n)
if n.TK == nil {
log.Log(WARN, "Tree sent an action on a widget we didn't seem to have.")
// do this init here again? Probably something
// went wrong and we should reset the our while gocui.View tree
if n.WidgetId == 1 || n.WidgetId == 2 {
// this is normal at plugin init() time
} else {
// this probably shouldn't be happening
log.Log(WARN, "newAdd() Tree sent an action on a widget we didn't seem to have.", n.WidgetId, n.WidgetType, n.ProgName())
}
// Probably something went wrong and we should reset / redraw everything?
n.TK = initWidget(n)
}
// show(n, !a.State.Hidden)
@ -69,7 +76,7 @@ func newAdd(n *tree.Node) {
if n.State.Enable {
// nothing to do
} else {
enable(n, false)
realEnable(n, false)
}
}
}

View File

@ -6,10 +6,7 @@ import (
"go.wit.com/widget"
)
func compareStrings(n *tree.Node, ss []string) {
}
func addText(n *tree.Node, s string) {
func realAddText(n *tree.Node, s string) {
var tk *guiWidget
tk = n.TK.(*guiWidget)
log.Log(ANDLABS, "addText() START with s =", s)
@ -21,19 +18,7 @@ func addText(n *tree.Node, s string) {
switch n.WidgetType {
case widget.Dropdown:
for i, s := range n.State.Strings {
log.Log(ANDLABS, "n.State.Strings =", i, s)
_, ok := n.Strings[s]
// If the key exists
if ok {
log.Log(ANDLABS, "string is already in the dropdown", i, s)
} else {
log.Log(ANDLABS, "adding new string to dropdown", i, s)
addDropdownName(n, s)
// TODO: make numbers
n.Strings[s] = 21
}
}
addDropdownName(n, s)
case widget.Combobox:
addComboboxName(n, s)
default:

View File

@ -34,7 +34,7 @@ func (t *guiWidget) checked() bool {
return t.uiCheckbox.Checked()
}
func setChecked(n *tree.Node, b bool) {
func realSetChecked(n *tree.Node, b bool) {
if n.WidgetType != widget.Checkbox {
}
var tk *guiWidget

View File

@ -23,7 +23,7 @@ func init() {
NOW = log.NewFlag("NOW", true, full, short, "temp debugging stuff")
INFO = log.NewFlag("INFO", false, full, short, "normal debugging stuff")
WARN = log.NewFlag("WARN", false, full, short, "bad things")
WARN = log.NewFlag("WARN", true, full, short, "bad things")
full = "go.wit.com/gui"
short = "andlabs"

View File

@ -1,27 +1,36 @@
// plugin
package main
import (
"runtime/debug"
"sync"
"time"
"go.wit.com/log"
"go.wit.com/toolkits/tree"
"go.wit.com/widget"
"go.wit.com/dev/andlabs/ui"
// the _ means we only need this for the init()
_ "go.wit.com/dev/andlabs/ui/winmanifest"
)
// sent via -ldflags
var VERSION string
var BUILDTIME string
var PLUGIN string = "andlabs"
var uiMainUndef bool = true
var uiMain sync.Once
var muAction sync.Mutex
func queueAction(n *tree.Node, atype widget.ActionType) {
/*
func newaction(n *tree.Node, atype widget.ActionType) {
ui.QueueMain(func() {
newAction(n, atype)
})
}
*/
func queueAdd(n *tree.Node) {
ui.QueueMain(func() {
@ -29,33 +38,51 @@ func queueAdd(n *tree.Node) {
})
}
func queueSetTitle(n *tree.Node, s string) {
func enableWidget(n *tree.Node) {
ui.QueueMain(func() {
realEnable(n, true)
})
}
func disableWidget(n *tree.Node) {
ui.QueueMain(func() {
realEnable(n, false)
})
}
func setTitle(n *tree.Node, s string) {
ui.QueueMain(func() {
SetText(n, s)
})
}
func queueSetLabel(n *tree.Node, s string) {
func setLabel(n *tree.Node, s string) {
ui.QueueMain(func() {
SetText(n, s)
realSetText(n, s)
})
}
func queueSetText(n *tree.Node, s string) {
func setText(n *tree.Node, s string) {
ui.QueueMain(func() {
SetText(n, s)
realSetText(n, s)
})
}
func queueAddText(n *tree.Node, s string) {
func addText(n *tree.Node, s string) {
ui.QueueMain(func() {
AddText(n, s)
realAddText(n, s)
})
}
func queueSetChecked(n *tree.Node, b bool) {
func setChecked(n *tree.Node, b bool) {
ui.QueueMain(func() {
setChecked(n, b)
realSetChecked(n, b)
})
}
func toolkitClose() {
ui.QueueMain(func() {
ui.Quit()
})
}
@ -87,20 +114,37 @@ func queueMain(currentA widget.Action) {
func guiMain() {
defer func() {
if r := recover(); r != nil {
log.Log(WARN, "YAHOOOO Recovered in guiMain application:", r)
log.Log(WARN, "Recovered from panic:", r)
log.Log(WARN, "YAHOO andlabs GUI recovered in guiMain()")
log.Log(WARN, "Stack trace:")
debug.PrintStack()
log.Log(WARN, "Recovered from panic:", r)
log.Log(WARN, "andlabs GUI recovered in guiMain()")
log.Log(WARN, "YAHOO andlabs GUI recovered in guiMain()")
me.myTree.SendToolkitPanic()
return
}
}()
// TODO: THIS IS THE PROBLEM
ui.Main(func() {
// this is a bad hack for now.
// a better way would be to spawn ui.Main on the first actual window
// that is supposed to be displayed
if r := recover(); r != nil {
log.Log(WARN, "YAHOO andlabs GUI recovered in guiMain()")
log.Log(WARN, "Stack trace:")
debug.PrintStack()
log.Log(WARN, "Recovered from panic:", r)
log.Log(WARN, "andlabs GUI recovered in guiMain()")
log.Log(WARN, "YAHOO andlabs GUI recovered in guiMain()")
me.myTree.SendToolkitPanic()
return
}
time.Sleep(time.Second)
placeholderUI()
me.myTree.InitOK()
// if nothing is working, run this instead to make
// sure you have something
// demoUI()
@ -112,24 +156,30 @@ func Init() {
}
// This is important. This sets the defaults for the gui. Without this, there isn't correct padding, etc
func init() {
func initPlugin() {
log.Log(INFO, "Init() START")
log.Log(INFO, "Init()")
// Can you pass values to a plugin init() ? Otherwise, there is no way to safely print
// log.Log(INFO, "init() Setting defaultBehavior = true")
// setDefaultBehavior(true)
me.myTree = tree.New()
me.myTree.PluginName = "andlabs"
// me.myTree.ActionFromChannel = queueMain
me.myTree = initTree()
me.myTree.NodeAction = queueAction
me.myTree.Add = queueAdd
me.myTree.SetTitle = queueSetTitle
me.myTree.SetLabel = queueSetLabel
me.myTree.SetText = queueSetText
me.myTree.AddText = queueAddText
me.myTree.SetChecked = queueSetChecked
// me.ok = true // this tells init() it's okay to work with gocui
/*
me.myTree = tree.New()
me.myTree.PluginName = "andlabs"
// me.myTree.ActionFromChannel = queueMain
me.myTree.NodeAction = queueAction
me.myTree.Add = queueAdd
me.myTree.SetTitle = queueSetTitle
me.myTree.SetLabel = queueSetLabel
me.myTree.SetText = queueSetText
me.myTree.AddText = queueAddText
me.myTree.SetChecked = queueSetChecked
me.myTree.ToolkitClose = queueToolkitClose
*/
// 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

View File

@ -2,6 +2,9 @@ package main
import (
// "os"
"os"
"go.wit.com/dev/andlabs/ui"
_ "go.wit.com/dev/andlabs/ui/winmanifest"
@ -38,6 +41,16 @@ import (
func place(p *tree.Node, n *tree.Node) bool {
log.Log(INFO, "place() 1 START", n.WidgetType, n.GetProgName(), n.GetLabel())
if p == nil {
log.Log(WARN, "place() parent == nil")
os.Exit(-1)
return false
}
if n == nil {
log.Log(WARN, "place() node == nil")
os.Exit(-1)
return false
}
if !ready(n) {
if n.WidgetType == widget.Window {
// TODO: figure out window in window placement
@ -57,13 +70,15 @@ func place(p *tree.Node, n *tree.Node) bool {
log.Sleep(1)
panic("ptk == nil")
}
// p.DumpWidget("parent: ")
// n.DumpWidget("child: ")
log.Log(INFO, "place() switch", p.WidgetType, n.WidgetId, n.GetProgName())
// log.Log(WARN, "place() switch", p.WidgetType, n.WidgetId, n.GetProgName())
switch p.WidgetType {
case widget.Grid:
tk.gridX = n.State.GridOffset.X - 1
tk.gridY = n.State.GridOffset.Y - 1
log.Log(INFO, "place() on Grid at gridX,gridY", tk.gridX, tk.gridY)
// log.Log(WARN, "place() on Grid at gridX,gridY", tk.gridX, tk.gridY)
ptk.uiGrid.Append(tk.uiControl,
tk.gridX, tk.gridY, 1, 1,
false, ui.AlignFill, false, ui.AlignFill)
@ -106,6 +121,10 @@ func place(p *tree.Node, n *tree.Node) bool {
return true
case widget.Window:
log.Log(INFO, "Adding Something to Window", n.WidgetId, n.GetProgName())
if n.WidgetType == widget.Window {
log.Log(INFO, "TODO: make window in a window a tab", n.WidgetId, n.GetProgName())
return true
}
ptk.uiWindow.SetChild(tk.uiControl)
return true
default:

View File

@ -6,7 +6,7 @@ import (
"go.wit.com/widget"
)
func setText(n *tree.Node, name string) {
func realSetText(n *tree.Node, name string) {
// name := widget.GetString(a.Value)
var tk *guiWidget
tk = n.TK.(*guiWidget)

View File

@ -1,12 +1,16 @@
package main
import (
"sync"
"go.wit.com/toolkits/tree"
"go.wit.com/dev/andlabs/ui"
_ "go.wit.com/dev/andlabs/ui/winmanifest"
)
var initOnce sync.Once // run initPlugin() only once
// It's probably a terrible idea to call this 'me'
var me config

13
table.go Normal file
View File

@ -0,0 +1,13 @@
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
package main
import (
"go.wit.com/lib/protobuf/guipb"
"go.wit.com/log"
)
func showTable(t *guipb.Table) {
log.Info("should show table here")
}

31
tree.go
View File

@ -1,31 +0,0 @@
package main
/*
This code should be common to all gui plugins
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 (
"go.wit.com/widget"
)
// Other goroutines must use this to access the GUI
//
// You can not acess / process the GUI thread directly from
// other goroutines. This is due to the nature of how
// Linux, MacOS and Windows work (they all work differently. suprise. surprise.)
//
// this sets the channel to send user events back from the plugin
func Callback(guiCallback chan widget.Action) {
me.myTree.Callback(guiCallback)
}
func PluginChannel() chan widget.Action {
return me.myTree.PluginChannel()
}

79
treeInit.go Normal file
View File

@ -0,0 +1,79 @@
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
/*
DO NOT EDIT THIS FILE
this file is the same for every GUI toolkit plugin
when you are making a new GUI toolkit plugin for
a specific toolkit, you just need to define these
functions.
for example, in the "gocui" toolkit, the functions
below are what triggers the "gocui" GO package
to draw labels, buttons, windows, etc
If you are starting out trying to make a new GUI toolkit,
all you have to do is copy this file over. Then
work on making these functions. addWidget(), setText(), etc.
That's it!
*/
package main
/*
This is reference code for toolkit developers
This is how information is passed in GO back to the application
via the GO 'plugin' concept
TODO: switch this to protocol buffers
*/
import (
"go.wit.com/toolkits/tree"
"go.wit.com/widget"
)
// Other goroutines must use this to access the GUI
//
// You can not acess / process the GUI thread directly from
// other goroutines. This is due to the nature of how
// Linux, MacOS and Windows work (they all work differently. suprise. surprise.)
//
// this sets the channel to send user events back from the plugin
func Callback(guiCallback chan widget.Action) {
me.myTree.Callback(guiCallback)
}
func PluginChannel() chan widget.Action {
initOnce.Do(initPlugin)
return me.myTree.PluginChannel()
}
func FrozenChannel() chan widget.Action {
return me.myTree.FrozenChannel()
}
func initTree() *tree.TreeInfo {
t := tree.New()
t.PluginName = PLUGIN
t.Add = newAdd
t.SetTitle = setTitle
t.SetLabel = setLabel
t.SetText = setText
t.AddText = addText
t.Enable = enableWidget
t.Disable = disableWidget
t.Show = showWidget
t.Hide = hideWidget
t.SetChecked = setChecked
t.ToolkitClose = toolkitClose
t.ShowTable = showTable
return t
}

View File

@ -3,6 +3,8 @@ package main
import (
"go.wit.com/dev/andlabs/ui"
_ "go.wit.com/dev/andlabs/ui/winmanifest"
"go.wit.com/log"
"go.wit.com/widget"
"go.wit.com/toolkits/tree"
)
@ -24,16 +26,20 @@ func newWindow(p, n *tree.Node) {
win.SetBorderless(n.State.Borderless)
win.SetMargined(n.State.Pad)
win.OnClosing(func(*ui.Window) bool {
// show(n, false)
newt.uiWindow = nil // delete the local reference to the window
me.myTree.SendWindowCloseEvent(n)
n.DeleteNode()
// n.DeleteNode()
return true
})
newt.uiWindow = win
newt.uiControl = win
n.TK = newt
place(p, n)
if p.WidgetType == widget.Window {
log.Log(WARN, "newWindow() TODO: make this window a tab")
} else {
place(p, n)
}
win.Show()
return
}