1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
9 * (based upon 1.1 by calpefrosch) updated by www.HuwSy.ukhackers.net
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 ****************************************************************************/
24 #if defined(HAVE_LCD_BITMAP) && (CONFIG_RTC != 0)
26 #include <timefuncs.h>
30 static const struct plugin_api
* rb
;
32 static bool leap_year
;
33 static 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},
39 int mday
; /* day of the month */
41 int year
; /* year since 1900 */
42 int wday
; /* day of the week */
46 int mday
; /* day of the 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
)
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();
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
;
98 shown
->mday
= today
->mday
;
99 shown
->mon
= today
->mon
;
100 shown
->year
= today
->year
;
101 shown
->wday
= today
->wday
;
103 shown
->firstday
= calc_weekday(shown
);
104 leap_year
= is_leap_year(shown
->year
);
107 static int space
= LCD_WIDTH
/ 7;
108 static void draw_headers(void)
111 char *Dayname
[7] = {"M","T","W","T","F","S","S"};
113 rb
->lcd_getstringsize("A",&w
,&h
);
116 rb
->lcd_putsxy(ws
, 0 , Dayname
[i
++]);
119 rb
->lcd_hline(0, LCD_WIDTH
-1 ,h
);
122 static bool day_has_memo
[31];
123 static bool wday_has_memo
[6];
124 static void draw_calendar(struct shown
*shown
)
127 int ws
,row
,pos
,days_per_month
,j
;
129 char *Monthname
[] = {
143 rb
->lcd_getstringsize("A",&w
,&h
);
144 rb
->lcd_clear_display();
146 if (shown
->firstday
> 6)
147 shown
->firstday
-= 7;
149 pos
= shown
->firstday
;
150 days_per_month
= days_in_month
[leap_year
][shown
->mon
];
151 ws
= 2 + (pos
* space
);
152 for (j
= 0; j
< days_per_month
;)
154 if ( (day_has_memo
[++j
]) || (wday_has_memo
[pos
]) )
155 rb
->snprintf(buffer
,4,"%02d.", j
);
157 rb
->snprintf(buffer
,4,"%02d", j
);
158 rb
->lcd_putsxy(ws
, (row
* h
) + 5 ,buffer
);
159 if (shown
->mday
== j
)
161 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
162 rb
->lcd_fillrect(ws
, row
*h
+5, space
, h
);
163 rb
->lcd_set_drawmode(DRMODE_SOLID
);
175 rb
->lcd_vline(60,LCD_HEIGHT
-h
-3,LCD_HEIGHT
-1);
176 rb
->lcd_hline(60,LCD_WIDTH
-1,LCD_HEIGHT
-h
-3);
177 rb
->snprintf(buffer
,9,"%s %04d",Monthname
[shown
->mon
-1],shown
->year
);
178 rb
->lcd_putsxy(62,(LCD_HEIGHT
-h
-1),buffer
);
179 shown
->lastday
= pos
;
183 #define MAX_CHAR_MEMO_LEN 63
184 #define MAX_MEMOS_IN_A_MONTH 127
186 char message
[MAX_CHAR_MEMO_LEN
];
189 int file_pointer_start
;
190 int file_pointer_end
;
194 } memos
[MAX_MEMOS_IN_A_MONTH
];
195 static int pointer_array
[MAX_MEMOS_IN_A_MONTH
];
196 static int memos_in_memory
= 0;
197 static int memos_in_shown_memory
= 0;
199 static void load_memo(struct shown
*shown
)
206 for (k
= 0; k
< memos_in_memory
; k
++)
210 memos
[k
].file_pointer_start
= 0;
211 memos
[k
].file_pointer_end
= 0;
215 for (i
= 0; i
<= MAX_CHAR_MEMO_LEN
; i
++)
216 rb
->strcpy(&memos
[k
].message
[i
],"");
218 for (k
= 1; k
< 32; k
++)
219 day_has_memo
[k
] = false;
220 for (k
= 0; k
< 7; k
++)
221 wday_has_memo
[k
] = false;
223 fp
= rb
->open(ROCKBOX_DIR
"/.memo",O_RDONLY
);
226 int count
= rb
->filesize(fp
);
227 rb
->lseek(fp
, 0, SEEK_SET
);
230 memos
[memos_in_memory
].file_pointer_start
= rb
->lseek(fp
, 0,
232 if (rb
->read(fp
, temp_memo2
, 2) == 2)
233 memos
[memos_in_memory
].day
= rb
->atoi(&temp_memo2
[0]);
235 memos
[memos_in_memory
].day
= 0;
236 if (rb
->read(fp
, temp_memo2
, 2) == 2)
237 memos
[memos_in_memory
].month
= rb
->atoi(&temp_memo2
[0]);
239 memos
[memos_in_memory
].month
= 0;
240 if (rb
->read(fp
, temp_memo4
, 4) == 4)
241 memos
[memos_in_memory
].year
= rb
->atoi(&temp_memo4
[0]);
243 memos
[memos_in_memory
].year
= 0;
244 /* as the year returned is sometimes yearmonth, ie if yr should =
245 2003, and month = 06, then it returns 200306 */
246 if (memos
[memos_in_memory
].year
> (shown
->year
* 10))
247 memos
[memos_in_memory
].year
= (memos
[memos_in_memory
].year
-
248 memos
[memos_in_memory
].month
) /
250 if (rb
->read(fp
, temp_memo1
, 1) == 1)
251 memos
[memos_in_memory
].wday
= rb
->atoi(&temp_memo1
[0]);
253 memos
[memos_in_memory
].wday
= 0;
254 if (rb
->read(fp
, temp_memo1
, 1) == 1)
255 memos
[memos_in_memory
].type
= rb
->atoi(&temp_memo1
[0]);
257 memos
[memos_in_memory
].type
= 0;
258 for (k
= 0; k
<= count
; k
++)
260 if (rb
->read(fp
, temp_memo1
, 1) == 1)
263 (memos
[memos_in_memory
].type
< 2)
266 (memos
[memos_in_memory
].type
== 2)
268 (memos
[memos_in_memory
].month
== shown
->mon
)
272 (memos
[memos_in_memory
].type
> 2)
274 (memos
[memos_in_memory
].month
== shown
->mon
)
276 (memos
[memos_in_memory
].year
== shown
->year
)
280 if (temp_memo1
[0] == '\n')
282 if (memos
[memos_in_memory
].type
> 0)
283 day_has_memo
[memos
[memos_in_memory
].day
] =
286 wday_has_memo
[memos
[memos_in_memory
].wday
] =
288 memos
[memos_in_memory
++].file_pointer_end
=
289 rb
->lseek(fp
, 0, SEEK_CUR
);
291 else if ( (temp_memo1
[0] != '\r') &&
292 (temp_memo1
[0] != '\t') )
293 memos
[memos_in_memory
].message
[k
] = temp_memo1
[0];
295 if (temp_memo1
[0] == '\n')
300 memos
[memos_in_memory
].day
= 0;
301 memos
[memos_in_memory
].month
= 0;
302 memos
[memos_in_memory
].file_pointer_start
= 0;
303 memos
[memos_in_memory
].file_pointer_end
= 0;
304 memos
[memos_in_memory
].year
= 0;
305 memos
[memos_in_memory
].type
= 0;
306 memos
[memos_in_memory
].wday
= 0;
307 rb
->strcpy(&memos
[memos_in_memory
].message
[0], "");
317 static bool save_memo(int changed
, bool new_mod
, struct shown
*shown
)
320 fp
= rb
->open(ROCKBOX_DIR
"/.memo",O_RDONLY
| O_CREAT
);
321 fq
= rb
->creat(ROCKBOX_DIR
"/~temp");
322 if ( (fq
!= -1) && (fp
!= -1) )
325 char temp
[MAX_CHAR_MEMO_LEN
+ 1];
326 rb
->lseek(fp
, 0, SEEK_SET
);
327 for (i
= 0; i
< memos
[changed
].file_pointer_start
; i
++)
329 rb
->read(fp
, temp
, 1);
330 rb
->write(fq
,temp
,1);
334 rb
->fdprintf(fq
, "%02d%02d%04d%01d%01d%s\n",
336 memos
[changed
].month
,
340 memos
[changed
].message
);
342 rb
->lseek(fp
, memos
[changed
].file_pointer_end
, SEEK_SET
);
343 for (i
= memos
[changed
].file_pointer_end
;
344 i
< rb
->filesize(fp
); i
++)
346 rb
->read(fp
, temp
, 1);
347 rb
->write(fq
,temp
,1);
350 fp
= rb
->creat(ROCKBOX_DIR
"/.memo");
351 rb
->lseek(fp
, 0, SEEK_SET
);
352 rb
->lseek(fq
, 0, SEEK_SET
);
353 for (i
= 0; i
< rb
->filesize(fq
); i
++)
355 rb
->read(fq
, temp
, 1);
356 rb
->write(fp
,temp
,1);
360 rb
->remove(ROCKBOX_DIR
"/~temp");
371 static void add_memo(struct shown
*shown
, int type
)
374 if (rb
->kbd_input(memos
[memos_in_memory
].message
,
375 sizeof memos
[memos_in_memory
].message
) != -1)
377 if (rb
->strlen(memos
[memos_in_memory
].message
))
379 memos
[memos_in_memory
].file_pointer_start
= 0;
380 memos
[memos_in_memory
].file_pointer_end
= 0;
381 memos
[memos_in_memory
].day
= shown
->mday
;
382 memos
[memos_in_memory
].month
= shown
->mon
;
383 memos
[memos_in_memory
].wday
= shown
->wday
;
384 memos
[memos_in_memory
].year
= shown
->year
;
385 memos
[memos_in_memory
].type
= type
;
386 if (save_memo(memos_in_memory
,true,shown
))
393 memos
[memos_in_memory
].file_pointer_start
= 0;
394 memos
[memos_in_memory
].file_pointer_end
= 0;
395 memos
[memos_in_memory
].day
= 0;
396 memos
[memos_in_memory
].month
= 0;
397 memos
[memos_in_memory
].year
= 0;
398 memos
[memos_in_memory
].type
= 0;
399 memos
[memos_in_memory
].wday
= 0;
403 rb
->lcd_clear_display();
405 rb
->lcd_setfont(FONT_SYSFIXED
);
407 rb
->lcd_puts(0,0,"Event added");
409 rb
->lcd_puts(0,0,"Event not added");
414 static bool edit_memo(int change
, struct shown
*shown
)
421 rb
->lcd_clear_display();
422 if (memos_in_shown_memory
> 0)
424 rb
->lcd_puts(0,0,"Remove : Up");
425 rb
->lcd_puts(0,1,"Edit : Down");
426 rb
->lcd_puts(0,2,"New :");
427 rb
->lcd_puts(2,3,"weekly : Left");
428 rb
->lcd_puts(2,4,"monthly : Play");
429 rb
->lcd_puts(2,5,"annually : Right");
430 rb
->lcd_puts(2,6,"one off : On");
434 rb
->lcd_puts(0,0,"New :");
435 rb
->lcd_puts(2,1,"weekly : Left");
436 rb
->lcd_puts(2,2,"monthly : Play");
437 rb
->lcd_puts(2,3,"anualy : Right");
438 rb
->lcd_puts(2,4,"one off : On");
441 button
= rb
->button_get(true);
464 if (memos_in_shown_memory
> 0)
466 if(rb
->kbd_input(memos
[pointer_array
[change
]].message
,
467 sizeof memos
[pointer_array
[change
]].message
) != -1)
468 save_memo(pointer_array
[change
],true,shown
);
470 rb
->lcd_setfont(FONT_SYSFIXED
);
476 if (memos_in_shown_memory
> 0)
478 save_memo(pointer_array
[change
],false,shown
);
484 if(rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
485 been_in_usb_mode
= true;
492 static int start
= 0;
494 static void show_lines(int selected
, struct shown
*shown
)
496 int lines
,j
= 1,w
,h
,i
,k
= 0, pos
= 1,m
= 0;
497 char temp
[MAX_CHAR_MEMO_LEN
+ 12];
498 rb
->lcd_getstringsize("A",&w
,&h
);
499 lines
= (LCD_HEIGHT
/ h
) - 1;
501 rb
->lcd_clear_display();
502 rb
->lcd_puts(0,0,"Events (play : menu)");
504 while (selected
>= (lines
+ start
))
506 while (selected
< start
)
509 while ( (i
< memos_in_shown_memory
) && (k
< lines
) )
511 if (memos
[pointer_array
[i
]].type
== 2)
512 rb
->snprintf(temp
, sizeof temp
, "%s (%d yrs)",
513 memos
[pointer_array
[i
]].message
,
514 shown
->year
- memos
[pointer_array
[i
]].year
);
516 rb
->snprintf(temp
, sizeof temp
, "%s",
517 memos
[pointer_array
[i
]].message
);
522 rb
->lcd_puts_scroll(m
,j
++,temp
);
525 rb
->lcd_puts(m
,j
++,temp
);
529 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
530 rb
->lcd_fillrect(0, (pos
) * h
, LCD_WIDTH
, h
);
531 rb
->lcd_set_drawmode(DRMODE_SOLID
);
534 static void update_memos_shown(struct shown
*shown
)
537 memos_in_shown_memory
= 0;
539 for (i
= 0; i
< memos_in_memory
; i
++)
541 (memos
[i
].day
== shown
->mday
)
546 (memos
[i
].wday
== shown
->wday
)
549 pointer_array
[memos_in_shown_memory
++] = i
;
552 static bool any_events(struct shown
*shown
, bool force
)
554 int lines_displayed
= 0;
558 update_memos_shown(shown
);
559 if (memos_in_shown_memory
> 0)
560 show_lines(lines_displayed
,shown
);
562 return edit_memo(lines_displayed
, shown
);
568 button
= rb
->button_get(true);
572 if (memos_in_shown_memory
> 0)
575 if (lines_displayed
>= memos_in_shown_memory
)
576 lines_displayed
= memos_in_shown_memory
- 1;
577 show_lines(lines_displayed
,shown
);
583 if (memos_in_shown_memory
> 0)
586 if (lines_displayed
< 0)
588 show_lines(lines_displayed
,shown
);
594 return edit_memo(lines_displayed
, shown
);
600 if(rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
601 been_in_usb_mode
= true;
602 show_lines(lines_displayed
,shown
);
610 static void next_month(struct shown
*shown
, int step
)
617 leap_year
= is_leap_year(shown
->year
);
620 shown
->mday
= shown
->mday
- days_in_month
[leap_year
][shown
->mon
-1];
621 else if (shown
->mday
> days_in_month
[leap_year
][shown
->mon
])
622 shown
->mday
= days_in_month
[leap_year
][shown
->mon
];
623 shown
->firstday
= shown
->lastday
;
625 draw_calendar(shown
);
628 static void prev_month(struct shown
*shown
, int step
)
635 leap_year
= is_leap_year(shown
->year
);
638 shown
->mday
= shown
->mday
+ days_in_month
[leap_year
][shown
->mon
];
639 else if (shown
->mday
> days_in_month
[leap_year
][shown
->mon
])
640 shown
->mday
= days_in_month
[leap_year
][shown
->mon
];
641 shown
->firstday
+= 7 - (days_in_month
[leap_year
][shown
->mon
] % 7);
643 draw_calendar(shown
);
646 static void next_day(struct shown
*shown
, int step
)
649 if (shown
->mday
> days_in_month
[leap_year
][shown
->mon
])
650 next_month(shown
, step
);
652 draw_calendar(shown
);
655 static void prev_day(struct shown
*shown
, int step
)
659 prev_month(shown
, step
);
661 draw_calendar(shown
);
664 enum plugin_status
plugin_start(const struct plugin_api
* api
, const void* parameter
)
675 calendar_init(&today
, &shown
);
677 any_events(&shown
, false);
678 draw_calendar(&shown
);
681 button
= rb
->button_get(true);
687 case BUTTON_ON
| BUTTON_DOWN
:
688 case BUTTON_ON
| BUTTON_DOWN
| BUTTON_REPEAT
:
689 next_month(&shown
, 0);
692 case BUTTON_ON
| BUTTON_UP
:
693 case BUTTON_ON
| BUTTON_UP
| BUTTON_REPEAT
:
694 prev_month(&shown
, 0);
698 case BUTTON_DOWN
| BUTTON_REPEAT
:
703 case BUTTON_UP
| BUTTON_REPEAT
:
708 case BUTTON_LEFT
| BUTTON_REPEAT
:
713 case BUTTON_RIGHT
| BUTTON_REPEAT
:
718 any_events(&shown
, true);
719 draw_calendar(&shown
);
723 if(rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
724 been_in_usb_mode
= true;
725 draw_calendar(&shown
);
729 return been_in_usb_mode
?PLUGIN_USB_CONNECTED
:PLUGIN_OK
;