drop strokes with score < 2
[k8-protractor.git] / src / sdltest.c
blob90ad77e194916c8a33d9353810308efeaff8af05
1 /* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar)
2 * Understanding is not required. Only obedience.
4 * This program is free software. It comes without any warranty, to
5 * the extent permitted by applicable law. You can redistribute it
6 * and/or modify it under the terms of the Do What The Fuck You Want
7 * To Public License, Version 2, as published by Sam Hocevar. See
8 * http://www.wtfpl.net/txt/copying/ for more details.
9 */
10 #include <math.h>
11 #include <stdlib.h>
12 #include <stdio.h>
14 #include "SDL.h"
16 #include "videolib/videolib.h"
17 #include "gestureng/gestureng.h"
20 static gengesture_t stk;
21 static gengtemplate_t stkpat;
22 static int stkpat_inited = 0;
23 static genglib_t stklib;
24 static char *message = NULL;
25 static SDL_TimerID tid_msghide = NULL;
28 ////////////////////////////////////////////////////////////////////////////////
29 enum {
30 EVT_MESSAGE_RESET = 1,
34 ////////////////////////////////////////////////////////////////////////////////
35 static void draw_stroke (const gengesture_t *stk) {
36 if (stk->count > 1) {
37 Uint32 col = SDL_MapRGB(sfc_screen->format, 255, 255, 0);
38 for (int f = 1; f < stk->count-1; ++f) {
39 int x0 = geng_ptx(stk, f-1);
40 int y0 = geng_pty(stk, f-1);
41 int x1 = geng_ptx(stk, f);
42 int y1 = geng_pty(stk, f);
43 draw_line(x0, y0, x1, y1, col);
49 static void draw_template (const gengtemplate_t stk) {
50 for (int f = 1; f < GENG_PTS_PER_STK; ++f) {
51 int g = 255*f/(GENG_PTS_PER_STK-1), b = 255-(255*f/(GENG_PTS_PER_STK-1));
52 Uint32 col = SDL_MapRGB(sfc_screen->format, 0, g, b);
53 double x0 = stk[(f-1)*2+0];
54 double y0 = stk[(f-1)*2+1];
55 double x1 = stk[f*2+0];
56 double y1 = stk[f*2+1];
57 x0 = x0*200+400;
58 y0 = y0*200+300;
59 x1 = x1*200+400;
60 y1 = y1*200+300;
61 draw_line(x0, y0, x1, y1, col);
66 ////////////////////////////////////////////////////////////////////////////////
67 static int stklist_curptr = -1;
68 static char **stknames = NULL;
69 static int stknames_count = 0;
70 static int stknames_maxlen = 0;
71 static const char *curstkname = NULL;
74 static void stroke_list_clear (void) {
75 for (int f = stknames_count-1; f >= 0; --f) free(stknames[f]);
76 free(stknames);
77 stklist_curptr = -1;
78 stknames = NULL;
79 stknames_count = 0;
80 stknames_maxlen = 0;
84 static void stroke_list_rebuild (void) {
85 int cmp (const void *ps0, const void *ps1) {
86 const char **s0 = (const char **)ps0;
87 const char **s1 = (const char **)ps1;
88 return strcmp(*s0, *s1);
91 stroke_list_clear();
92 for (int f = 0; f < stklib.count; ++f) {
93 int found = 0;
94 for (int c = 0; c < stknames_count && !found; ++c) if (strcmp(stklib.names[f], stknames[c]) == 0) found = 1;
95 if (!found) {
96 stknames = realloc(stknames, sizeof(stknames[0])*(stknames_count+1));
97 stknames[stknames_count++] = strdup(stklib.names[f]);
98 //fprintf(stderr, "[%s]\n", stknames[stknames_count-1]);
99 if (strlen(stklib.names[f]) > stknames_maxlen) stknames_maxlen = strlen(stklib.names[f]);
102 qsort(stknames, stknames_count, sizeof(stknames[0]), cmp);
103 stknames_maxlen = stknames_maxlen*12+8;
107 static int stroke_list_curptr (int x, int y) {
108 if (x >= 4 && y >= 4 && x < stknames_maxlen-8 && y < stknames_count*16+4) return (y-4)/16;
109 return -1;
113 static void draw_stroke_list (int curptr) {
114 if (stknames_count > 0) {
115 fill_rect(0, 0, stknames_maxlen, stknames_count*16+8, SDL_MapRGB(sfc_screen->format, 0, 0, 127));
117 for (int f = 0; f < stknames_count; ++f) {
118 Uint32 col, bkcol;
119 if (curstkname != NULL && strcmp(stknames[f], curstkname) == 0) {
120 col = SDL_MapRGB(sfc_screen->format, 255, 255, 255);
121 bkcol = SDL_MapRGB(sfc_screen->format, 0, 0, 255);
122 } else {
123 col = SDL_MapRGB(sfc_screen->format, 255, 127, 0);
124 bkcol = SDL_MapRGB(sfc_screen->format, 0, 0, 127);
126 if (curptr == f) bkcol = SDL_MapRGB(sfc_screen->format, 0, 127, 0);
127 fill_rect(0, f*16+4, stknames_maxlen, 16, bkcol);
128 draw_str6(4, f*16+4, stknames[f], col, TRANSPARENT_COLOR);
130 if (stknames_count > 0) {
131 draw_rect(0, 0, stknames_maxlen, stknames_count*16+8, SDL_MapRGB(sfc_screen->format, 255, 255, 255));
132 draw_rect(1, 1, stknames_maxlen-2, stknames_count*16+6, SDL_MapRGB(sfc_screen->format, 0, 0, 0));
137 ////////////////////////////////////////////////////////////////////////////////
138 static int show_help = 0;
139 static const char *help_text[] = {
140 "\x1fProtractor demo actions",
141 "\x1f-----------------------",
142 "\3keyboard:\1",
143 " \2F1\1: toggle help",
144 " \2F2\1: save library to '\4strokes.dat\1'",
145 " \2F3\1: replace library with '\4strokes.dat\1'",
146 " \2F8\1: clear library",
147 " \2F10\1: quit",
148 " \2DEL\1: delete selected stroke",
150 "\3mouse:\1",
151 " \2LMB\1: select name or start drawing",
152 " \2RMB\1: register current stroke as template for selected name",
153 " \2MMB\1: register current stroke as template for new name",
157 static int stlen (const char *str) {
158 int len = 0;
159 for (; *str; ++str) if ((unsigned char)(str[0]) >= 32) ++len;
160 return len;
164 static void stdraw (int x, int y, const char *str) {
165 Uint32 fg = SDL_MapRGB(sfc_screen->format, 255, 255, 255);
166 if (str[0] == '\x1f') {
167 x = (sfc_screen->w-stlen(str)*12)/2;
168 ++str;
170 for (; *str; ++str) {
171 unsigned char ch = (unsigned char)(str[0]);
172 if (ch < 32) {
173 switch (ch) {
174 case 1: fg = SDL_MapRGB(sfc_screen->format, 255, 255, 255); break;
175 case 2: fg = SDL_MapRGB(sfc_screen->format, 0, 255, 0); break;
176 case 3: fg = SDL_MapRGB(sfc_screen->format, 255, 255, 0); break;
177 case 4: fg = SDL_MapRGB(sfc_screen->format, 255, 127, 0); break;
179 } else {
180 draw_char8(x, y, ch, fg, TRANSPARENT_COLOR);
181 x += 12;
187 static void toggle_help (void) {
188 show_help = !show_help;
192 static void draw_help (void) {
193 if (show_help) {
194 int x, y;
195 int wdt = 0, hgt = sizeof(help_text)/sizeof(help_text[0])*16+8;
196 Uint32 fg = SDL_MapRGB(sfc_screen->format, 255, 255, 255);
197 Uint32 bg = SDL_MapRGB(sfc_screen->format, 25, 69, 247);
198 for (size_t f = 0; f < sizeof(help_text)/sizeof(help_text[0]); ++f) {
199 int l = stlen(help_text[f]);
200 if (l > wdt) wdt = l;
202 wdt = wdt*12+8;
203 x = (sfc_screen->w-wdt)/2;
204 y = (sfc_screen->h-hgt)/2;
205 fill_rect(x, y, wdt, hgt, fg);
206 fill_rect(x+1, y+1, wdt-2, hgt-2, SDL_MapRGB(sfc_screen->format, 0, 0, 0));
207 fill_rect(x+2, y+2, wdt-4, hgt-4, bg);
208 x += 4;
209 y += 4;
210 for (size_t f = 0; f < sizeof(help_text)/sizeof(help_text[0]); ++f, y += 16) stdraw(x, y, help_text[f]);
215 ////////////////////////////////////////////////////////////////////////////////
216 static void rebuild_screen (void) {
217 int locked = 0;
218 if (SDL_MUSTLOCK(sfc_screen) != 0) {
219 if (SDL_LockSurface(sfc_screen) < 0) return;
220 locked = 1;
222 fill_rect(0, 0, sfc_screen->w, sfc_screen->h, SDL_MapRGB(sfc_screen->format, 0, 0, 0));
223 draw_stroke(&stk);
224 if (stkpat_inited) draw_template(stkpat);
225 draw_stroke_list(stklist_curptr);
226 if (message != NULL) {
227 int w = strlen(message)*16;
228 int h = 16;
229 int x = (sfc_screen->w-w)/2;
230 int y = sfc_screen->h-h-2;
231 Uint32 fg = SDL_MapRGB(sfc_screen->format, 255, 255, 255);
232 Uint32 bg = SDL_MapRGB(sfc_screen->format, 25, 69, 247);
233 Uint32 blk = SDL_MapRGB(sfc_screen->format, 0, 0, 0);
234 fill_rect(x-2, y-2, w+4, h+4, fg);
235 fill_rect(x-1, y-1, w+2, h+2, blk);
236 draw_str8(x, y, message, fg, bg);
238 draw_help();
239 if (locked) SDL_UnlockSurface(sfc_screen);
243 ////////////////////////////////////////////////////////////////////////////////
244 static Uint32 timer_msghide (Uint32 interval, void *param) {
245 SDL_Event evt;
246 evt.user.type = SDL_USEREVENT;
247 evt.user.code = EVT_MESSAGE_RESET;
248 SDL_PushEvent(&evt);
249 tid_msghide = NULL; /* cancelled */
250 return 0;
254 static void show_message (const char *msg) {
255 if (tid_msghide != NULL) SDL_RemoveTimer(tid_msghide);
256 if (message != NULL) free(message);
257 if (msg && msg[0]) message = strdup(msg); else message = NULL;
258 tid_msghide = SDL_AddTimer(5000, timer_msghide, NULL);
259 rebuild_screen();
260 paint_screen();
264 static void hide_message (void) {
265 if (message != NULL) {
266 free(message);
267 message = NULL;
268 if (tid_msghide != NULL) SDL_RemoveTimer(tid_msghide);
269 tid_msghide = NULL;
270 rebuild_screen();
271 paint_screen();
276 ////////////////////////////////////////////////////////////////////////////////
277 static void main_loop (void) {
278 SDL_Event event;
279 if (genglib_load_file(&stklib, "strokes.dat") == 0) {
280 stroke_list_rebuild();
281 show_message("'strokes.dat' loaded...");
283 rebuild_screen();
284 paint_screen();
285 while (SDL_WaitEvent(&event)) {
286 switch (event.type) {
287 case SDL_QUIT: return;
288 case SDL_VIDEOEXPOSE: paint_screen(); break;
289 case SDL_MOUSEMOTION:
290 if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON) {
291 if ((event.motion.state&SDL_BUTTON(1)) != 0) {
292 if (stklist_curptr == -1) {
293 geng_add_point(&stk, event.motion.x, event.motion.y);
294 rebuild_screen();
295 paint_screen();
298 } else if (event.motion.state == 0) {
299 int np = stroke_list_curptr(event.motion.x, event.motion.y);
300 if (np != stklist_curptr) {
301 stklist_curptr = np;
302 rebuild_screen();
303 paint_screen();
306 break;
307 case SDL_MOUSEBUTTONDOWN:
308 if (show_help) {
309 toggle_help();
310 } else {
311 if (event.button.button == SDL_BUTTON_LEFT) {
312 if (stklist_curptr == -1) {
313 geng_clear(&stk);
314 SDL_WM_GrabInput(SDL_GRAB_ON);
315 geng_add_point(&stk, event.button.x, event.button.y);
316 rebuild_screen();
317 paint_screen();
318 } else {
319 stkpat_inited = 0;
320 curstkname = NULL;
321 for (int f = 0; f < stklib.count; ++f) {
322 if (strcmp(stklib.names[f], stknames[stklist_curptr]) == 0) {
323 geng_copytpl(stkpat, stklib.tpls[f]);
324 curstkname = stklib.names[f];
325 stkpat_inited = 1;
326 break;
330 } else if (event.button.button == SDL_BUTTON_RIGHT || event.button.button == SDL_BUTTON_MIDDLE) {
331 if (stk.count > 1) {
332 const char *nm = (event.button.button == SDL_BUTTON_MIDDLE ? NULL : curstkname);
333 geng_normalize(stkpat, &stk);
334 stkpat_inited = 1;
335 if (nm == NULL) {
336 hide_message();
337 if ((nm = read_str()) == READSTR_QUIT) return;
339 if (nm != NULL) {
340 genglib_add_stk(&stklib, nm, &stk);
341 stroke_list_rebuild();
342 stklist_curptr = stroke_list_curptr(event.button.x, event.button.y);
343 geng_clear(&stk);
348 rebuild_screen();
349 paint_screen();
350 break;
351 case SDL_MOUSEBUTTONUP:
352 if (event.button.button == SDL_BUTTON_LEFT) {
353 if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON) {
354 SDL_WM_GrabInput(SDL_GRAB_OFF);
355 if (stk.count > 1) {
356 double score;
357 char buf[128];
358 curstkname = genglib_find_match(&stklib, &stk, &score);
359 if (curstkname != NULL && score < 2.0) curstkname = NULL;
360 if (curstkname != NULL) {
361 snprintf(buf, sizeof(buf), "%s: score=%.15g", curstkname, score);
362 } else {
363 snprintf(buf, sizeof(buf), "can't recognize stroke");
365 show_message(buf);
369 rebuild_screen();
370 paint_screen();
371 break;
372 case SDL_KEYDOWN:
373 switch (event.key.keysym.sym) {
374 case SDLK_ESCAPE:
375 if (show_help) {
376 toggle_help();
377 rebuild_screen();
378 paint_screen();
380 break;
381 case SDLK_F1:
382 if (SDL_WM_GrabInput(SDL_GRAB_QUERY) != SDL_GRAB_ON) {
383 toggle_help();
384 rebuild_screen();
385 paint_screen();
387 break;
388 case SDLK_F2:
389 if (genglib_save_file(&stklib, "strokes.dat") == 0) show_message("'strokes.dat' saved...");
390 break;
391 case SDLK_F3:
392 curstkname = NULL;
393 if (genglib_load_file(&stklib, "strokes.dat") == 0) show_message("'strokes.dat' loaded...");
394 stroke_list_rebuild();
395 rebuild_screen();
396 paint_screen();
397 break;
398 case SDLK_F8:
399 curstkname = NULL;
400 genglib_clear(&stklib);
401 stroke_list_rebuild();
402 show_message("library cleared...");
403 break;
404 case SDLK_r: case SDLK_DELETE: case SDLK_KP_PERIOD:
405 if (stklist_curptr >= 0) {
406 genglib_remove(&stklib, stknames[stklist_curptr]);
407 curstkname = NULL;
408 stroke_list_rebuild();
409 rebuild_screen();
410 paint_screen();
412 break;
413 case SDLK_F10: return;
414 default: ;
416 break;
417 case SDL_USEREVENT:
418 switch (event.user.code) {
419 case EVT_MESSAGE_RESET:
420 hide_message();
421 break;
423 break;
424 default: ;
430 int main (int argc, char *argv[]) {
431 if (video_init()) return 1;
432 genglib_init(&stklib);
433 geng_init(&stk);
434 main_loop();
435 SDL_WM_GrabInput(SDL_GRAB_OFF);
436 geng_done(&stk);
437 genglib_done(&stklib);
438 stroke_list_clear();
439 if (message != NULL) free(message);
440 return 0;