Compare commits

...

12 Commits

15 changed files with 362 additions and 65 deletions

2
.gitignore vendored
View File

@ -2,5 +2,5 @@
go.mod
go.sum
fyne
fyne.so
*.so
nocui

1
.plugin Normal file
View File

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

View File

@ -1,8 +1,23 @@
all: plugin
ldd fyne.so
VERSION = $(shell git describe --tags)
BUILDTIME = $(shell date +%Y.%m.%d)
all: clean goimports plugin
#ldd fyne.so
deps:
sudo apt install libxxf86vm-dev libxxf86vm1
plugin:
go build -v -x -buildmode=plugin -o fyne.so
# LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/ GO111MODULE=off go build -v -x -buildmode=plugin -o fyne.so
GO111MODULE=off go build -v -x -buildmode=plugin -o fyne.so
install: clean
go build -v -buildmode=plugin -o ~/go/lib/fyne-${VERSION}.so \
-ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
cd ~/go/lib && ln -f -s fyne-${VERSION}.so fyne.so
clean:
rm -f fyne fyne.so
binary:
go build -v -x
@ -11,6 +26,10 @@ non-plugin:
go build -v -x
./fyne
GO111-non-plugin:
GO111MODULE=off go build -v -x
./fyne
check-git-clean:
@git diff-index --quiet HEAD -- || (echo "Git repository is dirty, please commit your changes first"; exit 1)
@ -22,8 +41,3 @@ pkgsite:
goimports:
goimports -w *.go
redomod:
rm -f go.*
GO111MODULE= go mod init
GO111MODULE= go mod tidy

View File

@ -1,5 +1,18 @@
# nogui
# fyne
Package gui implements a abstraction layer for Go visual elements.
This is a sample plugin. It's a skeleton intended to be used when making a new toolkit plugin.
fyne appears to require:
runtime.LockOSThread() // Ensure main stays on one OS thread
a := app.New()
w := a.NewWindow("Fyne Plugin Fix")
w.ShowAndRun()
error:
gui doing TestDraw() Forge: (this kinda works sometimes)
panic: Run() or ShowAndRun() must be called from main goroutine
so for fyne to work, there must be a protocol buffer GO GUI plugin first that
can spawn and talk to fyne

View File

@ -7,12 +7,15 @@ package main
*/
import (
"slices"
"go.wit.com/lib/protobuf/guipb"
"go.wit.com/log"
"go.wit.com/toolkits/tree"
"go.wit.com/widget"
)
func Add(n *tree.Node) {
func newAdd(n *tree.Node) {
log.Log(INFO, "Add() END =", n.WidgetType, n.String())
if n == nil {
log.Warn("Tree Error: Add() sent n == nil")
@ -58,7 +61,7 @@ func newaction(n *tree.Node, atype widget.ActionType) {
// w.disableColor()
case widget.Delete:
log.Info("newaction() DeleteNode()")
n.DeleteNode()
// n.DeleteNode()
case widget.ToolkitClose:
log.Info("newaction() toolkit closed. are the channels cleand up?")
return
@ -68,15 +71,15 @@ func newaction(n *tree.Node, atype widget.ActionType) {
log.Log(INFO, "newaction() END", atype, n.String())
}
func SetTitle(n *tree.Node, s string) {
SetText(n, s)
func setTitle(n *tree.Node, s string) {
setText(n, s)
}
func SetLabel(n *tree.Node, s string) {
SetText(n, s)
func setLabel(n *tree.Node, s string) {
setText(n, s)
}
func SetText(n *tree.Node, s string) {
func setText(n *tree.Node, s string) {
if n == nil {
log.Warn("Tree Error: Add() sent n == nil")
return
@ -90,7 +93,7 @@ func SetText(n *tree.Node, s string) {
log.Info("SetText()", n.WidgetType, n.String())
}
func AddText(n *tree.Node, s string) {
func addText(n *tree.Node, s string) {
if n == nil {
log.Warn("Tree Error: Add() sent n == nil")
return
@ -103,3 +106,55 @@ func AddText(n *tree.Node, s string) {
// w := n.TK.(*guiWidget)
// w.AddText(s)
}
func setChecked(n *tree.Node, b bool) {
log.Info("do enable() here")
}
func toolkitClose() {
log.Info("do enable() here")
}
func showTable(t *guipb.Table) {
log.Info("gocui: should show table here")
if t == nil {
return
}
log.Info("gocui: table.Title", t.Title)
}
func enableWidget(n *tree.Node) {
tk := n.TK.(*guiWidget)
tk.Enable()
}
func disableWidget(n *tree.Node) {
tk := n.TK.(*guiWidget)
tk.Disable()
}
func showWidget(n *tree.Node) {
tk := n.TK.(*guiWidget)
tk.Show()
}
func hideWidget(n *tree.Node) {
tk := n.TK.(*guiWidget)
if n.WidgetType == widget.Window {
// tk.windowFrame.Hide()
// tk.hideWidgets()
}
tk.Hide()
tk.deleteWidget()
}
func (tk *guiWidget) deleteWidget() {
log.Info("gocui deleteWidget() looking for child to delete:", tk.cuiName)
p := tk.parent
for i, child := range p.children {
if tk == child {
log.Info("deleteWidget() found parent with child to delete:", i, child.cuiName)
p.children = slices.Delete(p.children, i, i+1)
}
}
}

View File

@ -17,8 +17,8 @@ var WARN *log.LogFlag
var ERROR *log.LogFlag
func init() {
full := "toolkit/nocui"
short := "nocui"
full := "toolkit/fyne"
short := "fyne"
NOW = log.NewFlag("NOW", true, full, short, "temp debugging stuff")
INFO = log.NewFlag("INFO", true, full, short, "normal debugging stuff")

3
fyne.go Normal file
View File

@ -0,0 +1,3 @@
package main // import "go.wit.com/toolkits/fyne"
// the above line overrides the default 'go mod init' to use whatever is here
// `go-clean `go-get github.com/go-gl/glfw`

View File

@ -9,6 +9,7 @@ import (
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
"go.wit.com/log"
)
var a fyne.App
@ -16,6 +17,7 @@ var w fyne.Window
var w2 fyne.Window
func fynetest() {
log.Info("FYNE TEST START")
a = app.New()
w = a.NewWindow("Hello")
@ -28,6 +30,7 @@ func fynetest() {
}),
))
log.Info("FYNE TEST SHOW")
w.Show()
// bobWindow()

59
main.go
View File

@ -8,31 +8,36 @@ package main
*/
import (
"runtime"
"fyne.io/fyne/v2/app"
"go.wit.com/log"
"go.wit.com/toolkits/tree"
)
func init() {
var PLUGIN string = "fyne"
func blah() {
fynetest()
a.Run()
}
func initPlugin() {
log.Log(INFO, "Init()")
me.myTree = tree.New()
me.myTree.PluginName = "nocui"
// me.myTree.ActionFromChannel = doAction
me.myTree.NodeAction = newaction
me.myTree.Add = Add
me.myTree.SetTitle = SetTitle
me.myTree.SetLabel = SetLabel
me.myTree.SetText = SetText
me.myTree.AddText = AddText
me.myTree = initTree()
me.exit = false
log.Log(INFO, "Init() END")
showOptions()
go simpleStdin()
log.Log(INFO, "Init() FYNE END")
// blah()
me.myTree.InitOK()
}
func init() {
// fynetest()
// a.Run()
}
// this must be defined for plugin's, but is never run
@ -41,3 +46,25 @@ func main() {
fynetest()
a.Run()
}
// this is called at the very initial connection
// between the app and this gocui plugin
// this is a good place to initialize gocui's default behavior
func toolkitInit() {
log.Log(INFO, "TOOLKIT Init()")
me.exit = false
showOptions()
log.Log(INFO, "TOOLKIT Init() END")
fynetest()
go a.Run()
}
func testmain() {
runtime.LockOSThread() // Ensure main stays on one OS thread
a := app.New()
w := a.NewWindow("Fyne Plugin Fix")
w.ShowAndRun()
// use w.QueueUpdate() to talk to fyne (?)
}

63
node.go Normal file
View File

@ -0,0 +1,63 @@
// 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/widget"
)
func (tk *guiWidget) WidgetType() widget.WidgetType {
if tk.node == nil {
return widget.Label
}
return tk.node.WidgetType
}
func (tk *guiWidget) WidgetId() int {
return tk.node.WidgetId
}
func (tk *guiWidget) GetLabel() string {
return tk.node.GetLabel()
}
func (tk *guiWidget) IsEnabled() bool {
return tk.node.IsEnabled()
}
func (tk *guiWidget) Checked() bool {
return tk.node.State.Checked
}
func (tk *guiWidget) Hidden() bool {
if tk.node == nil {
return false
}
if tk.parent == nil {
return tk.node.Hidden()
}
if tk.parent.WidgetId() == 0 {
return tk.node.Hidden()
}
if tk.parent.Hidden() {
return true
}
return tk.node.Hidden()
}
func (tk *guiWidget) Direction() widget.Orientation {
return tk.node.State.Direction
}
func (tk *guiWidget) GridW() int {
return tk.node.State.AtW
}
func (tk *guiWidget) GridH() int {
return tk.node.State.AtH
}
func (tk *guiWidget) SetChecked(b bool) {
tk.node.State.Checked = b
}

46
plugin.go Normal file
View File

@ -0,0 +1,46 @@
package main
import (
"go.wit.com/log"
"go.wit.com/widget"
)
func (tk *guiWidget) Show() {
}
func (tk *guiWidget) Hide() {
}
func (tk *guiWidget) Disable() {
if tk == nil {
log.Info("widget is nil")
return
}
switch tk.WidgetType() {
case widget.Box:
return
case widget.Button:
return
default:
log.Log(NOW, "fixme")
}
}
func (tk *guiWidget) Enable() {
if tk == nil {
log.Info("widget is nil")
return
}
switch tk.WidgetType() {
case widget.Box:
// hideDisable()
return
case widget.Button:
// tk.restoreEnableColor()
return
default:
log.Log(NOW, "fixme")
}
}

View File

@ -33,7 +33,7 @@ func showOptions() {
func simpleStdin() {
defer func() {
if r := recover(); r != nil {
log.Warn("nocui YAHOOOO Recovered in simpleStdin()", r)
log.Warn("fyne YAHOOOO Recovered in simpleStdin()", r)
log.Println("Recovered from panic:", r)
log.Println("Stack trace:")
debug.PrintStack()

View File

@ -1,20 +1,26 @@
package main
import (
"sync"
"go.wit.com/toolkits/tree"
)
// stores the raw toolkit internals
type guiWidget struct {
Width int
Height int
parent *guiWidget
children []*guiWidget
node *tree.Node // the pointer back to the tree
cuiName string
Width int
Height int
c int
val map[string]int
}
// It's probably a terrible idea to call this 'me'
var me config
var initOnce sync.Once // run initPlugin() only once
var me config // It's probably a terrible idea to call this 'me'
type config struct {
treeRoot *tree.Node // the base of the binary tree. it should have id == 0

24
tree.go
View File

@ -1,24 +0,0 @@
package main
/*
This is reference code for toolkit developers
*/
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()
}

90
treeInit.go Normal file
View File

@ -0,0 +1,90 @@
// 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 (
"time"
log "go.wit.com/log"
"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)
for {
if me.myTree != nil {
break
}
log.Info("me.myTree == nil")
time.Sleep(300 * time.Millisecond)
}
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.ToolkitInit = toolkitInit
t.ToolkitClose = toolkitClose
t.ShowTable = showTable
return t
}