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 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},
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
;
94 shown
->mday
= today
->mday
;
95 shown
->mon
= today
->mon
;
96 shown
->year
= today
->year
;
97 shown
->wday
= today
->wday
;
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)
107 const char *Dayname
[7] = {"M","T","W","T","F","S","S"};
109 rb
->lcd_getstringsize("A",&w
,&h
);
110 for (i
= 0; i
< 7; i
++)
112 rb
->lcd_putsxy(ws
, 0 , Dayname
[i
]);
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
)
123 int ws
,row
,pos
,days_per_month
,j
;
125 const char *Monthname
[] = {
139 rb
->lcd_getstringsize("A",&w
,&h
);
140 rb
->lcd_clear_display();
142 if (shown
->firstday
> 6)
143 shown
->firstday
-= 7;
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
);
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
);
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
;
179 #define MAX_CHAR_MEMO_LEN 63
180 #define MAX_MEMOS_IN_A_MONTH 127
182 char message
[MAX_CHAR_MEMO_LEN
];
185 int file_pointer_start
;
186 int file_pointer_end
;
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
)
202 for (k
= 0; k
< memos_in_memory
; k
++)
206 memos
[k
].file_pointer_start
= 0;
207 memos
[k
].file_pointer_end
= 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;
219 fp
= rb
->open(ROCKBOX_DIR
"/.memo",O_RDONLY
);
222 int count
= rb
->filesize(fp
);
223 rb
->lseek(fp
, 0, SEEK_SET
);
226 memos
[memos_in_memory
].file_pointer_start
= rb
->lseek(fp
, 0,
228 if (rb
->read(fp
, temp_memo2
, 2) == 2)
229 memos
[memos_in_memory
].day
= rb
->atoi(&temp_memo2
[0]);
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]);
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]);
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
) /
246 if (rb
->read(fp
, temp_memo1
, 1) == 1)
247 memos
[memos_in_memory
].wday
= rb
->atoi(&temp_memo1
[0]);
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]);
253 memos
[memos_in_memory
].type
= 0;
254 for (k
= 0; k
<= count
; k
++)
256 if (rb
->read(fp
, temp_memo1
, 1) == 1)
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
] =
282 wday_has_memo
[memos
[memos_in_memory
].wday
] =
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')
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], "");
313 static bool save_memo(int changed
, bool new_mod
, struct shown
*shown
)
316 fp
= rb
->open(ROCKBOX_DIR
"/.memo",O_RDONLY
| O_CREAT
);
317 fq
= rb
->creat(ROCKBOX_DIR
"/~temp");
318 if ( (fq
!= -1) && (fp
!= -1) )
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);
330 rb
->fdprintf(fq
, "%02d%02d%04d%01d%01d%s\n",
332 memos
[changed
].month
,
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);
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);
356 rb
->remove(ROCKBOX_DIR
"/~temp");
367 static void add_memo(struct shown
*shown
, int type
)
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
))
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();
401 rb
->lcd_setfont(FONT_SYSFIXED
);
403 rb
->lcd_puts(0,0,"Event added");
405 rb
->lcd_puts(0,0,"Event not added");
410 static bool edit_memo(int change
, struct shown
*shown
)
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");
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");
437 button
= rb
->button_get(true);
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
);
466 rb
->lcd_setfont(FONT_SYSFIXED
);
472 if (memos_in_shown_memory
> 0)
474 save_memo(pointer_array
[change
],false,shown
);
480 if(rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
481 been_in_usb_mode
= true;
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
))
502 while (selected
< 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
);
512 rb
->snprintf(temp
, sizeof temp
, "%s",
513 memos
[pointer_array
[i
]].message
);
518 rb
->lcd_puts_scroll(m
,j
++,temp
);
521 rb
->lcd_puts(m
,j
++,temp
);
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
)
533 memos_in_shown_memory
= 0;
535 for (i
= 0; i
< memos_in_memory
; i
++)
537 (memos
[i
].day
== shown
->mday
)
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;
554 update_memos_shown(shown
);
555 if (memos_in_shown_memory
> 0)
556 show_lines(lines_displayed
,shown
);
558 return edit_memo(lines_displayed
, shown
);
564 button
= rb
->button_get(true);
568 if (memos_in_shown_memory
> 0)
571 if (lines_displayed
>= memos_in_shown_memory
)
572 lines_displayed
= memos_in_shown_memory
- 1;
573 show_lines(lines_displayed
,shown
);
579 if (memos_in_shown_memory
> 0)
582 if (lines_displayed
< 0)
584 show_lines(lines_displayed
,shown
);
590 return edit_memo(lines_displayed
, shown
);
596 if(rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
597 been_in_usb_mode
= true;
598 show_lines(lines_displayed
,shown
);
606 static void next_month(struct shown
*shown
, int step
)
613 leap_year
= is_leap_year(shown
->year
);
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
;
621 draw_calendar(shown
);
624 static void prev_month(struct shown
*shown
, int step
)
631 leap_year
= is_leap_year(shown
->year
);
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);
639 draw_calendar(shown
);
642 static void next_day(struct shown
*shown
, int step
)
645 if (shown
->mday
> days_in_month
[leap_year
][shown
->mon
])
646 next_month(shown
, step
);
648 draw_calendar(shown
);
651 static void prev_day(struct shown
*shown
, int step
)
655 prev_month(shown
, step
);
657 draw_calendar(shown
);
660 enum plugin_status
plugin_start(const struct plugin_api
* api
, const void* parameter
)
671 calendar_init(&today
, &shown
);
673 any_events(&shown
, false);
674 draw_calendar(&shown
);
677 button
= rb
->button_get(true);
683 case BUTTON_ON
| BUTTON_DOWN
:
684 case BUTTON_ON
| BUTTON_DOWN
| BUTTON_REPEAT
:
685 next_month(&shown
, 0);
688 case BUTTON_ON
| BUTTON_UP
:
689 case BUTTON_ON
| BUTTON_UP
| BUTTON_REPEAT
:
690 prev_month(&shown
, 0);
694 case BUTTON_DOWN
| BUTTON_REPEAT
:
699 case BUTTON_UP
| BUTTON_REPEAT
:
704 case BUTTON_LEFT
| BUTTON_REPEAT
:
709 case BUTTON_RIGHT
| BUTTON_REPEAT
:
714 any_events(&shown
, true);
715 draw_calendar(&shown
);
719 if(rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
720 been_in_usb_mode
= true;
721 draw_calendar(&shown
);
725 return been_in_usb_mode
?PLUGIN_USB_CONNECTED
:PLUGIN_OK
;