1package main
2
3import (
4	"github.com/xyproto/vt100"
5	"os"
6	"os/signal"
7	"sync"
8	"syscall"
9	"time"
10)
11
12type Bob struct {
13	x, y  int
14	color string
15	state rune
16}
17
18func (b *Bob) ToggleColor() {
19	const c1 = "Red"
20	const c2 = "Yellow"
21	if b.color == c1 {
22		b.color = c2
23	} else {
24		b.color = c1
25	}
26}
27
28func (b *Bob) ToggleState() {
29	const up = 'O'
30	const down = 'o'
31	if b.state == up {
32		b.state = down
33	} else {
34		b.state = up
35	}
36}
37
38func (b *Bob) Draw(c *vt100.Canvas) {
39	c.PlotColor(uint(b.x), uint(b.y), vt100.LightColorMap[b.color], b.state)
40}
41
42func (b *Bob) Right(c *vt100.Canvas) bool {
43	b.x += 1
44	if b.x >= int(c.W()) {
45		b.x -= 1
46		return false
47	}
48	return true
49}
50
51func (b *Bob) Left(c *vt100.Canvas) bool {
52	if b.x-1 < 0 {
53		return false
54	}
55	b.x -= 1
56	return true
57}
58
59func (b *Bob) Up(c *vt100.Canvas) bool {
60	if b.y-1 < 0 {
61		return false
62	}
63	b.y -= 1
64	return true
65}
66
67func (b *Bob) Down(c *vt100.Canvas) bool {
68	b.y += 1
69	if b.y >= int(c.H()) {
70		b.y -= 1
71		return false
72	}
73	return true
74}
75
76func main() {
77
78	c := vt100.NewCanvas()
79	tty, err := vt100.NewTTY()
80	if err != nil {
81		panic(err)
82	}
83
84	var bob Bob
85	bob.state = 'o'
86	bob.color = "Yellow"
87	bob.x = 10
88	bob.y = 10
89
90	var draw sync.RWMutex
91	sigChan := make(chan os.Signal, 1)
92	signal.Notify(sigChan, syscall.SIGWINCH)
93	go func() {
94		for range sigChan {
95			// Terminal was resized
96
97			// Prepare to resize the canvas
98			draw.Lock()
99
100			// Clear the screen after the resize
101			vt100.Clear()
102
103			// Create a new canvas, with the new size
104			nc := c.Resized()
105			if nc != nil {
106				c.Clear()
107				c.Draw()
108				c = nc
109			}
110			// Clear again, for good measure
111			vt100.Clear()
112			// Redraw the characters
113			c.Redraw()
114			// Done
115			draw.Unlock()
116		}
117	}()
118
119	vt100.Clear()
120	vt100.ShowCursor(false)
121	vt100.SetLineWrap(true)
122
123	running := true
124	for running {
125
126		//vt100.Clear()
127
128		// Draw elements in their new positions
129		draw.Lock()
130		bob.Draw(c)
131		draw.Unlock()
132
133		// Update the canvas
134		draw.Lock()
135		c.Draw()
136		draw.Unlock()
137
138		// Wait a bit
139		time.Sleep(time.Millisecond * 10)
140
141		// Change state
142		oldx := bob.x
143		oldy := bob.y
144		moved := false
145
146		// Handle events
147		draw.Lock()
148		switch tty.Key() {
149		case 253: // Up
150			moved = bob.Up(c)
151		case 255: // Down
152			moved = bob.Down(c)
153		case 254: // Right
154			moved = bob.Right(c)
155		case 252: // Left
156			moved = bob.Left(c)
157		case 27, 113: // ESC or q
158			running = false
159			break
160		case 32: // Space
161			bob.ToggleColor()
162		}
163		draw.Unlock()
164
165		if moved {
166			bob.ToggleState()
167
168			// Erase elements at their old positions
169			draw.Lock()
170			c.Plot(uint(oldx), uint(oldy), ' ')
171			draw.Unlock()
172		}
173	}
174	tty.Close()
175
176	vt100.SetLineWrap(true)
177	vt100.ShowCursor(true)
178	vt100.Home()
179}
180