diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index a29431f..d1bf6cf 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -30,7 +30,4 @@ jobs: - name: Build run: | cd _examples/ - for file in *.go - do - go build $file - done + go build . diff --git a/_examples/README.md b/_examples/README.md new file mode 100644 index 0000000..b707417 --- /dev/null +++ b/_examples/README.md @@ -0,0 +1,47 @@ +## Examples + +Each of the samples in `_examples` demonstrates a specific aspect of the API. + +Each can be run be alone or selected from the 'main' example. + +### Build & run + +``` +gocui $ cd _examples/ + +_examples $ go run . --help +usage: +go run . : select a demo from the gui and run it +go run . : run the 'demo' argument + + where 'demo' can be one of: + active + bufs + colors + colors-256 + colors-true + custom-frames + demo + dynamic + flow-layout + goroutine + hello + keybinds + layout + mask + mouse + on-top + overlap + size + stdin + table + title + widgets + wrap + +``` + +### Select a demo through the gui + +Demo Screen + diff --git a/_examples/active.go b/_examples/active.go index 2c5ac9f..e322dce 100644 --- a/_examples/active.go +++ b/_examples/active.go @@ -12,21 +12,21 @@ import ( "github.com/awesome-gocui/gocui" ) -var ( - viewArr = []string{"v1", "v2", "v3", "v4"} - active = 0 -) +type demoActive struct { + viewArr []string + active int +} -func setCurrentViewOnTop(g *gocui.Gui, name string) (*gocui.View, error) { +func (d *demoActive) setCurrentViewOnTop(g *gocui.Gui, name string) (*gocui.View, error) { if _, err := g.SetCurrentView(name); err != nil { return nil, err } return g.SetViewOnTop(name) } -func nextView(g *gocui.Gui, v *gocui.View) error { - nextIndex := (active + 1) % len(viewArr) - name := viewArr[nextIndex] +func (d *demoActive) nextView(g *gocui.Gui, v *gocui.View) error { + nextIndex := (d.active + 1) % len(d.viewArr) + name := d.viewArr[nextIndex] out, err := g.View("v2") if err != nil { @@ -34,7 +34,7 @@ func nextView(g *gocui.Gui, v *gocui.View) error { } fmt.Fprintln(out, "Going from view "+v.Name()+" to "+name) - if _, err := setCurrentViewOnTop(g, name); err != nil { + if _, err := d.setCurrentViewOnTop(g, name); err != nil { return err } @@ -44,11 +44,11 @@ func nextView(g *gocui.Gui, v *gocui.View) error { g.Cursor = false } - active = nextIndex + d.active = nextIndex return nil } -func layout(g *gocui.Gui) error { +func (d *demoActive) layout(g *gocui.Gui) error { maxX, maxY := g.Size() if v, err := g.SetView("v1", 0, 0, maxX/2-1, maxY/2-1, 0); err != nil { if !errors.Is(err, gocui.ErrUnknownView) { @@ -58,7 +58,7 @@ func layout(g *gocui.Gui) error { v.Editable = true v.Wrap = true - if _, err = setCurrentViewOnTop(g, "v1"); err != nil { + if _, err = d.setCurrentViewOnTop(g, "v1"); err != nil { return err } } @@ -90,11 +90,15 @@ func layout(g *gocui.Gui) error { return nil } -func quit(g *gocui.Gui, v *gocui.View) error { +func (d *demoActive) quit(*gocui.Gui, *gocui.View) error { return gocui.ErrQuit } -func main() { +func mainActive() { + d := &demoActive{ + viewArr: []string{"v1", "v2", "v3", "v4"}, + active: 0, + } g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { log.Panicln(err) @@ -105,12 +109,12 @@ func main() { g.Cursor = true g.SelFgColor = gocui.ColorGreen - g.SetManagerFunc(layout) + g.SetManagerFunc(d.layout) - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, d.quit); err != nil { log.Panicln(err) } - if err := g.SetKeybinding("", gocui.KeyTab, gocui.ModNone, nextView); err != nil { + if err := g.SetKeybinding("", gocui.KeyTab, gocui.ModNone, d.nextView); err != nil { log.Panicln(err) } diff --git a/_examples/bufs.go b/_examples/bufs.go index 2ccb93c..5b0d420 100644 --- a/_examples/bufs.go +++ b/_examples/bufs.go @@ -14,20 +14,22 @@ import ( "github.com/awesome-gocui/gocui" ) -var vbuf, buf string +type demoBufs struct { + vbuf, buf string +} -func quit(g *gocui.Gui, v *gocui.View) error { - vbuf = v.ViewBuffer() - buf = v.Buffer() +func (d *demoBufs) quit(_ *gocui.Gui, v *gocui.View) error { + d.vbuf = v.ViewBuffer() + d.buf = v.Buffer() return gocui.ErrQuit } -func overwrite(g *gocui.Gui, v *gocui.View) error { +func (d *demoBufs) overwrite(g *gocui.Gui, v *gocui.View) error { v.Overwrite = !v.Overwrite return nil } -func layout(g *gocui.Gui) error { +func (d *demoBufs) layout(g *gocui.Gui) error { _, maxY := g.Size() if v, err := g.SetView("main", 0, 0, 20, maxY-1, 0); err != nil { if !errors.Is(err, gocui.ErrUnknownView) { @@ -42,21 +44,23 @@ func layout(g *gocui.Gui) error { return nil } -func main() { +func mainBufs() { g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { log.Panicln(err) } + d := &demoBufs{} + g.Cursor = true g.Mouse = true - g.SetManagerFunc(layout) + g.SetManagerFunc(d.layout) - if err := g.SetKeybinding("main", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { + if err := g.SetKeybinding("main", gocui.KeyCtrlC, gocui.ModNone, d.quit); err != nil { log.Panicln(err) } - if err := g.SetKeybinding("main", gocui.KeyCtrlI, gocui.ModNone, overwrite); err != nil { + if err := g.SetKeybinding("main", gocui.KeyCtrlI, gocui.ModNone, d.overwrite); err != nil { log.Panicln(err) } @@ -66,6 +70,6 @@ func main() { g.Close() - fmt.Printf("VBUF:\n%s\n", vbuf) - fmt.Printf("BUF:\n%s\n", buf) + fmt.Printf("VBUF:\n%s\n", d.vbuf) + fmt.Printf("BUF:\n%s\n", d.buf) } diff --git a/_examples/colors.go b/_examples/colors.go index 27f8f8a..25a562d 100644 --- a/_examples/colors.go +++ b/_examples/colors.go @@ -12,16 +12,21 @@ import ( "github.com/awesome-gocui/gocui" ) -func main() { +type demoColors struct { +} + +func mainColors() { g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { log.Panicln(err) } defer g.Close() - g.SetManagerFunc(layout) + d := &demoColors{} + + g.SetManagerFunc(d.layout) - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, d.quit); err != nil { log.Panicln(err) } @@ -30,7 +35,7 @@ func main() { } } -func layout(g *gocui.Gui) error { +func (d *demoColors) layout(g *gocui.Gui) error { maxX, maxY := g.Size() if v, err := g.SetView("colors", maxX/2-7, maxY/2-12, maxX/2+7, maxY/2+13, 0); err != nil { if !errors.Is(err, gocui.ErrUnknownView) { @@ -48,6 +53,6 @@ func layout(g *gocui.Gui) error { return nil } -func quit(g *gocui.Gui, v *gocui.View) error { +func (d *demoColors) quit(*gocui.Gui, *gocui.View) error { return gocui.ErrQuit } diff --git a/_examples/colors256.go b/_examples/colors256.go index 931ac66..188571d 100644 --- a/_examples/colors256.go +++ b/_examples/colors256.go @@ -12,7 +12,9 @@ import ( "github.com/awesome-gocui/gocui" ) -func main() { +type demoColors256 struct{} + +func mainColors256() { g, err := gocui.NewGui(gocui.Output256, true) if err != nil { @@ -20,9 +22,10 @@ func main() { } defer g.Close() - g.SetManagerFunc(layout) + d := demoColors256{} + g.SetManagerFunc(d.layout) - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, d.quit); err != nil { log.Panicln(err) } @@ -31,7 +34,7 @@ func main() { } } -func layout(g *gocui.Gui) error { +func (d *demoColors256) layout(g *gocui.Gui) error { maxX, maxY := g.Size() if v, err := g.SetView("colors", -1, -1, maxX, maxY, 0); err != nil { if !errors.Is(err, gocui.ErrUnknownView) { @@ -73,6 +76,6 @@ func layout(g *gocui.Gui) error { return nil } -func quit(g *gocui.Gui, v *gocui.View) error { +func (d *demoColors256) quit(*gocui.Gui, *gocui.View) error { return gocui.ErrQuit } diff --git a/_examples/colorstrue.go b/_examples/colorstrue.go index 060af91..55e127e 100644 --- a/_examples/colorstrue.go +++ b/_examples/colorstrue.go @@ -14,9 +14,11 @@ import ( colorful "github.com/lucasb-eyer/go-colorful" ) -var dark = false +type demoColorsTrue struct { + dark bool +} -func main() { +func mainColorsTrue() { os.Setenv("COLORTERM", "truecolor") g, err := gocui.NewGui(gocui.OutputTrue, true) @@ -25,19 +27,20 @@ func main() { } defer g.Close() - g.SetManagerFunc(layout) + d := &demoColorsTrue{dark: false} + g.SetManagerFunc(d.layout) - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, d.quit); err != nil { log.Panicln(err) } if err := g.SetKeybinding("", gocui.KeyCtrlR, gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { - if dark { - dark = false + if d.dark { + d.dark = false } else { - dark = true + d.dark = true } - displayHsv(v) + d.displayHsv(v) return nil }); err != nil { @@ -49,7 +52,7 @@ func main() { } } -func layout(g *gocui.Gui) error { +func (d *demoColorsTrue) layout(g *gocui.Gui) error { maxX, maxY := g.Size() rows := 33 cols := 182 @@ -66,7 +69,7 @@ func layout(g *gocui.Gui) error { } v.FrameColor = gocui.GetColor("#FFAA55") - displayHsv(v) + d.displayHsv(v) if _, err := g.SetCurrentView("colors"); err != nil { return err @@ -75,15 +78,15 @@ func layout(g *gocui.Gui) error { return nil } -func displayHsv(v *gocui.View) { +func (d *demoColorsTrue) displayHsv(v *gocui.View) { v.Clear() str := "" // HSV color space (lines are value or saturation) for i := 50; i > 0; i -= 2 { // Hue for j := 0; j < 360; j += 2 { - ir, ig, ib := hsv(j, i-1) - ir2, ig2, ib2 := hsv(j, i) + ir, ig, ib := d.hsv(j, i-1) + ir2, ig2, ib2 := d.hsv(j, i) str += fmt.Sprintf("\x1b[48;2;%d;%d;%dm\x1b[38;2;%d;%d;%dmâ–€\x1b[0m", ir, ig, ib, ir2, ig2, ib2) } str += "\n" @@ -96,8 +99,8 @@ func displayHsv(v *gocui.View) { fmt.Fprint(v, "Example should enable true color, but if it doesn't work run this command: \x1b[0mexport COLORTERM=truecolor") } -func hsv(hue, sv int) (uint32, uint32, uint32) { - if !dark { +func (d *demoColorsTrue) hsv(hue, sv int) (uint32, uint32, uint32) { + if !d.dark { ir, ig, ib, _ := colorful.Hsv(float64(hue), float64(sv)/50, float64(1)).RGBA() return ir >> 8, ig >> 8, ib >> 8 } @@ -105,6 +108,6 @@ func hsv(hue, sv int) (uint32, uint32, uint32) { return ir >> 8, ig >> 8, ib >> 8 } -func quit(g *gocui.Gui, v *gocui.View) error { +func (d *demoColorsTrue) quit(*gocui.Gui, *gocui.View) error { return gocui.ErrQuit } diff --git a/_examples/custom_frame.go b/_examples/custom_frame.go index af34d99..c972f43 100644 --- a/_examples/custom_frame.go +++ b/_examples/custom_frame.go @@ -8,21 +8,21 @@ import ( "github.com/awesome-gocui/gocui" ) -var ( - viewArr = []string{"v1", "v2", "v3", "v4"} - active = 0 -) +type demoCustomFrames struct { + viewArr []string + active int +} -func setCurrentViewOnTop(g *gocui.Gui, name string) (*gocui.View, error) { +func (d *demoCustomFrames) setCurrentViewOnTop(g *gocui.Gui, name string) (*gocui.View, error) { if _, err := g.SetCurrentView(name); err != nil { return nil, err } return g.SetViewOnTop(name) } -func nextView(g *gocui.Gui, v *gocui.View) error { - nextIndex := (active + 1) % len(viewArr) - name := viewArr[nextIndex] +func (d *demoCustomFrames) nextView(g *gocui.Gui, v *gocui.View) error { + nextIndex := (d.active + 1) % len(d.viewArr) + name := d.viewArr[nextIndex] out, err := g.View("v1") if err != nil { @@ -30,7 +30,7 @@ func nextView(g *gocui.Gui, v *gocui.View) error { } fmt.Fprintln(out, "Going from view "+v.Name()+" to "+name) - if _, err := setCurrentViewOnTop(g, name); err != nil { + if _, err := d.setCurrentViewOnTop(g, name); err != nil { return err } @@ -40,11 +40,11 @@ func nextView(g *gocui.Gui, v *gocui.View) error { g.Cursor = false } - active = nextIndex + d.active = nextIndex return nil } -func layout(g *gocui.Gui) error { +func (d *demoCustomFrames) layout(g *gocui.Gui) error { maxX, maxY := g.Size() if v, err := g.SetView("v1", 0, 0, maxX/2-1, maxY/2-1, gocui.RIGHT); err != nil { if !errors.Is(err, gocui.ErrUnknownView) { @@ -54,7 +54,7 @@ func layout(g *gocui.Gui) error { v.Autoscroll = true fmt.Fprintln(v, "View with default frame color") fmt.Fprintln(v, "It's connected to v2 with overlay RIGHT.\n") - if _, err = setCurrentViewOnTop(g, "v1"); err != nil { + if _, err = d.setCurrentViewOnTop(g, "v1"); err != nil { return err } } @@ -104,16 +104,16 @@ func layout(g *gocui.Gui) error { return nil } -func quit(g *gocui.Gui, v *gocui.View) error { +func (d *demoCustomFrames) quit(*gocui.Gui, *gocui.View) error { return gocui.ErrQuit } -func toggleOverlap(g *gocui.Gui, v *gocui.View) error { +func (d *demoCustomFrames) toggleOverlap(g *gocui.Gui, v *gocui.View) error { g.SupportOverlaps = !g.SupportOverlaps return nil } -func main() { +func mainCustomFrames() { g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { log.Panicln(err) @@ -124,15 +124,19 @@ func main() { g.SelFgColor = gocui.ColorGreen g.SelFrameColor = gocui.ColorGreen - g.SetManagerFunc(layout) + d := &demoCustomFrames{ + viewArr: []string{"v1", "v2", "v3", "v4"}, + active: 0, + } + g.SetManagerFunc(d.layout) - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, d.quit); err != nil { log.Panicln(err) } - if err := g.SetKeybinding("", gocui.KeyCtrlO, gocui.ModNone, toggleOverlap); err != nil { + if err := g.SetKeybinding("", gocui.KeyCtrlO, gocui.ModNone, d.toggleOverlap); err != nil { log.Panicln(err) } - if err := g.SetKeybinding("", gocui.KeyTab, gocui.ModNone, nextView); err != nil { + if err := g.SetKeybinding("", gocui.KeyTab, gocui.ModNone, d.nextView); err != nil { log.Panicln(err) } diff --git a/_examples/demo.go b/_examples/demo.go index d88fe6c..f12b1c6 100644 --- a/_examples/demo.go +++ b/_examples/demo.go @@ -15,7 +15,9 @@ import ( "github.com/awesome-gocui/gocui" ) -func nextView(g *gocui.Gui, v *gocui.View) error { +type demo struct{} + +func (d *demo) nextView(g *gocui.Gui, v *gocui.View) error { if v == nil || v.Name() == "side" { _, err := g.SetCurrentView("main") return err @@ -24,7 +26,7 @@ func nextView(g *gocui.Gui, v *gocui.View) error { return err } -func cursorDown(g *gocui.Gui, v *gocui.View) error { +func (d *demo) cursorDown(g *gocui.Gui, v *gocui.View) error { if v != nil { cx, cy := v.Cursor() if err := v.SetCursor(cx, cy+1); err != nil { @@ -37,7 +39,7 @@ func cursorDown(g *gocui.Gui, v *gocui.View) error { return nil } -func cursorUp(g *gocui.Gui, v *gocui.View) error { +func (d *demo) cursorUp(g *gocui.Gui, v *gocui.View) error { if v != nil { ox, oy := v.Origin() cx, cy := v.Cursor() @@ -50,7 +52,7 @@ func cursorUp(g *gocui.Gui, v *gocui.View) error { return nil } -func getLine(g *gocui.Gui, v *gocui.View) error { +func (d *demo) getLine(g *gocui.Gui, v *gocui.View) error { var l string var err error @@ -72,7 +74,7 @@ func getLine(g *gocui.Gui, v *gocui.View) error { return nil } -func delMsg(g *gocui.Gui, v *gocui.View) error { +func (d *demo) delMsg(g *gocui.Gui, v *gocui.View) error { if err := g.DeleteView("msg"); err != nil { return err } @@ -82,43 +84,43 @@ func delMsg(g *gocui.Gui, v *gocui.View) error { return nil } -func quit(g *gocui.Gui, v *gocui.View) error { +func (d *demo) quit(*gocui.Gui, *gocui.View) error { return gocui.ErrQuit } -func keybindings(g *gocui.Gui) error { - if err := g.SetKeybinding("side", gocui.KeyCtrlSpace, gocui.ModNone, nextView); err != nil { +func (d *demo) keybindings(g *gocui.Gui) error { + if err := g.SetKeybinding("side", gocui.KeyCtrlSpace, gocui.ModNone, d.nextView); err != nil { return err } - if err := g.SetKeybinding("main", gocui.KeyCtrlSpace, gocui.ModNone, nextView); err != nil { + if err := g.SetKeybinding("main", gocui.KeyCtrlSpace, gocui.ModNone, d.nextView); err != nil { return err } - if err := g.SetKeybinding("side", gocui.KeyArrowDown, gocui.ModNone, cursorDown); err != nil { + if err := g.SetKeybinding("side", gocui.KeyArrowDown, gocui.ModNone, d.cursorDown); err != nil { return err } - if err := g.SetKeybinding("side", gocui.KeyArrowUp, gocui.ModNone, cursorUp); err != nil { + if err := g.SetKeybinding("side", gocui.KeyArrowUp, gocui.ModNone, d.cursorUp); err != nil { return err } - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, d.quit); err != nil { return err } - if err := g.SetKeybinding("side", gocui.KeyEnter, gocui.ModNone, getLine); err != nil { + if err := g.SetKeybinding("side", gocui.KeyEnter, gocui.ModNone, d.getLine); err != nil { return err } - if err := g.SetKeybinding("msg", gocui.KeyEnter, gocui.ModNone, delMsg); err != nil { + if err := g.SetKeybinding("msg", gocui.KeyEnter, gocui.ModNone, d.delMsg); err != nil { return err } - if err := g.SetKeybinding("main", gocui.KeyCtrlS, gocui.ModNone, saveMain); err != nil { + if err := g.SetKeybinding("main", gocui.KeyCtrlS, gocui.ModNone, d.saveMain); err != nil { return err } - if err := g.SetKeybinding("main", gocui.KeyCtrlW, gocui.ModNone, saveVisualMain); err != nil { + if err := g.SetKeybinding("main", gocui.KeyCtrlW, gocui.ModNone, d.saveVisualMain); err != nil { return err } return nil } -func saveMain(g *gocui.Gui, v *gocui.View) error { +func (d *demo) saveMain(g *gocui.Gui, v *gocui.View) error { f, err := ioutil.TempFile("", "gocui_demo_") if err != nil { return err @@ -144,7 +146,7 @@ func saveMain(g *gocui.Gui, v *gocui.View) error { return nil } -func saveVisualMain(g *gocui.Gui, v *gocui.View) error { +func (d *demo) saveVisualMain(g *gocui.Gui, v *gocui.View) error { f, err := ioutil.TempFile("", "gocui_demo_") if err != nil { return err @@ -158,7 +160,7 @@ func saveVisualMain(g *gocui.Gui, v *gocui.View) error { return nil } -func layout(g *gocui.Gui) error { +func (d *demo) layout(g *gocui.Gui) error { maxX, maxY := g.Size() if v, err := g.SetView("side", -1, -1, 30, maxY, 0); err != nil { if !errors.Is(err, gocui.ErrUnknownView) { @@ -191,18 +193,18 @@ func layout(g *gocui.Gui) error { return nil } -func main() { +func mainDemo() { g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { log.Panicln(err) } defer g.Close() - g.Cursor = true - g.SetManagerFunc(layout) + d := &demo{} + g.SetManagerFunc(d.layout) - if err := keybindings(g); err != nil { + if err := d.keybindings(g); err != nil { log.Panicln(err) } diff --git a/_examples/demo_screen.png b/_examples/demo_screen.png new file mode 100644 index 0000000..81baee6 Binary files /dev/null and b/_examples/demo_screen.png differ diff --git a/_examples/dynamic.go b/_examples/dynamic.go index 01e6a1a..3ef6e6d 100644 --- a/_examples/dynamic.go +++ b/_examples/dynamic.go @@ -13,15 +13,14 @@ import ( "github.com/awesome-gocui/gocui" ) -const delta = 1 - -var ( - views = []string{} - curView = -1 - idxView = 0 -) +type demoDynamic struct { + views []string + curView int + idxView int + delta int +} -func main() { +func mainDynamic() { g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { log.Panicln(err) @@ -32,12 +31,18 @@ func main() { g.SelFgColor = gocui.ColorRed g.SelFrameColor = gocui.ColorRed - g.SetManagerFunc(layout) + d := &demoDynamic{ + views: []string{}, + curView: -1, + idxView: 0, + delta: 1, + } + g.SetManagerFunc(d.layout) - if err := initKeybindings(g); err != nil { + if err := d.initKeybindings(g); err != nil { log.Panicln(err) } - if err := newView(g); err != nil { + if err := d.newView(g); err != nil { log.Panicln(err) } @@ -46,7 +51,7 @@ func main() { } } -func layout(g *gocui.Gui) error { +func (d *demoDynamic) layout(g *gocui.Gui) error { maxX, _ := g.Size() v, err := g.SetView("help", maxX-25, 0, maxX-1, 9, 0) if err != nil { @@ -65,7 +70,7 @@ func layout(g *gocui.Gui) error { return nil } -func initKeybindings(g *gocui.Gui) error { +func (d *demoDynamic) initKeybindings(g *gocui.Gui) error { if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { return gocui.ErrQuit @@ -74,62 +79,62 @@ func initKeybindings(g *gocui.Gui) error { } if err := g.SetKeybinding("", gocui.KeySpace, gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { - return newView(g) + return d.newView(g) }); err != nil { return err } if err := g.SetKeybinding("", gocui.KeyBackspace, gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { - return delView(g) + return d.delView(g) }); err != nil { return err } if err := g.SetKeybinding("", gocui.KeyBackspace2, gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { - return delView(g) + return d.delView(g) }); err != nil { return err } if err := g.SetKeybinding("", gocui.KeyTab, gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { - return nextView(g, true) + return d.nextView(g, true) }); err != nil { return err } if err := g.SetKeybinding("", gocui.KeyArrowLeft, gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { - return moveView(g, v, -delta, 0) + return d.moveView(g, v, -d.delta, 0) }); err != nil { return err } if err := g.SetKeybinding("", gocui.KeyArrowRight, gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { - return moveView(g, v, delta, 0) + return d.moveView(g, v, d.delta, 0) }); err != nil { return err } if err := g.SetKeybinding("", gocui.KeyArrowDown, gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { - return moveView(g, v, 0, delta) + return d.moveView(g, v, 0, d.delta) }); err != nil { return err } if err := g.SetKeybinding("", gocui.KeyArrowUp, gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { - return moveView(g, v, 0, -delta) + return d.moveView(g, v, 0, -d.delta) }); err != nil { return err } if err := g.SetKeybinding("", 't', gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { - _, err := g.SetViewOnTop(views[curView]) + _, err := g.SetViewOnTop(d.views[d.curView]) return err }); err != nil { return err } if err := g.SetKeybinding("", 'b', gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { - _, err := g.SetViewOnBottom(views[curView]) + _, err := g.SetViewOnBottom(d.views[d.curView]) return err }); err != nil { return err @@ -137,9 +142,9 @@ func initKeybindings(g *gocui.Gui) error { return nil } -func newView(g *gocui.Gui) error { +func (d *demoDynamic) newView(g *gocui.Gui) error { maxX, maxY := g.Size() - name := fmt.Sprintf("v%v", idxView) + name := fmt.Sprintf("v%v", d.idxView) v, err := g.SetView(name, maxX/2-5, maxY/2-5, maxX/2+5, maxY/2+5, 0) if err != nil { if !errors.Is(err, gocui.ErrUnknownView) { @@ -152,40 +157,40 @@ func newView(g *gocui.Gui) error { return err } - views = append(views, name) - curView = len(views) - 1 - idxView += 1 + d.views = append(d.views, name) + d.curView = len(d.views) - 1 + d.idxView += 1 return nil } -func delView(g *gocui.Gui) error { - if len(views) <= 1 { +func (d *demoDynamic) delView(g *gocui.Gui) error { + if len(d.views) <= 1 { return nil } - if err := g.DeleteView(views[curView]); err != nil { + if err := g.DeleteView(d.views[d.curView]); err != nil { return err } - views = append(views[:curView], views[curView+1:]...) + d.views = append(d.views[:d.curView], d.views[d.curView+1:]...) - return nextView(g, false) + return d.nextView(g, false) } -func nextView(g *gocui.Gui, disableCurrent bool) error { - next := curView + 1 - if next > len(views)-1 { +func (d *demoDynamic) nextView(g *gocui.Gui, disableCurrent bool) error { + next := d.curView + 1 + if next > len(d.views)-1 { next = 0 } - if _, err := g.SetCurrentView(views[next]); err != nil { + if _, err := g.SetCurrentView(d.views[next]); err != nil { return err } - curView = next + d.curView = next return nil } -func moveView(g *gocui.Gui, v *gocui.View, dx, dy int) error { +func (d *demoDynamic) moveView(g *gocui.Gui, v *gocui.View, dx, dy int) error { name := v.Name() x0, y0, x1, y1, err := g.ViewPosition(name) if err != nil { diff --git a/_examples/flow_layout.go b/_examples/flow_layout.go index 9795c5b..948bfd0 100644 --- a/_examples/flow_layout.go +++ b/_examples/flow_layout.go @@ -13,6 +13,8 @@ import ( "github.com/awesome-gocui/gocui" ) +type demoFlowLayout struct{} + type Label struct { name string w, h int @@ -48,7 +50,7 @@ func (w *Label) Layout(g *gocui.Gui) error { return nil } -func flowLayout(g *gocui.Gui) error { +func (d *demoFlowLayout) flowLayout(g *gocui.Gui) error { views := g.Views() x := 0 for _, v := range views { @@ -62,22 +64,24 @@ func flowLayout(g *gocui.Gui) error { return nil } -func main() { +func mainFlowLayout() { g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { log.Panicln(err) } defer g.Close() + d := &demoFlowLayout{} + l1 := NewLabel("l1", "This") l2 := NewLabel("l2", "is") l3 := NewLabel("l3", "a") l4 := NewLabel("l4", "flow\nlayout") l5 := NewLabel("l5", "!") - fl := gocui.ManagerFunc(flowLayout) + fl := gocui.ManagerFunc(d.flowLayout) g.SetManager(l1, l2, l3, l4, l5, fl) - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, d.quit); err != nil { log.Panicln(err) } @@ -86,6 +90,6 @@ func main() { } } -func quit(g *gocui.Gui, v *gocui.View) error { +func (d *demoFlowLayout) quit(*gocui.Gui, *gocui.View) error { return gocui.ErrQuit } diff --git a/_examples/goroutine.go b/_examples/goroutine.go index ae37891..3e3327d 100644 --- a/_examples/goroutine.go +++ b/_examples/goroutine.go @@ -14,43 +14,47 @@ import ( "github.com/awesome-gocui/gocui" ) -const NumGoroutines = 20 - -var ( - done = make(chan struct{}) - wg sync.WaitGroup - - mu sync.Mutex // protects ctr - ctr = 0 -) +type demoGoRoutine struct { + numGoroutines int + done chan struct{} + wg sync.WaitGroup + mu sync.Mutex // protects ctr + ctr int +} -func main() { +func mainGoroutine() { g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { log.Panicln(err) } defer g.Close() - g.SetManagerFunc(layout) + d := &demoGoRoutine{ + numGoroutines: 20, + done: make(chan struct{}), + ctr: 0, + } + + g.SetManagerFunc(d.layout) - if err := keybindings(g); err != nil { + if err := d.keybindings(g); err != nil { log.Panicln(err) } - for i := 0; i < NumGoroutines; i++ { - wg.Add(1) - go counter(g) + for i := 0; i < d.numGoroutines; i++ { + d.wg.Add(1) + go d.counter(g) } if err := g.MainLoop(); err != nil && !errors.Is(err, gocui.ErrQuit) { log.Panicln(err) } - wg.Wait() + d.wg.Wait() } -func layout(g *gocui.Gui) error { - if v, err := g.SetView("ctr", 2, 2, 22, 2+NumGoroutines+1, 0); err != nil { +func (d *demoGoRoutine) layout(g *gocui.Gui) error { + if v, err := g.SetView("ctr", 2, 2, 22, 2+d.numGoroutines+1, 0); err != nil { if !errors.Is(err, gocui.ErrUnknownView) { return err } @@ -62,30 +66,30 @@ func layout(g *gocui.Gui) error { return nil } -func keybindings(g *gocui.Gui) error { - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { +func (d *demoGoRoutine) keybindings(g *gocui.Gui) error { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, d.quit); err != nil { return err } return nil } -func quit(g *gocui.Gui, v *gocui.View) error { - close(done) +func (d *demoGoRoutine) quit(*gocui.Gui, *gocui.View) error { + close(d.done) return gocui.ErrQuit } -func counter(g *gocui.Gui) { - defer wg.Done() +func (d *demoGoRoutine) counter(g *gocui.Gui) { + defer d.wg.Done() for { select { - case <-done: + case <-d.done: return case <-time.After(500 * time.Millisecond): - mu.Lock() - n := ctr - ctr++ - mu.Unlock() + d.mu.Lock() + n := d.ctr + d.ctr++ + d.mu.Unlock() g.Update(func(g *gocui.Gui) error { v, err := g.View("ctr") @@ -94,11 +98,11 @@ func counter(g *gocui.Gui) { } // use ctr to make it more chaotic // "pseudo-randomly" print in one of two columns (x = 0, and x = 10) - x := (ctr / NumGoroutines) & 1 + x := (d.ctr / d.numGoroutines) & 1 if x != 0 { x = 10 } - y := ctr % NumGoroutines + y := d.ctr % d.numGoroutines v.SetWritePos(x, y) fmt.Fprintln(v, n) return nil diff --git a/_examples/hello.go b/_examples/hello.go index d485196..c68002b 100644 --- a/_examples/hello.go +++ b/_examples/hello.go @@ -12,16 +12,21 @@ import ( "github.com/awesome-gocui/gocui" ) -func main() { +type demoHello struct { +} + +func mainHello() { + g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { log.Panicln(err) } defer g.Close() - g.SetManagerFunc(layout) + d := &demoHello{} + g.SetManagerFunc(d.layout) - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, d.quit); err != nil { log.Panicln(err) } @@ -30,7 +35,7 @@ func main() { } } -func layout(g *gocui.Gui) error { +func (d *demoHello) layout(g *gocui.Gui) error { maxX, maxY := g.Size() if v, err := g.SetView("hello", maxX/2-7, maxY/2, maxX/2+7, maxY/2+2, 0); err != nil { if !errors.Is(err, gocui.ErrUnknownView) { @@ -47,6 +52,6 @@ func layout(g *gocui.Gui) error { return nil } -func quit(g *gocui.Gui, v *gocui.View) error { +func (d *demoHello) quit(*gocui.Gui, *gocui.View) error { return gocui.ErrQuit } diff --git a/_examples/keybinds.go b/_examples/keybinds.go index c3de5b6..b65344e 100644 --- a/_examples/keybinds.go +++ b/_examples/keybinds.go @@ -7,8 +7,11 @@ import ( "github.com/awesome-gocui/gocui" ) +type demoKeybinds struct { +} + // layout generates the view -func layout(g *gocui.Gui) error { +func (d *demoKeybinds) layout(g *gocui.Gui) error { maxX, maxY := g.Size() if v, err := g.SetView("hello", maxX/2-7, maxY/2, maxX/2+7, maxY/2+2, 0); err != nil { if !errors.Is(err, gocui.ErrUnknownView) { @@ -26,11 +29,11 @@ func layout(g *gocui.Gui) error { } // quit stops the gui -func quit(_ *gocui.Gui, _ *gocui.View) error { +func (d *demoKeybinds) quit(*gocui.Gui, *gocui.View) error { return gocui.ErrQuit } -func main() { +func mainKeybinds() { // Create a gui g, err := gocui.NewGui(gocui.OutputNormal, false) if err != nil { @@ -38,8 +41,9 @@ func main() { } defer g.Close() + d := &demoKeybinds{} // Add a manager function - g.SetManagerFunc(layout) + g.SetManagerFunc(d.layout) // This will set up the recovery for MustParse defer func() { @@ -50,7 +54,7 @@ func main() { // The MustParse can panic, but only returns 2 values instead of 3 keyForced, modForced := gocui.MustParse("q") - if err := g.SetKeybinding("", keyForced, modForced, quit); err != nil { + if err := g.SetKeybinding("", keyForced, modForced, d.quit); err != nil { log.Panicln(err) } @@ -72,7 +76,7 @@ func main() { log.Panicln(err) } - if err = g.SetKeybinding("", keyNormal, modNormal, quit); err != nil { + if err = g.SetKeybinding("", keyNormal, modNormal, d.quit); err != nil { log.Panicln(err) } diff --git a/_examples/layout.go b/_examples/layout.go index 1fe1805..1b60711 100644 --- a/_examples/layout.go +++ b/_examples/layout.go @@ -11,7 +11,9 @@ import ( "github.com/awesome-gocui/gocui" ) -func layout(g *gocui.Gui) error { +type demoLayout struct{} + +func (d *demoLayout) layout(g *gocui.Gui) error { maxX, maxY := g.Size() if _, err := g.SetView("side", -1, -1, int(0.2*float32(maxX)), maxY-5, 0); err != nil && !errors.Is(err, gocui.ErrUnknownView) { return err @@ -30,20 +32,21 @@ func layout(g *gocui.Gui) error { return nil } -func quit(g *gocui.Gui, v *gocui.View) error { +func (d *demoLayout) quit(*gocui.Gui, *gocui.View) error { return gocui.ErrQuit } -func main() { +func mainLayout() { g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { log.Panicln(err) } defer g.Close() - g.SetManagerFunc(layout) + d := &demoLayout{} + g.SetManagerFunc(d.layout) - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, d.quit); err != nil { log.Panicln(err) } diff --git a/_examples/main.go b/_examples/main.go new file mode 100644 index 0000000..79d4400 --- /dev/null +++ b/_examples/main.go @@ -0,0 +1,279 @@ +package main + +import ( + "errors" + "fmt" + "log" + "os" + "sort" + "strings" + + "github.com/awesome-gocui/gocui" +) + +var demos = map[string]func(){ + "active": mainActive, + "bufs": mainBufs, + "colors": mainColors, + "colors-256": mainColors256, + "colors-true": mainColorsTrue, + "custom-frames": mainCustomFrames, + "demo": mainDemo, + "dynamic": mainDynamic, + "flow-layout": mainFlowLayout, + "goroutine": mainGoroutine, + "hello": mainHello, + "keybinds": mainKeybinds, + "layout": mainLayout, + "mask": mainMask, + "mouse": mainMouse, + "on-top": mainOntop, + "overlap": mainOverlap, + "size": mainSize, + "stdin": mainStdin, + "table": mainTable, + "title": mainTitle, + "widgets": mainWidgets, + "wrap": mainWrap, +} + +func demoNames() []string { + names := make([]string, 0) + for n := range demos { + names = append(names, n) + } + sort.Strings(names) + return names +} + +func usage() string { + sb := strings.Builder{} + sb.WriteString("usage:\n") + sb.WriteString("go run . : select a demo from the gui and run it\n") + sb.WriteString("go run . : run the 'demo' argument\n") + sb.WriteString("\n") + sb.WriteString(" where 'demo' can be one of: \n") + + names := demoNames() + for _, n := range names { + sb.WriteString(" " + n + "\n") + } + return sb.String() +} + +func main() { + demo := "" + if len(os.Args) > 1 { + demo = os.Args[1] + } + if demo == "-h" || demo == "--help" { + fmt.Println(usage()) + os.Exit(1) + } + if len(demo) > 0 { + demoFn := demos[demo] + if demoFn == nil { + fmt.Println("unknown demo...") + fmt.Println(usage()) + os.Exit(1) + } + demoFn() + return + } + doDemo() +} + +type runDemos struct { + g *gocui.Gui + demos []string + selected int +} + +func doDemo() { + g, err := gocui.NewGui(gocui.OutputNormal, true) + if err != nil { + log.Panicln(err) + } + defer g.Close() + + g.Highlight = true + g.Cursor = false + g.SelFgColor = gocui.ColorGreen + + d := &runDemos{ + g: g, + demos: demoNames(), + } + g.SetManagerFunc(d.layout) + + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, + func(*gocui.Gui, *gocui.View) error { + return gocui.ErrQuit + }); err != nil { + log.Panicln(err) + } + if err := g.SetKeybinding("demos", gocui.KeyArrowDown, gocui.ModNone, d.selectNext); err != nil { + log.Panicln(err) + } + if err := g.SetKeybinding("demos", gocui.KeyArrowUp, gocui.ModNone, d.selectPrev); err != nil { + log.Panicln(err) + } + if err := g.SetKeybinding("demos", gocui.KeyEnter, gocui.ModNone, d.runSelectedDemo); err != nil { + log.Panicln(err) + } + + if err := g.MainLoop(); err != nil && !errors.Is(err, gocui.ErrQuit) { + log.Panicln(err) + } + +} + +func (d *runDemos) moveSelected(v *gocui.View, delta int) { + _ = v.SetHighlight(d.selected, false) + d.selected += delta + if d.selected >= len(d.demos) { + d.selected = 0 + } + if d.selected < 0 { + d.selected = len(d.demos) - 1 + } + + x0, y0 := v.Origin() + _, _, _, y1 := v.Dimensions() + lcount := y1 - 1 + + for d.selected < y0+lcount { + y0-- + _ = v.SetOrigin(x0, y0) + _ = v.SetCursor(x0, y0) + } + for d.selected >= y0+lcount { + y0++ + _ = v.SetOrigin(x0, y0) + _ = v.SetCursor(x0, y0) + } + _ = v.SetHighlight(d.selected, true) +} + +func (d *runDemos) selectNext(_ *gocui.Gui, v *gocui.View) error { + d.moveSelected(v, +1) + return nil +} + +func (d *runDemos) selectPrev(_ *gocui.Gui, v *gocui.View) error { + d.moveSelected(v, -1) + return nil +} + +func (d *runDemos) adjustDim(max, minDim, pos, dim int) (p0 int, p1 int) { + p0 = pos + p1 = p0 + dim + for p1 > max { + for p0 > 0 { + p0-- + p1 = p0 + dim + if p1 < max { + return + } + } + for dim > minDim { + dim-- + p1 = p0 + dim + if p1 < max { + return + } + } + p1 = max + } + return +} + +func (d *runDemos) layout(g *gocui.Gui) error { + maxX, maxY := g.Size() + + x0, x1 := d.adjustDim(maxX, 20, 5, 80) + y0 := 0 + y1 := y0 + 4 + + view, err := g.SetView("help", x0, y0, x1, y1, 0) + if err != nil { + if !errors.Is(err, gocui.ErrUnknownView) { + return err + } + view.Wrap = true + _, _ = fmt.Fprintln(view, "Use the arrow keys to select a demo") + _, _ = fmt.Fprintln(view, "Press [Enter] to run the selected demo (Ctrl-C to exit the demo)") + _, _ = fmt.Fprintln(view, "Ctrl-C to exit") + } + + y0, y1 = d.adjustDim(maxY, 5, y1+1, len(d.demos)+1) + view, err = g.SetView("demos", x0, y0, x1, y1, 0) + if err != nil { + if !errors.Is(err, gocui.ErrUnknownView) { + return err + } + //view.Highlight = true + view.SelBgColor = gocui.ColorGreen + view.SelFgColor = gocui.ColorBlack + + for i, demo := range d.demos { + _ = view.SetWritePos(0, i) + view.WriteString(demo) + } + _ = view.SetHighlight(d.selected, true) + _, _ = g.SetCurrentView("demos") + } + return nil +} + +func (d *runDemos) runSelectedDemo(_ *gocui.Gui, _ *gocui.View) error { + name := d.demos[d.selected] + + if name == "stdin" { + lines := []string{ + "This example doesn't work when running `go run . stdin`", + "you are supposed to pipe something to this like: `/bin/ls | go run . stdin`", + "Press 'Esc' to close this view", + } + d.messageBox(d.g, 20, 20, "warning", "stdin", lines, "demos") + return nil + } + demoFn := demos[name] + + gocui.Suspend() + demoFn() + return gocui.Resume() +} + +func (d *runDemos) messageBox(g *gocui.Gui, x0, y0 int, title, viewName string, lines []string, nextView string) { + w := 20 + for _, l := range lines { + if len(l) > w { + w = len(l) + } + } + maxX, maxY := g.Size() + x0, x1 := d.adjustDim(maxX, 20, x0, w+2) + y0, y1 := d.adjustDim(maxY, 5, y0, len(lines)+1) + + view, err := g.SetView(viewName, x0, y0, x1, y1, 0) + if err != nil { + if !errors.Is(err, gocui.ErrUnknownView) { + return + } + + view.Title = title + view.Wrap = true + for _, line := range lines { + _, _ = fmt.Fprintln(view, line) + } + _, _ = g.SetViewOnTop(viewName) + _, _ = g.SetCurrentView(viewName) + _ = g.SetKeybinding(viewName, gocui.KeyEsc, gocui.ModNone, func(*gocui.Gui, *gocui.View) error { + view.Visible = false + _ = g.DeleteView(viewName) + _, _ = g.SetCurrentView(nextView) + return nil + }) + } +} diff --git a/_examples/mask.go b/_examples/mask.go index 5bd83f0..d490d44 100644 --- a/_examples/mask.go +++ b/_examples/mask.go @@ -12,7 +12,9 @@ import ( "github.com/awesome-gocui/gocui" ) -func main() { +type demoMask struct{} + +func mainMask() { g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { log.Fatalln(err) @@ -21,9 +23,10 @@ func main() { g.Cursor = true - g.SetManagerFunc(layout) + d := &demoMask{} + g.SetManagerFunc(d.layout) - if err := initKeybindings(g); err != nil { + if err := d.initKeybindings(g); err != nil { log.Fatalln(err) } @@ -32,7 +35,7 @@ func main() { } } -func layout(g *gocui.Gui) error { +func (d *demoMask) layout(g *gocui.Gui) error { maxX, maxY := g.Size() if v, err := g.SetView("help", maxX-23, 0, maxX-1, 3, 0); err != nil { @@ -58,7 +61,7 @@ func layout(g *gocui.Gui) error { return nil } -func initKeybindings(g *gocui.Gui) error { +func (d *demoMask) initKeybindings(g *gocui.Gui) error { if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { return gocui.ErrQuit diff --git a/_examples/mouse.go b/_examples/mouse.go index 762f8eb..840c55d 100644 --- a/_examples/mouse.go +++ b/_examples/mouse.go @@ -12,7 +12,12 @@ import ( "github.com/awesome-gocui/gocui" ) -func main() { +type demoMouse struct { + initialMouseX, initialMouseY, xOffset, yOffset int + globalMouseDown, msgMouseDown, movingMsg bool +} + +func mainMouse() { g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { log.Panicln(err) @@ -22,9 +27,10 @@ func main() { g.Cursor = false g.Mouse = true - g.SetManagerFunc(layout) + d := demoMouse{} + g.SetManagerFunc(d.layout) - if err := keybindings(g); err != nil { + if err := d.keybindings(g); err != nil { log.Panicln(err) } @@ -33,13 +39,10 @@ func main() { } } -var initialMouseX, initialMouseY, xOffset, yOffset int -var globalMouseDown, msgMouseDown, movingMsg bool - -func layout(g *gocui.Gui) error { +func (d *demoMouse) layout(g *gocui.Gui) error { maxX, maxY := g.Size() - if _, err := g.View("msg"); msgMouseDown && err == nil { - moveMsg(g) + if _, err := g.View("msg"); d.msgMouseDown && err == nil { + d.moveMsg(g) } if v, err := g.SetView("global", -1, -1, maxX, maxY, 0); err != nil { if !errors.Is(err, gocui.ErrUnknownView) { @@ -69,36 +72,36 @@ func layout(g *gocui.Gui) error { v.SelFgColor = gocui.ColorBlack fmt.Fprintln(v, "Button 2 - line 1") } - updateHighlightedView(g) + d.updateHighlightedView(g) return nil } -func keybindings(g *gocui.Gui) error { - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { +func (d *demoMouse) keybindings(g *gocui.Gui) error { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, d.quit); err != nil { return err } for _, n := range []string{"but1", "but2"} { - if err := g.SetKeybinding(n, gocui.MouseLeft, gocui.ModNone, showMsg); err != nil { + if err := g.SetKeybinding(n, gocui.MouseLeft, gocui.ModNone, d.showMsg); err != nil { return err } } - if err := g.SetKeybinding("", gocui.MouseRelease, gocui.ModNone, mouseUp); err != nil { + if err := g.SetKeybinding("", gocui.MouseRelease, gocui.ModNone, d.mouseUp); err != nil { return err } - if err := g.SetKeybinding("", gocui.MouseLeft, gocui.ModNone, globalDown); err != nil { + if err := g.SetKeybinding("", gocui.MouseLeft, gocui.ModNone, d.globalDown); err != nil { return err } - if err := g.SetKeybinding("msg", gocui.MouseLeft, gocui.ModNone, msgDown); err != nil { + if err := g.SetKeybinding("msg", gocui.MouseLeft, gocui.ModNone, d.msgDown); err != nil { return err } return nil } -func quit(g *gocui.Gui, v *gocui.View) error { +func (d *demoMouse) quit(*gocui.Gui, *gocui.View) error { return gocui.ErrQuit } -func showMsg(g *gocui.Gui, v *gocui.View) error { +func (d *demoMouse) showMsg(g *gocui.Gui, v *gocui.View) error { var l string var err error @@ -121,7 +124,7 @@ func showMsg(g *gocui.Gui, v *gocui.View) error { return nil } -func updateHighlightedView(g *gocui.Gui) { +func (d *demoMouse) updateHighlightedView(g *gocui.Gui) { mx, my := g.MousePosition() for _, view := range g.Views() { view.Highlight = false @@ -131,32 +134,32 @@ func updateHighlightedView(g *gocui.Gui) { } } -func moveMsg(g *gocui.Gui) { +func (d *demoMouse) moveMsg(g *gocui.Gui) { mx, my := g.MousePosition() - if !movingMsg && (mx != initialMouseX || my != initialMouseY) { - movingMsg = true + if !d.movingMsg && (mx != d.initialMouseX || my != d.initialMouseY) { + d.movingMsg = true } - g.SetView("msg", mx-xOffset, my-yOffset, mx-xOffset+20, my-yOffset+2, 0) + g.SetView("msg", mx-d.xOffset, my-d.yOffset, mx-d.xOffset+20, my-d.yOffset+2, 0) } -func msgDown(g *gocui.Gui, v *gocui.View) error { - initialMouseX, initialMouseY = g.MousePosition() +func (d *demoMouse) msgDown(g *gocui.Gui, v *gocui.View) error { + d.initialMouseX, d.initialMouseY = g.MousePosition() if vx, vy, _, _, err := g.ViewPosition("msg"); err == nil { - xOffset = initialMouseX - vx - yOffset = initialMouseY - vy - msgMouseDown = true + d.xOffset = d.initialMouseX - vx + d.yOffset = d.initialMouseY - vy + d.msgMouseDown = true } return nil } -func globalDown(g *gocui.Gui, v *gocui.View) error { +func (d *demoMouse) 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) + return d.msgDown(g, v) } } - globalMouseDown = true + d.globalMouseDown = true maxX, _ := g.Size() msg := fmt.Sprintf("Mouse down at: %d,%d", mx, my) x := mx - len(msg)/2 @@ -174,18 +177,18 @@ func globalDown(g *gocui.Gui, v *gocui.View) error { return nil } -func mouseUp(g *gocui.Gui, v *gocui.View) error { - if msgMouseDown { - msgMouseDown = false - if movingMsg { - movingMsg = false +func (d *demoMouse) mouseUp(g *gocui.Gui, v *gocui.View) error { + if d.msgMouseDown { + d.msgMouseDown = false + if d.movingMsg { + d.movingMsg = false return nil } else { - g.DeleteView("msg") + _ = g.DeleteView("msg") } - } else if globalMouseDown { - globalMouseDown = false - g.DeleteView("globalDown") + } else if d.globalMouseDown { + d.globalMouseDown = false + _ = g.DeleteView("globalDown") } return nil } diff --git a/_examples/ontop.go b/_examples/ontop.go index a221362..a4ff6d7 100644 --- a/_examples/ontop.go +++ b/_examples/ontop.go @@ -12,16 +12,19 @@ import ( "github.com/awesome-gocui/gocui" ) -func main() { +type demoOnTop struct{} + +func mainOntop() { g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { log.Panicln(err) } defer g.Close() - g.SetManagerFunc(layout) + d := &demoOnTop{} + g.SetManagerFunc(d.layout) - if err := keybindings(g); err != nil { + if err := d.keybindings(g); err != nil { log.Panicln(err) } @@ -30,7 +33,7 @@ func main() { } } -func layout(g *gocui.Gui) error { +func (d *demoOnTop) layout(g *gocui.Gui) error { if v, err := g.SetView("v1", 10, 2, 30, 6, 0); err != nil { if !errors.Is(err, gocui.ErrUnknownView) { return err @@ -56,7 +59,7 @@ func layout(g *gocui.Gui) error { return nil } -func keybindings(g *gocui.Gui) error { +func (d *demoOnTop) keybindings(g *gocui.Gui) error { err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { return gocui.ErrQuit }) diff --git a/_examples/overlap.go b/_examples/overlap.go index 7ecf31b..61652df 100644 --- a/_examples/overlap.go +++ b/_examples/overlap.go @@ -11,7 +11,9 @@ import ( "github.com/awesome-gocui/gocui" ) -func layout(g *gocui.Gui) error { +type demoOverlap struct{} + +func (d *demoOverlap) layout(g *gocui.Gui) error { maxX, maxY := g.Size() if _, err := g.SetView("v1", -1, -1, 10, 10, 0); err != nil && !errors.Is(err, gocui.ErrUnknownView) { @@ -56,20 +58,21 @@ func layout(g *gocui.Gui) error { return nil } -func quit(g *gocui.Gui, v *gocui.View) error { +func (d *demoOverlap) quit(*gocui.Gui, *gocui.View) error { return gocui.ErrQuit } -func main() { +func mainOverlap() { g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { log.Panicln(err) } defer g.Close() - g.SetManagerFunc(layout) + d := &demoOverlap{} + g.SetManagerFunc(d.layout) - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, d.quit); err != nil { log.Panicln(err) } diff --git a/_examples/size.go b/_examples/size.go index 8e065fd..3b03cda 100644 --- a/_examples/size.go +++ b/_examples/size.go @@ -12,16 +12,19 @@ import ( "github.com/awesome-gocui/gocui" ) -func main() { +type demoSize struct{} + +func mainSize() { g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { log.Panicln(err) } defer g.Close() - g.SetManagerFunc(layout) + d := &demoSize{} + g.SetManagerFunc(d.layout) - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, d.quit); err != nil { log.Panicln(err) } @@ -30,7 +33,7 @@ func main() { } } -func layout(g *gocui.Gui) error { +func (d *demoSize) layout(g *gocui.Gui) error { maxX, maxY := g.Size() v, err := g.SetView("size", maxX/2-7, maxY/2, maxX/2+7, maxY/2+2, 0) if err != nil { @@ -46,6 +49,6 @@ func layout(g *gocui.Gui) error { return nil } -func quit(g *gocui.Gui, v *gocui.View) error { +func (d *demoSize) quit(*gocui.Gui, *gocui.View) error { return gocui.ErrQuit } diff --git a/_examples/stdin.go b/_examples/stdin.go index d93bc02..4a5beca 100644 --- a/_examples/stdin.go +++ b/_examples/stdin.go @@ -17,7 +17,9 @@ import ( "github.com/awesome-gocui/gocui" ) -func main() { +type demoStdin struct{} + +func mainStdin() { g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { log.Fatalln(err) @@ -26,9 +28,10 @@ func main() { g.Cursor = true - g.SetManagerFunc(layout) + d := &demoStdin{} + g.SetManagerFunc(d.layout) - if err := initKeybindings(g); err != nil { + if err := d.initKeybindings(g); err != nil { log.Fatalln(err) } @@ -37,7 +40,7 @@ func main() { } } -func layout(g *gocui.Gui) error { +func (d *demoStdin) layout(g *gocui.Gui) error { maxX, _ := g.Size() if v, err := g.SetView("help", maxX-23, 0, maxX-1, 5, 0); err != nil { @@ -68,23 +71,23 @@ func layout(g *gocui.Gui) error { return nil } -func initKeybindings(g *gocui.Gui) error { - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { +func (d *demoStdin) initKeybindings(g *gocui.Gui) error { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, d.quit); err != nil { return err } - if err := g.SetKeybinding("stdin", 'a', gocui.ModNone, autoscroll); err != nil { + if err := g.SetKeybinding("stdin", 'a', gocui.ModNone, d.autoscroll); err != nil { return err } if err := g.SetKeybinding("stdin", gocui.KeyArrowUp, gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { - scrollView(v, -1) + d.scrollView(v, -1) return nil }); err != nil { return err } if err := g.SetKeybinding("stdin", gocui.KeyArrowDown, gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error { - scrollView(v, 1) + d.scrollView(v, 1) return nil }); err != nil { return err @@ -92,16 +95,16 @@ func initKeybindings(g *gocui.Gui) error { return nil } -func quit(g *gocui.Gui, v *gocui.View) error { +func (d *demoStdin) quit(*gocui.Gui, *gocui.View) error { return gocui.ErrQuit } -func autoscroll(g *gocui.Gui, v *gocui.View) error { +func (d *demoStdin) autoscroll(_ *gocui.Gui, v *gocui.View) error { v.Autoscroll = true return nil } -func scrollView(v *gocui.View, dy int) error { +func (d *demoStdin) scrollView(v *gocui.View, dy int) error { if v != nil { v.Autoscroll = false ox, oy := v.Origin() diff --git a/_examples/table.go b/_examples/table.go index 189680a..8946052 100644 --- a/_examples/table.go +++ b/_examples/table.go @@ -11,6 +11,8 @@ import ( "github.com/awesome-gocui/gocui" ) +type demoTable struct{} + type Column struct { Title string Size float32 @@ -63,12 +65,13 @@ func (t *Table) Layout(g *gocui.Gui) error { return nil } -func main() { +func mainTable() { g, err := gocui.NewGui(gocui.OutputNormal, false) if err != nil { log.Panicln(err) } defer g.Close() + d := &demoTable{} table := NewTable("t", 0, 2, 80, 10) table.Columns = []Column{ @@ -85,7 +88,7 @@ func main() { } g.SetManager(table) - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, d.quit); err != nil { log.Panicln(err) } @@ -94,6 +97,6 @@ func main() { } } -func quit(g *gocui.Gui, v *gocui.View) error { +func (d *demoTable) quit(*gocui.Gui, *gocui.View) error { return gocui.ErrQuit } diff --git a/_examples/title.go b/_examples/title.go index 23be338..803e522 100644 --- a/_examples/title.go +++ b/_examples/title.go @@ -11,16 +11,19 @@ import ( "github.com/awesome-gocui/gocui" ) -func main() { +type demoTitle struct{} + +func mainTitle() { g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { log.Panicln(err) } defer g.Close() - g.SetManagerFunc(layout) + d := &demoTitle{} + g.SetManagerFunc(d.layout) - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, d.quit); err != nil { log.Panicln(err) } @@ -29,11 +32,11 @@ func main() { } } -func quit(g *gocui.Gui, v *gocui.View) error { +func (d *demoTitle) quit(*gocui.Gui, *gocui.View) error { return gocui.ErrQuit } -func layout(g *gocui.Gui) error { +func (d *demoTitle) layout(g *gocui.Gui) error { maxX, maxY := g.Size() // Overlap (front) diff --git a/_examples/widgets.go b/_examples/widgets.go index 2e6c67a..e38b5b0 100644 --- a/_examples/widgets.go +++ b/_examples/widgets.go @@ -13,7 +13,9 @@ import ( "github.com/awesome-gocui/gocui" ) -const delta = 0.2 +type demoWidgets struct { + delta float64 +} type HelpWidget struct { name string @@ -112,26 +114,28 @@ func (w *ButtonWidget) Layout(g *gocui.Gui) error { return nil } -func main() { +func mainWidgets() { g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { log.Panicln(err) } defer g.Close() + d := &demoWidgets{delta: 0.2} + g.Highlight = true g.SelFrameColor = gocui.ColorRed help := NewHelpWidget("help", 1, 1, helpText) status := NewStatusbarWidget("status", 1, 7, 50) - butdown := NewButtonWidget("butdown", 52, 7, "DOWN", statusDown(status)) - butup := NewButtonWidget("butup", 58, 7, "UP", statusUp(status)) + butdown := NewButtonWidget("butdown", 52, 7, "DOWN", d.statusDown(status)) + butup := NewButtonWidget("butup", 58, 7, "UP", d.statusUp(status)) g.SetManager(help, status, butdown, butup) - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, d.quit); err != nil { log.Panicln(err) } - if err := g.SetKeybinding("", gocui.KeyTab, gocui.ModNone, toggleButton); err != nil { + if err := g.SetKeybinding("", gocui.KeyTab, gocui.ModNone, d.toggleButton); err != nil { log.Panicln(err) } @@ -140,11 +144,11 @@ func main() { } } -func quit(g *gocui.Gui, v *gocui.View) error { +func (d *demoWidgets) quit(*gocui.Gui, *gocui.View) error { return gocui.ErrQuit } -func toggleButton(g *gocui.Gui, v *gocui.View) error { +func (d *demoWidgets) toggleButton(g *gocui.Gui, v *gocui.View) error { nextview := "butdown" if v != nil && v.Name() == "butdown" { nextview = "butup" @@ -153,19 +157,19 @@ func toggleButton(g *gocui.Gui, v *gocui.View) error { return err } -func statusUp(status *StatusbarWidget) func(g *gocui.Gui, v *gocui.View) error { +func (d *demoWidgets) statusUp(status *StatusbarWidget) func(g *gocui.Gui, v *gocui.View) error { return func(g *gocui.Gui, v *gocui.View) error { - return statusSet(status, delta) + return d.statusSet(status, d.delta) } } -func statusDown(status *StatusbarWidget) func(g *gocui.Gui, v *gocui.View) error { +func (d *demoWidgets) statusDown(status *StatusbarWidget) func(g *gocui.Gui, v *gocui.View) error { return func(g *gocui.Gui, v *gocui.View) error { - return statusSet(status, -delta) + return d.statusSet(status, -d.delta) } } -func statusSet(sw *StatusbarWidget, inc float64) error { +func (d *demoWidgets) statusSet(sw *StatusbarWidget, inc float64) error { val := sw.Val() + inc if val < 0 || val > 1 { return nil diff --git a/_examples/wrap.go b/_examples/wrap.go index 6162ef4..817ccef 100644 --- a/_examples/wrap.go +++ b/_examples/wrap.go @@ -13,7 +13,9 @@ import ( "github.com/awesome-gocui/gocui" ) -func layout(g *gocui.Gui) error { +type demoWrap struct{} + +func (d *demoWrap) layout(g *gocui.Gui) error { maxX, maxY := g.Size() if v, err := g.SetView("main", 1, 1, maxX-1, maxY-1, 0); err != nil { if !errors.Is(err, gocui.ErrUnknownView) { @@ -32,20 +34,21 @@ func layout(g *gocui.Gui) error { return nil } -func quit(g *gocui.Gui, v *gocui.View) error { +func (d *demoWrap) quit(*gocui.Gui, *gocui.View) error { return gocui.ErrQuit } -func main() { +func mainWrap() { g, err := gocui.NewGui(gocui.OutputNormal, true) if err != nil { log.Panicln(err) } defer g.Close() - g.SetManagerFunc(layout) + d := &demoWrap{} + g.SetManagerFunc(d.layout) - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { + if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, d.quit); err != nil { log.Panicln(err) }