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