diff --git a/Makefile b/Makefile index b25d255..c390cd0 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,7 @@ cmds-helloconsole: github: git push origin master git push github master + git push github devel git push github --tags @echo @echo check https://github.com/wit-go/gui diff --git a/README-goreadme.md b/README-goreadme.md index 9dc4369..7317871 100644 --- a/README-goreadme.md +++ b/README-goreadme.md @@ -119,6 +119,10 @@ external things which might be useful Creates a window helpful for debugging this package +### func [ExampleCatcher](/chan.go#L37) + +`func ExampleCatcher(f func())` + ### func [Indent](/debug.go#L130) `func Indent(b bool, a ...interface{})` @@ -133,23 +137,12 @@ Creates a window helpful for debugging this package loads and initializes a toolkit (andlabs/ui, gocui, etc) -### func [Main](/main.go#L97) +### func [Main](/main.go#L118) `func Main(f func())` This should not pass a function -### func [Queue](/main.go#L127) - -`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 [SetDebug](/debug.go#L28) `func SetDebug(s bool)` @@ -162,7 +155,7 @@ For example: gui.Queue(NewWindow()) `func ShowDebugValues()` -### func [StandardExit](/main.go#L147) +### func [StandardExit](/main.go#L170) `func StandardExit()` @@ -180,13 +173,13 @@ This goroutine can be used like a watchdog timer ## Types -### type [GuiArgs](/structs.go#L25) +### type [GuiArgs](/structs.go#L26) `type GuiArgs struct { ... }` This struct can be used with the go-arg package -### type [GuiConfig](/structs.go#L33) +### type [GuiConfig](/structs.go#L34) `type GuiConfig struct { ... }` @@ -196,7 +189,7 @@ This struct can be used with the go-arg package var Config GuiConfig ``` -### type [Node](/structs.go#L57) +### type [Node](/structs.go#L58) `type Node struct { ... }` @@ -251,6 +244,14 @@ func main() { You get a window ``` +#### func [Start](/main.go#L96) + +`func Start() *Node` + +#### func [StartS](/main.go#L105) + +`func StartS(name string) *Node` + ### type [Symbol](/plugin.go#L16) `type Symbol any` diff --git a/chan.go b/chan.go index 28f759c..54eb4e4 100644 --- a/chan.go +++ b/chan.go @@ -8,8 +8,10 @@ import ( // "regexp" // "git.wit.org/wit/gui/toolkit" "sync" + "runtime" "github.com/sourcegraph/conc" "github.com/sourcegraph/conc/stream" + "github.com/sourcegraph/conc/panics" ) func makeConc() { @@ -17,15 +19,42 @@ func makeConc() { defer wg.Wait() startTheThing(&wg) + log(debugError, "panic?") + sleep(2) + log(debugError, "panic? after sleep(5)") } func startTheThing(wg *conc.WaitGroup) { - wg.Go(func() { - log(debugNow, "startTheThing()") + f := func() { + log(debugError, "startTheThing() == about to panic now") panic("test conc.WaitGroup") + } + wg.Go(func() { + ExampleCatcher(f) }) } +func ExampleCatcher(f func()) { + var pc panics.Catcher + i := 0 + pc.Try(func() { i += 1 }) + pc.Try(f) + pc.Try(func() { i += 1 }) + + recovered := pc.Recovered() + + log(debugError, "panic.Recovered():", recovered.Value.(string)) + frames := runtime.CallersFrames(recovered.Callers) + for { + frame, more := frames.Next() + log(debugError, "\t", frame.Function) + + if !more { + break + } + } +} + func mapStream( in chan int, out chan int, diff --git a/cmds/textbox/main.go b/cmds/textbox/main.go index 76d0a42..b2c7e6d 100644 --- a/cmds/textbox/main.go +++ b/cmds/textbox/main.go @@ -24,7 +24,9 @@ func main() { arg.MustParse(&args) log.Println("Toolkit = ", args.Toolkit) - // gui.InitPlugins([]string{"andlabs"}) + gui.SetDebug(true) + // gui.InitPlugins([]string{"gocui"}) + // gui.InitPlugins([]string{"democui"}) gui.Main(initGUI) } diff --git a/common.go b/common.go index 6abdf58..b1bf428 100644 --- a/common.go +++ b/common.go @@ -157,3 +157,50 @@ func commonCallback(n *Node) { n.Custom() } } + +func (n *Node) Margin() { + var a toolkit.Action + a.Type = toolkit.Margin + newaction(&a, n, nil) +} + +func (n *Node) Unmargin() { + var a toolkit.Action + a.Type = toolkit.Unmargin + newaction(&a, n, nil) +} + +func (n *Node) Pad() { + var a toolkit.Action + a.Type = toolkit.Pad + newaction(&a, n, nil) +} + +func (n *Node) Unpad() { + var a toolkit.Action + a.Type = toolkit.Unpad + newaction(&a, n, nil) +} + +func (n *Node) New2() *Node { + var newWin *Node + newWin = NewWindow() + log(debugError, "New2() END Main(f)") + return newWin +} + +func (n *Node) Window(title string) *Node { + log(debugError, "Window()", n) + n.SetText(title) + return n +} + +func (n *Node) Standard() *Node { + log(debugError, "Standard()") + return n +} + +func (n *Node) DoMargin() *Node { + log(debugError, "DoMargin()") + return n +} diff --git a/debugWindow.go b/debugWindow.go index 3275cb1..a445d28 100644 --- a/debugWindow.go +++ b/debugWindow.go @@ -74,7 +74,7 @@ func (n *Node) DebugTab(title string) *Node { dropdownWindowWidgets(g1) }) - g2 := newN.NewGroup("node things") + g2 := newN.NewGroup("more things") g2.NewButton("Node.ListChildren(true)", func () { if (activeWidget == nil) { @@ -87,6 +87,20 @@ func (n *Node) DebugTab(title string) *Node { makeConc() }) + g2.NewButton("List Plugins", func () { + for _, aplug := range allPlugins { + log("Loaded plugin:", aplug.name, aplug.filename) + } + }) + + g2.NewButton("load plugin 'gocui'", func () { + StartS("gocui") + }) + + g2.NewButton("load plugin 'democui'", func () { + StartS("democui") + }) + return newN } diff --git a/log/log.go b/log/log.go index fafc894..9862291 100644 --- a/log/log.go +++ b/log/log.go @@ -29,17 +29,24 @@ import ( // "net" ) +// various debugging flags +var LogNow bool = true // useful for active development +var LogError bool = true +var LogWarn bool = false +var LogInfo bool = false +var LogVerbose bool = false +var LogSleep bool = false + var LOGOFF bool = false // turn this off, all logging stops var debugToolkit bool = false // does spew stuff? var Where string = "gui/log" -type spewt struct { +type Spewt struct { a bool } -var SPEW spewt - +var SPEW Spewt /* sleep() # you know what this does? sleeps for 1 second. yep. dump. easy. @@ -51,7 +58,7 @@ func Sleep(a ...any) { return } - Log(true, "sleep", a[0]) + Log(LogSleep, "sleep", a[0]) switch a[0].(type) { case int: @@ -69,7 +76,7 @@ func Sleep(a ...any) { exit("dont like apples") # ok. I'll make a note of that */ func Exit(a ...any) { - Log(true, "exit", a) + Log(LogError, "exit", a) //if (a) { // os.Exit(a) //} diff --git a/main.go b/main.go index 9f4b93c..89eacbe 100644 --- a/main.go +++ b/main.go @@ -57,7 +57,7 @@ func InitPlugins(names []string) { log(debugGui, "Starting gui.Init()") for _, aplug := range allPlugins { - log(debugGui, "gui.LoadToolkit() already loaded toolkit plugin =", aplug.name) + log(debugGui, "LoadToolkit() already loaded toolkit plugin =", aplug.name) for _, name := range names { if (name == aplug.name) { return @@ -93,6 +93,27 @@ func InitPlugins(names []string) { // StandardExit("golang wit/gui could not load a plugin TODO: do something to STDOUT (?)") } +func Start() *Node { + log(logInfo, "Start() Main(f)") + f := func() { + } + go Main(f) + sleep(1) + return Config.master +} + +func StartS(name string) *Node { + log(logInfo, "Start() Main(f) for name =", name) + if (LoadToolkit(name) == false) { + return Config.master + } + f := func() { + } + go Main(f) + sleep(1) + return Config.master +} + // This should not pass a function func Main(f func()) { log(debugGui, "Starting gui.Main() (using gtk via andlabs/ui)") @@ -111,11 +132,12 @@ func Main(f func()) { } aplug.MainOk = true aplug.Main(f) - // f() } - // toolkit.Main(f) } +/* +This is deprecated and will be implemented more correctly with waitgroups + // This should never be exposed(?) // Other goroutines must use this to access the GUI @@ -135,6 +157,7 @@ func Queue(f func()) { aplug.Queue(f) } } +*/ // The window is destroyed but the application does not quit func (n *Node) StandardClose() { diff --git a/node.go b/node.go index f997571..7fb7444 100644 --- a/node.go +++ b/node.go @@ -55,9 +55,11 @@ func (n *Node) Parent() *Node { return n.parent } +/* func (n *Node) Window() *Node { return n.parent } +*/ func (n *Node) Append(child *Node) { n.children = append(n.children, child) diff --git a/plugin.go b/plugin.go index d378672..0f458ef 100644 --- a/plugin.go +++ b/plugin.go @@ -29,12 +29,12 @@ type aplug struct { // TODO: make Main() main() and never allow the user to call it // run plugin.Main() when the plugin is loaded Main func(func ()) // this never returns. Each plugin must have it's own goroutine - Queue func(func ()) // Should this return right away? Should it wait (can it wait?) + // Queue func(func ()) // Should this return right away? Should it wait (can it wait?) Quit func() // NewWindow func(*toolkit.Widget) // simplifies passing to the plugin - Send func(*toolkit.Widget, *toolkit.Widget) + // Send func(*toolkit.Widget, *toolkit.Widget) // should replace Send() Action func(*toolkit.Action) @@ -74,7 +74,7 @@ func LoadToolkit(name string) bool { newPlug.Main = loadFuncF(&newPlug, "Main") // should send things to the goroutine above - newPlug.Queue = loadFuncF(&newPlug, "Queue") + // newPlug.Queue = loadFuncF(&newPlug, "Queue") // unload the plugin and restore state newPlug.Quit = loadFuncE(&newPlug, "Quit") diff --git a/structs.go b/structs.go index 5477d2e..62e5f92 100644 --- a/structs.go +++ b/structs.go @@ -2,6 +2,7 @@ package gui import ( "git.wit.org/wit/gui/toolkit" + "sync" ) // @@ -56,6 +57,7 @@ type GuiConfig struct { // simply the name and the size of whatever GUI element exists type Node struct { id int + initOnce sync.Once widget toolkit.Widget diff --git a/toolkit/andlabs/add.go b/toolkit/andlabs/add.go index 6dc8bb4..6bc8f2d 100644 --- a/toolkit/andlabs/add.go +++ b/toolkit/andlabs/add.go @@ -35,9 +35,10 @@ func add(a *toolkit.Action) { if (andlabs[a.WhereId] == nil) { // listMap(debugError) // memory corruption? - log(debugError, "add() Widget.Name =", a.Title, a.WidgetT) - // log(debugError, "add() Where.Name =", a.Where.Name) - log(debugError, "ERROR add() ERROR a.Where map to t == nil.", a.WidgetId, a.WhereId) + log(debugError, "add() Widget.Name =", a.Title) + log(debugError, "add() Widget.Type =", a.WidgetT) + log(debugError, "ERROR add() ERROR a.Where map to t == nil. WidgetId =", a.WidgetId, "WhereId =", a.WhereId) + exit("can not add()") return } diff --git a/toolkit/democui/, b/toolkit/democui/, new file mode 100644 index 0000000..762f8eb --- /dev/null +++ b/toolkit/democui/, @@ -0,0 +1,191 @@ +// 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 ( + "errors" + "fmt" + "log" + + "github.com/awesome-gocui/gocui" +) + +func main() { + g, err := gocui.NewGui(gocui.OutputNormal, true) + if err != nil { + log.Panicln(err) + } + defer g.Close() + + g.Cursor = false + g.Mouse = true + + g.SetManagerFunc(layout) + + if err := keybindings(g); err != nil { + log.Panicln(err) + } + + if err := g.MainLoop(); err != nil && !errors.Is(err, gocui.ErrQuit) { + log.Panicln(err) + } +} + +var initialMouseX, initialMouseY, xOffset, yOffset int +var globalMouseDown, msgMouseDown, movingMsg bool + +func layout(g *gocui.Gui) error { + maxX, maxY := g.Size() + if _, err := g.View("msg"); msgMouseDown && err == nil { + moveMsg(g) + } + if v, err := g.SetView("global", -1, -1, maxX, maxY, 0); err != nil { + if !errors.Is(err, gocui.ErrUnknownView) { + return err + } + v.Frame = false + } + if v, err := g.SetView("but1", 2, 2, 22, 7, 0); err != nil { + if !errors.Is(err, gocui.ErrUnknownView) { + return err + } + v.SelBgColor = gocui.ColorGreen + v.SelFgColor = gocui.ColorBlack + fmt.Fprintln(v, "Button 1 - line 1") + fmt.Fprintln(v, "Button 1 - line 2") + fmt.Fprintln(v, "Button 1 - line 3") + fmt.Fprintln(v, "Button 1 - line 4") + if _, err := g.SetCurrentView("but1"); err != nil { + return err + } + } + if v, err := g.SetView("but2", 24, 2, 44, 4, 0); err != nil { + if !errors.Is(err, gocui.ErrUnknownView) { + return err + } + v.SelBgColor = gocui.ColorGreen + v.SelFgColor = gocui.ColorBlack + fmt.Fprintln(v, "Button 2 - line 1") + } + updateHighlightedView(g) + return nil +} + +func keybindings(g *gocui.Gui) error { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { + return err + } + for _, n := range []string{"but1", "but2"} { + if err := g.SetKeybinding(n, gocui.MouseLeft, gocui.ModNone, showMsg); err != nil { + return err + } + } + if err := g.SetKeybinding("", gocui.MouseRelease, gocui.ModNone, mouseUp); err != nil { + return err + } + if err := g.SetKeybinding("", gocui.MouseLeft, gocui.ModNone, globalDown); err != nil { + return err + } + if err := g.SetKeybinding("msg", gocui.MouseLeft, gocui.ModNone, msgDown); err != nil { + return err + } + return nil +} + +func quit(g *gocui.Gui, v *gocui.View) error { + return gocui.ErrQuit +} + +func showMsg(g *gocui.Gui, v *gocui.View) error { + var l string + var err error + + if _, err := g.SetCurrentView(v.Name()); err != nil { + return err + } + + _, cy := v.Cursor() + if l, err = v.Line(cy); err != nil { + l = "" + } + + maxX, maxY := g.Size() + if v, err := g.SetView("msg", maxX/2-10, maxY/2, maxX/2+10, maxY/2+2, 0); err == nil || errors.Is(err, gocui.ErrUnknownView) { + v.Clear() + v.SelBgColor = gocui.ColorCyan + v.SelFgColor = gocui.ColorBlack + fmt.Fprintln(v, l) + } + return nil +} + +func updateHighlightedView(g *gocui.Gui) { + mx, my := g.MousePosition() + for _, view := range g.Views() { + view.Highlight = false + } + if v, err := g.ViewByPosition(mx, my); err == nil { + v.Highlight = true + } +} + +func moveMsg(g *gocui.Gui) { + mx, my := g.MousePosition() + if !movingMsg && (mx != initialMouseX || my != initialMouseY) { + movingMsg = true + } + g.SetView("msg", mx-xOffset, my-yOffset, mx-xOffset+20, my-yOffset+2, 0) +} + +func msgDown(g *gocui.Gui, v *gocui.View) error { + initialMouseX, initialMouseY = g.MousePosition() + if vx, vy, _, _, err := g.ViewPosition("msg"); err == nil { + xOffset = initialMouseX - vx + yOffset = initialMouseY - vy + msgMouseDown = true + } + return nil +} + +func globalDown(g *gocui.Gui, v *gocui.View) error { + mx, my := g.MousePosition() + if vx0, vy0, vx1, vy1, err := g.ViewPosition("msg"); err == nil { + if mx >= vx0 && mx <= vx1 && my >= vy0 && my <= vy1 { + return msgDown(g, v) + } + } + globalMouseDown = true + maxX, _ := g.Size() + msg := fmt.Sprintf("Mouse down at: %d,%d", mx, my) + x := mx - len(msg)/2 + if x < 0 { + x = 0 + } else if x+len(msg)+1 > maxX-1 { + x = maxX - 1 - len(msg) - 1 + } + if v, err := g.SetView("globalDown", x, my-1, x+len(msg)+1, my+1, 0); err != nil { + if !errors.Is(err, gocui.ErrUnknownView) { + return err + } + v.WriteString(msg) + } + return nil +} + +func mouseUp(g *gocui.Gui, v *gocui.View) error { + if msgMouseDown { + msgMouseDown = false + if movingMsg { + movingMsg = false + return nil + } else { + g.DeleteView("msg") + } + } else if globalMouseDown { + globalMouseDown = false + g.DeleteView("globalDown") + } + return nil +} diff --git a/toolkit/democui/help.go b/toolkit/democui/help.go new file mode 100644 index 0000000..ce88b92 --- /dev/null +++ b/toolkit/democui/help.go @@ -0,0 +1,40 @@ +// 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 ( + "errors" + "fmt" + + "github.com/awesome-gocui/gocui" +) + +func addHelp() { + baseGui.SetManagerFunc(helplayout) +} + +func helplayout(g *gocui.Gui) error { + var err error + maxX, _ := g.Size() + + helpLabel, err = g.SetView("help", maxX-32, 0, maxX-1, 12, 0) + if err != nil { + if !errors.Is(err, gocui.ErrUnknownView) { + return err + } + fmt.Fprintln(helpLabel, "KEYBINDINGS") + fmt.Fprintln(helpLabel, "Enter: Click Button") + fmt.Fprintln(helpLabel, "Tab/Space: Switch Buttons") + fmt.Fprintln(helpLabel, "") + fmt.Fprintln(helpLabel, "h: Help") + fmt.Fprintln(helpLabel, "Backspace: Delete Button") + fmt.Fprintln(helpLabel, "Arrow keys: Move Button") + fmt.Fprintln(helpLabel, "t: Move Button to the top") + fmt.Fprintln(helpLabel, "b: Move Button to the button") + fmt.Fprintln(helpLabel, "STDOUT: /tmp/witgui.log") + fmt.Fprintln(helpLabel, "Ctrl-C or Q: Exit") + } + return nil +} diff --git a/toolkit/democui/log.go b/toolkit/democui/log.go index 527d057..2d7e27e 100644 --- a/toolkit/democui/log.go +++ b/toolkit/democui/log.go @@ -5,7 +5,15 @@ import ( witlog "git.wit.org/wit/gui/log" ) +// various debugging flags +var logNow bool = true // useful for active development +var logError bool = true +var logWarn bool = false +var logInfo bool = false +var logVerbose bool = false + func log(a ...any) { + witlog.Where = "wit/democui" witlog.Log(a...) } diff --git a/toolkit/democui/main.go b/toolkit/democui/main.go new file mode 100644 index 0000000..1e0e3d8 --- /dev/null +++ b/toolkit/democui/main.go @@ -0,0 +1,58 @@ +// 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 ( + "os" +) + +func OnExit(f func(string)) { + Custom = f +} + +func Init() { + log("Init() of democui") +} + +func Exit() { + g.Close() +} + +func mouseClick(name string) { + // output screws up the console. Need to fix this by redirecting all console output to a file from log.Println() + // log.Println("g.Close()") + // g.Close() + + log("Found andlabs Running custom function for the mouse click") + Custom(name) + // panic("got andlabs") +} + +func Main(f func()) { + log("start Init()") + + outf, err := os.OpenFile("/tmp/witgui.log", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666) + if err != nil { + exit("error opening file: %v", err) + } + defer outf.Close() + + setOutput(outf) + log("This is a test log entry") + + MouseMain() +} + +/* +func StartConsoleMouse() { + defer g.Close() + log("start Main()") + + if err := g.MainLoop(); err != nil && !errors.Is(err, gocui.ErrQuit) { + exit(err) + } + log("exit Main()") +} +*/ diff --git a/toolkit/democui/mouse.go b/toolkit/democui/mouse.go index efda307..659adb3 100644 --- a/toolkit/democui/mouse.go +++ b/toolkit/democui/mouse.go @@ -7,49 +7,18 @@ package main import ( "errors" "fmt" - "os" "github.com/awesome-gocui/gocui" ) -var g *gocui.Gui -var err error -var Custom func(string) - -func OnExit(f func(string)) { - Custom = f -} - -func Exit() { - g.Close() -} - -func mouseClick(name string) { - // output screws up the console. Need to fix this by redirecting all console output to a file from log.Println() - // log.Println("g.Close()") - // g.Close() - - log("Found andlabs Running custom function for the mouse click") - Custom(name) - // panic("got andlabs") -} - -func Init() { - log("start Init()") - - f, err := os.OpenFile("/tmp/guilogfile", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666) +func MouseMain() { + g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { - exit("error opening file: %v", err) + panic(err) } - defer f.Close() + defer g.Close() - setOutput(f) - log("This is a test log entry") - - g, err = gocui.NewGui(gocui.OutputNormal, true) - if err != nil { - exit(err) - } + baseGui = g g.Cursor = true g.Mouse = true @@ -57,35 +26,35 @@ func Init() { g.SetManagerFunc(layout) if err := keybindings(g); err != nil { - exit(err) + panic(err) } - log("exit Init()") -} - -func StartConsoleMouse() { - defer g.Close() - log("start Main()") if err := g.MainLoop(); err != nil && !errors.Is(err, gocui.ErrQuit) { - exit(err) + panic(err) } - log("exit Main()") } func layout(g *gocui.Gui) error { - if v, err := g.SetView("but1", 2, 2, 22, 17, 0); err != nil { + maxX, maxY := g.Size() + if _, err := g.View("msg"); msgMouseDown && err == nil { + moveMsg(g) + } + if v, err := g.SetView("global", -1, -1, maxX, maxY, 0); err != nil { + if !errors.Is(err, gocui.ErrUnknownView) { + return err + } + v.Frame = false + } + if v, err := g.SetView("but1", 2, 2, 22, 7, 0); err != nil { if !errors.Is(err, gocui.ErrUnknownView) { return err } - v.Highlight = true v.SelBgColor = gocui.ColorGreen v.SelFgColor = gocui.ColorBlack - fmt.Fprintln(v, "andlabs") - fmt.Fprintln(v, "addDemoTab") - fmt.Fprintln(v, "DemoToolkitWindow") - fmt.Fprintln(v, "DebugWindow") - fmt.Fprintln(v, "do nothing") - fmt.Fprintln(v, "exit") + fmt.Fprintln(v, "Button 1 - line 1") + fmt.Fprintln(v, "Button 1 - line 2") + fmt.Fprintln(v, "Button 1 - line 3") + fmt.Fprintln(v, "Button 1 - line 4") if _, err := g.SetCurrentView("but1"); err != nil { return err } @@ -94,38 +63,12 @@ func layout(g *gocui.Gui) error { if !errors.Is(err, gocui.ErrUnknownView) { return err } - v.Highlight = true - v.SelBgColor = gocui.ColorGreen - v.SelFgColor = gocui.ColorBlack - fmt.Fprintln(v, "Button 2 - line 1") - } - if v, err := g.SetView("but3", 24, 2, 44, 4, 0); err != nil { - if !errors.Is(err, gocui.ErrUnknownView) { - return err - } - v.Highlight = true - v.SelBgColor = gocui.ColorGreen - v.SelFgColor = gocui.ColorBlack - fmt.Fprintln(v, "Button 2 - line 1") - } - if v, err := g.SetView("but4", 24, 2, 44, 4, 0); err != nil { - if !errors.Is(err, gocui.ErrUnknownView) { - return err - } - v.Highlight = true - v.SelBgColor = gocui.ColorGreen - v.SelFgColor = gocui.ColorBlack - fmt.Fprintln(v, "Button 2 - line 1") - } - if v, err := g.SetView("but5", 24, 2, 44, 4, 0); err != nil { - if !errors.Is(err, gocui.ErrUnknownView) { - return err - } - v.Highlight = true v.SelBgColor = gocui.ColorGreen v.SelFgColor = gocui.ColorBlack fmt.Fprintln(v, "Button 2 - line 1") } + helplayout(g) + updateHighlightedView(g) return nil } @@ -138,13 +81,13 @@ func keybindings(g *gocui.Gui) error { return err } } - if err := g.SetKeybinding("msg", gocui.MouseLeft, gocui.ModNone, delMsg); err != nil { + if err := g.SetKeybinding("", gocui.MouseRelease, gocui.ModNone, mouseUp); err != nil { return err } - if err := g.SetKeybinding("", gocui.MouseRight, gocui.ModNone, delMsg); err != nil { + if err := g.SetKeybinding("", gocui.MouseLeft, gocui.ModNone, globalDown); err != nil { return err } - if err := g.SetKeybinding("", gocui.MouseMiddle, gocui.ModNone, delMsg); err != nil { + if err := g.SetKeybinding("msg", gocui.MouseLeft, gocui.ModNone, msgDown); err != nil { return err } return nil @@ -168,18 +111,80 @@ func showMsg(g *gocui.Gui, v *gocui.View) error { } maxX, maxY := g.Size() - if v, err := g.SetView("msg", maxX/2-10, maxY/2, maxX/2+10, maxY/2+2, 0); err != nil { - if !errors.Is(err, gocui.ErrUnknownView) { - return err - } - mouseClick(l) + if v, err := g.SetView("msg", maxX/2-10, maxY/2, maxX/2+10, maxY/2+2, 0); err == nil || errors.Is(err, gocui.ErrUnknownView) { + v.Clear() + v.SelBgColor = gocui.ColorCyan + v.SelFgColor = gocui.ColorBlack fmt.Fprintln(v, l) } return nil } -func delMsg(g *gocui.Gui, v *gocui.View) error { - // Error check removed, because delete could be called multiple times with the above keybindings - g.DeleteView("msg") +func updateHighlightedView(g *gocui.Gui) { + mx, my := g.MousePosition() + for _, view := range g.Views() { + view.Highlight = false + } + if v, err := g.ViewByPosition(mx, my); err == nil { + v.Highlight = true + } +} + +func moveMsg(g *gocui.Gui) { + mx, my := g.MousePosition() + if !movingMsg && (mx != initialMouseX || my != initialMouseY) { + movingMsg = true + } + g.SetView("msg", mx-xOffset, my-yOffset, mx-xOffset+20, my-yOffset+2, 0) +} + +func msgDown(g *gocui.Gui, v *gocui.View) error { + initialMouseX, initialMouseY = g.MousePosition() + if vx, vy, _, _, err := g.ViewPosition("msg"); err == nil { + xOffset = initialMouseX - vx + yOffset = initialMouseY - vy + msgMouseDown = true + } + return nil +} + +func globalDown(g *gocui.Gui, v *gocui.View) error { + mx, my := g.MousePosition() + if vx0, vy0, vx1, vy1, err := g.ViewPosition("msg"); err == nil { + if mx >= vx0 && mx <= vx1 && my >= vy0 && my <= vy1 { + return msgDown(g, v) + } + } + globalMouseDown = true + maxX, _ := g.Size() + msg := fmt.Sprintf("Mouse down at: %d,%d", mx, my) + x := mx - len(msg)/2 + if x < 0 { + x = 0 + } else if x+len(msg)+1 > maxX-1 { + x = maxX - 1 - len(msg) - 1 + } + if v, err := g.SetView("globalDown", x, my-1, x+len(msg)+1, my+1, 0); err != nil { + if !errors.Is(err, gocui.ErrUnknownView) { + return err + } + v.WriteString(msg) + } + return nil +} + +func mouseUp(g *gocui.Gui, v *gocui.View) error { + if msgMouseDown { + msgMouseDown = false + if movingMsg { + movingMsg = false + return nil + } else { + g.DeleteView("msg") + } + } else if globalMouseDown { + globalMouseDown = false + g.DeleteView("globalDown") + } return nil } diff --git a/toolkit/democui/plugin.go b/toolkit/democui/plugin.go index 2c0d42e..50d84a2 100644 --- a/toolkit/democui/plugin.go +++ b/toolkit/democui/plugin.go @@ -113,3 +113,19 @@ func Send(p *toolkit.Widget, c *toolkit.Widget) { log(debugError, "plugin Send() Don't know how to do", c.Type, "yet") } } + +func Action(a *toolkit.Action) { + log(logNow, "Action() START a.Type =", a.Type) + log(logNow, "Action() START a.S =", a.S) + log(logNow, "Action() START a.Widget =", a.Widget) + + log(logNow, "Action() START a.WidgetId =", a.WidgetId, "a.WhereId =", a.WhereId) + + switch a.Type { + case toolkit.Add: + log(logError, "Action() do add here() =", a.Type, a.Widget) + default: + log(logError, "Action() Unknown =", a.Type, a.Widget) + } + log(logNow, "Action() END =", a.Type, a.Widget) +} diff --git a/toolkit/democui/structs.go b/toolkit/democui/structs.go new file mode 100644 index 0000000..a73b9e7 --- /dev/null +++ b/toolkit/democui/structs.go @@ -0,0 +1,32 @@ +// 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 ( + "os" + "github.com/awesome-gocui/gocui" +) + +const delta = 1 + +var ( + g *gocui.Gui + Custom func(string) + + initialMouseX, initialMouseY, xOffset, yOffset int + globalMouseDown, msgMouseDown, movingMsg bool + + views = []string{} + curView = -1 + idxView = 0 + currentX = 5 + currentY = 2 + groupSize = 0 + baseGui *gocui.Gui + helpLabel *gocui.View + err error + ch chan(func ()) + outf *os.File +)