summaryrefslogtreecommitdiff
path: root/apps/plugins/calendar.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/calendar.c')
-rw-r--r--apps/plugins/calendar.c722
1 files changed, 722 insertions, 0 deletions
diff --git a/apps/plugins/calendar.c b/apps/plugins/calendar.c
new file mode 100644
index 0000000000..448c1a824f
--- /dev/null
+++ b/apps/plugins/calendar.c
@@ -0,0 +1,722 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 * (based upon 1.1 by calpefrosch) www.HuwSy.ukhackers.net
10 *
11 * Copyright (C) 2002
12 *
13 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
15 *
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
18 *
19 ****************************************************************************/
20#include "plugin.h"
21
22#ifdef HAVE_LCD_BITMAP
23
24#include <timefuncs.h>
25
26static struct plugin_api* rb;
27
28static bool leap_year;
29static int days_in_month[2][13] = {
30 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
31 {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
32};
33
34struct today {
35 int mday; /* day of the month */
36 int mon; /* month */
37 int year; /* year since 1900 */
38 int wday; /* day of the week */
39};
40
41struct shown {
42 int mday; /* day of the month */
43 int mon; /* month */
44 int year; /* year since 1900 */
45 int wday; /* day of the week */
46 int firstday; /* first (w)day of month */
47 int lastday; /* last (w)day of month */
48};
49
50/* leap year -- account for gregorian reformation in 1752 */
51static int is_leap_year(int yr)
52{
53 return ((yr) <= 1752 ? !((yr) % 4) : \
54 (!((yr) % 4) && ((yr) % 100)) || !((yr) % 400)) ? 1:0 ;
55}
56
57/* searches the weekday of the first day in month, relative to the given values */
58static int calc_weekday( struct shown *shown )
59{
60 return ( shown->wday + 36 - shown->mday ) % 7 ;
61
62}
63
64static void calendar_init(struct today *today, struct shown *shown)
65{
66 int w,h;
67 rb->lcd_getstringsize("A",&w,&h);
68 if ( ((w * 14) > LCD_WIDTH) || ((h * 7) > LCD_HEIGHT) )
69 rb->lcd_setfont(FONT_SYSFIXED);
70 rb->lcd_clear_display();
71#ifdef HAVE_RTC
72 struct tm *tm;
73 tm = rb->get_time();
74 today->mon = tm->tm_mon +1;
75 today->year = 2000+tm->tm_year%100;
76 today->wday = tm->tm_wday-1;
77 today->mday = tm->tm_mday;
78#ifdef SIMULATOR
79 today->wday = 3;
80 today->mday = 13;
81#endif
82 shown->mday = today->mday;
83 shown->mon = today->mon;
84 shown->year = today->year;
85 shown->wday = today->wday;
86#endif
87 shown->firstday = calc_weekday(shown);
88 leap_year = is_leap_year(shown->year);
89}
90
91static int space = LCD_WIDTH / 7;
92static void draw_headers(void)
93{
94 int i,w,h;
95 rb->lcd_getstringsize("A",&w,&h);
96 char *Dayname[7] = {"M","T","W","T","F","S","S"};
97 int ws = 2;
98 for (i = 0; i < 8;)
99 {
100 rb->lcd_putsxy(ws, 0 , Dayname[i++]);
101 ws += space;
102 }
103 rb->lcd_drawline(0 ,h ,LCD_WIDTH ,h);
104}
105
106static bool day_has_memo[31];
107static bool wday_has_memo[6];
108static void draw_calendar(struct shown *shown)
109{
110 int w,h;
111 rb->lcd_getstringsize("A",&w,&h);
112 char *Monthname[] = {
113 "Jan",
114 "Feb",
115 "Mar",
116 "Apr",
117 "May",
118 "Jun",
119 "Jul",
120 "Aug",
121 "Sep",
122 "Oct",
123 "Nov",
124 "Dec"
125 };
126 rb->lcd_clear_display();
127 draw_headers();
128 int row,pos,days_per_month,j;
129 if (shown->firstday > 6)
130 shown->firstday -= 7;
131 char buffer[7];
132 row = 1;
133 pos = shown->firstday;
134 days_per_month = days_in_month[leap_year][shown->mon];
135 int ws = 2 + (pos * space);
136 for (j = 0; j < days_per_month;)
137 {
138 if ( (day_has_memo[++j]) || (wday_has_memo[pos]) )
139 rb->snprintf(buffer,3,"%02d.", j);
140 else
141 rb->snprintf(buffer,3,"%02d", j);
142 rb->lcd_putsxy(ws, (row * h) + 5 ,buffer);
143 if (shown->mday == j)
144 {
145 rb->lcd_invertrect(ws, row*h+5, space, h);
146 shown->wday = pos;
147 }
148 ws += space;
149 pos++;
150 if (pos >= 7)
151 {
152 row++;
153 pos = 0;
154 ws = 2;
155 }
156 }
157 rb->lcd_drawline(60,LCD_HEIGHT-h-3,60,LCD_HEIGHT-1);
158 rb->lcd_drawline(60,LCD_HEIGHT-h-3,LCD_WIDTH-1,LCD_HEIGHT-h-3);
159 rb->snprintf(buffer,8,"%s %04d",Monthname[shown->mon-1],shown->year);
160 rb->lcd_putsxy(62,(LCD_HEIGHT-h-1),buffer);
161 shown->lastday = pos;
162 rb->lcd_update();
163}
164
165#define MAX_CHAR_MEMO_LEN 63
166#define MAX_MEMOS_IN_A_MONTH 127
167struct memo {
168 char message[MAX_CHAR_MEMO_LEN];
169 int day;
170 int month;
171 int file_pointer_start;
172 int file_pointer_end;
173 int year;
174 int wday;
175 int type;
176} memos[MAX_MEMOS_IN_A_MONTH];
177static int pointer_array[MAX_MEMOS_IN_A_MONTH];
178static int memos_in_memory = 0;
179static int memos_in_shown_memory = 0;
180static void load_memo(struct shown *shown)
181{
182 int i, k, fp;
183 bool exit = false;
184 char temp_memo0[0];
185 char temp_memo1[1];
186 char temp_memo3[3];
187 for (k = 0; k < memos_in_memory; k++)
188 {
189 memos[k].day = 0;
190 memos[k].month = 0;
191 memos[k].file_pointer_start = 0;
192 memos[k].file_pointer_end = 0;
193 memos[k].year = 0;
194 memos[k].type = 0;
195 memos[k].wday = 0;
196 for (i = 0; i <= MAX_CHAR_MEMO_LEN; i++)
197 rb->strcpy(&memos[k].message[i],"");
198 }
199 for (k = 1; k < 32; k++)
200 day_has_memo[k] = false;
201 for (k = 0; k < 7; k++)
202 wday_has_memo[k] = false;
203 memos_in_memory = 0;
204 fp = rb->open("/.rockbox/.memo",O_RDONLY);
205 if (fp > -1)
206 {
207 int count = rb->filesize(fp);
208 rb->lseek(fp, 0, SEEK_SET);
209 while (!exit)
210 {
211 memos[memos_in_memory].file_pointer_start = rb->lseek(fp, 0,
212 SEEK_CUR);
213 if (rb->read(fp, temp_memo1, 2) == 2)
214 memos[memos_in_memory].day = rb->atoi(&temp_memo1[0]);
215 else
216 memos[memos_in_memory].day = 0;
217 if (rb->read(fp, temp_memo1, 2) == 2)
218 memos[memos_in_memory].month = rb->atoi(&temp_memo1[0]);
219 else
220 memos[memos_in_memory].month = 0;
221 if (rb->read(fp, temp_memo3, 4) == 4)
222 memos[memos_in_memory].year = rb->atoi(&temp_memo3[0]);
223 else
224 memos[memos_in_memory].year = 0;
225 /* as the year returned is sometimes yearmonth, ie if yr should =
226 2003, and month = 06, then it returns 200306 */
227 if (memos[memos_in_memory].year > (shown->year * 10))
228 memos[memos_in_memory].year = (memos[memos_in_memory].year -
229 memos[memos_in_memory].month) /
230 100;
231 if (rb->read(fp, temp_memo0, 1) == 1)
232 memos[memos_in_memory].wday = rb->atoi(&temp_memo0[0]);
233 else
234 memos[memos_in_memory].wday = 0;
235 if (rb->read(fp, temp_memo0, 1) == 1)
236 memos[memos_in_memory].type = rb->atoi(&temp_memo0[0]);
237 else
238 memos[memos_in_memory].type = 0;
239 for (k = 0; k <= count; k++)
240 {
241 if (rb->read(fp, temp_memo0, 1) == 1)
242 {
243 if (
244 (memos[memos_in_memory].type < 2)
245 ||
246 (
247 (memos[memos_in_memory].type == 2)
248 &&
249 (memos[memos_in_memory].month == shown->mon)
250 )
251 ||
252 (
253 (memos[memos_in_memory].type > 2)
254 &&
255 (memos[memos_in_memory].month == shown->mon)
256 &&
257 (memos[memos_in_memory].year == shown->year)
258 )
259 )
260 {
261 if (temp_memo0[0] == '\n')
262 {
263 if (memos[memos_in_memory].type > 0)
264 day_has_memo[memos[memos_in_memory].day] =
265 true;
266 else
267 wday_has_memo[memos[memos_in_memory].wday] =
268 true;
269 memos[memos_in_memory++].file_pointer_end =
270 rb->lseek(fp, 0, SEEK_CUR);
271 }
272 else if ( (temp_memo0[0] != '\r') &&
273 (temp_memo0[0] != '\t') )
274 memos[memos_in_memory].message[k] = temp_memo0[0];
275 }
276 if (temp_memo0[0] == '\n')
277 break;
278 }
279 else
280 {
281 memos[memos_in_memory].day = 0;
282 memos[memos_in_memory].month = 0;
283 memos[memos_in_memory].file_pointer_start = 0;
284 memos[memos_in_memory].file_pointer_end = 0;
285 memos[memos_in_memory].year = 0;
286 memos[memos_in_memory].type = 0;
287 memos[memos_in_memory].wday = 0;
288 rb->strcpy(&memos[memos_in_memory].message[0], "");
289 exit = true;
290 break;
291 }
292 }
293 }
294 }
295 rb->close(fp);
296}
297
298static bool save_memo(int changed, bool new_mod, struct shown *shown)
299{
300 int fp,fq;
301 fp = rb->open("/.rockbox/.memo",O_RDONLY | O_CREAT);
302 fq = rb->open("/.rockbox/~temp",O_RDWR | O_CREAT | O_TRUNC);
303 if ( (fq != -1) && (fp != -1) )
304 {
305 int i;
306 char temp[MAX_CHAR_MEMO_LEN + 1];
307 rb->lseek(fp, 0, SEEK_SET);
308 if ( (memos[changed].file_pointer_start == 0) &&
309 (memos[changed].file_pointer_end == 0) && (new_mod) )
310 {
311 rb->close(fp);
312 rb->close(fq);
313 fq = rb->open("/.rockbox/.memo",O_RDONLY | O_CREAT | O_APPEND);
314 rb->snprintf(temp, 2, "%02d", memos[changed].day);
315 rb->write(fq,temp,2);
316 rb->snprintf(temp, 2, "%02d", memos[changed].month);
317 rb->write(fq,temp,2);
318 rb->snprintf(temp, 4, "%04d", memos[changed].year);
319 rb->write(fq,temp,4);
320 rb->snprintf(temp, 1, "%01d", memos[changed].wday);
321 rb->write(fq,temp,1);
322 rb->snprintf(temp, 1, "%01d", memos[changed].type);
323 rb->write(fq,temp,1);
324 rb->snprintf(temp, rb->strlen(memos[changed].message)+1, "%s\n",
325 memos[changed].message);
326 rb->write(fq,temp,rb->strlen(temp));
327 }
328 else
329 {
330 for (i = 0; i < memos[changed].file_pointer_start; i++)
331 {
332 rb->read(fp, temp, 1);
333 rb->write(fq,temp,1);
334 }
335 if (new_mod)
336 {
337 rb->snprintf(temp, 2, "%02d", memos[changed].day);
338 rb->write(fq,temp,2);
339 rb->snprintf(temp, 2, "%02d", memos[changed].month);
340 rb->write(fq,temp,2);
341 rb->snprintf(temp, 4, "%04d", memos[changed].year);
342 rb->write(fq,temp,4);
343 rb->snprintf(temp, 1, "%01d", memos[changed].wday);
344 rb->write(fq,temp,1);
345 rb->snprintf(temp, 1, "%01d", memos[changed].type);
346 rb->write(fq,temp,1);
347 rb->snprintf(temp, rb->strlen(memos[changed].message)+1,
348 "%s\n", memos[changed].message);
349 rb->write(fq,temp, rb->strlen(temp));
350 }
351 rb->lseek(fp, memos[changed].file_pointer_end, SEEK_SET);
352 for (i = memos[changed].file_pointer_end;
353 i < rb->filesize(fp); i++)
354 {
355 rb->read(fp, temp, 1);
356 rb->write(fq,temp,1);
357 }
358 rb->close(fp);
359 fp = rb->open("/.rockbox/.memo",O_WRONLY | O_CREAT | O_TRUNC);
360 rb->lseek(fp, 0, SEEK_SET);
361 rb->lseek(fq, 0, SEEK_SET);
362 for (i = 0; i < rb->filesize(fq); i++)
363 {
364 rb->read(fq, temp, 1);
365 rb->write(fp,temp,1);
366 }
367 rb->close(fp);
368 }
369 rb->close(fq);
370 rb->remove("/.rockbox/~temp");
371 load_memo(shown);
372 return true;
373 }
374 else if (fp != -1)
375 rb->close(fp);
376 else if (fq != -1)
377 rb->close(fq);
378 return false;
379}
380
381static void add_memo(struct shown *shown, int type)
382{
383 bool saved = false;
384 if (rb->kbd_input(memos[memos_in_memory].message,
385 sizeof memos[memos_in_memory].message) != -1)
386 {
387 if (memos[memos_in_memory].message != "")
388 {
389 memos[memos_in_memory].file_pointer_start = 0;
390 memos[memos_in_memory].file_pointer_end = 0;
391 memos[memos_in_memory].day = shown->mday;
392 memos[memos_in_memory].month = shown->mon;
393 memos[memos_in_memory].wday = shown->wday;
394 memos[memos_in_memory].year = shown->year;
395 memos[memos_in_memory].type = type;
396 if (save_memo(memos_in_memory,true,shown))
397 {
398 saved = true;
399 memos_in_memory++;
400 }
401 else
402 {
403 memos[memos_in_memory].file_pointer_start = 0;
404 memos[memos_in_memory].file_pointer_end = 0;
405 memos[memos_in_memory].day = 0;
406 memos[memos_in_memory].month = 0;
407 memos[memos_in_memory].year = 0;
408 memos[memos_in_memory].type = 0;
409 memos[memos_in_memory].wday = 0;
410 }
411 }
412 }
413 rb->lcd_clear_display();
414 if (saved)
415 rb->lcd_puts(0,0,"Event added");
416 else
417 rb->lcd_puts(0,0,"Event not added");
418 rb->lcd_update();
419 rb->sleep(HZ/2);
420}
421
422static bool edit_memo(int change, struct shown *shown)
423{
424 bool exit = false;
425 rb->lcd_clear_display();
426 if (memos_in_shown_memory > 0)
427 {
428 rb->lcd_puts(0,0,"Remove : Up");
429 rb->lcd_puts(0,1,"Edit : Down");
430 rb->lcd_puts(0,2,"New :");
431 rb->lcd_puts(6,3,"weekly : Left");
432 rb->lcd_puts(6,4,"monthly : Play");
433 rb->lcd_puts(6,5,"annually : Right");
434 rb->lcd_puts(6,6,"one off : On");
435 }
436 else
437 {
438 rb->lcd_puts(0,0,"New :");
439 rb->lcd_puts(6,1,"weekly : Left");
440 rb->lcd_puts(6,2,"monthly : Play");
441 rb->lcd_puts(6,3,"anualy : Right");
442 rb->lcd_puts(6,4,"one off : On");
443 }
444 rb->lcd_update();
445 while (!exit)
446 {
447 switch (rb->button_get(true))
448 {
449 case BUTTON_OFF:
450 return false;
451
452 case BUTTON_LEFT:
453 add_memo(shown,0);
454 return false;
455
456 case BUTTON_PLAY:
457 add_memo(shown,1);
458 return false;
459
460 case BUTTON_RIGHT:
461 add_memo(shown,2);
462 return false;
463
464 case BUTTON_ON:
465 add_memo(shown,3);
466 return false;
467
468 case BUTTON_DOWN:
469 if (memos_in_shown_memory > 0)
470 {
471 if(rb->kbd_input(memos[pointer_array[change]].message,
472 sizeof memos[pointer_array[change]].message) != -1)
473 save_memo(pointer_array[change],true,shown);
474 exit = true;
475 }
476 break;
477
478 case BUTTON_UP:
479 if (memos_in_shown_memory > 0)
480 {
481 save_memo(pointer_array[change],false,shown);
482 exit = true;
483 }
484 break;
485
486 case SYS_USB_CONNECTED:
487 return true;
488 }
489 }
490 return false;
491}
492
493static int start = 0;
494
495static void show_lines(int selected, struct shown *shown)
496{
497 int j = 1,w,h,i,k = 0, pos = 1,m = 0;
498 rb->lcd_getstringsize("A",&w,&h);
499 int lines = (LCD_HEIGHT / h) - 1;
500 char temp[MAX_CHAR_MEMO_LEN + 12];
501
502 rb->lcd_clear_display();
503 rb->lcd_puts(0,0,"Events (play : menu)");
504
505 while (selected >= (lines + start))
506 start++;
507 while (selected < start)
508 start--;
509 i = start;
510 while ( (i < memos_in_shown_memory) && (k < lines) )
511 {
512 if (memos[pointer_array[i]].type == 2)
513 rb->snprintf(temp, sizeof temp, "%s (%d yrs)",
514 memos[pointer_array[i]].message,
515 shown->year - memos[pointer_array[i]].year);
516 else
517 rb->snprintf(temp, sizeof temp, "%s",
518 memos[pointer_array[i]].message);
519 m = 0;
520 if (i == selected)
521 {
522 pos = k + 1;
523 rb->lcd_puts_scroll(m,j++,temp);
524 }
525 else
526 rb->lcd_puts(m,j++,temp);
527 k++;
528 i++;
529 }
530 rb->lcd_invertrect(0, (pos) * h, LCD_WIDTH, h);
531}
532
533static void update_memos_shown(struct shown *shown)
534{
535 memos_in_shown_memory = 0;
536 start = 0;
537 int i;
538 for (i = 0; i < memos_in_memory; i++)
539 if (
540 (memos[i].day == shown->mday)
541 ||
542 (
543 (memos[i].type < 1)
544 &&
545 (memos[i].wday == shown->wday)
546 )
547 )
548 pointer_array[memos_in_shown_memory++] = i;
549}
550
551static bool any_events(struct shown *shown, bool force)
552{
553 update_memos_shown(shown);
554 int lines_displayed = 0;
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 bool exit = false;
563 while (!exit)
564 {
565 switch (rb->button_get(true))
566 {
567 case BUTTON_DOWN:
568 if (memos_in_shown_memory > 0)
569 {
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();
575 }
576 break;
577
578 case BUTTON_UP:
579 if (memos_in_shown_memory > 0)
580 {
581 lines_displayed--;
582 if (lines_displayed < 0)
583 lines_displayed = 0;
584 show_lines(lines_displayed,shown);
585 rb->lcd_update();
586 }
587 break;
588
589 case BUTTON_PLAY:
590 return edit_memo(lines_displayed, shown);
591
592 case BUTTON_OFF:
593 return false;
594
595 case SYS_USB_CONNECTED:
596 return true;
597 }
598 }
599 return false;
600}
601
602static void next_month(struct shown *shown, int step)
603{
604 shown->mon++;
605 if (shown->mon > 12)
606 {
607 shown->mon=1;
608 shown->year++;
609 leap_year = is_leap_year(shown->year);
610 }
611 else if (step > 0)
612 shown->mday = shown->mday - days_in_month[leap_year][shown->mon-1];
613 else if (shown->mday > days_in_month[leap_year][shown->mon])
614 shown->mday = days_in_month[leap_year][shown->mon];
615 shown->firstday = shown->lastday;
616 load_memo(shown);
617 draw_calendar(shown);
618}
619
620static void prev_month(struct shown *shown, int step)
621{
622 shown->mon--;
623 if (shown->mon < 1)
624 {
625 shown->mon = 12;
626 shown->year--;
627 leap_year = is_leap_year(shown->year);
628 }
629 if (step > 0)
630 shown->mday = shown->mday + days_in_month[leap_year][shown->mon];
631 else if (shown->mday > days_in_month[leap_year][shown->mon])
632 shown->mday = days_in_month[leap_year][shown->mon];
633 shown->firstday += 7 - (days_in_month[leap_year][shown->mon] % 7);
634 load_memo(shown);
635 draw_calendar(shown);
636}
637
638static void next_day(struct shown *shown, int step)
639{
640 shown->mday += step;
641 if (shown->mday > days_in_month[leap_year][shown->mon])
642 next_month(shown, step);
643 else
644 draw_calendar(shown);
645}
646
647static void prev_day(struct shown *shown, int step)
648{
649 shown->mday -= step;
650 if (shown->mday < 1)
651 prev_month(shown, step);
652 else
653 draw_calendar(shown);
654}
655
656enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
657{
658 TEST_PLUGIN_API(api);
659 (void)(parameter);
660 rb = api;
661
662 struct today today;
663 struct shown shown;
664
665 calendar_init(&today, &shown);
666 load_memo(&shown);
667 any_events(&shown, false);
668 draw_calendar(&shown);
669 bool exit = false;
670 while (!exit)
671 {
672 switch (rb->button_get(true))
673 {
674 case BUTTON_OFF:
675 return false;
676
677 case BUTTON_ON | BUTTON_DOWN:
678 case BUTTON_ON | BUTTON_DOWN | BUTTON_REPEAT:
679 next_month(&shown, 0);
680 break;
681
682 case BUTTON_ON | BUTTON_UP:
683 case BUTTON_ON | BUTTON_UP | BUTTON_REPEAT:
684 prev_month(&shown, 0);
685 break;
686
687 case BUTTON_DOWN:
688 case BUTTON_DOWN | BUTTON_REPEAT:
689 next_day(&shown, 7);
690 break;
691
692 case BUTTON_UP:
693 case BUTTON_UP | BUTTON_REPEAT:
694 prev_day(&shown, 7);
695 break;
696
697 case BUTTON_LEFT:
698 case BUTTON_LEFT | BUTTON_REPEAT:
699 prev_day(&shown, 1);
700 break;
701
702 case BUTTON_RIGHT:
703 case BUTTON_RIGHT | BUTTON_REPEAT:
704 next_day(&shown, 1);
705 break;
706
707 case BUTTON_PLAY:
708 if (any_events(&shown, true))
709 rb->usb_screen();
710 draw_calendar(&shown);
711 break;
712
713 case SYS_USB_CONNECTED:
714 rb->usb_screen();
715 draw_calendar(&shown);
716 break;
717 }
718 }
719 return false;
720}
721
722#endif