better toolkit init options

Signed-off-by: Jeff Carr <jcarr@wit.com>
This commit is contained in:
Jeff Carr 2023-04-12 13:00:29 -05:00
parent a235371d1a
commit ca708db97e
12 changed files with 97 additions and 85 deletions

View File

@ -123,20 +123,17 @@ Creates a window helpful for debugging this package
`func ExampleCatcher(f func())` `func ExampleCatcher(f func())`
### func [FindPlugin](/plugin.go#L64)
`func FindPlugin(name string) *aplug`
loads and initializes a toolkit (andlabs/ui, gocui, etc)
attempts to locate the .so file
### func [Indent](/debug.go#L120) ### func [Indent](/debug.go#L120)
`func Indent(b bool, a ...interface{})` `func Indent(b bool, a ...interface{})`
### func [LoadPlugin](/main.go#L114)
`func LoadPlugin(name string) bool`
### func [LoadToolkit](/plugin.go#L68)
`func LoadToolkit(name string) *aplug`
loads and initializes a toolkit (andlabs/ui, gocui, etc)
### func [SetDebug](/debug.go#L28) ### func [SetDebug](/debug.go#L28)
`func SetDebug(s bool)` `func SetDebug(s bool)`
@ -149,7 +146,7 @@ loads and initializes a toolkit (andlabs/ui, gocui, etc)
`func ShowDebugValues()` `func ShowDebugValues()`
### func [StandardExit](/main.go#L155) ### func [StandardExit](/main.go#L153)
`func StandardExit()` `func StandardExit()`
@ -190,7 +187,7 @@ var Config GuiConfig
The Node is a binary tree. This is how all GUI elements are stored The Node is a binary tree. This is how all GUI elements are stored
simply the name and the size of whatever GUI element exists simply the name and the size of whatever GUI element exists
#### func [New](/main.go#L132) #### func [New](/main.go#L126)
`func New() *Node` `func New() *Node`

View File

@ -18,7 +18,7 @@ func main() {
// This will turn on all debugging // This will turn on all debugging
// gui.SetDebug(true) // gui.SetDebug(true)
myGui = gui.New() myGui = gui.New().LoadToolkit("gocui")
buttonWindow() buttonWindow()
// This is just a optional goroutine to watch that things are alive // This is just a optional goroutine to watch that things are alive
@ -55,11 +55,11 @@ func buttonWindow() {
g.NewButton("Load 'gocui'", func () { g.NewButton("Load 'gocui'", func () {
// this set the xterm and mate-terminal window title. maybe works generally? // this set the xterm and mate-terminal window title. maybe works generally?
fmt.Println("\033]0;" + title + "blah \007") fmt.Println("\033]0;" + title + "blah \007")
gui.LoadPlugin("gocui") myGui.LoadToolkit("gocui")
}) })
g.NewButton("Load 'andlabs'", func () { g.NewButton("Load 'andlabs'", func () {
gui.LoadPlugin("andlabs") myGui.LoadToolkit("andlabs")
}) })
g.NewButton("NewButton(more)", func () { g.NewButton("NewButton(more)", func () {

View File

@ -90,8 +90,8 @@ func (n *Node) DebugTab(title string) *Node {
} }
}) })
g2.NewButton("load plugin 'gocui'", func () { g2.NewButton("load toolkit 'gocui'", func () {
LoadPlugin("gocui") Config.rootNode.LoadToolkit("gocui")
}) })
return newN return newN

31
main.go
View File

@ -40,7 +40,7 @@ func init() {
Config.flag = Config.rootNode.newNode("flag", 0, nil) Config.flag = Config.rootNode.newNode("flag", 0, nil)
Config.flag.WidgetType = toolkit.Flag Config.flag.WidgetType = toolkit.Flag
Config.guiChan = make(chan toolkit.Action) Config.guiChan = make(chan toolkit.Action, 1)
go watchCallback() go watchCallback()
} }
@ -111,18 +111,12 @@ func (n *Node) doUserEvent(a toolkit.Action) {
} }
} }
func LoadPlugin(name string) bool { func (n *Node) LoadToolkit(name string) *Node {
log(logInfo, "Start() Main(f) for name =", name) log(logInfo, "Start() Main(f) for name =", name)
newPlugin := LoadToolkit(name) if (FindPlugin(name) == nil) {
if (newPlugin == nil) { return n
return false
} }
return n
sleep(1) // temp hack until chan communication is setup
// TODO: find a new way to do this that is locking, safe and accurate
Config.rootNode.redraw(newPlugin)
return true
} }
// There should only be one of these per application // There should only be one of these per application
@ -130,18 +124,22 @@ func LoadPlugin(name string) bool {
// some toolkit's on some operating systems don't support more than one // some toolkit's on some operating systems don't support more than one
// Keep things simple. Do the default expected thing whenever possible // Keep things simple. Do the default expected thing whenever possible
func New() *Node { func New() *Node {
if (LoadPlugin("gocui")) { return Config.rootNode
}
func (n *Node) Default() *Node {
if (FindPlugin("gocui") == nil) {
log(logError, "New() failed to load gocui") log(logError, "New() failed to load gocui")
} }
// if DISPLAY isn't set, return since gtk can't load // if DISPLAY isn't set, return since gtk can't load
// TODO: figure out how to check what to do in macos and mswindows // TODO: figure out how to check what to do in macos and mswindows
if (os.Getenv("DISPLAY") == "") { if (os.Getenv("DISPLAY") == "") {
return Config.rootNode return n
} }
if (LoadPlugin("andlabs")) { if (FindPlugin("andlabs") == nil) {
log(logError, "New() failed to load andlabs") log(logError, "New() failed to load andlabs")
} }
return Config.rootNode return n
} }
// The window is destroyed but the application does not quit // The window is destroyed but the application does not quit
@ -157,9 +155,6 @@ func StandardExit() {
log("StandardExit() attempt to exit each toolkit plugin") log("StandardExit() attempt to exit each toolkit plugin")
for i, aplug := range allPlugins { for i, aplug := range allPlugins {
log("NewButton()", i, aplug) log("NewButton()", i, aplug)
if (aplug.Quit != nil) {
aplug.Quit()
}
} }
exit(0) exit(0)
} }

View File

@ -21,10 +21,11 @@ type aplug struct {
filename string filename string
plug *plugin.Plugin plug *plugin.Plugin
sym *plugin.Symbol sym *plugin.Symbol
LoadOk bool // LoadOk bool
InitOk bool InitOk bool
MainOk bool // MainOk bool
// startup whatever might need to be setup in the plugin
Init func() Init func()
// This passes the go channel to the plugin // This passes the go channel to the plugin
@ -47,35 +48,30 @@ type aplug struct {
// each toolkit has it's own goroutine and each one is sent this // each toolkit has it's own goroutine and each one is sent this
// add button request // add button request
pluginChan chan toolkit.Action pluginChan chan toolkit.Action
PluginChannel func() chan toolkit.Action PluginChannel func() chan toolkit.Action
// deprecate all this // deprecate all this
// TODO: make Main() main() and never allow the user to call it // TODO: make Main() main() and never allow the user to call it
// run plugin.Main() when the plugin is loaded // run plugin.Main() when the plugin is loaded
Main func(func ()) // this never returns. Each plugin must have it's own goroutine // Main func(func ()) // this never returns. Each plugin must have it's own goroutine
Quit func() // Quit func()
// simplifies passing to the plugin
// Send func(*toolkit.Widget, *toolkit.Widget)
// should replace Send()
// Action func(*toolkit.Action)
} }
var allPlugins []*aplug var allPlugins []*aplug
// loads and initializes a toolkit (andlabs/ui, gocui, etc) // loads and initializes a toolkit (andlabs/ui, gocui, etc)
func LoadToolkit(name string) *aplug { // attempts to locate the .so file
func FindPlugin(name string) *aplug {
var newPlug *aplug var newPlug *aplug
newPlug = new(aplug) newPlug = new(aplug)
log(logInfo, "LoadToolkit() START") log(logInfo, "FindPlugin() START")
newPlug.LoadOk = false newPlug.InitOk = false
for _, aplug := range allPlugins { for _, aplug := range allPlugins {
log(debugGui, "LoadToolkit() already loaded toolkit plugin =", aplug.name) log(debugGui, "FindPlugin() already loaded toolkit plugin =", aplug.name)
if (aplug.name == name) { if (aplug.name == name) {
log(debugError, "LoadToolkit() SKIPPING", name, "as you can't load it twice") log(debugError, "FindPlugin() SKIPPING", name, "as you can't load it twice")
return aplug return aplug
} }
} }
@ -94,13 +90,13 @@ func LoadToolkit(name string) *aplug {
newPlug.Init = loadFuncE(newPlug, "Init") newPlug.Init = loadFuncE(newPlug, "Init")
// should make a goroutine that never exits // should make a goroutine that never exits
newPlug.Main = loadFuncF(newPlug, "Main") // newPlug.Main = loadFuncF(newPlug, "Main")
// should send things to the goroutine above // should send things to the goroutine above
// newPlug.Queue = loadFuncF(&newPlug, "Queue") // newPlug.Queue = loadFuncF(&newPlug, "Queue")
// unload the plugin and restore state // unload the plugin and restore state
newPlug.Quit = loadFuncE(newPlug, "Quit") // newPlug.Quit = loadFuncE(newPlug, "Quit")
// Sends instructions like "Add", "Delete", "Disable", etc // Sends instructions like "Add", "Delete", "Disable", etc
// Sends a widget (button, checkbox, etc) and it's parent widget // Sends a widget (button, checkbox, etc) and it's parent widget
@ -116,14 +112,20 @@ func LoadToolkit(name string) *aplug {
allPlugins = append(allPlugins, newPlug) allPlugins = append(allPlugins, newPlug)
log(debugPlugin, "LoadToolkit() END", newPlug.name, filename) log(debugPlugin, "FindPlugin() END", newPlug.name, filename)
newPlug.Init() newPlug.Init()
// set the communication to the plugins // set the communication to the plugins
newPlug.pluginChan = newPlug.PluginChannel() newPlug.pluginChan = newPlug.PluginChannel()
newPlug.Callback(Config.guiChan) newPlug.Callback(Config.guiChan)
newPlug.LoadOk = true newPlug.InitOk = true
sleep(1) // temp hack until chan communication is setup
// TODO: find a new way to do this that is locking, safe and accurate
Config.rootNode.redraw(newPlug)
return newPlug return newPlug
} }

View File

@ -15,21 +15,21 @@ func actionDump(b bool, a *toolkit.Action) {
log(b, "actionDump() ParentId =", a.ParentId) log(b, "actionDump() ParentId =", a.ParentId)
} }
func add(a *toolkit.Action) { func add(a toolkit.Action) {
if (andlabs[a.WidgetId] != nil) { if (andlabs[a.WidgetId] != nil) {
log(debugError, "add() error. can't make a widget that already exists. id =", a.WidgetId) log(debugError, "add() error. can't make a widget that already exists. id =", a.WidgetId)
actionDump(debugError, a) actionDump(debugError, &a)
return return
} }
if (a.WidgetId == 0) { if (a.WidgetId == 0) {
log(debugError, "add() error. w.WidgetId == 0") log(debugError, "add() error. w.WidgetId == 0")
actionDump(debugError, a) actionDump(debugError, &a)
return return
} }
// for now, window gets handled without checking where == nil) // for now, window gets handled without checking where == nil)
if (a.WidgetType == toolkit.Window) { if (a.WidgetType == toolkit.Window) {
newWindow(*a) newWindow(a)
return return
} }
@ -44,49 +44,49 @@ func add(a *toolkit.Action) {
switch a.WidgetType { switch a.WidgetType {
case toolkit.Window: case toolkit.Window:
newWindow(*a) newWindow(a)
return return
case toolkit.Tab: case toolkit.Tab:
log(debugError, "add() CAME AT THIS FROM add() =", a.Name) log(debugError, "add() CAME AT THIS FROM add() =", a.Name)
log(debugError, "add() CAME AT THIS FROM add() =", a.Name) log(debugError, "add() CAME AT THIS FROM add() =", a.Name)
log(debugError, "add() CAME AT THIS FROM add() =", a.Name) log(debugError, "add() CAME AT THIS FROM add() =", a.Name)
newTab(*a) newTab(a)
return return
case toolkit.Label: case toolkit.Label:
newLabel(a) newLabel(&a)
return return
case toolkit.Button: case toolkit.Button:
newButton(a) newButton(&a)
return return
case toolkit.Grid: case toolkit.Grid:
newGrid(a) newGrid(&a)
return return
case toolkit.Checkbox: case toolkit.Checkbox:
newCheckbox(a) newCheckbox(&a)
return return
case toolkit.Spinner: case toolkit.Spinner:
newSpinner(a) newSpinner(&a)
return return
case toolkit.Slider: case toolkit.Slider:
newSlider(a) newSlider(&a)
return return
case toolkit.Dropdown: case toolkit.Dropdown:
newDropdown(a) newDropdown(&a)
return return
case toolkit.Combobox: case toolkit.Combobox:
newCombobox(a) newCombobox(&a)
return return
case toolkit.Textbox: case toolkit.Textbox:
newTextbox(a) newTextbox(&a)
return return
case toolkit.Group: case toolkit.Group:
newGroup(a) newGroup(&a)
return return
case toolkit.Box: case toolkit.Box:
newBox(a) newBox(&a)
return return
case toolkit.Image: case toolkit.Image:
newImage(a) newImage(&a)
return return
default: default:
log(debugError, "add() error TODO: ", a.WidgetType, a.Name) log(debugError, "add() error TODO: ", a.WidgetType, a.Name)
@ -122,13 +122,14 @@ func place(a *toolkit.Action, t *andlabsT, newt *andlabsT) bool {
// add the structure to the array // add the structure to the array
if (andlabs[a.WidgetId] == nil) { if (andlabs[a.WidgetId] == nil) {
log(logInfo, "newTab() MAPPED", a.WidgetId, a.ParentId) log(logInfo, "place() MAPPED", a.WidgetId, a.ParentId)
andlabs[a.WidgetId] = newt andlabs[a.WidgetId] = newt
newt.WidgetType = a.WidgetType newt.WidgetType = a.WidgetType
} else { } else {
log(debugError, "newTab() DO WHAT?", a.WidgetId, a.ParentId) log(debugError, "place() DO WHAT?", a.WidgetId, a.ParentId)
log(debugError, "THIS IS BAD") log(debugError, "place() THIS IS BAD")
} }
log(logInfo, "place() DONE MAPPED", a.WidgetId, a.ParentId)
if (newt.uiControl == nil) { if (newt.uiControl == nil) {
log(debugError, "place() ERROR uiControl == nil", a.ParentId) log(debugError, "place() ERROR uiControl == nil", a.ParentId)
@ -141,12 +142,13 @@ func place(a *toolkit.Action, t *andlabsT, newt *andlabsT) bool {
return false return false
} }
log(logInfo, "place() switch", where.WidgetType)
switch where.WidgetType { switch where.WidgetType {
case toolkit.Grid: case toolkit.Grid:
log(debugGrid, "add() Grid try at Parent X,Y =", a.X, a.Y) log(debugGrid, "place() Grid try at Parent X,Y =", a.X, a.Y)
newt.gridX = a.X newt.gridX = a.X
newt.gridY = a.Y newt.gridY = a.Y
log(debugGrid, "add() Grid try at gridX,gridY", newt.gridX, newt.gridY) log(debugGrid, "place() Grid try at gridX,gridY", newt.gridX, newt.gridY)
// at the very end, subtract 1 from X & Y since andlabs/ui starts counting at zero // at the very end, subtract 1 from X & Y since andlabs/ui starts counting at zero
t.uiGrid.Append(newt.uiControl, t.uiGrid.Append(newt.uiControl,
newt.gridY - 1, newt.gridX - 1, 1, 1, newt.gridY - 1, newt.gridX - 1, 1, 1,
@ -155,7 +157,7 @@ func place(a *toolkit.Action, t *andlabsT, newt *andlabsT) bool {
case toolkit.Group: case toolkit.Group:
if (t.uiBox == nil) { if (t.uiBox == nil) {
t.uiGroup.SetChild(newt.uiControl) t.uiGroup.SetChild(newt.uiControl)
log(debugGrid, "add() hack Group to use this as the box?", a.Name, a.WidgetType) log(debugGrid, "place() hack Group to use this as the box?", a.Name, a.WidgetType)
t.uiBox = newt.uiBox t.uiBox = newt.uiBox
} else { } else {
t.uiBox.Append(newt.uiControl, stretchy) t.uiBox.Append(newt.uiControl, stretchy)
@ -166,6 +168,8 @@ func place(a *toolkit.Action, t *andlabsT, newt *andlabsT) bool {
t.boxC += 1 t.boxC += 1
return true return true
case toolkit.Box: case toolkit.Box:
log(logInfo, "place() uiBox =", t.uiBox)
log(logInfo, "place() uiControl =", newt.uiControl)
t.uiBox.Append(newt.uiControl, stretchy) t.uiBox.Append(newt.uiControl, stretchy)
t.boxC += 1 t.boxC += 1
return true return true
@ -173,7 +177,7 @@ func place(a *toolkit.Action, t *andlabsT, newt *andlabsT) bool {
t.uiWindow.SetChild(newt.uiControl) t.uiWindow.SetChild(newt.uiControl)
return true return true
default: default:
log(debugError, "add() how?", a.ParentId) log(debugError, "place() how?", a.ParentId)
} }
return false return false
} }

View File

@ -24,7 +24,6 @@ func newButton(a *toolkit.Action) {
newt.uiButton = b newt.uiButton = b
newt.uiControl = b newt.uiControl = b
newt.wId = a.WidgetId newt.wId = a.WidgetId
// newt.tw = a.Widget
newt.WidgetType = a.WidgetType newt.WidgetType = a.WidgetType
newt.parent = t newt.parent = t

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"sync"
"embed" "embed"
"git.wit.org/wit/gui/toolkit" "git.wit.org/wit/gui/toolkit"
@ -16,14 +17,20 @@ var res embed.FS
var pluginChan chan toolkit.Action var pluginChan chan toolkit.Action
var uiMainUndef bool = true var uiMainUndef bool = true
var uiMain sync.Once
var muAction sync.Mutex
func catchActionChannel() { func catchActionChannel() {
log(logNow, "catchActionChannel() START") log(logNow, "catchActionChannel() START")
for { for {
log(logNow, "catchActionChannel() for loop") log(logNow, "catchActionChannel() for loop")
uiMain.Do(func() {
go ui.Main(demoUI)
})
select { select {
case a := <-pluginChan: case a := <-pluginChan:
log(logNow, "catchActionChannel() SELECT widget id =", a.WidgetId, a.Name) log(logNow, "catchActionChannel() SELECT widget id =", a.WidgetId, a.Name)
/*
// go Action(a) // go Action(a)
if (uiMainUndef) { if (uiMainUndef) {
log(logError,"catchActionChannel() main() was not run yet") log(logError,"catchActionChannel() main() was not run yet")
@ -34,7 +41,7 @@ func catchActionChannel() {
log(logError,"catchActionChannel() ui.Main() START") log(logError,"catchActionChannel() ui.Main() START")
log(logError,"catchActionChannel() ui.Main() START") log(logError,"catchActionChannel() ui.Main() START")
sleep(1) sleep(1)
go ui.Main(demoUI) // go ui.Main(demoUI)
// go ui.Main( func() { // go ui.Main( func() {
// rawAction(a) // rawAction(a)
// }) // })
@ -46,6 +53,12 @@ func catchActionChannel() {
rawAction(a) rawAction(a)
log(logNow, "catchActionChannel() STUFF END", a.WidgetId, a.ActionType, a.WidgetType) log(logNow, "catchActionChannel() STUFF END", a.WidgetId, a.ActionType, a.WidgetType)
} }
*/
log(logNow, "catchActionChannel() STUFF", a.WidgetId, a.ActionType, a.WidgetType)
muAction.Lock()
rawAction(a)
muAction.Unlock()
log(logNow, "catchActionChannel() STUFF END", a.WidgetId, a.ActionType, a.WidgetType)
} }
} }
} }
@ -90,7 +103,7 @@ func Init() {
setDefaultBehavior(true) setDefaultBehavior(true)
andlabs = make(map[int]*andlabsT) andlabs = make(map[int]*andlabsT)
pluginChan = make(chan toolkit.Action) pluginChan = make(chan toolkit.Action, 1)
log(logNow, "Init() start channel reciever") log(logNow, "Init() start channel reciever")
go catchActionChannel() go catchActionChannel()

View File

@ -55,7 +55,7 @@ func rawAction(a toolkit.Action) {
switch a.ActionType { switch a.ActionType {
case toolkit.Add: case toolkit.Add:
add(&a) add(a)
case toolkit.Show: case toolkit.Show:
a.B = true a.B = true
show(&a) show(&a)

View File

@ -22,6 +22,7 @@ type andlabsT struct {
// tw *toolkit.Widget // tw *toolkit.Widget
parent *andlabsT parent *andlabsT
a toolkit.Action
uiControl ui.Control uiControl ui.Control

View File

@ -127,6 +127,7 @@ const (
Append Append
Move Move
Dump Dump
Quit
) )
func (s WidgetType) String() string { func (s WidgetType) String() string {

View File

@ -24,10 +24,10 @@ func Watchdog() {
} }
} }
if (i == 2) { if (i == 2) {
LoadPlugin("gocui") Config.rootNode.LoadToolkit("gocui")
} }
// if (i == 3) { // if (i == 3) {
// LoadPlugin("andlabs") // Config.rootNode.LoadToolkit("andlabs")
// } // }
i += 1 i += 1
time.Sleep(watchtime * time.Second / 10) time.Sleep(watchtime * time.Second / 10)