summaryrefslogtreecommitdiff
path: root/apps/plugins
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2003-07-24 10:03:33 +0000
committerDaniel Stenberg <daniel@haxx.se>2003-07-24 10:03:33 +0000
commitc1512e1a9b27d66072c5d15f19692120bfee9a5a (patch)
tree3053fd249003740fcd79337e959cef63b7b18da5 /apps/plugins
parent7b247093c8ae7d380e9c06ab0b82f807814a8f78 (diff)
downloadrockbox-c1512e1a9b27d66072c5d15f19692120bfee9a5a.zip
rockbox-c1512e1a9b27d66072c5d15f19692120bfee9a5a.tar.gz
rockbox-c1512e1a9b27d66072c5d15f19692120bfee9a5a.tar.bz2
rockbox-c1512e1a9b27d66072c5d15f19692120bfee9a5a.tar.xz
Huw Smith's calendar plugin
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3877 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins')
-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 0000000..448c1a8
--- /dev/null
+++ b/apps/plugins/calendar.c
@@ -0,0 +1,722 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ * (based upon 1.1 by calpefrosch) www.HuwSy.ukhackers.net
+ *
+ * Copyright (C) 2002
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "plugin.h"
+
+#ifdef HAVE_LCD_BITMAP
+
+#include <timefuncs.h>
+
+static struct plugin_api* rb;
+
+static bool leap_year;
+static int days_in_month[2][13] = {
+ {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+ {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+};
+
+struct today {
+ int mday; /* day of the month */
+ int mon; /* month */
+ int year; /* year since 1900 */
+ int wday; /* day of the week */
+};
+
+struct shown {
+ int mday; /* day of the month */
+ int mon; /* month */
+ int year; /* year since 1900 */
+ int wday; /* day of the week */
+ int firstday; /* first (w)day of month */
+ int lastday; /* last (w)day of month */
+};
+
+/* leap year -- account for gregorian reformation in 1752 */
+static int is_leap_year(int yr)
+{
+ return ((yr) <= 1752 ? !((yr) % 4) : \
+ (!((yr) % 4) && ((yr) % 100)) || !((yr) % 400)) ? 1:0 ;
+}
+
+/* searches the weekday of the first day in month, relative to the given values */
+static int calc_weekday( struct shown *shown )
+{
+ return ( shown->wday + 36 - shown->mday ) % 7 ;
+
+}
+
+static void calendar_init(struct today *today, struct shown *shown)
+{
+ int w,h;
+ rb->lcd_getstringsize("A",&w,&h);
+ if ( ((w * 14) > LCD_WIDTH) || ((h * 7) > LCD_HEIGHT) )
+ rb->lcd_setfont(FONT_SYSFIXED);
+ rb->lcd_clear_display();
+#ifdef HAVE_RTC
+ struct tm *tm;
+ tm = rb->get_time();
+ today->mon = tm->tm_mon +1;
+ today->year = 2000+tm->tm_year%100;
+ today->wday = tm->tm_wday-1;
+ today->mday = tm->tm_mday;
+#ifdef SIMULATOR
+ today->wday = 3;
+ today->mday = 13;
+#endif
+ shown->mday = today->mday;
+ shown->mon = today->mon;
+ shown->year = today->year;
+ shown->wday = today->wday;
+#endif
+ shown->firstday = calc_weekday(shown);
+ leap_year = is_leap_year(shown->year);
+}
+
+static int space = LCD_WIDTH / 7;
+static void draw_headers(void)
+{
+ int i,w,h;
+ rb->lcd_getstringsize("A",&w,&h);
+ char *Dayname[7] = {"M","T","W","T","F","S","S"};
+ int ws = 2;
+ for (i = 0; i < 8;)
+ {
+ rb->lcd_putsxy(ws, 0 , Dayname[i++]);
+ ws += space;
+ }
+ rb->lcd_drawline(0 ,h ,LCD_WIDTH ,h);
+}
+
+static bool day_has_memo[31];
+static bool wday_has_memo[6];
+static void draw_calendar(struct shown *shown)
+{
+ int w,h;
+ rb->lcd_getstringsize("A",&w,&h);
+ char *Monthname[] = {
+ "Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec"
+ };
+ rb->lcd_clear_display();
+ draw_headers();
+ int row,pos,days_per_month,j;
+ if (shown->firstday > 6)
+ shown->firstday -= 7;
+ char buffer[7];
+ row = 1;
+ pos = shown->firstday;
+ days_per_month = days_in_month[leap_year][shown->mon];
+ int ws = 2 + (pos * space);
+ for (j = 0; j < days_per_month;)
+ {
+ if ( (day_has_memo[++j]) || (wday_has_memo[pos]) )
+ rb->snprintf(buffer,3,"%02d.", j);
+ else
+ rb->snprintf(buffer,3,"%02d", j);
+ rb->lcd_putsxy(ws, (row * h) + 5 ,buffer);
+ if (shown->mday == j)
+ {
+ rb->lcd_invertrect(ws, row*h+5, space, h);
+ shown->wday = pos;
+ }
+ ws += space;
+ pos++;
+ if (pos >= 7)
+ {
+ row++;
+ pos = 0;
+ ws = 2;
+ }
+ }
+ rb->lcd_drawline(60,LCD_HEIGHT-h-3,60,LCD_HEIGHT-1);
+ rb->lcd_drawline(60,LCD_HEIGHT-h-3,LCD_WIDTH-1,LCD_HEIGHT-h-3);
+ rb->snprintf(buffer,8,"%s %04d",Monthname[shown->mon-1],shown->year);
+ rb->lcd_putsxy(62,(LCD_HEIGHT-h-1),buffer);
+ shown->lastday = pos;
+ rb->lcd_update();
+}
+
+#define MAX_CHAR_MEMO_LEN 63
+#define MAX_MEMOS_IN_A_MONTH 127
+struct memo {
+ char message[MAX_CHAR_MEMO_LEN];
+ int day;
+ int month;
+ int file_pointer_start;
+ int file_pointer_end;
+ int year;
+ int wday;
+ int type;
+} memos[MAX_MEMOS_IN_A_MONTH];
+static int pointer_array[MAX_MEMOS_IN_A_MONTH];
+static int memos_in_memory = 0;
+static int memos_in_shown_memory = 0;
+static void load_memo(struct shown *shown)
+{
+ int i, k, fp;
+ bool exit = false;
+ char temp_memo0[0];
+ char temp_memo1[1];
+ char temp_memo3[3];
+ for (k = 0; k < memos_in_memory; k++)
+ {
+ memos[k].day = 0;
+ memos[k].month = 0;
+ memos[k].file_pointer_start = 0;
+ memos[k].file_pointer_end = 0;
+ memos[k].year = 0;
+ memos[k].type = 0;
+ memos[k].wday = 0;
+ for (i = 0; i <= MAX_CHAR_MEMO_LEN; i++)
+ rb->strcpy(&memos[k].message[i],"");
+ }
+ for (k = 1; k < 32; k++)
+ day_has_memo[k] = false;
+ for (k = 0; k < 7; k++)
+ wday_has_memo[k] = false;
+ memos_in_memory = 0;
+ fp = rb->open("/.rockbox/.memo",O_RDONLY);
+ if (fp > -1)
+ {
+ int count = rb->filesize(fp);
+ rb->lseek(fp, 0, SEEK_SET);
+ while (!exit)
+ {
+ memos[memos_in_memory].file_pointer_start = rb->lseek(fp, 0,
+ SEEK_CUR);
+ if (rb->read(fp, temp_memo1, 2) == 2)
+ memos[memos_in_memory].day = rb->atoi(&temp_memo1[0]);
+ else
+ memos[memos_in_memory].day = 0;
+ if (rb->read(fp, temp_memo1, 2) == 2)
+ memos[memos_in_memory].month = rb->atoi(&temp_memo1[0]);
+ else
+ memos[memos_in_memory].month = 0;
+ if (rb->read(fp, temp_memo3, 4) == 4)
+ memos[memos_in_memory].year = rb->atoi(&temp_memo3[0]);
+ else
+ memos[memos_in_memory].year = 0;
+ /* as the year returned is sometimes yearmonth, ie if yr should =
+ 2003, and month = 06, then it returns 200306 */
+ if (memos[memos_in_memory].year > (shown->year * 10))
+ memos[memos_in_memory].year = (memos[memos_in_memory].year -
+ memos[memos_in_memory].month) /
+ 100;
+ if (rb->read(fp, temp_memo0, 1) == 1)
+ memos[memos_in_memory].wday = rb->atoi(&temp_memo0[0]);
+ else
+ memos[memos_in_memory].wday = 0;
+ if (rb->read(fp, temp_memo0, 1) == 1)
+ memos[memos_in_memory].type = rb->atoi(&temp_memo0[0]);
+ else
+ memos[memos_in_memory].type = 0;
+ for (k = 0; k <= count; k++)
+ {
+ if (rb->read(fp, temp_memo0, 1) == 1)
+ {
+ if (
+ (memos[memos_in_memory].type < 2)
+ ||
+ (
+ (memos[memos_in_memory].type == 2)
+ &&
+ (memos[memos_in_memory].month == shown->mon)
+ )
+ ||
+ (
+ (memos[memos_in_memory].type > 2)
+ &&
+ (memos[memos_in_memory].month == shown->mon)
+ &&
+ (memos[memos_in_memory].year == shown->year)
+ )
+ )
+ {
+ if (temp_memo0[0] == '\n')
+ {
+ if (memos[memos_in_memory].type > 0)
+ day_has_memo[memos[memos_in_memory].day] =
+ true;
+ else
+ wday_has_memo[memos[memos_in_memory].wday] =
+ true;
+ memos[memos_in_memory++].file_pointer_end =
+ rb->lseek(fp, 0, SEEK_CUR);
+ }
+ else if ( (temp_memo0[0] != '\r') &&
+ (temp_memo0[0] != '\t') )
+ memos[memos_in_memory].message[k] = temp_memo0[0];
+ }
+ if (temp_memo0[0] == '\n')
+ break;
+ }
+ else
+ {
+ memos[memos_in_memory].day = 0;
+ memos[memos_in_memory].month = 0;
+ memos[memos_in_memory].file_pointer_start = 0;
+ memos[memos_in_memory].file_pointer_end = 0;
+ memos[memos_in_memory].year = 0;
+ memos[memos_in_memory].type = 0;
+ memos[memos_in_memory].wday = 0;
+ rb->strcpy(&memos[memos_in_memory].message[0], "");
+ exit = true;
+ break;
+ }
+ }
+ }
+ }
+ rb->close(fp);
+}
+
+static bool save_memo(int changed, bool new_mod, struct shown *shown)
+{
+ int fp,fq;
+ fp = rb->open("/.rockbox/.memo",O_RDONLY | O_CREAT);
+ fq = rb->open("/.rockbox/~temp",O_RDWR | O_CREAT | O_TRUNC);
+ if ( (fq != -1) && (fp != -1) )
+ {
+ int i;
+ char temp[MAX_CHAR_MEMO_LEN + 1];
+ rb->lseek(fp, 0, SEEK_SET);
+ if ( (memos[changed].file_pointer_start == 0) &&
+ (memos[changed].file_pointer_end == 0) && (new_mod) )
+ {
+ rb->close(fp);
+ rb->close(fq);
+ fq = rb->open("/.rockbox/.memo",O_RDONLY | O_CREAT | O_APPEND);
+ rb->snprintf(temp, 2, "%02d", memos[changed].day);
+ rb->write(fq,temp,2);
+ rb->snprintf(temp, 2, "%02d", memos[changed].month);
+ rb->write(fq,temp,2);
+ rb->snprintf(temp, 4, "%04d", memos[changed].year);
+ rb->write(fq,temp,4);
+ rb->snprintf(temp, 1, "%01d", memos[changed].wday);
+ rb->write(fq,temp,1);
+ rb->snprintf(temp, 1, "%01d", memos[changed].type);
+ rb->write(fq,temp,1);
+ rb->snprintf(temp, rb->strlen(memos[changed].message)+1, "%s\n",
+ memos[changed].message);
+ rb->write(fq,temp,rb->strlen(temp));
+ }
+ else
+ {
+ for (i = 0; i < memos[changed].file_pointer_start; i++)
+ {
+ rb->read(fp, temp, 1);
+ rb->write(fq,temp,1);
+ }
+ if (new_mod)
+ {
+ rb->snprintf(temp, 2, "%02d", memos[changed].day);
+ rb->write(fq,temp,2);
+ rb->snprintf(temp, 2, "%02d", memos[changed].month);
+ rb->write(fq,temp,2);
+ rb->snprintf(temp, 4, "%04d", memos[changed].year);
+ rb->write(fq,temp,4);
+ rb->snprintf(temp, 1, "%01d", memos[changed].wday);
+ rb->write(fq,temp,1);
+ rb->snprintf(temp, 1, "%01d", memos[changed].type);
+ rb->write(fq,temp,1);
+ rb->snprintf(temp, rb->strlen(memos[changed].message)+1,
+ "%s\n", memos[changed].message);
+ rb->write(fq,temp, rb->strlen(temp));
+ }
+ rb->lseek(fp, memos[changed].file_pointer_end, SEEK_SET);
+ for (i = memos[changed].file_pointer_end;
+ i < rb->filesize(fp); i++)
+ {
+ rb->read(fp, temp, 1);
+ rb->write(fq,temp,1);
+ }
+ rb->close(fp);
+ fp = rb->open("/.rockbox/.memo",O_WRONLY | O_CREAT | O_TRUNC);
+ rb->lseek(fp, 0, SEEK_SET);
+ rb->lseek(fq, 0, SEEK_SET);
+ for (i = 0; i < rb->filesize(fq); i++)
+ {
+ rb->read(fq, temp, 1);
+ rb->write(fp,temp,1);
+ }
+ rb->close(fp);
+ }
+ rb->close(fq);
+ rb->remove("/.rockbox/~temp");
+ load_memo(shown);
+ return true;
+ }
+ else if (fp != -1)
+ rb->close(fp);
+ else if (fq != -1)
+ rb->close(fq);
+ return false;
+}
+
+static void add_memo(struct shown *shown, int type)
+{
+ bool saved = false;
+ if (rb->kbd_input(memos[memos_in_memory].message,
+ sizeof memos[memos_in_memory].message) != -1)
+ {
+ if (memos[memos_in_memory].message != "")
+ {
+ memos[memos_in_memory].file_pointer_start = 0;
+ memos[memos_in_memory].file_pointer_end = 0;
+ memos[memos_in_memory].day = shown->mday;
+ memos[memos_in_memory].month = shown->mon;
+ memos[memos_in_memory].wday = shown->wday;
+ memos[memos_in_memory].year = shown->year;
+ memos[memos_in_memory].type = type;
+ if (save_memo(memos_in_memory,true,shown))
+ {
+ saved = true;
+ memos_in_memory++;
+ }
+ else
+ {
+ memos[memos_in_memory].file_pointer_start = 0;
+ memos[memos_in_memory].file_pointer_end = 0;
+ memos[memos_in_memory].day = 0;
+ memos[memos_in_memory].month = 0;
+ memos[memos_in_memory].year = 0;
+ memos[memos_in_memory].type = 0;
+ memos[memos_in_memory].wday = 0;
+ }
+ }
+ }
+ rb->lcd_clear_display();
+ if (saved)
+ rb->lcd_puts(0,0,"Event added");
+ else
+ rb->lcd_puts(0,0,"Event not added");
+ rb->lcd_update();
+ rb->sleep(HZ/2);
+}
+
+static bool edit_memo(int change, struct shown *shown)
+{
+ bool exit = false;
+ rb->lcd_clear_display();
+ if (memos_in_shown_memory > 0)
+ {
+ rb->lcd_puts(0,0,"Remove : Up");
+ rb->lcd_puts(0,1,"Edit : Down");
+ rb->lcd_puts(0,2,"New :");
+ rb->lcd_puts(6,3,"weekly : Left");
+ rb->lcd_puts(6,4,"monthly : Play");
+ rb->lcd_puts(6,5,"annually : Right");
+ rb->lcd_puts(6,6,"one off : On");
+ }
+ else
+ {
+ rb->lcd_puts(0,0,"New :");
+ rb->lcd_puts(6,1,"weekly : Left");
+ rb->lcd_puts(6,2,"monthly : Play");
+ rb->lcd_puts(6,3,"anualy : Right");
+ rb->lcd_puts(6,4,"one off : On");
+ }
+ rb->lcd_update();
+ while (!exit)
+ {
+ switch (rb->button_get(true))
+ {
+ case BUTTON_OFF:
+ return false;
+
+ case BUTTON_LEFT:
+ add_memo(shown,0);
+ return false;
+
+ case BUTTON_PLAY:
+ add_memo(shown,1);
+ return false;
+
+ case BUTTON_RIGHT:
+ add_memo(shown,2);
+ return false;
+
+ case BUTTON_ON:
+ add_memo(shown,3);
+ return false;
+
+ case BUTTON_DOWN:
+ if (memos_in_shown_memory > 0)
+ {
+ if(rb->kbd_input(memos[pointer_array[change]].message,
+ sizeof memos[pointer_array[change]].message) != -1)
+ save_memo(pointer_array[change],true,shown);
+ exit = true;
+ }
+ break;
+
+ case BUTTON_UP:
+ if (memos_in_shown_memory > 0)
+ {
+ save_memo(pointer_array[change],false,shown);
+ exit = true;
+ }
+ break;
+
+ case SYS_USB_CONNECTED:
+ return true;
+ }
+ }
+ return false;
+}
+
+static int start = 0;
+
+static void show_lines(int selected, struct shown *shown)
+{
+ int j = 1,w,h,i,k = 0, pos = 1,m = 0;
+ rb->lcd_getstringsize("A",&w,&h);
+ int lines = (LCD_HEIGHT / h) - 1;
+ char temp[MAX_CHAR_MEMO_LEN + 12];
+
+ rb->lcd_clear_display();
+ rb->lcd_puts(0,0,"Events (play : menu)");
+
+ while (selected >= (lines + start))
+ start++;
+ while (selected < start)
+ start--;
+ i = start;
+ while ( (i < memos_in_shown_memory) && (k < lines) )
+ {
+ if (memos[pointer_array[i]].type == 2)
+ rb->snprintf(temp, sizeof temp, "%s (%d yrs)",
+ memos[pointer_array[i]].message,
+ shown->year - memos[pointer_array[i]].year);
+ else
+ rb->snprintf(temp, sizeof temp, "%s",
+ memos[pointer_array[i]].message);
+ m = 0;
+ if (i == selected)
+ {
+ pos = k + 1;
+ rb->lcd_puts_scroll(m,j++,temp);
+ }
+ else
+ rb->lcd_puts(m,j++,temp);
+ k++;
+ i++;
+ }
+ rb->lcd_invertrect(0, (pos) * h, LCD_WIDTH, h);
+}
+
+static void update_memos_shown(struct shown *shown)
+{
+ memos_in_shown_memory = 0;
+ start = 0;
+ int i;
+ for (i = 0; i < memos_in_memory; i++)
+ if (
+ (memos[i].day == shown->mday)
+ ||
+ (
+ (memos[i].type < 1)
+ &&
+ (memos[i].wday == shown->wday)
+ )
+ )
+ pointer_array[memos_in_shown_memory++] = i;
+}
+
+static bool any_events(struct shown *shown, bool force)
+{
+ update_memos_shown(shown);
+ int lines_displayed = 0;
+ if (memos_in_shown_memory > 0)
+ show_lines(lines_displayed,shown);
+ else if (force)
+ return edit_memo(lines_displayed, shown);
+ else
+ return false;
+ rb->lcd_update();
+ bool exit = false;
+ while (!exit)
+ {
+ switch (rb->button_get(true))
+ {
+ case BUTTON_DOWN:
+ if (memos_in_shown_memory > 0)
+ {
+ lines_displayed++;
+ if (lines_displayed >= memos_in_shown_memory)
+ lines_displayed = memos_in_shown_memory - 1;
+ show_lines(lines_displayed,shown);
+ rb->lcd_update();
+ }
+ break;
+
+ case BUTTON_UP:
+ if (memos_in_shown_memory > 0)
+ {
+ lines_displayed--;
+ if (lines_displayed < 0)
+ lines_displayed = 0;
+ show_lines(lines_displayed,shown);
+ rb->lcd_update();
+ }
+ break;
+
+ case BUTTON_PLAY:
+ return edit_memo(lines_displayed, shown);
+
+ case BUTTON_OFF:
+ return false;
+
+ case SYS_USB_CONNECTED:
+ return true;
+ }
+ }
+ return false;
+}
+
+static void next_month(struct shown *shown, int step)
+{
+ shown->mon++;
+ if (shown->mon > 12)
+ {
+ shown->mon=1;
+ shown->year++;
+ leap_year = is_leap_year(shown->year);
+ }
+ else if (step > 0)
+ shown->mday = shown->mday - days_in_month[leap_year][shown->mon-1];
+ else if (shown->mday > days_in_month[leap_year][shown->mon])
+ shown->mday = days_in_month[leap_year][shown->mon];
+ shown->firstday = shown->lastday;
+ load_memo(shown);
+ draw_calendar(shown);
+}
+
+static void prev_month(struct shown *shown, int step)
+{
+ shown->mon--;
+ if (shown->mon < 1)
+ {
+ shown->mon = 12;
+ shown->year--;
+ leap_year = is_leap_year(shown->year);
+ }
+ if (step > 0)
+ shown->mday = shown->mday + days_in_month[leap_year][shown->mon];
+ else if (shown->mday > days_in_month[leap_year][shown->mon])
+ shown->mday = days_in_month[leap_year][shown->mon];
+ shown->firstday += 7 - (days_in_month[leap_year][shown->mon] % 7);
+ load_memo(shown);
+ draw_calendar(shown);
+}
+
+static void next_day(struct shown *shown, int step)
+{
+ shown->mday += step;
+ if (shown->mday > days_in_month[leap_year][shown->mon])
+ next_month(shown, step);
+ else
+ draw_calendar(shown);
+}
+
+static void prev_day(struct shown *shown, int step)
+{
+ shown->mday -= step;
+ if (shown->mday < 1)
+ prev_month(shown, step);
+ else
+ draw_calendar(shown);
+}
+
+enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
+{
+ TEST_PLUGIN_API(api);
+ (void)(parameter);
+ rb = api;
+
+ struct today today;
+ struct shown shown;
+
+ calendar_init(&today, &shown);
+ load_memo(&shown);
+ any_events(&shown, false);
+ draw_calendar(&shown);
+ bool exit = false;
+ while (!exit)
+ {
+ switch (rb->button_get(true))
+ {
+ case BUTTON_OFF:
+ return false;
+
+ case BUTTON_ON | BUTTON_DOWN:
+ case BUTTON_ON | BUTTON_DOWN | BUTTON_REPEAT:
+ next_month(&shown, 0);
+ break;
+
+ case BUTTON_ON | BUTTON_UP:
+ case BUTTON_ON | BUTTON_UP | BUTTON_REPEAT:
+ prev_month(&shown, 0);
+ break;
+
+ case BUTTON_DOWN:
+ case BUTTON_DOWN | BUTTON_REPEAT:
+ next_day(&shown, 7);
+ break;
+
+ case BUTTON_UP:
+ case BUTTON_UP | BUTTON_REPEAT:
+ prev_day(&shown, 7);
+ break;
+
+ case BUTTON_LEFT:
+ case BUTTON_LEFT | BUTTON_REPEAT:
+ prev_day(&shown, 1);
+ break;
+
+ case BUTTON_RIGHT:
+ case BUTTON_RIGHT | BUTTON_REPEAT:
+ next_day(&shown, 1);
+ break;
+
+ case BUTTON_PLAY:
+ if (any_events(&shown, true))
+ rb->usb_screen();
+ draw_calendar(&shown);
+ break;
+
+ case SYS_USB_CONNECTED:
+ rb->usb_screen();
+ draw_calendar(&shown);
+ break;
+ }
+ }
+ return false;
+}
+
+#endif