altos/draw: Split out draw test scaffolding from lco-test.c
[fw/altos] / src / draw / lco-test.c
1 /*
2  * Copyright © 2023 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #define TIMEOUT 50
20
21 #define PASS_KEYS
22 #include "test-frame.c"
23
24 #define BIG_FONT FrutigerLT_Roman_64_font
25 #define VOLT_FONT FrutigerLT_Roman_64_font
26 #define SMALL_FONT NotoMono_12_font
27 #define TINY_FONT NotoMono_10_font
28 #define LOGO_FONT BenguiatGothicStd_Bold_26_font
29
30 #define LABEL_Y         (int16_t) (SMALL_FONT.ascent)
31 #define VALUE_Y         (int16_t) (LABEL_Y + BIG_FONT.ascent)
32 #define BOX_X           2
33 #define PAD_X           90
34 #define BOX_LABEL_X     30
35 #define VOLT_LABEL_X    25
36 #define RSSI_LABEL_X    15
37 #define PAD_LABEL_X     95
38 #define SEP_X           (PAD_X - 10)
39
40 static int      box_number = 1;
41 static int      pad_number = 1;
42 static int      do_polys = 1;
43 static int      scan_number = 0;
44
45 static const struct ao_coord trek[] = {
46         { .x = 90, .y = 0 },
47         { .x = 60, .y = 40 },
48         { .x = 90, .y = 20 },
49         { .x = 120, .y = 40 },
50 };
51
52 #define NCOORD_TREK (sizeof(trek)/sizeof(trek[0]))
53
54 static const struct ao_coord donut[] = {
55         { .x = 30, .y = 0 },
56         { .x = 0, .y = 30 },
57         { .x = 30, .y = 60 },
58         { .x = 60, .y = 30 },
59         { .x = 30, .y = 0 },
60         { .x = 30, .y = 10 },
61         { .x = 50, .y = 30 },
62         { .x = 30, .y = 50 },
63         { .x = 10, .y = 30 },
64         { .x = 30, .y = 10 },
65 };
66
67 #define NCOORD_DONUT (sizeof(donut)/sizeof(donut[0]))
68
69 static const struct ao_coord bowtie[] = {
70         { .x = 0, .y = 0 },
71         { .x = 32, .y = 32 },
72         { .x = 0, .y = 32 },
73         { .x = 32, .y = 0 },
74 };
75
76 #define NCOORD_BOWTIE (sizeof(bowtie)/sizeof(bowtie[0]))
77
78 static const struct ao_transform logo_transform = {
79         .x_scale = 48, .x_off = 0,
80         .y_scale = 48, .y_off = 0,
81 };
82
83 #define SCAN_X          (WIDTH - 100) / 2
84 #define SCAN_Y          51
85 #define SCAN_HEIGHT     4
86 #define FOUND_Y         64
87 #define FOUND_WIDTH     14
88 #define MAX_VALID       (WIDTH / FOUND_WIDTH)
89
90 static const struct ao_transform bowtie_transform = {
91         .x_scale = 1, .x_off = 50,
92         .y_scale = 1, .y_off = 20,
93 };
94
95 static const float pad_volts = 12.3f;
96 static const float lco_volts = 4.1f;
97 static const int rssi = -30;
98
99 static int      boxes[] = { 1, 2, 3, 5, 8, 11, 13, 17, 19, 23, 29, 31, 37, 62, 97 };
100
101 static int      max_box = 97;
102
103 #define ARRAYSIZE(a)    (sizeof(a) / sizeof((a)[0]))
104
105 static bool
106 valid_box(int box)
107 {
108         size_t i;
109         if (box == 0)
110                 return true;
111         for (i = 0; i < ARRAYSIZE(boxes); i++)
112                 if (boxes[i] == box)
113                         return true;
114         return false;
115 }
116
117 static void
118 next_box(void)
119 {
120         for (int n = box_number + 1; n <= max_box; n++)
121                 if (valid_box(n)) {
122                         box_number = n;
123                         return;
124                 }
125         box_number = 0;
126 }
127
128 static void
129 prev_box(void)
130 {
131         for (int n = box_number - 1; n >= 0; n--)
132                 if (valid_box(n)) {
133                         box_number = n;
134                         return;
135                 }
136         box_number = max_box;
137 }
138
139 void HandleExpose(Display *dpy, Window win, GC gc)
140 {
141         char    str[64];
142         int     i;
143         int     v;
144         int16_t b;
145
146         ao_rect(&fb, 0, 0, WIDTH, HEIGHT, 0xffffffff, AO_COPY);
147
148         if (do_polys == 1)
149                 current_timeout = TIMEOUT;
150         else
151                 current_timeout = 0;
152         switch (do_polys) {
153         case 1:
154                 ao_logo(&fb, &logo_transform, &LOGO_FONT, 0x00000000, AO_COPY);
155                 if (scan_number) {
156                         ao_rect(&fb, SCAN_X, SCAN_Y, (int16_t) scan_number, SCAN_HEIGHT, 0x00000000, AO_COPY);
157                         b = 0;
158                         v = 0;
159                         for (i = scan_number; i > 1; i--) {
160                                 if (valid_box(i)) {
161                                         v++;
162                                         if (v == MAX_VALID)
163                                                 break;
164                                 }
165                         }
166                         for (; i <= scan_number; i++) {
167                                 if (valid_box(i)) {
168                                         sprintf(str, "%02d", i);
169                                         ao_text(&fb, &TINY_FONT, 0 + FOUND_WIDTH * b, FOUND_Y, str, 0x00000000, AO_COPY);
170                                         b++;
171                                 }
172                         }
173                 }
174                 break;
175         case 2:
176                 ao_poly(&fb, trek, NCOORD_TREK, NULL, 0x00000000, AO_COPY);
177                 ao_poly(&fb, donut, NCOORD_DONUT, NULL, 0x00000000, AO_COPY);
178                 break;
179         case 3:
180                 ao_poly(&fb, bowtie, NCOORD_BOWTIE, &bowtie_transform, 0x00000000, AO_COPY);
181                 break;
182         default:
183         case 0:
184                 switch (box_number) {
185                 case 0:
186                         sprintf(str, "%4.1f", lco_volts);
187                         ao_text(&fb, &VOLT_FONT, BOX_X, VALUE_Y, str, 0x00000000, AO_COPY);
188                         ao_text(&fb, &SMALL_FONT, VOLT_LABEL_X, LABEL_Y, "LCO Battery", 0x00000000, AO_COPY);
189                         break;
190                 default:
191                         switch (pad_number) {
192                         case -1:
193                                 sprintf(str, "%4.1f", pad_volts);
194                                 ao_text(&fb, &VOLT_FONT, BOX_X, VALUE_Y, str, 0x00000000, AO_COPY);
195                                 ao_text(&fb, &SMALL_FONT, VOLT_LABEL_X, LABEL_Y, "Pad Battery", 0x00000000, AO_COPY);
196                                 break;
197                         case 0:
198                                 sprintf(str, "%4d", rssi);
199                                 ao_text(&fb, &VOLT_FONT, BOX_X, VALUE_Y, str, 0x00000000, AO_COPY);
200                                 ao_text(&fb, &SMALL_FONT, RSSI_LABEL_X, LABEL_Y, "Signal Strength", 0x00000000, AO_COPY);
201                                 break;
202                         default:
203                                 sprintf(str, "%02d", box_number);
204                                 ao_text(&fb, &BIG_FONT, BOX_X, VALUE_Y, str, 0x00000000, AO_COPY);
205                                 ao_text(&fb, &SMALL_FONT, BOX_LABEL_X, LABEL_Y, "Box", 0x00000000, AO_COPY);
206
207                                 sprintf(str, "%d", pad_number);
208                                 ao_text(&fb, &BIG_FONT, PAD_X, VALUE_Y, str, 0x00000000, AO_COPY);
209                                 ao_text(&fb, &SMALL_FONT, PAD_LABEL_X, LABEL_Y, "Pad", 0x00000000, AO_COPY);
210
211                                 ao_rect(&fb, SEP_X, 0, 2, HEIGHT, 0x00000000, AO_COPY);
212                         }
213                         break;
214                 }
215                 break;
216         }
217
218         DoDisplay(dpy, win, gc);
219 }
220
221 void
222 HandleKeyPress(Display *dpy, Window win, GC gc, XEvent *ev)
223 {
224         char    string[10];
225         if (XLookupString ((XKeyEvent *) ev, string, sizeof (string), 0, 0) >= 1) {
226                 switch (string[0]) {
227                 case 'q':
228                         exit (0);
229                 case 'p':
230                         if (box_number != 0) {
231                                 pad_number++;
232                                 if (pad_number > 8)
233                                         pad_number = -1;
234                         }
235                         break;
236                 case 'P':
237                         if (box_number != 0) {
238                                 pad_number--;
239                                 if (pad_number < -1)
240                                         pad_number = 8;
241                         }
242                         break;
243                 case 'b':
244                         next_box();
245                         break;
246                 case 'B':
247                         prev_box();
248                         break;
249                 case 'i':
250                         do_polys++;
251                         if (do_polys == 4)
252                                 do_polys = 0;
253                         if (do_polys == 1)
254                                 scan_number = 0;
255                         break;
256                 case 'I':
257                         do_polys--;
258                         if (do_polys < 0)
259                                 do_polys = 4;
260                         if (do_polys == 1)
261                                 scan_number = 0;
262                         break;
263                 case 's':
264                         if (scan_number < 99)
265                                 scan_number++;
266                         break;
267                 case 'S':
268                         if (scan_number > 0)
269                                 scan_number--;
270                         break;
271                 case 'c':
272                         break;
273                 }
274                 HandleExpose(dpy, win, gc);
275         }
276 }
277
278 void
279 HandleKeyRelease(Display *dpy, Window win, GC gc, XEvent *ev)
280 {
281         (void) dpy;
282         (void) win;
283         (void) gc;
284         (void) ev;
285 }
286
287 void
288 HandleTimeout(Display *dpy, Window win, GC gc)
289 {
290         if (do_polys == 1) {
291                 if (scan_number < 99)
292                         scan_number++;
293                 else {
294                         box_number = boxes[0];
295                         pad_number = 1;
296                         do_polys = 0;
297                 }
298                 HandleExpose(dpy, win, gc);
299         }
300 }