when changing settings from the Talk and Voice window also update the main widgets...
[Rockbox.git] / apps / plugins / chessclock.c
blob6523021b6d99dacab91745f8b180c4f75da00b0e
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 #else
174 #error No keymap defined!
175 #endif
179 /* leave first line blank on bitmap display, for pause icon */
180 #ifdef HAVE_LCD_BITMAP
181 #define FIRST_LINE 1
182 #else
183 #define FIRST_LINE 0
184 #endif
186 /* here is a global api struct pointer. while not strictly necessary,
187 it's nice not to have to pass the api pointer in all function calls
188 in the plugin */
189 static struct plugin_api* rb;
190 MEM_FUNCTION_WRAPPERS(rb);
191 #define MAX_PLAYERS 10
193 static struct {
194 int nr_timers;
195 int total_time;
196 int round_time;
197 } settings;
199 static struct {
200 int total_time;
201 int used_time;
202 bool hidden;
203 } timer_holder[MAX_PLAYERS];
205 static int run_timer(int nr);
206 static int chessclock_set_int(char* string,
207 int* variable,
208 int step,
209 int min,
210 int max,
211 int flags);
212 #define FLAGS_SET_INT_SECONDS 1
214 static char * show_time(int secs);
215 static int simple_menu(int nr, unsigned char **strarr);
217 static bool pause;
219 #define MAX_TIME 7200
221 /* this is the plugin entry point */
222 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
224 int i;
225 bool done;
226 int nr;
228 (void)parameter;
229 rb=api;
230 rb->memset(&settings, 0, sizeof(settings));
232 /* now go ahead and have fun! */
233 rb->splash(HZ, "Chess Clock");
235 rb->lcd_clear_display();
236 i=0;
237 while (i>=0) {
238 int res;
239 switch (i) {
240 case 0:
241 res=chessclock_set_int("Number of players",
242 &settings.nr_timers, 1, 1,
243 MAX_PLAYERS, 0);
244 break;
245 case 1:
246 res=chessclock_set_int("Total time",
247 &settings.total_time, 10, 0, MAX_TIME,
248 FLAGS_SET_INT_SECONDS);
249 settings.round_time=settings.total_time;
250 break;
251 case 2:
252 res=chessclock_set_int("Max round time", &settings.round_time,
253 10, 0, settings.round_time,
254 FLAGS_SET_INT_SECONDS);
255 break;
256 default:
257 i=-1; /* done */
258 res=-2;
259 break;
261 if (res==-1) {
262 return PLUGIN_USB_CONNECTED;
264 if (res==0) {
265 i--;
266 if (i<0) {
267 return PLUGIN_OK;
270 if (res>0) {
271 i++;
274 for (i=0; i<settings.nr_timers; i++) {
275 timer_holder[i].total_time=settings.total_time;
276 timer_holder[i].used_time=0;
277 timer_holder[i].hidden=false;
280 pause=true; /* We start paused */
282 nr=0;
283 do {
284 int ret=0;
285 done=true;
286 for (i=0; done && i<settings.nr_timers; i++) {
287 if (!timer_holder[i].hidden)
288 done=false;
290 if (done) {
291 return PLUGIN_OK;
293 if (!timer_holder[nr].hidden) {
294 done=false;
295 ret=run_timer(nr);
297 switch (ret) {
298 case -1: /* exit */
299 done=true;
300 break;
301 case 3:
302 return PLUGIN_USB_CONNECTED;
303 case 1:
304 nr++;
305 if (nr>=settings.nr_timers)
306 nr=0;
307 break;
308 case 2:
309 nr--;
310 if (nr<0)
311 nr=settings.nr_timers-1;
312 break;
314 } while (!done);
315 return PLUGIN_OK;
318 #ifdef HAVE_LCD_BITMAP
319 static void show_pause_mode(bool enabled)
321 static const char pause_icon[] = {0x00,0x7f,0x7f,0x00,0x7f,0x7f,0x00};
323 if (enabled)
324 rb->lcd_mono_bitmap((unsigned char *)pause_icon, 52, 0, 7, 8);
325 else
327 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
328 rb->lcd_fillrect(52, 0, 7, 8);
329 rb->lcd_set_drawmode(DRMODE_SOLID);
332 #endif
335 -1= exit
336 1 = next player
337 2 = prev player
338 3 = usb connected
340 static int run_timer(int nr)
342 char buf[40];
343 char player_info[13];
344 long last_tick;
345 bool done=false;
346 int retval=0;
347 long max_ticks=timer_holder[nr].total_time*HZ-timer_holder[nr].used_time;
348 long ticks=0;
349 bool round_time=false;
351 #ifdef HAVE_LCD_CHARCELLS
352 rb->lcd_icon(ICON_PAUSE, pause);
353 #else
354 show_pause_mode(pause);
355 #endif
357 if (settings.round_time*HZ<max_ticks) {
358 max_ticks=settings.round_time*HZ;
359 round_time=true;
361 rb->snprintf(player_info, sizeof(player_info), "Player %d", nr+1);
362 rb->lcd_puts(0, FIRST_LINE, (unsigned char *)player_info);
363 last_tick=*rb->current_tick;
365 while (!done) {
366 int button;
367 long now;
368 if (ticks>max_ticks) {
369 if (round_time)
370 rb->lcd_puts(0, FIRST_LINE+1, (unsigned char *)"ROUND UP!");
371 else
372 rb->lcd_puts(0, FIRST_LINE+1, (unsigned char *)"TIME OUT!");
373 rb->backlight_on();
374 } else {
376 if (((int)(rb->current_tick - start_ticks)/HZ)&1) {
377 rb->lcd_puts(0, FIRST_LINE, player_info);
378 } else {
379 rb->lcd_puts(0, FIRST_LINE, player_info);
382 rb->lcd_puts(0, FIRST_LINE, (unsigned char *)player_info);
383 now=*rb->current_tick;
384 if (!pause) {
385 ticks+=now-last_tick;
386 if ((max_ticks-ticks)/HZ == 10) {
387 /* Backlight on if 10 seconds remain */
388 rb->backlight_on();
391 last_tick=now;
392 if (round_time) {
393 rb->snprintf(buf, sizeof(buf), "%s/",
394 show_time((max_ticks-ticks+HZ-1)/HZ));
395 /* Append total time */
396 rb->strcpy(&buf[rb->strlen(buf)],
397 show_time((timer_holder[nr].total_time*HZ-
398 timer_holder[nr].used_time-
399 ticks+HZ-1)/HZ));
400 rb->lcd_puts(0, FIRST_LINE+1, (unsigned char *)buf);
401 } else {
402 rb->lcd_puts(0, FIRST_LINE+1,
403 (unsigned char *)show_time((max_ticks-ticks+HZ-1)/HZ));
406 rb->lcd_update();
408 button = rb->button_get(false);
409 switch (button) {
410 /* OFF/ON key to exit */
411 case CHC_QUIT:
412 return -1; /* Indicate exit */
414 /* PLAY = Stop/Start toggle */
415 case CHC_STARTSTOP:
416 pause=!pause;
417 #ifdef HAVE_LCD_CHARCELLS
418 rb->lcd_icon(ICON_PAUSE, pause);
419 #else
420 show_pause_mode(pause);
421 #endif
422 break;
424 /* LEFT = Reset timer */
425 case CHC_RESET:
426 ticks=0;
427 break;
429 /* MENU */
430 case CHC_MENU:
432 int ret;
433 char *menu[]={"Delete player", "Restart round",
434 "Set round time", "Set total time"};
435 ret=simple_menu(4, (unsigned char **)menu);
436 if (ret==-1) {
437 retval = 3;
438 done=true;
439 } else if (ret==-2) {
440 } else if (ret==0) {
441 /* delete timer */
442 timer_holder[nr].hidden=true;
443 retval=1;
444 done=true;
445 break;
446 } else if (ret==1) {
447 /* restart */
448 ticks=0;
449 break;
450 } else if (ret==2) {
451 /* set round time */
452 int res;
453 int val=(max_ticks-ticks)/HZ;
454 res=chessclock_set_int("Round time",
455 &val,
456 10, 0, MAX_TIME,
457 FLAGS_SET_INT_SECONDS);
458 if (res==-1) { /*usb*/
459 retval = 3;
460 done=true;
461 } else if (res==1) {
462 ticks=max_ticks-val*HZ;
464 } else if (ret==3) {
465 /* set total time */
466 int res;
467 int val=timer_holder[nr].total_time;
468 res=chessclock_set_int("Total time",
469 &val,
470 10, 0, MAX_TIME,
471 FLAGS_SET_INT_SECONDS);
472 if (res==-1) { /*usb*/
473 retval = 3;
474 done=true;
475 } else if (res==1) {
476 timer_holder[nr].total_time=val;
480 break;
482 /* UP (RIGHT/+) = Scroll Lap timer up */
483 case CHC_SETTINGS_INC:
484 retval = 1;
485 done = true;
486 break;
488 /* DOWN (LEFT/-) = Scroll Lap timer down */
489 case CHC_SETTINGS_DEC:
490 retval = 2;
491 done = true;
492 break;
494 default:
495 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) {
496 retval = 3; /* been in usb mode */
497 done = true;
499 break;
501 rb->sleep(HZ/4); /* Sleep 1/4 of a second */
504 timer_holder[nr].used_time+=ticks;
506 return retval;
509 static int chessclock_set_int(char* string,
510 int* variable,
511 int step,
512 int min,
513 int max,
514 int flags)
516 bool done = false;
517 int button;
519 rb->lcd_clear_display();
520 rb->lcd_puts_scroll(0, FIRST_LINE, (unsigned char *)string);
522 while (!done) {
523 char str[32];
524 if (flags & FLAGS_SET_INT_SECONDS)
525 rb->snprintf(str, sizeof str,"%s (m:s)", show_time(*variable));
526 else
527 rb->snprintf(str, sizeof str,"%d", *variable);
528 rb->lcd_puts(0, FIRST_LINE+1, (unsigned char *)str);
529 rb->lcd_update();
531 button = rb->button_get(true);
532 switch(button) {
533 case CHC_SETTINGS_INC:
534 case CHC_SETTINGS_INC | BUTTON_REPEAT:
535 *variable += step;
536 break;
538 case CHC_SETTINGS_DEC:
539 case CHC_SETTINGS_DEC | BUTTON_REPEAT:
540 *variable -= step;
541 break;
543 case CHC_SETTINGS_OK:
544 #ifdef CHC_SETTINGS_OK2
545 case CHC_SETTINGS_OK2:
546 #endif
547 done = true;
548 break;
550 case CHC_SETTINGS_CANCEL:
551 #ifdef CHC_SETTINGS_CANCEL2
552 case CHC_SETTINGS_CANCEL2:
553 #endif
554 return 0; /* cancel */
555 break;
557 default:
558 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
559 return -1; /* been in usb mode */
560 break;
563 if(*variable > max )
564 *variable = max;
566 if(*variable < min )
567 *variable = min;
570 rb->lcd_stop_scroll();
572 return 1;
575 static char * show_time(int seconds)
577 static char buf[]="00:00";
578 rb->snprintf(buf, sizeof(buf), "%02d:%02d", seconds/60, seconds%60);
579 return buf;
582 /* -1 = USB
583 -2 = cancel
585 static int simple_menu(int nr, unsigned char **strarr)
587 int show=0;
588 int button;
589 rb->lcd_clear_display();
591 while (1) {
592 if (show>=nr)
593 show=0;
594 if (show<0)
595 show=nr-1;
596 rb->lcd_puts_scroll(0, FIRST_LINE, strarr[show]);
597 rb->lcd_update();
599 button = rb->button_get(true);
600 switch(button) {
601 case CHC_SETTINGS_INC:
602 case CHC_SETTINGS_INC | BUTTON_REPEAT:
603 show++;
604 break;
606 case CHC_SETTINGS_DEC:
607 case CHC_SETTINGS_DEC | BUTTON_REPEAT:
608 show--;
609 break;
611 case CHC_SETTINGS_OK:
612 #ifdef CHC_SETTINGS_OK2
613 case CHC_SETTINGS_OK2:
614 #endif
615 return show;
616 break;
618 case CHC_SETTINGS_CANCEL:
619 #ifdef CHC_SETTINGS_CANCEL2
620 case CHC_SETTINGS_CANCEL2:
621 #endif
622 return -2; /* cancel */
623 break;
625 default:
626 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
627 return -1; /* been in usb mode */
628 break;