diff --git a/.gitignore b/.gitignore index 47191be..6bda501 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,10 @@ *.swp + +# ignore compiled plugins +toolkit/*.so + +cmds/buttonplugin/buttonplugin +cmds/console-ui-helloworld/console-ui-helloworld +cmds/debug/debug cmds/helloworld/helloworld cmds/textbox/textbox -cmds/gui-demo/gui-demo -cmds/consolemouse/consolemouse -cmds/console-hello-world/console-hello-world -cmds/gocli-as-plugin/gocli-as-plugin -cmds/buttonAsPlugin/buttonAsPlugin - -tookit/gocui/gocli - -toolkit/*.so diff --git a/Makefile b/Makefile index 306800f..8cd82c7 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ all: README.md @echo - @echo "make examples # will run all the examples" + @echo "make cmds # will run all the cmds" @echo "make update # full git update" @echo make -C cmds/helloworld @@ -12,16 +12,22 @@ update: git pull go get -v -t -u ./... -examples: examples-consolemouse examples-helloworld examples-gui-demo +cmds: cmds-buttonplugin cmds-console-ui-helloworld cmds-debug cmds-helloworld cmds-textbox -examples-consolemouse: - make -C cmds/consolemouse +cmds-buttonplugin: + make -C cmds/buttonplugin -examples-helloworld: +cmds-console-ui-helloworld: + make -C cmds/console-ui-helloworld + +cmds-helloworld: make -C cmds/helloworld -examples-gui-demo: - make -C cmds/gui-demo +cmds-debug: + make -C cmds/debug + +cmds-textbox: + make -C cmds/textbox # sync repo to the github backup github: @@ -34,7 +40,11 @@ doc: # GO111MODULE=on go install github.com/posener/goreadme/cmd/goreadme@latest (worked Oct 20 2022) README.md: doc.go - goreadme -factories -types -functions -variabless > README.md + goreadme -factories -types -functions -variabless > README-goreadme.md + +clean: + rm -f toolkit/*.so plugins: - GO111MODULE="off" go build -buildmode=plugin -o toolkit/gocli.so toolkit/gocli/greeter.go + # GO111MODULE="off" go build -buildmode=plugin -o toolkit/test.so toolkit/gocui/*.go + make -C toolkit/gocui diff --git a/README-goreadme.md b/README-goreadme.md new file mode 100644 index 0000000..2a0470c --- /dev/null +++ b/README-goreadme.md @@ -0,0 +1,335 @@ +# gui + +Package gui implements a abstraction layer for Go visual elements in +a cross platform and library independent way. (hopefully this is will work) + +A quick overview of the features, some general design guidelines +and principles for how this package should generally work: + +Definitions: + +```go +* Toolkit: the underlying library (MacOS gui, Windows gui, gtk, qt, etc) +* Node: A binary tree of all the underlying GUI toolkit elements +``` + +Principles: + +```go +* Make code using this package simple to use +* When in doubt, search upward in the binary tree +* It's ok to guess. We will return something close. +* Hide complexity internally here +* Isolate the GUI toolkit +* Try to use [Wikipedia Graphical widget] names +``` + +## Quick Start + +This section demonstrates how to quickly get started with spew. See the +sections below for further details on formatting and configuration options. + +```go +// This creates a simple hello world window +package main + +import ( + "log" + "git.wit.org/wit/gui" +) + +var window *gui.Node // This is the beginning of the binary tree of widgets + +// go will sit here until the window exits +func main() { + gui.Main(helloworld) +} + +// This initializes the first window and 2 tabs +func helloworld() { + gui.Config.Title = "Hello World golang wit/gui Window" + gui.Config.Width = 640 + gui.Config.Height = 480 + + window := gui.NewWindow() + addTab(window, "A Simple Tab Demo") + addTab(window, "A Second Tab") +} + +func addTab(w *gui.Node, title string) { + tab := w.NewTab(title) + + group := tab.NewGroup("foo bar") + group.NewButton("hello", func() { + log.Println("world") + }) +} +``` + +## Debian Build + +This worked on debian sid on 2022/10/20 +I didn't record the dependances needed + +```go +GO111MODULE="off" go get -v -t -u git.wit.org/wit/gui +cd ~/go/src/git.wit.org/wit/gui/cmds/helloworld/ +GO111MODULE="off" go build -v -x +[./helloworld](./helloworld) +``` + +## Toolkits + +* Andlabs - [https://github.com/andlabs/ui](https://github.com/andlabs/ui) +* gocui - [https://github.com/awesome-gocui/gocui](https://github.com/awesome-gocui/gocui) + +The goal is to design something that will work with more than one. + +Right now, this abstraction is built on top of the go package 'andlabs/ui' +which does the cross platform support. +The next step is to intent is to allow this to work directly against GTK and QT. + +It should be able to add Fyne, WASM, native macos & windows, android and +hopefully also things like libSDL, faiface/pixel, slint + +## Errors + +Since it is possible for custom Stringer/error interfaces to panic, spew +detects them and handles them internally by printing the panic information +inline with the output. Since spew is intended to provide deep pretty printing +capabilities on structures, it intentionally does not return any errors. + +## Debugging + +To dump variables with full newlines, indentation, type, and pointer +information this uses spew.Dump() + +## Bugs + +"The author's idea of friendly may differ to that of many other people." + +-- manpage quote from the excellent minimalistic window manager 'evilwm' + +## References + +Useful links and other +external things +which might be useful + +[Wikipedia Graphical widget]: [https://en.wikipedia.org/wiki/Graphical_widget](https://en.wikipedia.org/wiki/Graphical_widget) +[Github mirror]: [https://github.com/witorg/gui](https://github.com/witorg/gui) + +```go +* [Wikipedia Graphical widget] +* [Github mirror] +``` + +## Variables + +```golang +var PlugGocli *plugin.Plugin +``` + +```golang +var PlugGocliOk bool +``` + +```golang +var PlugHello *plugin.Plugin +``` + +## Functions + +### func [DebugTab](/example_window_debug.go#L26) + +`func DebugTab()` + +this function is used by the examples to add a tab +dynamically to the bugWin node +TODO: make this smarter once this uses toolkit/ + +### func [DebugWindow](/example_window_debug.go#L14) + +`func DebugWindow()` + +Creates a window helpful for debugging this package + +### func [DemoToolkitWindow](/example_window_demo_toolkit.go#L24) + +`func DemoToolkitWindow()` + +This creates a window that shows how the toolkit works +internally using it's raw unchanged code for the toolkit itself + +This is a way to test and see if the toolkit is working at all +right now it shows the andlabs/ui/DemoNumbersPage() + +### func [DemoWindow](/example_window_demo.go#L10) + +`func DemoWindow()` + +This creates a window that shows how this package works + +### func [GetDebug](/structs.go#L24) + +`func GetDebug() bool` + +### func [GetDebugToolkit](/structs.go#L36) + +`func GetDebugToolkit() bool` + +### func [GocuiAddButton](/plugin.go#L108) + +`func GocuiAddButton(name string)` + +### func [GolangDebugWindow](/example_window_golang_debug.go#L12) + +`func GolangDebugWindow()` + +### func [IndentPrintln](/structs.go#L216) + +`func IndentPrintln(a ...interface{})` + +### func [LoadPlugin](/plugin.go#L36) + +`func LoadPlugin(name string) *plugin.Plugin` + +### func [LookupJcarrButton](/plugin.go#L98) + +`func LookupJcarrButton()` + +### func [Main](/main.go#L38) + +`func Main(f func())` + +### func [Queue](/main.go#L51) + +`func Queue(f func())` + +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.) +For example: gui.Queue(NewWindow()) + +### func [RunGreet](/plugin.go#L88) + +`func RunGreet()` + +### func [SetDebug](/structs.go#L28) + +`func SetDebug(s bool)` + +### func [SetDebugToolkit](/structs.go#L40) + +`func SetDebugToolkit(s bool)` + +### func [ShowDebugValues](/structs.go#L44) + +`func ShowDebugValues()` + +### func [StandardClose](/main.go#L57) + +`func StandardClose(n *Node)` + +The window is destroyed but the application does not quit + +### func [StandardExit](/main.go#L65) + +`func StandardExit(n *Node)` + +The window is destroyed but the application does not quit + +## Types + +### type [Greeter](/plugin.go#L17) + +`type Greeter interface { ... }` + +TODO: could a protobuf work here? + +### type [GuiConfig](/structs.go#L67) + +`type GuiConfig struct { ... }` + +#### Variables + +```golang +var Config GuiConfig +``` + +### type [GuiOptions](/structs.go#L56) + +`type GuiOptions struct { ... }` + +This struct can be used with go-arg + +### type [Node](/structs.go#L117) + +`type Node struct { ... }` + +The Node is simply the name and the size of whatever GUI element exists + +#### func [NewStandardWindow](/example_window_demo_toolkit.go#L7) + +`func NewStandardWindow(title string) *Node` + +#### func [NewWindow](/window.go#L15) + +`func NewWindow() *Node` + +This routine creates a blank window with a Title and size (W x H) + +This routine can not have any arguements due to the nature of how +it can be passed via the 'andlabs/ui' queue which, because it is +cross platform, must pass UI changes into the OS threads (that is +my guess). + +This example demonstrates how to create a NewWindow() + +Interacting with a GUI in a cross platform fashion adds some +unusual problems. To obvuscate those, andlabs/ui starts a +goroutine that interacts with the native gui toolkits +on the Linux, MacOS, Windows, etc. + +Because of this oddity, to initialize a new window, the +function is not passed any arguements and instead passes +the information via the Config type. + +```golang +package main + +import ( + "git.wit.org/wit/gui" +) + +func main() { + // Define the name and size + gui.Config.Title = "WIT GUI Window 1" + gui.Config.Width = 640 + gui.Config.Height = 480 + + // Create the Window + gui.NewWindow() + +} + +``` + + Output: + +``` +You get a window +``` + +### type [Widget](/widget.go#L12) + +`type Widget struct { ... }` + +what names should be used? This is not part of [[Graphical Widget]] +Event() seems like a good name. +Could a protobuf be used here? (Can functions be passed?) + +--- +Readme created from Go doc with [goreadme](https://github.com/posener/goreadme) diff --git a/README.md b/README.md index 56358e0..77acae7 100644 --- a/README.md +++ b/README.md @@ -8,21 +8,17 @@ and principles for how this package should generally work: Definitions: -```go * Toolkit: the underlying library (MacOS gui, Windows gui, gtk, qt, etc) * Node: A binary tree of all the underlying GUI toolkit elements -``` Principles: -```go * Make code using this package simple to use * When in doubt, search upward in the binary tree * It's ok to guess. We will return something close. * Hide complexity internally here * Isolate the GUI toolkit * Try to use [Wikipedia Graphical widget] names -``` ## Quick Start @@ -113,13 +109,8 @@ Useful links and other external things which might be useful -[Wikipedia Graphical widget]: [https://en.wikipedia.org/wiki/Graphical_widget](https://en.wikipedia.org/wiki/Graphical_widget) -[Github mirror]: [https://github.com/witorg/gui](https://github.com/witorg/gui) - -```go -* [Wikipedia Graphical widget] -* [Github mirror] -``` +* [Wikipedia Graphical widget](https://en.wikipedia.org/wiki/Graphical_widget) +* [Github mirror](https://github.com/witorg/gui) ## Functions diff --git a/button.go b/button.go index 1ce7327..7b01e1e 100644 --- a/button.go +++ b/button.go @@ -4,21 +4,34 @@ import "log" func (n *Node) NewButton(name string, custom func()) *Node { if (n.toolkit == nil) { - log.Println("gui.Node.AppendButton() filed node.toolkit == nil") - panic("gui.Node.AppendButton() filed node.toolkit == nil") + log.Println("gui.Node.NewButton() filed node.toolkit == nil") + panic("gui.Node.NewButton() filed node.toolkit == nil") return n } newNode := n.New(name) newNode.toolkit = n.toolkit.NewButton(name) + log.Println("gui.Node.NewButton()", name) + if (PlugGocliOk) { + log.Println("wit/gui gocui is loaded", PlugGocliOk) + greeter.AddButton(name) + log.Println("GOT HERE PlugGocliOk TRUE") + } else { + log.Println("GOT HERE PlugGocliOk FALSE") + } + // TODO: this is still confusing and probably wrong. This needs to communicate through a channel newNode.toolkit.Custom = func() { if (Config.Options.Debug) { - log.Println("gui.AppendButton() Button Clicked. Running custom() from outside toolkit START") + log.Println("gui.Newutton() Button Clicked. Running custom() from outside toolkit START") + } + if (custom != nil) { + custom() + } else { + log.Println("wit/gui No callback function is defined for button name =", name) } - custom() if (Config.Options.Debug) { - log.Println("gui.AppendButton() Button Clicked. Running custom() from outside toolkit END") + log.Println("gui.NewButton() Button Clicked. Running custom() from outside toolkit END") } } newNode.custom = custom diff --git a/cmds/buttonAsPlugin/Makefile b/cmds/buttonAsPlugin/Makefile deleted file mode 100644 index d9a67bf..0000000 --- a/cmds/buttonAsPlugin/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -run: build - ./buttonAsPlugin >/tmp/buttonAsPlugin.log 2>&1 - -build-release: - go get -v -u -x . - go build - ./buttonAsPlugin - -build: - GO111MODULE="off" go get -v -x . - GO111MODULE="off" go build - -update: - GO111MODULE="off" go get -v -u -x . diff --git a/cmds/console-hello-world/Makefile b/cmds/buttonplugin/Makefile similarity index 74% rename from cmds/console-hello-world/Makefile rename to cmds/buttonplugin/Makefile index 9c3540d..cf60369 100644 --- a/cmds/console-hello-world/Makefile +++ b/cmds/buttonplugin/Makefile @@ -1,11 +1,10 @@ run: build - ./console-hello-world - reset - ldd ./console-hello-world + ./buttonplugin >/tmp/buttonplugin.log 2>&1 build-release: go get -v -u -x . go build + ./buttonplugin build: GO111MODULE="off" go get -v -x . diff --git a/cmds/buttonAsPlugin/log.go b/cmds/buttonplugin/log.go similarity index 100% rename from cmds/buttonAsPlugin/log.go rename to cmds/buttonplugin/log.go diff --git a/cmds/buttonAsPlugin/main.go b/cmds/buttonplugin/main.go similarity index 66% rename from cmds/buttonAsPlugin/main.go rename to cmds/buttonplugin/main.go index e26c75e..cd4d770 100644 --- a/cmds/buttonAsPlugin/main.go +++ b/cmds/buttonplugin/main.go @@ -3,19 +3,19 @@ package main import ( "log" + "strconv" "git.wit.org/wit/gui" ) func main() { - // go loadPlugin(plugHello, "../../toolkit/hello.so") - // this doesn't seem to work captureSTDOUT() - // go loadPlugin("../../toolkit/gocli.so") gui.Main(buttonWindow) } +var counter int = 10 + // This creates a window func buttonWindow() { var w, g *gui.Node @@ -30,13 +30,6 @@ func buttonWindow() { log.Println("world") }) - /* - g.NewButton("LoadPlugin()", func () { - log.Println("world") - gui.LoadPlugin("../../toolkit/gocli.so") - }) - */ - g.NewButton("RunGreet()", func () { log.Println("world") go gui.RunGreet() @@ -47,8 +40,10 @@ func buttonWindow() { gui.LookupJcarrButton() }) - g.NewButton("gui.GocuiAddButton()", func () { - log.Println("gui.GocuiAddButton()") - gui.GocuiAddButton("new foobar") + g.NewButton("new foobar 2", func () { + log.Println("new foobar 2. Adding button 'foobar 3'") + name := "foobar " + strconv.Itoa(counter) + counter += 1 + g.NewButton(name, nil) }) } diff --git a/cmds/consolemouse/Makefile b/cmds/console-ui-helloworld/Makefile similarity index 76% rename from cmds/consolemouse/Makefile rename to cmds/console-ui-helloworld/Makefile index 7061e7e..f63c8a9 100644 --- a/cmds/consolemouse/Makefile +++ b/cmds/console-ui-helloworld/Makefile @@ -1,6 +1,7 @@ run: build - ./consolemouse + ./console-ui-helloworld reset + ldd ./console-ui-helloworld build-release: go get -v -u -x . diff --git a/cmds/console-hello-world/keybindings.go b/cmds/console-ui-helloworld/keybindings.go similarity index 100% rename from cmds/console-hello-world/keybindings.go rename to cmds/console-ui-helloworld/keybindings.go diff --git a/cmds/console-hello-world/log.go b/cmds/console-ui-helloworld/log.go similarity index 100% rename from cmds/console-hello-world/log.go rename to cmds/console-ui-helloworld/log.go diff --git a/cmds/console-hello-world/main.go b/cmds/console-ui-helloworld/main.go similarity index 92% rename from cmds/console-hello-world/main.go rename to cmds/console-ui-helloworld/main.go index dd360d5..d16b805 100644 --- a/cmds/console-hello-world/main.go +++ b/cmds/console-ui-helloworld/main.go @@ -51,17 +51,9 @@ func main() { } addButton("hello") - addButton("world") - addButton("foo") addGroup("blank") - addButton("bar") - addButton("bar none") - addButton("bar going") - - addGroup("te") - addButton("world 2") - addButton("foo 2") + addButton("world") if err := g.MainLoop(); err != nil && !errors.Is(err, gocui.ErrQuit) { log.Panicln(err) diff --git a/cmds/console-hello-world/newJ.go b/cmds/console-ui-helloworld/newJ.go similarity index 100% rename from cmds/console-hello-world/newJ.go rename to cmds/console-ui-helloworld/newJ.go diff --git a/cmds/console-hello-world/views.go b/cmds/console-ui-helloworld/views.go similarity index 100% rename from cmds/console-hello-world/views.go rename to cmds/console-ui-helloworld/views.go diff --git a/cmds/consolemouse/gocui.go b/cmds/consolemouse/gocui.go deleted file mode 100644 index 7da888e..0000000 --- a/cmds/consolemouse/gocui.go +++ /dev/null @@ -1,51 +0,0 @@ -// This creates a simple hello world window -package main - -import ( - "log" - "time" - "git.wit.org/wit/gui" -) - -import toolkit "git.wit.org/wit/gui/toolkit/gocui" - -func configureGogui() { - toolkit.Init() - toolkit.OnExit(mycallback) -} - -func startGogui() { - toolkit.StartConsoleMouse() -} - -func mycallback(name string) { - log.Println("run andlabs here? name =", name) - if (name == "andlabs") { - go gui.Main(initGUI) - } - if (name == "something") { - log.Println("add something to do here") - } - if (name == "DemoToolkitWindow") { - gui.Queue( func () { - gui.DemoToolkitWindow() - }) - } - if (name == "addDemoTab") { - gui.Queue( func () { - addDemoTab(w, "A Tab from gocui") - }) - } - if (name == "DebugWindow") { - log.Println("Opening a Debug Window via the gui.Queue()") - gui.Config.Width = 800 - gui.Config.Height = 300 - gui.Config.Exit = myExit - gui.Queue(gui.DebugWindow) - time.Sleep(1 * time.Second) - gui.Queue(gui.DebugTab) - } - if (name == "exit") { - myExit(nil) - } -} diff --git a/cmds/consolemouse/main.go b/cmds/consolemouse/main.go deleted file mode 100644 index 3f4ce58..0000000 --- a/cmds/consolemouse/main.go +++ /dev/null @@ -1,52 +0,0 @@ -// This creates a simple hello world window -package main - -import ( - "os" - "log" -// "time" - "git.wit.org/wit/gui" -) - -import toolkit "git.wit.org/wit/gui/toolkit/gocui" - -var w *gui.Node - -func main() { - go gui.Main(initGUI) - - configureGogui() - startGogui() -} - -// This initializes the first window -func initGUI() { - gui.Config.Title = "Hello World golang wit/gui Window" - gui.Config.Width = 640 - gui.Config.Height = 480 - gui.Config.Exit = myExit - - w = gui.NewWindow() - w.Dump() - addDemoTab(w, "A Simple Tab Demo") - addDemoTab(w, "A Second Tab") -} - -func addDemoTab(w *gui.Node, title string) { - var newNode, g *gui.Node - - newNode = w.NewTab(title) - - g = newNode.NewGroup("group 1") - - dd := g.NewDropdown("demoCombo2") - dd.AddDropdown("more 1") - dd.AddDropdown("less 2") - dd.AddDropdown("foo 3") -} - -func myExit(n *gui.Node) { - log.Println("You can Do exit() things here") - toolkit.Exit() - os.Exit(0) -} diff --git a/cmds/gui-demo/Makefile b/cmds/debug/Makefile similarity index 70% rename from cmds/gui-demo/Makefile rename to cmds/debug/Makefile index 41fdd10..25c994d 100644 --- a/cmds/gui-demo/Makefile +++ b/cmds/debug/Makefile @@ -1,5 +1,5 @@ run: build - ./gui-demo + ./debug build: go build diff --git a/cmds/debug/helloworld.go b/cmds/debug/helloworld.go new file mode 100644 index 0000000..d0998bf --- /dev/null +++ b/cmds/debug/helloworld.go @@ -0,0 +1,20 @@ +// A simple helloworld window +package main + +import ( + "log" + "git.wit.org/wit/gui" +) + +// This creates a window +func helloworld() { + var w *gui.Node + gui.Config.Title = "helloworld golang wit/gui window" + gui.Config.Width = 400 + gui.Config.Height = 100 + + w = gui.NewWindow() + w.NewButton("hello", func () { + log.Println("world") + }) +} diff --git a/cmds/gui-demo/main.go b/cmds/debug/main.go similarity index 90% rename from cmds/gui-demo/main.go rename to cmds/debug/main.go index 54ad449..5e3a350 100644 --- a/cmds/gui-demo/main.go +++ b/cmds/debug/main.go @@ -17,16 +17,12 @@ import ( func main() { log.Println("Starting my Control Panel") - go gui.Main(initGUI) + go gui.Main(helloworld) +// go gui.DemoToolkitWindow() watchGUI() } -// This initializes the first window -func initGUI() { - gui.DemoToolkitWindow() -} - // This demonstrates how to properly interact with the GUI // You can not involke the GUI from external goroutines in most cases. func watchGUI() { diff --git a/cmds/gocli-as-plugin/Makefile b/cmds/gocli-as-plugin/Makefile deleted file mode 100644 index 277d737..0000000 --- a/cmds/gocli-as-plugin/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -run: build - ./gocli-as-plugin - # ldd ./gocli-as-plugin - -build-release: - go get -v -u -x . - go build - -build: - GO111MODULE="off" go get -v -x . - GO111MODULE="off" go build - -update: - GO111MODULE="off" go get -v -u -x . diff --git a/cmds/gocli-as-plugin/log.go b/cmds/gocli-as-plugin/log.go deleted file mode 100644 index b05beaf..0000000 --- a/cmds/gocli-as-plugin/log.go +++ /dev/null @@ -1,35 +0,0 @@ -// This creates a simple hello world window -package main - -import ( - "log" - "fmt" - "os" - arg "github.com/alexflint/go-arg" -) - - -var args struct { - Foo string - Bar bool - User string `arg:"env:USER"` - Demo bool `help:"run a demo"` -} - -var f *os.File -var err error - -func init() { - arg.MustParse(&args) - fmt.Println(args.Foo, args.Bar, args.User) - - f, err = os.OpenFile("/tmp/guilogfile", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666) - if err != nil { - log.Fatalf("error opening file: %v", err) - } - // hmm. is there a trick here or must this be in main() - // defer f.Close() - - log.SetOutput(f) - log.Println("This is a test log entry") -} diff --git a/cmds/gocli-as-plugin/main.go b/cmds/gocli-as-plugin/main.go deleted file mode 100644 index a9bd632..0000000 --- a/cmds/gocli-as-plugin/main.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2014 The gocui Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "log" - "os" - - "plugin" -// "github.com/awesome-gocui/gocui" -) - -type Greeter interface { - Greet() -} - -var plugGocli *plugin.Plugin -var plugHello *plugin.Plugin - -func main() { - log.Println("attempt plugin") - - go loadPlugin(plugHello, "../../toolkit/hello.so") - loadPlugin(plugGocli, "../../toolkit/gocli.so") -} - -func loadPlugin(plug *plugin.Plugin, name string) { - // load module - // 1. open the so file to load the symbols - plug, err = plugin.Open(name) - if err != nil { - log.Println(err) - os.Exit(1) - } - - // 2. look up a symbol (an exported function or variable) - // in this case, variable Greeter - symGreeter, err := plug.Lookup("Greeter") - if err != nil { - log.Println(err) - os.Exit(1) - } - - log.Println("symGreater", symGreeter) - - // 3. Assert that loaded symbol is of a desired type - // in this case interface type Greeter (defined above) - // var greeter Greeter - greeter, ok := symGreeter.(Greeter) - if !ok { - log.Println("unexpected type from module symbol") - os.Exit(1) - } - - // 4. use the module - greeter.Greet() -} diff --git a/doc.go b/doc.go index 541cdc1..41e976f 100644 --- a/doc.go +++ b/doc.go @@ -73,6 +73,9 @@ I didn't record the dependances needed Toolkits +* Andlabs - https://github.com/andlabs/ui +* gocui - https://github.com/awesome-gocui/gocui + The goal is to design something that will work with more than one. Right now, this abstraction is built on top of the go package 'andlabs/ui' diff --git a/window-debug.go b/example_window_debug.go similarity index 100% rename from window-debug.go rename to example_window_debug.go diff --git a/window-demo.go b/example_window_demo.go similarity index 100% rename from window-demo.go rename to example_window_demo.go diff --git a/window-demo-toolkit.go b/example_window_demo_toolkit.go similarity index 100% rename from window-demo-toolkit.go rename to example_window_demo_toolkit.go diff --git a/window-golang-debug.go b/example_window_golang_debug.go similarity index 100% rename from window-golang-debug.go rename to example_window_golang_debug.go diff --git a/main.go b/main.go index e3e6609..21cbd02 100644 --- a/main.go +++ b/main.go @@ -30,8 +30,9 @@ func init() { Config.master.Dump() } - // load the gocli plugin - PlugGocli = LoadPlugin("../../toolkit/gocli.so") + // load the gocui plugin + PlugGocli = LoadPlugin("../../toolkit/gocui.so") + PlugGocliOk = false } func Main(f func()) { diff --git a/plugin.go b/plugin.go index 5c10e03..58e6dbe 100644 --- a/plugin.go +++ b/plugin.go @@ -1,5 +1,10 @@ package gui +// This is based off of the excellent example and documentation here: +// https://github.com/vladimirvivien/go-plugin-example +// There truly are great people in this world. +// It's a pleasure to be here with all of you + import ( "log" "os" @@ -8,6 +13,7 @@ import ( "github.com/davecgh/go-spew/spew" ) +// TODO: could a protobuf work here? type Greeter interface { Greet() JcarrButton() @@ -15,6 +21,7 @@ type Greeter interface { } var PlugGocli *plugin.Plugin +var PlugGocliOk bool var PlugHello *plugin.Plugin // var gBut plugin.Symbol @@ -23,6 +30,9 @@ var symGreeter plugin.Symbol var greeter Greeter var ok bool +var typeToolkit plugin.Symbol +var typeToolkitCast Greeter + func LoadPlugin(name string) *plugin.Plugin { scs := spew.ConfigState{MaxDepth: 1} @@ -33,12 +43,19 @@ func LoadPlugin(name string) *plugin.Plugin { log.Println(scs.Sdump(plug)) if err != nil { log.Println(err) - os.Exit(1) + return nil } - PlugGocli = plug // 2. look up a symbol (an exported function or variable) // in this case, variable Greeter + typeToolkit, err = plug.Lookup("Toolkit") + log.Println("plugin.Toolkit", typeToolkit) + log.Println(scs.Sdump(typeToolkit)) + if err != nil { + log.Println(err) + os.Exit(1) + } + symGreeter, err = plug.Lookup("Greeter") log.Println("symGreater", symGreeter) log.Println(scs.Sdump(symGreeter)) @@ -57,6 +74,14 @@ func LoadPlugin(name string) *plugin.Plugin { log.Println("unexpected type from module symbol") os.Exit(1) } + + /* + typeToolkitCast, ok = typeToolkit.(Greeter) + if !ok { + log.Println("unexpected cast of Toolkit to Greeter") + os.Exit(1) + } + */ return plug } @@ -66,6 +91,7 @@ func RunGreet() { log.Println("wit/gui gocui plugin didn't load") return } + PlugGocliOk = true greeter.Greet() } diff --git a/structs.go b/structs.go index bf16758..22ec988 100644 --- a/structs.go +++ b/structs.go @@ -82,35 +82,6 @@ type GuiConfig struct { prefix string } -type Widget int - -// https://ieftimov.com/post/golang-datastructures-trees/ -const ( - Unknown Widget = iota - Window - Tab - Frame - Dropbox - Spinner - Label -) - -func (s Widget) String() string { - switch s { - case Window: - return "Window" - case Tab: - return "Tab" - case Frame: - return "Frame" - case Label: - return "Label" - case Dropbox: - return "Dropbox" - } - return "unknown" -} - // The Node is simply the name and the size of whatever GUI element exists type Node struct { id int diff --git a/toolkit/gocui/Makefile b/toolkit/gocui/Makefile index 42798cc..27f23ed 100644 --- a/toolkit/gocui/Makefile +++ b/toolkit/gocui/Makefile @@ -1,8 +1,8 @@ all: plugin - ldd ../gocli.so + ldd ../gocui.so build: GO111MODULE="off" go build plugin: - GO111MODULE="off" go build -buildmode=plugin -o ../gocli.so + GO111MODULE="off" go build -buildmode=plugin -o ../gocui.so diff --git a/toolkit/gocui/button.go b/toolkit/gocui/button.go new file mode 100644 index 0000000..8fb6e05 --- /dev/null +++ b/toolkit/gocui/button.go @@ -0,0 +1,48 @@ +package main + +import ( + "errors" + "fmt" + "log" + "strings" + + "github.com/awesome-gocui/gocui" +) + +func (w *Widget) AddButton() { +// func (g greeting) AddButton() { + log.Println("gui.gocui.AddButton()", w.Name) + addButton2(w.Name, w.Event) +} + +func addButton2(name string, e func(*Widget) *Widget) { + addButton(name) +} + +func addButton(name string) error { + t := len(name) + v, err := baseGui.SetView(name, currentX, currentY, currentX+t+3, currentY+2, 0) + if err == nil { + return err + } + if !errors.Is(err, gocui.ErrUnknownView) { + return err + } + + v.Wrap = true + fmt.Fprintln(v, " " + name) + fmt.Fprintln(v, strings.Repeat("foo\n", 2)) + + if _, err := baseGui.SetCurrentView(name); err != nil { + return err + } + + views = append(views, name) + curView = len(views) - 1 + idxView += 1 + currentY += 3 + if (groupSize < len(views)) { + groupSize = len(views) + } + return nil +} diff --git a/toolkit/gocui/greeter.go b/toolkit/gocui/greeter.go index de6ee68..e3094e5 100644 --- a/toolkit/gocui/greeter.go +++ b/toolkit/gocui/greeter.go @@ -1,28 +1,37 @@ package main import ( - "errors" - "fmt" "log" - "strings" - "github.com/awesome-gocui/gocui" + // "errors" + // "fmt" + // "strings" + // "github.com/awesome-gocui/gocui" ) type greeting string +// stores the raw toolkit internals +type toolkit struct { + id string + Name string + + OnChanged func(toolkit) +} + // this is exported var Greeter greeting +var Toolkit toolkit // func main() { func (g greeting) Greet() { - fmt.Println("Hello Universe") + log.Println("Hello Universe") Init() // ToolkitMain() } func (g greeting) JcarrButton() { - fmt.Println("Hello GreetButton meet Universe") + log.Println("Hello GreetButton meet Universe") addButton("Greet foo") addButton("Greet foo 2") } @@ -39,6 +48,7 @@ func (g greeting) AddButton(name string) { addButton(name) } +/* func addButton(name string) error { t := len(name) v, err := baseGui.SetView(name, currentX, currentY, currentX+t+3, currentY+2, 0) @@ -66,3 +76,4 @@ func addButton(name string) error { } return nil } +*/ diff --git a/toolkit/gocui/widget.go b/toolkit/gocui/widget.go new file mode 100644 index 0000000..758ac38 --- /dev/null +++ b/toolkit/gocui/widget.go @@ -0,0 +1,26 @@ +package main + +// passes information between the toolkit library (plugin) + +// All Toolkit interactions should be done via a channel or Queue() + +// This is the only thing that is passed between the toolkit plugin + +// what names should be used? This is not part of [[Graphical Widget]] +// Event() seems like a good name. +// Could a protobuf be used here? (Can functions be passed?) +type Widget struct { + i int + s string + + Name string + Width int + Height int + + Event func(*Widget) *Widget + + // Probably deprecate these + OnChanged func(*Widget) + Custom func(*Widget) + OnExit func(*Widget) +} diff --git a/widget.go b/widget.go new file mode 100644 index 0000000..2d97f61 --- /dev/null +++ b/widget.go @@ -0,0 +1,57 @@ +package gui + +// passes information between the toolkit library (plugin) + +// All Toolkit interactions should be done via a channel or Queue() + +// This is the only thing that is passed between the toolkit plugin + +// what names should be used? This is not part of [[Graphical Widget]] +// Event() seems like a good name. +// Could a protobuf be used here? (Can functions be passed?) +type Widget struct { + i int + s string + + Name string + Width int + Height int + + Event func(*Widget) *Widget + + // Probably deprecate these + OnChanged func(*Widget) + Custom func(*Widget) + OnExit func(*Widget) +} + +/* +type Widget int + +// https://ieftimov.com/post/golang-datastructures-trees/ +const ( + Unknown Widget = iota + Window + Tab + Frame + Dropbox + Spinner + Label +) + +func (s Widget) String() string { + switch s { + case Window: + return "Window" + case Tab: + return "Tab" + case Frame: + return "Frame" + case Label: + return "Label" + case Dropbox: + return "Dropbox" + } + return "unknown" +} +*/