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.
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 ////////////////////////////////////////////////////////////////////////////////
30 EVT_MESSAGE_RESET
= 1,
34 ////////////////////////////////////////////////////////////////////////////////
35 static void draw_stroke (const gengesture_t
*stk
) {
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];
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
]);
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
);
92 for (int f
= 0; f
< stklib
.count
; ++f
) {
94 for (int c
= 0; c
< stknames_count
&& !found
; ++c
) if (strcmp(stklib
.names
[f
], stknames
[c
]) == 0) found
= 1;
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;
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
) {
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);
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-----------------------",
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",
148 " \2DEL\1: delete selected stroke",
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
) {
159 for (; *str
; ++str
) if ((unsigned char)(str
[0]) >= 32) ++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;
170 for (; *str
; ++str
) {
171 unsigned char ch
= (unsigned char)(str
[0]);
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;
180 draw_char8(x
, y
, ch
, fg
, TRANSPARENT_COLOR
);
187 static void toggle_help (void) {
188 show_help
= !show_help
;
192 static void draw_help (void) {
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
;
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
);
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) {
218 if (SDL_MUSTLOCK(sfc_screen
) != 0) {
219 if (SDL_LockSurface(sfc_screen
) < 0) return;
222 fill_rect(0, 0, sfc_screen
->w
, sfc_screen
->h
, SDL_MapRGB(sfc_screen
->format
, 0, 0, 0));
224 if (stkpat_inited
) draw_template(stkpat
);
225 draw_stroke_list(stklist_curptr
);
226 if (message
!= NULL
) {
227 int w
= strlen(message
)*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
);
239 if (locked
) SDL_UnlockSurface(sfc_screen
);
243 ////////////////////////////////////////////////////////////////////////////////
244 static Uint32
timer_msghide (Uint32 interval
, void *param
) {
246 evt
.user
.type
= SDL_USEREVENT
;
247 evt
.user
.code
= EVT_MESSAGE_RESET
;
249 tid_msghide
= NULL
; /* cancelled */
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
);
264 static void hide_message (void) {
265 if (message
!= NULL
) {
268 if (tid_msghide
!= NULL
) SDL_RemoveTimer(tid_msghide
);
276 ////////////////////////////////////////////////////////////////////////////////
277 static void main_loop (void) {
279 if (genglib_load_file(&stklib
, "strokes.dat") == 0) {
280 stroke_list_rebuild();
281 show_message("'strokes.dat' loaded...");
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
);
298 } else if (event
.motion
.state
== 0) {
299 int np
= stroke_list_curptr(event
.motion
.x
, event
.motion
.y
);
300 if (np
!= stklist_curptr
) {
307 case SDL_MOUSEBUTTONDOWN
:
311 if (event
.button
.button
== SDL_BUTTON_LEFT
) {
312 if (stklist_curptr
== -1) {
314 SDL_WM_GrabInput(SDL_GRAB_ON
);
315 geng_add_point(&stk
, event
.button
.x
, event
.button
.y
);
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
];
330 } else if (event
.button
.button
== SDL_BUTTON_RIGHT
|| event
.button
.button
== SDL_BUTTON_MIDDLE
) {
332 const char *nm
= (event
.button
.button
== SDL_BUTTON_MIDDLE
? NULL
: curstkname
);
333 geng_normalize(stkpat
, &stk
);
337 if ((nm
= read_str()) == READSTR_QUIT
) return;
340 genglib_add_stk(&stklib
, nm
, &stk
);
341 stroke_list_rebuild();
342 stklist_curptr
= stroke_list_curptr(event
.button
.x
, event
.button
.y
);
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
);
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
);
363 snprintf(buf
, sizeof(buf
), "can't recognize stroke");
373 switch (event
.key
.keysym
.sym
) {
382 if (SDL_WM_GrabInput(SDL_GRAB_QUERY
) != SDL_GRAB_ON
) {
389 if (genglib_save_file(&stklib
, "strokes.dat") == 0) show_message("'strokes.dat' saved...");
393 if (genglib_load_file(&stklib
, "strokes.dat") == 0) show_message("'strokes.dat' loaded...");
394 stroke_list_rebuild();
400 genglib_clear(&stklib
);
401 stroke_list_rebuild();
402 show_message("library cleared...");
404 case SDLK_r
: case SDLK_DELETE
: case SDLK_KP_PERIOD
:
405 if (stklist_curptr
>= 0) {
406 genglib_remove(&stklib
, stknames
[stklist_curptr
]);
408 stroke_list_rebuild();
413 case SDLK_F10
: return;
418 switch (event
.user
.code
) {
419 case EVT_MESSAGE_RESET
:
430 int main (int argc
, char *argv
[]) {
431 if (video_init()) return 1;
432 genglib_init(&stklib
);
435 SDL_WM_GrabInput(SDL_GRAB_OFF
);
437 genglib_done(&stklib
);
439 if (message
!= NULL
) free(message
);