1// Copyright 2014 The gocui Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package main 6 7import ( 8 "fmt" 9 "log" 10 "strings" 11 12 "github.com/miguelmota/gocui" 13) 14 15const delta = 1 16 17var ( 18 views = []string{} 19 curView = -1 20 idxView = 0 21) 22 23func main() { 24 g, err := gocui.NewGui(gocui.OutputNormal) 25 if err != nil { 26 log.Panicln(err) 27 } 28 defer g.Close() 29 30 g.Highlight = true 31 g.SelFgColor = gocui.ColorRed 32 33 g.SetManagerFunc(layout) 34 35 if err := initKeybindings(g); err != nil { 36 log.Panicln(err) 37 } 38 if err := newView(g); err != nil { 39 log.Panicln(err) 40 } 41 42 if err := g.MainLoop(); err != nil && err != gocui.ErrQuit { 43 log.Panicln(err) 44 } 45} 46 47func layout(g *gocui.Gui) error { 48 maxX, _ := g.Size() 49 v, err := g.SetView("help", maxX-25, 0, maxX-1, 9) 50 if err != nil { 51 if err != gocui.ErrUnknownView { 52 return err 53 } 54 fmt.Fprintln(v, "KEYBINDINGS") 55 fmt.Fprintln(v, "Space: New View") 56 fmt.Fprintln(v, "Tab: Next View") 57 fmt.Fprintln(v, "← ↑ → ↓: Move View") 58 fmt.Fprintln(v, "Backspace: Delete View") 59 fmt.Fprintln(v, "t: Set view on top") 60 fmt.Fprintln(v, "b: Set view on bottom") 61 fmt.Fprintln(v, "^C: Exit") 62 } 63 return nil 64} 65 66func initKeybindings(g *gocui.Gui) error { 67 if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, 68 func(g *gocui.Gui, v *gocui.View) error { 69 return gocui.ErrQuit 70 }); err != nil { 71 return err 72 } 73 if err := g.SetKeybinding("", gocui.KeySpace, gocui.ModNone, 74 func(g *gocui.Gui, v *gocui.View) error { 75 return newView(g) 76 }); err != nil { 77 return err 78 } 79 if err := g.SetKeybinding("", gocui.KeyBackspace2, gocui.ModNone, 80 func(g *gocui.Gui, v *gocui.View) error { 81 return delView(g) 82 }); err != nil { 83 return err 84 } 85 if err := g.SetKeybinding("", gocui.KeyTab, gocui.ModNone, 86 func(g *gocui.Gui, v *gocui.View) error { 87 return nextView(g, true) 88 }); err != nil { 89 return err 90 } 91 if err := g.SetKeybinding("", gocui.KeyArrowLeft, gocui.ModNone, 92 func(g *gocui.Gui, v *gocui.View) error { 93 return moveView(g, v, -delta, 0) 94 }); err != nil { 95 return err 96 } 97 if err := g.SetKeybinding("", gocui.KeyArrowRight, gocui.ModNone, 98 func(g *gocui.Gui, v *gocui.View) error { 99 return moveView(g, v, delta, 0) 100 }); err != nil { 101 return err 102 } 103 if err := g.SetKeybinding("", gocui.KeyArrowDown, gocui.ModNone, 104 func(g *gocui.Gui, v *gocui.View) error { 105 return moveView(g, v, 0, delta) 106 }); err != nil { 107 return err 108 } 109 if err := g.SetKeybinding("", gocui.KeyArrowUp, gocui.ModNone, 110 func(g *gocui.Gui, v *gocui.View) error { 111 return moveView(g, v, 0, -delta) 112 }); err != nil { 113 return err 114 } 115 if err := g.SetKeybinding("", 't', gocui.ModNone, 116 func(g *gocui.Gui, v *gocui.View) error { 117 _, err := g.SetViewOnTop(views[curView]) 118 return err 119 }); err != nil { 120 return err 121 } 122 if err := g.SetKeybinding("", 'b', gocui.ModNone, 123 func(g *gocui.Gui, v *gocui.View) error { 124 _, err := g.SetViewOnBottom(views[curView]) 125 return err 126 }); err != nil { 127 return err 128 } 129 return nil 130} 131 132func newView(g *gocui.Gui) error { 133 maxX, maxY := g.Size() 134 name := fmt.Sprintf("v%v", idxView) 135 v, err := g.SetView(name, maxX/2-5, maxY/2-5, maxX/2+5, maxY/2+5) 136 if err != nil { 137 if err != gocui.ErrUnknownView { 138 return err 139 } 140 v.Wrap = true 141 fmt.Fprintln(v, strings.Repeat(name+" ", 30)) 142 } 143 if _, err := g.SetCurrentView(name); err != nil { 144 return err 145 } 146 147 views = append(views, name) 148 curView = len(views) - 1 149 idxView += 1 150 return nil 151} 152 153func delView(g *gocui.Gui) error { 154 if len(views) <= 1 { 155 return nil 156 } 157 158 if err := g.DeleteView(views[curView]); err != nil { 159 return err 160 } 161 views = append(views[:curView], views[curView+1:]...) 162 163 return nextView(g, false) 164} 165 166func nextView(g *gocui.Gui, disableCurrent bool) error { 167 next := curView + 1 168 if next > len(views)-1 { 169 next = 0 170 } 171 172 if _, err := g.SetCurrentView(views[next]); err != nil { 173 return err 174 } 175 176 curView = next 177 return nil 178} 179 180func moveView(g *gocui.Gui, v *gocui.View, dx, dy int) error { 181 name := v.Name() 182 x0, y0, x1, y1, err := g.ViewPosition(name) 183 if err != nil { 184 return err 185 } 186 if _, err := g.SetView(name, x0+dx, y0+dy, x1+dx, y1+dy); err != nil { 187 return err 188 } 189 return nil 190} 191