Last part of bitmap strips for iCatcher: the 'big coloured' icon set for the 320x240x...
[kugel-rb.git] / apps / plugins / chessclock.c
blob34eeb6b0db1c0b9852ed363a93bff327da72a3e6
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Kjell Ericson
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include "plugin.h"
21 PLUGIN_HEADER
23 /* variable button definitions */
24 #if CONFIG_KEYPAD == RECORDER_PAD
25 #define CHC_QUIT BUTTON_OFF
26 #define CHC_STARTSTOP BUTTON_PLAY
27 #define CHC_RESET BUTTON_LEFT
28 #define CHC_MENU BUTTON_F1
29 #define CHC_SETTINGS_INC BUTTON_UP
30 #define CHC_SETTINGS_DEC BUTTON_DOWN
31 #define CHC_SETTINGS_OK BUTTON_PLAY
32 #define CHC_SETTINGS_OK2 BUTTON_LEFT
33 #define CHC_SETTINGS_CANCEL BUTTON_OFF
35 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
36 #define CHC_QUIT BUTTON_OFF
37 #define CHC_STARTSTOP BUTTON_SELECT
38 #define CHC_RESET BUTTON_LEFT
39 #define CHC_MENU BUTTON_F1
40 #define CHC_SETTINGS_INC BUTTON_UP
41 #define CHC_SETTINGS_DEC BUTTON_DOWN
42 #define CHC_SETTINGS_OK BUTTON_SELECT
43 #define CHC_SETTINGS_OK2 BUTTON_LEFT
44 #define CHC_SETTINGS_CANCEL BUTTON_OFF
46 #elif CONFIG_KEYPAD == ONDIO_PAD
47 #define CHC_QUIT BUTTON_OFF
48 #define CHC_STARTSTOP BUTTON_RIGHT
49 #define CHC_RESET BUTTON_LEFT
50 #define CHC_MENU BUTTON_MENU
51 #define CHC_SETTINGS_INC BUTTON_UP
52 #define CHC_SETTINGS_DEC BUTTON_DOWN
53 #define CHC_SETTINGS_OK BUTTON_RIGHT
54 #define CHC_SETTINGS_OK2 BUTTON_LEFT
55 #define CHC_SETTINGS_CANCEL BUTTON_MENU
57 #elif CONFIG_KEYPAD == PLAYER_PAD
58 #define CHC_QUIT BUTTON_ON
59 #define CHC_STARTSTOP BUTTON_PLAY
60 #define CHC_RESET BUTTON_STOP
61 #define CHC_MENU BUTTON_MENU
62 #define CHC_SETTINGS_INC BUTTON_RIGHT
63 #define CHC_SETTINGS_DEC BUTTON_LEFT
64 #define CHC_SETTINGS_OK BUTTON_PLAY
65 #define CHC_SETTINGS_CANCEL BUTTON_STOP
66 #define CHC_SETTINGS_CANCEL2 BUTTON_MENU
68 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
69 (CONFIG_KEYPAD == IRIVER_H300_PAD)
70 #define CHC_QUIT BUTTON_SELECT
71 #define CHC_STARTSTOP BUTTON_ON
72 #define CHC_RESET BUTTON_OFF
73 #define CHC_MENU BUTTON_REC
74 #define CHC_SETTINGS_INC BUTTON_RIGHT
75 #define CHC_SETTINGS_DEC BUTTON_LEFT
76 #define CHC_SETTINGS_OK BUTTON_ON
77 #define CHC_SETTINGS_CANCEL BUTTON_OFF
78 #define CHC_SETTINGS_CANCEL2 BUTTON_REC
80 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
81 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
82 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
83 #define CHC_QUIT BUTTON_PLAY
84 #define CHC_STARTSTOP BUTTON_SELECT
85 #define CHC_RESET BUTTON_LEFT
86 #define CHC_MENU BUTTON_MENU
87 #define CHC_SETTINGS_INC BUTTON_SCROLL_FWD
88 #define CHC_SETTINGS_DEC BUTTON_SCROLL_BACK
89 #define CHC_SETTINGS_OK BUTTON_SELECT
90 #define CHC_SETTINGS_CANCEL BUTTON_MENU
92 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
93 #define CHC_QUIT BUTTON_PLAY
94 #define CHC_STARTSTOP BUTTON_MODE
95 #define CHC_RESET BUTTON_EQ
96 #define CHC_MENU BUTTON_SELECT
97 #define CHC_SETTINGS_INC BUTTON_RIGHT
98 #define CHC_SETTINGS_DEC BUTTON_LEFT
99 #define CHC_SETTINGS_OK BUTTON_SELECT
100 #define CHC_SETTINGS_CANCEL BUTTON_PLAY
102 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
103 #define CHC_QUIT BUTTON_REC
104 #define CHC_STARTSTOP BUTTON_PLAY
105 #define CHC_RESET BUTTON_POWER
106 #define CHC_MENU BUTTON_SELECT
107 #define CHC_SETTINGS_INC BUTTON_RIGHT
108 #define CHC_SETTINGS_DEC BUTTON_LEFT
109 #define CHC_SETTINGS_OK BUTTON_SELECT
110 #define CHC_SETTINGS_CANCEL BUTTON_REC
112 #elif CONFIG_KEYPAD == GIGABEAT_PAD
113 #define CHC_QUIT BUTTON_POWER
114 #define CHC_STARTSTOP BUTTON_SELECT
115 #define CHC_RESET BUTTON_A
116 #define CHC_MENU BUTTON_MENU
117 #define CHC_SETTINGS_INC BUTTON_UP
118 #define CHC_SETTINGS_DEC BUTTON_DOWN
119 #define CHC_SETTINGS_OK BUTTON_SELECT
120 #define CHC_SETTINGS_CANCEL BUTTON_POWER
122 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
123 (CONFIG_KEYPAD == SANSA_C200_PAD)
124 #define CHC_QUIT BUTTON_POWER
125 #define CHC_STARTSTOP BUTTON_SELECT
126 #define CHC_RESET BUTTON_DOWN
127 #define CHC_MENU BUTTON_UP
128 #define CHC_SETTINGS_INC BUTTON_RIGHT
129 #define CHC_SETTINGS_DEC BUTTON_LEFT
130 #define CHC_SETTINGS_OK BUTTON_SELECT
131 #define CHC_SETTINGS_CANCEL BUTTON_POWER
133 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
134 #define CHC_QUIT BUTTON_POWER
135 #define CHC_STARTSTOP BUTTON_PLAY
136 #define CHC_RESET BUTTON_FF
137 #define CHC_MENU BUTTON_REW
138 #define CHC_SETTINGS_INC BUTTON_RIGHT
139 #define CHC_SETTINGS_DEC BUTTON_LEFT
140 #define CHC_SETTINGS_OK BUTTON_PLAY
141 #define CHC_SETTINGS_CANCEL BUTTON_POWER
143 #elif CONFIG_KEYPAD == MROBE500_PAD
144 #define CHC_QUIT BUTTON_POWER
145 #define CHC_STARTSTOP BUTTON_RC_PLAY
146 #define CHC_RESET BUTTON_RC_HEART
147 #define CHC_MENU BUTTON_RC_MODE
148 #define CHC_SETTINGS_INC BUTTON_RC_VOL_UP
149 #define CHC_SETTINGS_DEC BUTTON_RC_VOL_DOWN
150 #define CHC_SETTINGS_OK BUTTON_RC_PLAY
151 #define CHC_SETTINGS_CANCEL BUTTON_POWER
153 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
154 #define CHC_QUIT BUTTON_BACK
155 #define CHC_STARTSTOP BUTTON_PLAY
156 #define CHC_RESET BUTTON_PREV
157 #define CHC_MENU BUTTON_MENU
158 #define CHC_SETTINGS_INC BUTTON_UP
159 #define CHC_SETTINGS_DEC BUTTON_DOWN
160 #define CHC_SETTINGS_OK BUTTON_SELECT
161 #define CHC_SETTINGS_CANCEL BUTTON_BACK
163 #elif CONFIG_KEYPAD == MROBE100_PAD
164 #define CHC_QUIT BUTTON_POWER
165 #define CHC_STARTSTOP BUTTON_SELECT
166 #define CHC_RESET BUTTON_DISPLAY
167 #define CHC_MENU BUTTON_MENU
168 #define CHC_SETTINGS_INC BUTTON_UP
169 #define CHC_SETTINGS_DEC BUTTON_DOWN
170 #define CHC_SETTINGS_OK BUTTON_SELECT
171 #define CHC_SETTINGS_CANCEL BUTTON_POWER
173 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
174 #define CHC_QUIT BUTTON_RC_REC
175 #define CHC_STARTSTOP BUTTON_RC_PLAY
176 #define CHC_RESET BUTTON_RC_REW
177 #define CHC_MENU BUTTON_RC_MENU
178 #define CHC_SETTINGS_INC BUTTON_RC_VOL_UP
179 #define CHC_SETTINGS_DEC BUTTON_RC_VOL_DOWN
180 #define CHC_SETTINGS_OK BUTTON_RC_PLAY
181 #define CHC_SETTINGS_CANCEL BUTTON_RC_REC
183 #elif CONFIG_KEYPAD == COWOND2_PAD
184 #define CHC_QUIT BUTTON_POWER
185 #define CHC_STARTSTOP BUTTON_SELECT
186 #define CHC_RESET (BUTTON_SELECT|BUTTON_MENU)
187 #define CHC_MENU BUTTON_MENU
188 #define CHC_SETTINGS_INC BUTTON_UP
189 #define CHC_SETTINGS_DEC BUTTON_DOWN
190 #define CHC_SETTINGS_OK BUTTON_SELECT
191 #define CHC_SETTINGS_CANCEL BUTTON_POWER
193 #else
194 #error No keymap defined!
195 #endif
199 /* leave first line blank on bitmap display, for pause icon */
200 #ifdef HAVE_LCD_BITMAP
201 #define FIRST_LINE 1
202 #else
203 #define FIRST_LINE 0
204 #endif
206 /* here is a global api struct pointer. while not strictly necessary,
207 it's nice not to have to pass the api pointer in all function calls
208 in the plugin */
209 static struct plugin_api* rb;
210 MEM_FUNCTION_WRAPPERS(rb);
211 #define MAX_PLAYERS 10
213 static struct {
214 int nr_timers;
215 int total_time;
216 int round_time;
217 } settings;
219 static struct {
220 int total_time;
221 int used_time;
222 bool hidden;
223 } timer_holder[MAX_PLAYERS];
225 static int run_timer(int nr);
226 static int chessclock_set_int(char* string,
227 int* variable,
228 int step,
229 int min,
230 int max,
231 int flags);
232 #define FLAGS_SET_INT_SECONDS 1
234 static char * show_time(int secs);
235 static int simple_menu(int nr, unsigned char **strarr);
237 static bool pause;
239 #define MAX_TIME 7200
241 /* this is the plugin entry point */
242 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
244 int i;
245 bool done;
246 int nr;
248 (void)parameter;
249 rb=api;
250 rb->memset(&settings, 0, sizeof(settings));
252 /* now go ahead and have fun! */
253 rb->splash(HZ, "Chess Clock");
255 rb->lcd_clear_display();
256 i=0;
257 while (i>=0) {
258 int res;
259 switch (i) {
260 case 0:
261 res=chessclock_set_int("Number of players",
262 &settings.nr_timers, 1, 1,
263 MAX_PLAYERS, 0);
264 break;
265 case 1:
266 res=chessclock_set_int("Total time",
267 &settings.total_time, 10, 0, MAX_TIME,
268 FLAGS_SET_INT_SECONDS);
269 settings.round_time=settings.total_time;
270 break;
271 case 2:
272 res=chessclock_set_int("Max round time", &settings.round_time,
273 10, 0, settings.round_time,
274 FLAGS_SET_INT_SECONDS);
275 break;
276 default:
277 i=-1; /* done */
278 res=-2;
279 break;
281 if (res==-1) {
282 return PLUGIN_USB_CONNECTED;
284 if (res==0) {
285 i--;
286 if (i<0) {
287 return PLUGIN_OK;
290 if (res>0) {
291 i++;
294 for (i=0; i<settings.nr_timers; i++) {
295 timer_holder[i].total_time=settings.total_time;
296 timer_holder[i].used_time=0;
297 timer_holder[i].hidden=false;
300 pause=true; /* We start paused */
302 nr=0;
303 do {
304 int ret=0;
305 done=true;
306 for (i=0; done && i<settings.nr_timers; i++) {
307 if (!timer_holder[i].hidden)
308 done=false;
310 if (done) {
311 return PLUGIN_OK;
313 if (!timer_holder[nr].hidden) {
314 done=false;
315 ret=run_timer(nr);
317 switch (ret) {
318 case -1: /* exit */
319 done=true;
320 break;
321 case 3:
322 return PLUGIN_USB_CONNECTED;
323 case 1:
324 nr++;
325 if (nr>=settings.nr_timers)
326 nr=0;
327 break;
328 case 2:
329 nr--;
330 if (nr<0)
331 nr=settings.nr_timers-1;
332 break;
334 } while (!done);
335 return PLUGIN_OK;
338 #ifdef HAVE_LCD_BITMAP
339 static void show_pause_mode(bool enabled)
341 static const char pause_icon[] = {0x00,0x7f,0x7f,0x00,0x7f,0x7f,0x00};
343 if (enabled)
344 rb->lcd_mono_bitmap((unsigned char *)pause_icon, 52, 0, 7, 8);
345 else
347 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
348 rb->lcd_fillrect(52, 0, 7, 8);
349 rb->lcd_set_drawmode(DRMODE_SOLID);
352 #endif
355 -1= exit
356 1 = next player
357 2 = prev player
358 3 = usb connected
360 static int run_timer(int nr)
362 char buf[40];
363 char player_info[13];
364 long last_tick;
365 bool done=false;
366 int retval=0;
367 long max_ticks=timer_holder[nr].total_time*HZ-timer_holder[nr].used_time;
368 long ticks=0;
369 bool round_time=false;
371 #ifdef HAVE_LCD_CHARCELLS
372 rb->lcd_icon(ICON_PAUSE, pause);
373 #else
374 show_pause_mode(pause);
375 #endif
377 if (settings.round_time*HZ<max_ticks) {
378 max_ticks=settings.round_time*HZ;
379 round_time=true;
381 rb->snprintf(player_info, sizeof(player_info), "Player %d", nr+1);
382 rb->lcd_puts(0, FIRST_LINE, (unsigned char *)player_info);
383 last_tick=*rb->current_tick;
385 while (!done) {
386 int button;
387 long now;
388 if (ticks>max_ticks) {
389 if (round_time)
390 rb->lcd_puts(0, FIRST_LINE+1, (unsigned char *)"ROUND UP!");
391 else
392 rb->lcd_puts(0, FIRST_LINE+1, (unsigned char *)"TIME OUT!");
393 rb->backlight_on();
394 } else {
396 if (((int)(rb->current_tick - start_ticks)/HZ)&1) {
397 rb->lcd_puts(0, FIRST_LINE, player_info);
398 } else {
399 rb->lcd_puts(0, FIRST_LINE, player_info);
402 rb->lcd_puts(0, FIRST_LINE, (unsigned char *)player_info);
403 now=*rb->current_tick;
404 if (!pause) {
405 ticks+=now-last_tick;
406 if ((max_ticks-ticks)/HZ == 10) {
407 /* Backlight on if 10 seconds remain */
408 rb->backlight_on();
411 last_tick=now;
412 if (round_time) {
413 rb->snprintf(buf, sizeof(buf), "%s/",
414 show_time((max_ticks-ticks+HZ-1)/HZ));
415 /* Append total time */
416 rb->strcpy(&buf[rb->strlen(buf)],
417 show_time((timer_holder[nr].total_time*HZ-
418 timer_holder[nr].used_time-
419 ticks+HZ-1)/HZ));
420 rb->lcd_puts(0, FIRST_LINE+1, (unsigned char *)buf);
421 } else {
422 rb->lcd_puts(0, FIRST_LINE+1,
423 (unsigned char *)show_time((max_ticks-ticks+HZ-1)/HZ));
426 rb->lcd_update();
428 button = rb->button_get(false);
429 switch (button) {
430 /* OFF/ON key to exit */
431 case CHC_QUIT:
432 return -1; /* Indicate exit */
434 /* PLAY = Stop/Start toggle */
435 case CHC_STARTSTOP:
436 pause=!pause;
437 #ifdef HAVE_LCD_CHARCELLS
438 rb->lcd_icon(ICON_PAUSE, pause);
439 #else
440 show_pause_mode(pause);
441 #endif
442 break;
444 /* LEFT = Reset timer */
445 case CHC_RESET:
446 ticks=0;
447 break;
449 /* MENU */
450 case CHC_MENU:
452 int ret;
453 char *menu[]={"Delete player", "Restart round",
454 "Set round time", "Set total time"};
455 ret=simple_menu(4, (unsigned char **)menu);
456 if (ret==-1) {
457 retval = 3;
458 done=true;
459 } else if (ret==-2) {
460 } else if (ret==0) {
461 /* delete timer */
462 timer_holder[nr].hidden=true;
463 retval=1;
464 done=true;
465 break;
466 } else if (ret==1) {
467 /* restart */
468 ticks=0;
469 break;
470 } else if (ret==2) {
471 /* set round time */
472 int res;
473 int val=(max_ticks-ticks)/HZ;
474 res=chessclock_set_int("Round time",
475 &val,
476 10, 0, MAX_TIME,
477 FLAGS_SET_INT_SECONDS);
478 if (res==-1) { /*usb*/
479 retval = 3;
480 done=true;
481 } else if (res==1) {
482 ticks=max_ticks-val*HZ;
484 } else if (ret==3) {
485 /* set total time */
486 int res;
487 int val=timer_holder[nr].total_time;
488 res=chessclock_set_int("Total time",
489 &val,
490 10, 0, MAX_TIME,
491 FLAGS_SET_INT_SECONDS);
492 if (res==-1) { /*usb*/
493 retval = 3;
494 done=true;
495 } else if (res==1) {
496 timer_holder[nr].total_time=val;
500 break;
502 /* UP (RIGHT/+) = Scroll Lap timer up */
503 case CHC_SETTINGS_INC:
504 retval = 1;
505 done = true;
506 break;
508 /* DOWN (LEFT/-) = Scroll Lap timer down */
509 case CHC_SETTINGS_DEC:
510 retval = 2;
511 done = true;
512 break;
514 default:
515 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) {
516 retval = 3; /* been in usb mode */
517 done = true;
519 break;
521 rb->sleep(HZ/4); /* Sleep 1/4 of a second */
524 timer_holder[nr].used_time+=ticks;
526 return retval;
529 static int chessclock_set_int(char* string,
530 int* variable,
531 int step,
532 int min,
533 int max,
534 int flags)
536 bool done = false;
537 int button;
539 rb->lcd_clear_display();
540 rb->lcd_puts_scroll(0, FIRST_LINE, (unsigned char *)string);
542 while (!done) {
543 char str[32];
544 if (flags & FLAGS_SET_INT_SECONDS)
545 rb->snprintf(str, sizeof str,"%s (m:s)", show_time(*variable));
546 else
547 rb->snprintf(str, sizeof str,"%d", *variable);
548 rb->lcd_puts(0, FIRST_LINE+1, (unsigned char *)str);
549 rb->lcd_update();
551 button = rb->button_get(true);
552 switch(button) {
553 case CHC_SETTINGS_INC:
554 case CHC_SETTINGS_INC | BUTTON_REPEAT:
555 *variable += step;
556 break;
558 case CHC_SETTINGS_DEC:
559 case CHC_SETTINGS_DEC | BUTTON_REPEAT:
560 *variable -= step;
561 break;
563 case CHC_SETTINGS_OK:
564 #ifdef CHC_SETTINGS_OK2
565 case CHC_SETTINGS_OK2:
566 #endif
567 done = true;
568 break;
570 case CHC_SETTINGS_CANCEL:
571 #ifdef CHC_SETTINGS_CANCEL2
572 case CHC_SETTINGS_CANCEL2:
573 #endif
574 return 0; /* cancel */
575 break;
577 default:
578 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
579 return -1; /* been in usb mode */
580 break;
583 if(*variable > max )
584 *variable = max;
586 if(*variable < min )
587 *variable = min;
590 rb->lcd_stop_scroll();
592 return 1;
595 static char * show_time(int seconds)
597 static char buf[]="00:00";
598 rb->snprintf(buf, sizeof(buf), "%02d:%02d", seconds/60, seconds%60);
599 return buf;
602 /* -1 = USB
603 -2 = cancel
605 static int simple_menu(int nr, unsigned char **strarr)
607 int show=0;
608 int button;
609 rb->lcd_clear_display();
611 while (1) {
612 if (show>=nr)
613 show=0;
614 if (show<0)
615 show=nr-1;
616 rb->lcd_puts_scroll(0, FIRST_LINE, strarr[show]);
617 rb->lcd_update();
619 button = rb->button_get(true);
620 switch(button) {
621 case CHC_SETTINGS_INC:
622 case CHC_SETTINGS_INC | BUTTON_REPEAT:
623 show++;
624 break;
626 case CHC_SETTINGS_DEC:
627 case CHC_SETTINGS_DEC | BUTTON_REPEAT:
628 show--;
629 break;
631 case CHC_SETTINGS_OK:
632 #ifdef CHC_SETTINGS_OK2
633 case CHC_SETTINGS_OK2:
634 #endif
635 return show;
636 break;
638 case CHC_SETTINGS_CANCEL:
639 #ifdef CHC_SETTINGS_CANCEL2
640 case CHC_SETTINGS_CANCEL2:
641 #endif
642 return -2; /* cancel */
643 break;
645 default:
646 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
647 return -1; /* been in usb mode */
648 break;