| /*************************************************************************** |
| * __________ __ ___. |
| * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| * \/ \/ \/ \/ \/ |
| * $Id$ |
| * (based upon 1.1 by calpefrosch) updated by www.HuwSy.ukhackers.net |
| * |
| * Copyright (C) 2002 |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version 2 |
| * of the License, or (at your option) any later version. |
| * |
| * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| * KIND, either express or implied. |
| * |
| ****************************************************************************/ |
| #include "plugin.h" |
| |
| #if defined(HAVE_LCD_BITMAP) && (CONFIG_RTC != 0) |
| |
| #include <timefuncs.h> |
| |
| PLUGIN_HEADER |
| |
| static const 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 */ |
| }; |
| |
| static bool use_system_font = false; |
| |
| static bool been_in_usb_mode = false; |
| |
| /* 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; |
| #if CONFIG_RTC |
| struct tm *tm; |
| #else |
| (void)today; |
| #endif |
| rb->lcd_getstringsize("A",&w,&h); |
| if ( ((w * 14) > LCD_WIDTH) || ((h * 7) > LCD_HEIGHT) ) |
| { |
| rb->lcd_setfont(FONT_SYSFIXED); |
| use_system_font = true; |
| } |
| rb->lcd_clear_display(); |
| #if CONFIG_RTC |
| 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; |
| char *Dayname[7] = {"M","T","W","T","F","S","S"}; |
| int ws = 2; |
| rb->lcd_getstringsize("A",&w,&h); |
| for (i = 0; i < 8;) |
| { |
| rb->lcd_putsxy(ws, 0 , Dayname[i++]); |
| ws += space; |
| } |
| rb->lcd_hline(0, LCD_WIDTH-1 ,h); |
| } |
| |
| static bool day_has_memo[31]; |
| static bool wday_has_memo[6]; |
| static void draw_calendar(struct shown *shown) |
| { |
| int w,h; |
| int ws,row,pos,days_per_month,j; |
| char buffer[9]; |
| char *Monthname[] = { |
| "Jan", |
| "Feb", |
| "Mar", |
| "Apr", |
| "May", |
| "Jun", |
| "Jul", |
| "Aug", |
| "Sep", |
| "Oct", |
| "Nov", |
| "Dec" |
| }; |
| rb->lcd_getstringsize("A",&w,&h); |
| rb->lcd_clear_display(); |
| draw_headers(); |
| if (shown->firstday > 6) |
| shown->firstday -= 7; |
| row = 1; |
| pos = shown->firstday; |
| days_per_month = days_in_month[leap_year][shown->mon]; |
| ws = 2 + (pos * space); |
| for (j = 0; j < days_per_month;) |
| { |
| if ( (day_has_memo[++j]) || (wday_has_memo[pos]) ) |
| rb->snprintf(buffer,4,"%02d.", j); |
| else |
| rb->snprintf(buffer,4,"%02d", j); |
| rb->lcd_putsxy(ws, (row * h) + 5 ,buffer); |
| if (shown->mday == j) |
| { |
| rb->lcd_set_drawmode(DRMODE_COMPLEMENT); |
| rb->lcd_fillrect(ws, row*h+5, space, h); |
| rb->lcd_set_drawmode(DRMODE_SOLID); |
| shown->wday = pos; |
| } |
| ws += space; |
| pos++; |
| if (pos >= 7) |
| { |
| row++; |
| pos = 0; |
| ws = 2; |
| } |
| } |
| rb->lcd_vline(60,LCD_HEIGHT-h-3,LCD_HEIGHT-1); |
| rb->lcd_hline(60,LCD_WIDTH-1,LCD_HEIGHT-h-3); |
| rb->snprintf(buffer,9,"%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_memo1[2]; |
| char temp_memo2[3]; |
| char temp_memo4[5]; |
| 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_DIR "/.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_memo2, 2) == 2) |
| memos[memos_in_memory].day = rb->atoi(&temp_memo2[0]); |
| else |
| memos[memos_in_memory].day = 0; |
| if (rb->read(fp, temp_memo2, 2) == 2) |
| memos[memos_in_memory].month = rb->atoi(&temp_memo2[0]); |
| else |
| memos[memos_in_memory].month = 0; |
| if (rb->read(fp, temp_memo4, 4) == 4) |
| memos[memos_in_memory].year = rb->atoi(&temp_memo4[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_memo1, 1) == 1) |
| memos[memos_in_memory].wday = rb->atoi(&temp_memo1[0]); |
| else |
| memos[memos_in_memory].wday = 0; |
| if (rb->read(fp, temp_memo1, 1) == 1) |
| memos[memos_in_memory].type = rb->atoi(&temp_memo1[0]); |
| else |
| memos[memos_in_memory].type = 0; |
| for (k = 0; k <= count; k++) |
| { |
| if (rb->read(fp, temp_memo1, 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_memo1[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_memo1[0] != '\r') && |
| (temp_memo1[0] != '\t') ) |
| memos[memos_in_memory].message[k] = temp_memo1[0]; |
| } |
| if (temp_memo1[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_DIR "/.memo",O_RDONLY | O_CREAT); |
| fq = rb->creat(ROCKBOX_DIR "/~temp"); |
| if ( (fq != -1) && (fp != -1) ) |
| { |
| int i; |
| char temp[MAX_CHAR_MEMO_LEN + 1]; |
| rb->lseek(fp, 0, SEEK_SET); |
| for (i = 0; i < memos[changed].file_pointer_start; i++) |
| { |
| rb->read(fp, temp, 1); |
| rb->write(fq,temp,1); |
| } |
| if (new_mod) |
| { |
| rb->fdprintf(fq, "%02d%02d%04d%01d%01d%s\n", |
| memos[changed].day, |
| memos[changed].month, |
| memos[changed].year, |
| memos[changed].wday, |
| memos[changed].type, |
| memos[changed].message); |
| } |
| 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->creat(ROCKBOX_DIR "/.memo"); |
| 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_DIR "/~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 (rb->strlen(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(use_system_font) |
| rb->lcd_setfont(FONT_SYSFIXED); |
| 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; |
| int button; |
| |
| while (!exit) |
| { |
| 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(2,3,"weekly : Left"); |
| rb->lcd_puts(2,4,"monthly : Play"); |
| rb->lcd_puts(2,5,"annually : Right"); |
| rb->lcd_puts(2,6,"one off : On"); |
| } |
| else |
| { |
| rb->lcd_puts(0,0,"New :"); |
| rb->lcd_puts(2,1,"weekly : Left"); |
| rb->lcd_puts(2,2,"monthly : Play"); |
| rb->lcd_puts(2,3,"anualy : Right"); |
| rb->lcd_puts(2,4,"one off : On"); |
| } |
| rb->lcd_update(); |
| button = rb->button_get(true); |
| switch (button) |
| { |
| 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); |
| if(use_system_font) |
| rb->lcd_setfont(FONT_SYSFIXED); |
| exit = true; |
| } |
| break; |
| |
| case BUTTON_UP: |
| if (memos_in_shown_memory > 0) |
| { |
| save_memo(pointer_array[change],false,shown); |
| exit = true; |
| } |
| break; |
| |
| default: |
| if(rb->default_event_handler(button) == SYS_USB_CONNECTED) |
| been_in_usb_mode = true; |
| break; |
| } |
| } |
| return false; |
| } |
| |
| static int start = 0; |
| |
| static void show_lines(int selected, struct shown *shown) |
| { |
| int lines,j = 1,w,h,i,k = 0, pos = 1,m = 0; |
| char temp[MAX_CHAR_MEMO_LEN + 12]; |
| rb->lcd_getstringsize("A",&w,&h); |
| lines = (LCD_HEIGHT / h) - 1; |
| |
| 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_set_drawmode(DRMODE_COMPLEMENT); |
| rb->lcd_fillrect(0, (pos) * h, LCD_WIDTH, h); |
| rb->lcd_set_drawmode(DRMODE_SOLID); |
| } |
| |
| static void update_memos_shown(struct shown *shown) |
| { |
| int i; |
| memos_in_shown_memory = 0; |
| start = 0; |
| 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) |
| { |
| int lines_displayed = 0; |
| bool exit=false; |
| int button; |
| |
| update_memos_shown(shown); |
| 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(); |
| while (!exit) |
| { |
| button = rb->button_get(true); |
| switch (button) |
| { |
| 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; |
| |
| default: |
| if(rb->default_event_handler(button) == SYS_USB_CONNECTED) |
| been_in_usb_mode = true; |
| show_lines(lines_displayed,shown); |
| rb->lcd_update(); |
| break; |
| } |
| } |
| 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(const struct plugin_api* api, const void* parameter) |
| { |
| struct today today; |
| struct shown shown; |
| bool exit = false; |
| int button; |
| |
| (void)(parameter); |
| |
| rb = api; |
| |
| calendar_init(&today, &shown); |
| load_memo(&shown); |
| any_events(&shown, false); |
| draw_calendar(&shown); |
| while (!exit) |
| { |
| button = rb->button_get(true); |
| switch (button) |
| { |
| 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: |
| any_events(&shown, true); |
| draw_calendar(&shown); |
| break; |
| |
| default: |
| if(rb->default_event_handler(button) == SYS_USB_CONNECTED) |
| been_in_usb_mode = true; |
| draw_calendar(&shown); |
| break; |
| } |
| } |
| return been_in_usb_mode?PLUGIN_USB_CONNECTED:PLUGIN_OK; |
| } |
| |
| #endif |