From c1512e1a9b27d66072c5d15f19692120bfee9a5a Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 24 Jul 2003 10:03:33 +0000 Subject: Huw Smith's calendar plugin git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3877 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/calendar.c | 722 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 722 insertions(+) create mode 100644 apps/plugins/calendar.c (limited to 'apps/plugins/calendar.c') 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 @@ +/*************************************************************************** + * __________ __ ___. + * 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 + +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 -- cgit v1.2.3