add HAVE_DISK_STORAGE, and use that instead of HAVE_FLASH_STORAGE when checking for...
[kugel-rb.git] / apps / plugins / calendar.c
blob8fb9b7a61a2842df4b8c6c08307f8f11b7859152
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 * (based upon 1.1 by calpefrosch) updated by www.HuwSy.ukhackers.net
11 * Copyright (C) 2002
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
22 #include "plugin.h"
24 #if defined(HAVE_LCD_BITMAP) && (CONFIG_RTC != 0)
26 #include <timefuncs.h>
28 PLUGIN_HEADER
30 static const struct plugin_api* rb;
32 static bool leap_year;
33 static const int days_in_month[2][13] = {
34 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
35 {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
38 struct today {
39 int mday; /* day of the month */
40 int mon; /* month */
41 int year; /* year since 1900 */
42 int wday; /* day of the week */
45 struct shown {
46 int mday; /* day of the month */
47 int mon; /* month */
48 int year; /* year since 1900 */
49 int wday; /* day of the week */
50 int firstday; /* first (w)day of month */
51 int lastday; /* last (w)day of month */
54 static bool use_system_font = false;
56 static bool been_in_usb_mode = false;
58 /* leap year -- account for gregorian reformation in 1752 */
59 static int is_leap_year(int yr)
61 return ((yr) <= 1752 ? !((yr) % 4) : \
62 (!((yr) % 4) && ((yr) % 100)) || !((yr) % 400)) ? 1:0 ;
65 /* searches the weekday of the first day in month,
66 * relative to the given values */
67 static int calc_weekday( struct shown *shown )
69 return ( shown->wday + 36 - shown->mday ) % 7 ;
73 static void calendar_init(struct today *today, struct shown *shown)
75 int w,h;
76 #if CONFIG_RTC
77 struct tm *tm;
78 #else
79 (void)today;
80 #endif
81 rb->lcd_getstringsize("A",&w,&h);
82 if ( ((w * 14) > LCD_WIDTH) || ((h * 7) > LCD_HEIGHT) )
84 rb->lcd_setfont(FONT_SYSFIXED);
85 use_system_font = true;
87 rb->lcd_clear_display();
88 #if CONFIG_RTC
89 tm = rb->get_time();
90 today->mon = tm->tm_mon +1;
91 today->year = 2000+tm->tm_year%100;
92 today->wday = tm->tm_wday-1;
93 today->mday = tm->tm_mday;
94 shown->mday = today->mday;
95 shown->mon = today->mon;
96 shown->year = today->year;
97 shown->wday = today->wday;
98 #endif
99 shown->firstday = calc_weekday(shown);
100 leap_year = is_leap_year(shown->year);
103 static int space = LCD_WIDTH / 7;
104 static void draw_headers(void)
106 int i,w,h;
107 const char *Dayname[7] = {"M","T","W","T","F","S","S"};
108 int ws = 2;
109 rb->lcd_getstringsize("A",&w,&h);
110 for (i = 0; i < 7; i++)
112 rb->lcd_putsxy(ws, 0 , Dayname[i]);
113 ws += space;
115 rb->lcd_hline(0, LCD_WIDTH-1 ,h);
118 static bool day_has_memo[32];
119 static bool wday_has_memo[7];
120 static void draw_calendar(struct shown *shown)
122 int w,h;
123 int ws,row,pos,days_per_month,j;
124 char buffer[9];
125 const char *Monthname[] = {
126 "Jan",
127 "Feb",
128 "Mar",
129 "Apr",
130 "May",
131 "Jun",
132 "Jul",
133 "Aug",
134 "Sep",
135 "Oct",
136 "Nov",
137 "Dec"
139 rb->lcd_getstringsize("A",&w,&h);
140 rb->lcd_clear_display();
141 draw_headers();
142 if (shown->firstday > 6)
143 shown->firstday -= 7;
144 row = 1;
145 pos = shown->firstday;
146 days_per_month = days_in_month[leap_year][shown->mon];
147 ws = 2 + (pos * space);
148 for (j = 0; j < days_per_month;)
150 if ( (day_has_memo[++j]) || (wday_has_memo[pos]) )
151 rb->snprintf(buffer,4,"%02d.", j);
152 else
153 rb->snprintf(buffer,4,"%02d", j);
154 rb->lcd_putsxy(ws, (row * h) + 5 ,buffer);
155 if (shown->mday == j)
157 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
158 rb->lcd_fillrect(ws, row*h+5, space, h);
159 rb->lcd_set_drawmode(DRMODE_SOLID);
160 shown->wday = pos;
162 ws += space;
163 pos++;
164 if (pos >= 7)
166 row++;
167 pos = 0;
168 ws = 2;
171 rb->lcd_vline(60,LCD_HEIGHT-h-3,LCD_HEIGHT-1);
172 rb->lcd_hline(60,LCD_WIDTH-1,LCD_HEIGHT-h-3);
173 rb->snprintf(buffer,9,"%s %04d",Monthname[shown->mon-1],shown->year);
174 rb->lcd_putsxy(62,(LCD_HEIGHT-h-1),buffer);
175 shown->lastday = pos;
176 rb->lcd_update();
179 #define MAX_CHAR_MEMO_LEN 63
180 #define MAX_MEMOS_IN_A_MONTH 127
181 struct memo {
182 char message[MAX_CHAR_MEMO_LEN];
183 int day;
184 int month;
185 int file_pointer_start;
186 int file_pointer_end;
187 int year;
188 int wday;
189 int type;
190 } memos[MAX_MEMOS_IN_A_MONTH];
191 static int pointer_array[MAX_MEMOS_IN_A_MONTH];
192 static int memos_in_memory = 0;
193 static int memos_in_shown_memory = 0;
195 static void load_memo(struct shown *shown)
197 int i, k, fp;
198 bool exit = false;
199 char temp_memo1[2];
200 char temp_memo2[3];
201 char temp_memo4[5];
202 for (k = 0; k < memos_in_memory; k++)
204 memos[k].day = 0;
205 memos[k].month = 0;
206 memos[k].file_pointer_start = 0;
207 memos[k].file_pointer_end = 0;
208 memos[k].year = 0;
209 memos[k].type = 0;
210 memos[k].wday = 0;
211 for (i = 0; i <= MAX_CHAR_MEMO_LEN; i++)
212 rb->strcpy(&memos[k].message[i],"");
214 for (k = 1; k < 32; k++)
215 day_has_memo[k] = false;
216 for (k = 0; k < 7; k++)
217 wday_has_memo[k] = false;
218 memos_in_memory = 0;
219 fp = rb->open(ROCKBOX_DIR "/.memo",O_RDONLY);
220 if (fp > -1)
222 int count = rb->filesize(fp);
223 rb->lseek(fp, 0, SEEK_SET);
224 while (!exit)
226 memos[memos_in_memory].file_pointer_start = rb->lseek(fp, 0,
227 SEEK_CUR);
228 if (rb->read(fp, temp_memo2, 2) == 2)
229 memos[memos_in_memory].day = rb->atoi(&temp_memo2[0]);
230 else
231 memos[memos_in_memory].day = 0;
232 if (rb->read(fp, temp_memo2, 2) == 2)
233 memos[memos_in_memory].month = rb->atoi(&temp_memo2[0]);
234 else
235 memos[memos_in_memory].month = 0;
236 if (rb->read(fp, temp_memo4, 4) == 4)
237 memos[memos_in_memory].year = rb->atoi(&temp_memo4[0]);
238 else
239 memos[memos_in_memory].year = 0;
240 /* as the year returned is sometimes yearmonth, ie if yr should =
241 2003, and month = 06, then it returns 200306 */
242 if (memos[memos_in_memory].year > (shown->year * 10))
243 memos[memos_in_memory].year = (memos[memos_in_memory].year -
244 memos[memos_in_memory].month) /
245 100;
246 if (rb->read(fp, temp_memo1, 1) == 1)
247 memos[memos_in_memory].wday = rb->atoi(&temp_memo1[0]);
248 else
249 memos[memos_in_memory].wday = 0;
250 if (rb->read(fp, temp_memo1, 1) == 1)
251 memos[memos_in_memory].type = rb->atoi(&temp_memo1[0]);
252 else
253 memos[memos_in_memory].type = 0;
254 for (k = 0; k <= count; k++)
256 if (rb->read(fp, temp_memo1, 1) == 1)
258 if (
259 (memos[memos_in_memory].type < 2)
262 (memos[memos_in_memory].type == 2)
264 (memos[memos_in_memory].month == shown->mon)
268 (memos[memos_in_memory].type > 2)
270 (memos[memos_in_memory].month == shown->mon)
272 (memos[memos_in_memory].year == shown->year)
276 if (temp_memo1[0] == '\n')
278 if (memos[memos_in_memory].type > 0)
279 day_has_memo[memos[memos_in_memory].day] =
280 true;
281 else
282 wday_has_memo[memos[memos_in_memory].wday] =
283 true;
284 memos[memos_in_memory++].file_pointer_end =
285 rb->lseek(fp, 0, SEEK_CUR);
287 else if ( (temp_memo1[0] != '\r') &&
288 (temp_memo1[0] != '\t') )
289 memos[memos_in_memory].message[k] = temp_memo1[0];
291 if (temp_memo1[0] == '\n')
292 break;
294 else
296 memos[memos_in_memory].day = 0;
297 memos[memos_in_memory].month = 0;
298 memos[memos_in_memory].file_pointer_start = 0;
299 memos[memos_in_memory].file_pointer_end = 0;
300 memos[memos_in_memory].year = 0;
301 memos[memos_in_memory].type = 0;
302 memos[memos_in_memory].wday = 0;
303 rb->strcpy(&memos[memos_in_memory].message[0], "");
304 exit = true;
305 break;
310 rb->close(fp);
313 static bool save_memo(int changed, bool new_mod, struct shown *shown)
315 int fp,fq;
316 fp = rb->open(ROCKBOX_DIR "/.memo",O_RDONLY | O_CREAT);
317 fq = rb->creat(ROCKBOX_DIR "/~temp");
318 if ( (fq != -1) && (fp != -1) )
320 int i;
321 char temp[MAX_CHAR_MEMO_LEN + 1];
322 rb->lseek(fp, 0, SEEK_SET);
323 for (i = 0; i < memos[changed].file_pointer_start; i++)
325 rb->read(fp, temp, 1);
326 rb->write(fq,temp,1);
328 if (new_mod)
330 rb->fdprintf(fq, "%02d%02d%04d%01d%01d%s\n",
331 memos[changed].day,
332 memos[changed].month,
333 memos[changed].year,
334 memos[changed].wday,
335 memos[changed].type,
336 memos[changed].message);
338 rb->lseek(fp, memos[changed].file_pointer_end, SEEK_SET);
339 for (i = memos[changed].file_pointer_end;
340 i < rb->filesize(fp); i++)
342 rb->read(fp, temp, 1);
343 rb->write(fq,temp,1);
345 rb->close(fp);
346 fp = rb->creat(ROCKBOX_DIR "/.memo");
347 rb->lseek(fp, 0, SEEK_SET);
348 rb->lseek(fq, 0, SEEK_SET);
349 for (i = 0; i < rb->filesize(fq); i++)
351 rb->read(fq, temp, 1);
352 rb->write(fp,temp,1);
354 rb->close(fp);
355 rb->close(fq);
356 rb->remove(ROCKBOX_DIR "/~temp");
357 load_memo(shown);
358 return true;
360 else if (fp != -1)
361 rb->close(fp);
362 else if (fq != -1)
363 rb->close(fq);
364 return false;
367 static void add_memo(struct shown *shown, int type)
369 bool saved = false;
370 if (rb->kbd_input(memos[memos_in_memory].message,
371 sizeof memos[memos_in_memory].message) != -1)
373 if (rb->strlen(memos[memos_in_memory].message))
375 memos[memos_in_memory].file_pointer_start = 0;
376 memos[memos_in_memory].file_pointer_end = 0;
377 memos[memos_in_memory].day = shown->mday;
378 memos[memos_in_memory].month = shown->mon;
379 memos[memos_in_memory].wday = shown->wday;
380 memos[memos_in_memory].year = shown->year;
381 memos[memos_in_memory].type = type;
382 if (save_memo(memos_in_memory,true,shown))
384 saved = true;
385 memos_in_memory++;
387 else
389 memos[memos_in_memory].file_pointer_start = 0;
390 memos[memos_in_memory].file_pointer_end = 0;
391 memos[memos_in_memory].day = 0;
392 memos[memos_in_memory].month = 0;
393 memos[memos_in_memory].year = 0;
394 memos[memos_in_memory].type = 0;
395 memos[memos_in_memory].wday = 0;
399 rb->lcd_clear_display();
400 if(use_system_font)
401 rb->lcd_setfont(FONT_SYSFIXED);
402 if (saved)
403 rb->lcd_puts(0,0,"Event added");
404 else
405 rb->lcd_puts(0,0,"Event not added");
406 rb->lcd_update();
407 rb->sleep(HZ/2);
410 static bool edit_memo(int change, struct shown *shown)
412 bool exit = false;
413 int button;
415 while (!exit)
417 rb->lcd_clear_display();
418 if (memos_in_shown_memory > 0)
420 rb->lcd_puts(0,0,"Remove : Up");
421 rb->lcd_puts(0,1,"Edit : Down");
422 rb->lcd_puts(0,2,"New :");
423 rb->lcd_puts(2,3,"weekly : Left");
424 rb->lcd_puts(2,4,"monthly : Play");
425 rb->lcd_puts(2,5,"annually : Right");
426 rb->lcd_puts(2,6,"one off : On");
428 else
430 rb->lcd_puts(0,0,"New :");
431 rb->lcd_puts(2,1,"weekly : Left");
432 rb->lcd_puts(2,2,"monthly : Play");
433 rb->lcd_puts(2,3,"annually : Right");
434 rb->lcd_puts(2,4,"one off : On");
436 rb->lcd_update();
437 button = rb->button_get(true);
438 switch (button)
440 case BUTTON_OFF:
441 return false;
443 case BUTTON_LEFT:
444 add_memo(shown,0);
445 return false;
447 case BUTTON_PLAY:
448 add_memo(shown,1);
449 return false;
451 case BUTTON_RIGHT:
452 add_memo(shown,2);
453 return false;
455 case BUTTON_ON:
456 add_memo(shown,3);
457 return false;
459 case BUTTON_DOWN:
460 if (memos_in_shown_memory > 0)
462 if(rb->kbd_input(memos[pointer_array[change]].message,
463 sizeof memos[pointer_array[change]].message) != -1)
464 save_memo(pointer_array[change],true,shown);
465 if(use_system_font)
466 rb->lcd_setfont(FONT_SYSFIXED);
467 exit = true;
469 break;
471 case BUTTON_UP:
472 if (memos_in_shown_memory > 0)
474 save_memo(pointer_array[change],false,shown);
475 exit = true;
477 break;
479 default:
480 if(rb->default_event_handler(button) == SYS_USB_CONNECTED)
481 been_in_usb_mode = true;
482 break;
485 return false;
488 static int start = 0;
490 static void show_lines(int selected, struct shown *shown)
492 int lines,j = 1,w,h,i,k = 0, pos = 1,m = 0;
493 char temp[MAX_CHAR_MEMO_LEN + 12];
494 rb->lcd_getstringsize("A",&w,&h);
495 lines = (LCD_HEIGHT / h) - 1;
497 rb->lcd_clear_display();
498 rb->lcd_puts(0,0,"Events (play : menu)");
500 while (selected >= (lines + start))
501 start++;
502 while (selected < start)
503 start--;
504 i = start;
505 while ( (i < memos_in_shown_memory) && (k < lines) )
507 if (memos[pointer_array[i]].type == 2)
508 rb->snprintf(temp, sizeof temp, "%s (%d yrs)",
509 memos[pointer_array[i]].message,
510 shown->year - memos[pointer_array[i]].year);
511 else
512 rb->snprintf(temp, sizeof temp, "%s",
513 memos[pointer_array[i]].message);
514 m = 0;
515 if (i == selected)
517 pos = k + 1;
518 rb->lcd_puts_scroll(m,j++,temp);
520 else
521 rb->lcd_puts(m,j++,temp);
522 k++;
523 i++;
525 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
526 rb->lcd_fillrect(0, (pos) * h, LCD_WIDTH, h);
527 rb->lcd_set_drawmode(DRMODE_SOLID);
530 static void update_memos_shown(struct shown *shown)
532 int i;
533 memos_in_shown_memory = 0;
534 start = 0;
535 for (i = 0; i < memos_in_memory; i++)
536 if (
537 (memos[i].day == shown->mday)
540 (memos[i].type < 1)
542 (memos[i].wday == shown->wday)
545 pointer_array[memos_in_shown_memory++] = i;
548 static bool any_events(struct shown *shown, bool force)
550 int lines_displayed = 0;
551 bool exit=false;
552 int button;
554 update_memos_shown(shown);
555 if (memos_in_shown_memory > 0)
556 show_lines(lines_displayed,shown);
557 else if (force)
558 return edit_memo(lines_displayed, shown);
559 else
560 return false;
561 rb->lcd_update();
562 while (!exit)
564 button = rb->button_get(true);
565 switch (button)
567 case BUTTON_DOWN:
568 if (memos_in_shown_memory > 0)
570 lines_displayed++;
571 if (lines_displayed >= memos_in_shown_memory)
572 lines_displayed = memos_in_shown_memory - 1;
573 show_lines(lines_displayed,shown);
574 rb->lcd_update();
576 break;
578 case BUTTON_UP:
579 if (memos_in_shown_memory > 0)
581 lines_displayed--;
582 if (lines_displayed < 0)
583 lines_displayed = 0;
584 show_lines(lines_displayed,shown);
585 rb->lcd_update();
587 break;
589 case BUTTON_PLAY:
590 return edit_memo(lines_displayed, shown);
592 case BUTTON_OFF:
593 return false;
595 default:
596 if(rb->default_event_handler(button) == SYS_USB_CONNECTED)
597 been_in_usb_mode = true;
598 show_lines(lines_displayed,shown);
599 rb->lcd_update();
600 break;
603 return false;
606 static void next_month(struct shown *shown, int step)
608 shown->mon++;
609 if (shown->mon > 12)
611 shown->mon=1;
612 shown->year++;
613 leap_year = is_leap_year(shown->year);
615 else if (step > 0)
616 shown->mday = shown->mday - days_in_month[leap_year][shown->mon-1];
617 else if (shown->mday > days_in_month[leap_year][shown->mon])
618 shown->mday = days_in_month[leap_year][shown->mon];
619 shown->firstday = shown->lastday;
620 load_memo(shown);
621 draw_calendar(shown);
624 static void prev_month(struct shown *shown, int step)
626 shown->mon--;
627 if (shown->mon < 1)
629 shown->mon = 12;
630 shown->year--;
631 leap_year = is_leap_year(shown->year);
633 if (step > 0)
634 shown->mday = shown->mday + days_in_month[leap_year][shown->mon];
635 else if (shown->mday > days_in_month[leap_year][shown->mon])
636 shown->mday = days_in_month[leap_year][shown->mon];
637 shown->firstday += 7 - (days_in_month[leap_year][shown->mon] % 7);
638 load_memo(shown);
639 draw_calendar(shown);
642 static void next_day(struct shown *shown, int step)
644 shown->mday += step;
645 if (shown->mday > days_in_month[leap_year][shown->mon])
646 next_month(shown, step);
647 else
648 draw_calendar(shown);
651 static void prev_day(struct shown *shown, int step)
653 shown->mday -= step;
654 if (shown->mday < 1)
655 prev_month(shown, step);
656 else
657 draw_calendar(shown);
660 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
662 struct today today;
663 struct shown shown;
664 bool exit = false;
665 int button;
667 (void)(parameter);
669 rb = api;
671 calendar_init(&today, &shown);
672 load_memo(&shown);
673 any_events(&shown, false);
674 draw_calendar(&shown);
675 while (!exit)
677 button = rb->button_get(true);
678 switch (button)
680 case BUTTON_OFF:
681 return false;
683 case BUTTON_ON | BUTTON_DOWN:
684 case BUTTON_ON | BUTTON_DOWN | BUTTON_REPEAT:
685 next_month(&shown, 0);
686 break;
688 case BUTTON_ON | BUTTON_UP:
689 case BUTTON_ON | BUTTON_UP | BUTTON_REPEAT:
690 prev_month(&shown, 0);
691 break;
693 case BUTTON_DOWN:
694 case BUTTON_DOWN | BUTTON_REPEAT:
695 next_day(&shown, 7);
696 break;
698 case BUTTON_UP:
699 case BUTTON_UP | BUTTON_REPEAT:
700 prev_day(&shown, 7);
701 break;
703 case BUTTON_LEFT:
704 case BUTTON_LEFT | BUTTON_REPEAT:
705 prev_day(&shown, 1);
706 break;
708 case BUTTON_RIGHT:
709 case BUTTON_RIGHT | BUTTON_REPEAT:
710 next_day(&shown, 1);
711 break;
713 case BUTTON_PLAY:
714 any_events(&shown, true);
715 draw_calendar(&shown);
716 break;
718 default:
719 if(rb->default_event_handler(button) == SYS_USB_CONNECTED)
720 been_in_usb_mode = true;
721 draw_calendar(&shown);
722 break;
725 return been_in_usb_mode?PLUGIN_USB_CONNECTED:PLUGIN_OK;
728 #endif