diff options
Diffstat (limited to 'apps/plugins')
152 files changed, 3988 insertions, 1341 deletions
diff --git a/apps/plugins/2048.c b/apps/plugins/2048.c index 2633753071..2f4eb4c001 100644 --- a/apps/plugins/2048.c +++ b/apps/plugins/2048.c @@ -91,9 +91,16 @@ static const int BACKGROUND_Y = (BASE_Y-MIN_SPACE); #define KEY_DOWN PLA_DOWN #define KEY_LEFT PLA_LEFT #define KEY_RIGHT PLA_RIGHT -#define KEY_EXIT PLA_CANCEL #define KEY_UNDO PLA_SELECT +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define KEY_EXIT PLA_SELECT_REPEAT +#else +#define KEY_EXIT PLA_CANCEL +#endif + /* notice how "color" is spelled :P */ #ifdef HAVE_LCD_COLOR @@ -148,9 +155,7 @@ static inline int rand_range(int min, int max) /* prepares for exit */ static void cleanup(void) { -#ifdef HAVE_BACKLIGHT backlight_use_settings(); -#endif } /* returns 2 or 4 */ @@ -700,9 +705,8 @@ static void init_game(bool newgame) max_numeral_width = rb->font_get_width(rb->font_get(WHAT_FONT), '0'); #endif -#ifdef HAVE_BACKLIGHT backlight_ignore_timeout(); -#endif + draw(); } diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES index 332dd1bde4..cb0e407d31 100644 --- a/apps/plugins/CATEGORIES +++ b/apps/plugins/CATEGORIES @@ -50,6 +50,7 @@ keybox,apps keyremap,apps lamp,apps lastfm_scrobbler,apps +lastfm_scrobbler_viewer,viewers logo,demos lrcplayer,apps lua,viewers @@ -178,6 +179,7 @@ test_resize,apps test_sampr,apps test_scanrate,apps test_touchscreen,apps +test_usb,apps test_viewports,apps test_greylib_bitmap_scale,viewers text_editor,apps diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index c169b61cd1..28a4bc38f5 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES @@ -13,6 +13,7 @@ jackpot.c keybox.c keyremap.c lastfm_scrobbler.c +lastfm_scrobbler_viewer.c logo.c lrcplayer.c mosaique.c @@ -82,8 +83,7 @@ crypt_firmware.c /* Overlays loaders */ -#if defined(HAVE_LCD_COLOR) && \ - (!defined(LCD_STRIDEFORMAT) || (LCD_STRIDEFORMAT != VERTICAL_STRIDE)) +#if defined(HAVE_LCD_COLOR) && (LCD_STRIDEFORMAT == HORIZONTAL_STRIDE) #if (PLUGIN_BUFFER_SIZE > 0x14000) && (CONFIG_PLATFORM & (PLATFORM_NATIVE |PLATFORM_HOSTED)) && (defined(CPU_ARM) || defined(CPU_MIPS)) duke3d.c quake.c @@ -226,5 +226,6 @@ test_sampr.c #ifdef HAVE_TOUCHSCREEN test_touchscreen.c #endif +test_usb.c test_viewports.c #endif /* HAVE_TEST_PLUGINS */ diff --git a/apps/plugins/SUBDIRS b/apps/plugins/SUBDIRS index 8479e4b3dd..4cb57edb1b 100644 --- a/apps/plugins/SUBDIRS +++ b/apps/plugins/SUBDIRS @@ -9,8 +9,7 @@ clock #endif /* color horizontal-stride LCDs */ -#if defined(HAVE_LCD_COLOR) && \ - (!defined(LCD_STRIDEFORMAT) || (LCD_STRIDEFORMAT != VERTICAL_STRIDE)) +#if defined(HAVE_LCD_COLOR) && (LCD_STRIDEFORMAT == HORIZONTAL_STRIDE) xworld /* for duke3d, wolf3d and quake */ diff --git a/apps/plugins/alarmclock.c b/apps/plugins/alarmclock.c index ecafceddc7..aa7c13d1a4 100644 --- a/apps/plugins/alarmclock.c +++ b/apps/plugins/alarmclock.c @@ -138,7 +138,13 @@ enum plugin_status plugin_start(const void* parameter) while(!quit) { button = get_button(); +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) + if (button == PLA_EXIT || button == PLA_CANCEL || button == PLA_UP) +#else if (button == PLA_EXIT || button == PLA_CANCEL) +#endif quit = true; FOR_NB_SCREENS(i) { diff --git a/apps/plugins/announce_status.c b/apps/plugins/announce_status.c index 77e9015000..1ccfc1e70a 100644 --- a/apps/plugins/announce_status.c +++ b/apps/plugins/announce_status.c @@ -97,6 +97,7 @@ enum plugin_status plugin_start(const void* parameter); /* entry */ static struct { bool exiting; /* signal to the thread that we want to exit */ + bool resume; unsigned int id; /* worker thread id */ struct event_queue queue; /* thread event queue */ long stack[THREAD_STACK_SIZE / sizeof(long)]; @@ -393,7 +394,7 @@ static int settings_menu(void) break; case 4: /*sep*/ continue; - case 5: + case 5: /* quit the plugin */ return -1; break; case 6: @@ -433,7 +434,8 @@ void thread(void) in_usb = false; /*fall through*/ case EV_STARTUP: - rb->beep_play(1500, 100, 1000); + if (!gThread.resume) + rb->beep_play(1500, 100, 1000); break; case EV_EXIT: return; @@ -479,17 +481,45 @@ void thread_quit(void) } } +static bool check_user_input(void) +{ + int i = 0; + rb->button_clear_queue(); + if (rb->button_get_w_tmo(HZ) > BUTTON_NONE) + { + while ((rb->button_get(false) & BUTTON_REL) != BUTTON_REL) + { + if (i & 1) + rb->beep_play(800, 100, 1000 - i * (1000 / 15)); + + if (++i > 15) + { + return true; + } + rb->sleep(HZ / 5); + } + } + return false; +} + /* callback to end the TSR plugin, called before a new one gets loaded */ -static bool exit_tsr(bool reenter) +static int exit_tsr(bool reenter) { if (reenter) { rb->queue_post(&gThread.queue, EV_OTHINSTANCE, 0); - return false; /* dont let it start again */ + + /* quit the plugin if user holds a button */ + if (check_user_input() == true) + { + if (settings_menu() < 0) + return PLUGIN_TSR_TERMINATE; /*kill TSR dont let it start again */ + } + return PLUGIN_TSR_CONTINUE; /* dont let new plugin start*/ } thread_quit(); - return true; + return PLUGIN_TSR_SUSPEND; } @@ -497,58 +527,35 @@ static bool exit_tsr(bool reenter) int plugin_main(const void* parameter) { - (void)parameter; - bool settings = false; - int i = 0; - rb->memset(&gThread, 0, sizeof(gThread)); gAnnounce.index = 0; gAnnounce.timeout = 0; - - rb->splash(HZ / 2, "Announce Status"); - - if (configfile_load(CFG_FILE, config, gCfg_sz, CFG_VER) < 0) - { - /* If the loading failed, save a new config file */ - config_set_defaults(); - configfile_save(CFG_FILE, config, gCfg_sz, CFG_VER); - - rb->splash(HZ, ID2P(LANG_HOLD_FOR_SETTINGS)); - } - - if (gAnnounce.show_prompt) + /* Resume plugin ? */ + if (parameter == rb->plugin_tsr) { - if (rb->mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) != CHANNEL_PLAYING) - { - rb->talk_id(LANG_HOLD_FOR_SETTINGS, false); - } - rb->splash(HZ, ID2P(LANG_HOLD_FOR_SETTINGS)); + gThread.resume = true; } - - rb->button_clear_queue(); - if (rb->button_get_w_tmo(HZ) > BUTTON_NONE) + else { - while ((rb->button_get(false) & BUTTON_REL) != BUTTON_REL) + rb->splash(HZ / 2, "Announce Status"); + if (gAnnounce.show_prompt) { - if (i & 1) - rb->beep_play(800, 100, 1000); - - if (++i > 15) + if (rb->mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) != CHANNEL_PLAYING) { - settings = true; - break; + rb->talk_id(LANG_HOLD_FOR_SETTINGS, false); } - rb->sleep(HZ / 5); + rb->splash(HZ, ID2P(LANG_HOLD_FOR_SETTINGS)); } - } - if (settings) - { - rb->splash(100, ID2P(LANG_SETTINGS)); - int ret = settings_menu(); - if (ret < 0) - return 0; + + if (check_user_input() == true) + { + rb->splash(100, ID2P(LANG_SETTINGS)); + int ret = settings_menu(); + if (ret < 0) + return 0; + } } gAnnounce.timeout = *rb->current_tick; @@ -571,6 +578,16 @@ enum plugin_status plugin_start(const void* parameter) /* now go ahead and have fun! */ if (rb->usb_inserted() == true) return PLUGIN_USB_CONNECTED; + + config_set_defaults(); + if (configfile_load(CFG_FILE, config, gCfg_sz, CFG_VER) < 0) + { + /* If the loading failed, save a new config file */ + config_set_defaults(); + configfile_save(CFG_FILE, config, gCfg_sz, CFG_VER); + rb->splash(HZ, ID2P(LANG_HOLD_FOR_SETTINGS)); + } + int ret = plugin_main(parameter); return (ret==0) ? PLUGIN_OK : PLUGIN_ERROR; } diff --git a/apps/plugins/battery_bench.c b/apps/plugins/battery_bench.c index 17d3b918cf..f258492363 100644 --- a/apps/plugins/battery_bench.c +++ b/apps/plugins/battery_bench.c @@ -289,11 +289,11 @@ static struct event_queue thread_q SHAREDBSS_ATTR; static bool in_usb_mode; static unsigned int buf_idx; -static bool exit_tsr(bool reenter) +static int exit_tsr(bool reenter) { - bool is_exit; + int exit_status; long button; - (void)reenter; + rb->lcd_clear_display(); rb->lcd_puts_scroll(0, 0, "Batt.Bench is currently running."); rb->lcd_puts_scroll(0, 1, "Press " BATTERY_OFF_TXT " to cancel the test"); @@ -313,16 +313,17 @@ static bool exit_tsr(bool reenter) rb->thread_wait(gThread.id); /* remove the thread's queue from the broadcast list */ rb->queue_delete(&thread_q); - is_exit = true; + exit_status = (reenter ? PLUGIN_TSR_TERMINATE : PLUGIN_TSR_SUSPEND); + } - else is_exit = false; + else exit_status = PLUGIN_TSR_CONTINUE; break; } FOR_NB_SCREENS(idx) rb->screens[idx]->scroll_stop(); - return is_exit; + return exit_status; } #define BIT_CHARGER 0x1 @@ -502,14 +503,19 @@ static void put_centered_str(const char* str, plcdfunc putsxy, int lcd_width, in enum plugin_status plugin_start(const void* parameter) { - (void)parameter; int button, fd; + bool resume = false; bool on = false; start_tick = *rb->current_tick; int i; const char *msgs[] = { "Battery Benchmark","Check file", BATTERY_LOG, "for more info", BATTERY_ON_TXT, BATTERY_OFF_TXT " - quit" }; - rb->lcd_clear_display(); + + if (parameter == rb->plugin_tsr) + { + resume = true; + on = true; + } rb->lcd_clear_display(); rb->lcd_setfont(FONT_SYSFIXED); @@ -529,36 +535,38 @@ enum plugin_status plugin_start(const void* parameter) rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,2); rb->lcd_remote_update(); #endif - - do + if (!resume) { - button = rb->button_get(true); - switch (button) + do { - case BATTERY_ON: -#ifdef BATTERY_RC_ON - case BATTERY_RC_ON: -#endif - on = true; - break; - case BATTERY_OFF: -#ifdef BATTERY_RC_OFF - case BATTERY_RC_OFF: -#endif - return PLUGIN_OK; - - default: - if (rb->default_event_handler(button) == SYS_USB_CONNECTED) - return PLUGIN_USB_CONNECTED; - } - }while(!on); - + button = rb->button_get(true); + switch (button) + { + case BATTERY_ON: + #ifdef BATTERY_RC_ON + case BATTERY_RC_ON: + #endif + on = true; + break; + case BATTERY_OFF: + #ifdef BATTERY_RC_OFF + case BATTERY_RC_OFF: + #endif + return PLUGIN_OK; + + default: + if (rb->default_event_handler(button) == SYS_USB_CONNECTED) + return PLUGIN_USB_CONNECTED; + } + }while(!on); + } fd = rb->open(BATTERY_LOG, O_RDONLY); if (fd < 0) { fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT, 0666); if (fd >= 0) { + rb->fdprintf(fd, "# This plugin will log your battery performance in a\n" "# file (%s) every minute.\n" diff --git a/apps/plugins/bitmaps/native/SOURCES b/apps/plugins/bitmaps/native/SOURCES index f207f358b2..814845dc5b 100644 --- a/apps/plugins/bitmaps/native/SOURCES +++ b/apps/plugins/bitmaps/native/SOURCES @@ -548,8 +548,7 @@ pegbox_pieces.9x7x1.bmp #endif /* Puzzles */ -#if defined(HAVE_LCD_COLOR) && \ - (!defined(LCD_STRIDEFORMAT) || (LCD_STRIDEFORMAT != VERTICAL_STRIDE)) +#if defined(HAVE_LCD_COLOR) && (LCD_STRIDEFORMAT == HORIZONTAL_STRIDE) puzzles_cursor.11x16x24.bmp #endif @@ -974,6 +973,45 @@ rockboxlogo.91x32x1.bmp #endif #endif +/* Credits logo */ +#if (LCD_DEPTH == 1) +#if (LCD_WIDTH == 160) +creditslogo.160x53x1.bmp +#elif (LCD_WIDTH == 128) +creditslogo.128x42x1.bmp +#else +creditslogo.112x30x1.bmp +#endif +#elif (LCD_WIDTH == 96) && (LCD_DEPTH >= 16) +creditslogo.96x30x16.bmp +#elif (LCD_WIDTH == 128) && (LCD_DEPTH == 2) +creditslogo.128x42x2.bmp +#elif (LCD_WIDTH == 128) && (LCD_DEPTH >= 16) +creditslogo.128x40x16.bmp +#elif (LCD_WIDTH == 132) && (LCD_DEPTH >= 16) +creditslogo.132x40x16.bmp +#elif (LCD_WIDTH == 138) && (LCD_DEPTH >= 2) +creditslogo.138x46x2.bmp +#elif (LCD_WIDTH == 160) && (LCD_DEPTH == 2) +creditslogo.160x53x2.bmp +#elif (LCD_WIDTH == 320) && (LCD_DEPTH == 2) +creditslogo.160x53x2.bmp +#elif (LCD_WIDTH == 160) && (LCD_DEPTH >= 16) +creditslogo.160x50x16.bmp +#elif (LCD_WIDTH == 176) && (LCD_DEPTH >= 16) +creditslogo.176x54x16.bmp +#elif (LCD_WIDTH == 220) && (LCD_DEPTH >= 16) +creditslogo.220x68x16.bmp +#elif (LCD_WIDTH == 240) && (LCD_DEPTH >= 16) +creditslogo.240x74x16.bmp +#elif (LCD_WIDTH >= 320) && (LCD_WIDTH < 480) && (LCD_DEPTH >= 16) +creditslogo.320x98x16.bmp +#elif (LCD_WIDTH >= 480) && (LCD_WIDTH < 640) && (LCD_DEPTH >= 16) +creditslogo.480x149x16.bmp +#elif (LCD_WIDTH >= 640) && (LCD_DEPTH >= 16) +creditslogo.640x198x16.bmp +#endif + /* Pitch detector */ /* The following preprocessor condition must match the condition */ /* for pitch detector from plugins/SOURCES */ diff --git a/apps/plugins/bitmaps/native/creditslogo.112x30x1.bmp b/apps/plugins/bitmaps/native/creditslogo.112x30x1.bmp Binary files differnew file mode 100644 index 0000000000..c414ffb27b --- /dev/null +++ b/apps/plugins/bitmaps/native/creditslogo.112x30x1.bmp diff --git a/apps/plugins/bitmaps/native/creditslogo.128x40x16.bmp b/apps/plugins/bitmaps/native/creditslogo.128x40x16.bmp Binary files differnew file mode 100644 index 0000000000..228dbddbd5 --- /dev/null +++ b/apps/plugins/bitmaps/native/creditslogo.128x40x16.bmp diff --git a/apps/plugins/bitmaps/native/creditslogo.128x42x1.bmp b/apps/plugins/bitmaps/native/creditslogo.128x42x1.bmp Binary files differnew file mode 100644 index 0000000000..27d8e5fc26 --- /dev/null +++ b/apps/plugins/bitmaps/native/creditslogo.128x42x1.bmp diff --git a/apps/plugins/bitmaps/native/creditslogo.128x42x2.bmp b/apps/plugins/bitmaps/native/creditslogo.128x42x2.bmp Binary files differnew file mode 100644 index 0000000000..fa12aa4bd7 --- /dev/null +++ b/apps/plugins/bitmaps/native/creditslogo.128x42x2.bmp diff --git a/apps/plugins/bitmaps/native/creditslogo.132x40x16.bmp b/apps/plugins/bitmaps/native/creditslogo.132x40x16.bmp Binary files differnew file mode 100644 index 0000000000..865a8ed59d --- /dev/null +++ b/apps/plugins/bitmaps/native/creditslogo.132x40x16.bmp diff --git a/apps/plugins/bitmaps/native/creditslogo.138x46x2.bmp b/apps/plugins/bitmaps/native/creditslogo.138x46x2.bmp Binary files differnew file mode 100644 index 0000000000..4b5d7beb16 --- /dev/null +++ b/apps/plugins/bitmaps/native/creditslogo.138x46x2.bmp diff --git a/apps/plugins/bitmaps/native/creditslogo.160x50x16.bmp b/apps/plugins/bitmaps/native/creditslogo.160x50x16.bmp Binary files differnew file mode 100644 index 0000000000..59e472def1 --- /dev/null +++ b/apps/plugins/bitmaps/native/creditslogo.160x50x16.bmp diff --git a/apps/plugins/bitmaps/native/creditslogo.160x53x1.bmp b/apps/plugins/bitmaps/native/creditslogo.160x53x1.bmp Binary files differnew file mode 100644 index 0000000000..7e34b23c6b --- /dev/null +++ b/apps/plugins/bitmaps/native/creditslogo.160x53x1.bmp diff --git a/apps/plugins/bitmaps/native/creditslogo.160x53x2.bmp b/apps/plugins/bitmaps/native/creditslogo.160x53x2.bmp Binary files differnew file mode 100644 index 0000000000..240cf10686 --- /dev/null +++ b/apps/plugins/bitmaps/native/creditslogo.160x53x2.bmp diff --git a/apps/plugins/bitmaps/native/creditslogo.176x54x16.bmp b/apps/plugins/bitmaps/native/creditslogo.176x54x16.bmp Binary files differnew file mode 100644 index 0000000000..bf43a65e42 --- /dev/null +++ b/apps/plugins/bitmaps/native/creditslogo.176x54x16.bmp diff --git a/apps/plugins/bitmaps/native/creditslogo.220x68x16.bmp b/apps/plugins/bitmaps/native/creditslogo.220x68x16.bmp Binary files differnew file mode 100644 index 0000000000..1dc68a09f2 --- /dev/null +++ b/apps/plugins/bitmaps/native/creditslogo.220x68x16.bmp diff --git a/apps/plugins/bitmaps/native/creditslogo.240x74x16.bmp b/apps/plugins/bitmaps/native/creditslogo.240x74x16.bmp Binary files differnew file mode 100644 index 0000000000..fd335b2fb8 --- /dev/null +++ b/apps/plugins/bitmaps/native/creditslogo.240x74x16.bmp diff --git a/apps/plugins/bitmaps/native/creditslogo.320x98x16.bmp b/apps/plugins/bitmaps/native/creditslogo.320x98x16.bmp Binary files differnew file mode 100644 index 0000000000..26dcac89c3 --- /dev/null +++ b/apps/plugins/bitmaps/native/creditslogo.320x98x16.bmp diff --git a/apps/plugins/bitmaps/native/creditslogo.480x149x16.bmp b/apps/plugins/bitmaps/native/creditslogo.480x149x16.bmp Binary files differnew file mode 100644 index 0000000000..c73d9374e4 --- /dev/null +++ b/apps/plugins/bitmaps/native/creditslogo.480x149x16.bmp diff --git a/apps/plugins/bitmaps/native/creditslogo.640x198x16.bmp b/apps/plugins/bitmaps/native/creditslogo.640x198x16.bmp Binary files differnew file mode 100644 index 0000000000..ec6a16da5d --- /dev/null +++ b/apps/plugins/bitmaps/native/creditslogo.640x198x16.bmp diff --git a/apps/plugins/bitmaps/native/creditslogo.96x30x16.bmp b/apps/plugins/bitmaps/native/creditslogo.96x30x16.bmp Binary files differnew file mode 100644 index 0000000000..e032ebae34 --- /dev/null +++ b/apps/plugins/bitmaps/native/creditslogo.96x30x16.bmp diff --git a/apps/plugins/bitmaps/remote_native/SOURCES b/apps/plugins/bitmaps/remote_native/SOURCES index b3cc2157ff..2142674c67 100644 --- a/apps/plugins/bitmaps/remote_native/SOURCES +++ b/apps/plugins/bitmaps/remote_native/SOURCES @@ -22,3 +22,10 @@ remote_rockboxlogo.91x32x1.bmp #elif (LCD_REMOTE_DEPTH == 2) remote_rockboxlogo.91x32x2.bmp #endif + +/* Credits logo */ +#if (LCD_REMOTE_DEPTH == 1) +remote_creditslogo.128x42x1.bmp +#elif (LCD_REMOTE_DEPTH == 2) +remote_creditslogo.128x42x2.bmp +#endif diff --git a/apps/plugins/bitmaps/remote_native/remote_creditslogo.128x42x1.bmp b/apps/plugins/bitmaps/remote_native/remote_creditslogo.128x42x1.bmp Binary files differnew file mode 100644 index 0000000000..27d8e5fc26 --- /dev/null +++ b/apps/plugins/bitmaps/remote_native/remote_creditslogo.128x42x1.bmp diff --git a/apps/plugins/bitmaps/remote_native/remote_creditslogo.128x42x2.bmp b/apps/plugins/bitmaps/remote_native/remote_creditslogo.128x42x2.bmp Binary files differnew file mode 100644 index 0000000000..fa12aa4bd7 --- /dev/null +++ b/apps/plugins/bitmaps/remote_native/remote_creditslogo.128x42x2.bmp diff --git a/apps/plugins/bounce.c b/apps/plugins/bounce.c index e6f29817d6..a42a0af6ba 100644 --- a/apps/plugins/bounce.c +++ b/apps/plugins/bounce.c @@ -34,10 +34,6 @@ static const struct button_mapping *plugin_contexts[] = { pla_main_ctx }; /* We set button maping with PLA */ -#define BOUNCE_UP PLA_UP -#define BOUNCE_UP_REPEAT PLA_UP_REPEAT -#define BOUNCE_DOWN PLA_DOWN -#define BOUNCE_DOWN_REPEAT PLA_DOWN_REPEAT #ifdef HAVE_SCROLLWHEEL #define BOUNCE_LEFT PLA_SCROLL_BACK @@ -52,7 +48,22 @@ static const struct button_mapping *plugin_contexts[] = { pla_main_ctx }; #endif #define BOUNCE_QUIT PLA_EXIT + +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define BOUNCE_QUIT2 PLA_UP +#define BOUNCE_DOWN PLA_LEFT +#define BOUNCE_DOWN_REPEAT PLA_LEFT_REPEAT +#define BOUNCE_UP PLA_RIGHT +#define BOUNCE_UP_REPEAT PLA_RIGHT_REPEAT +#else #define BOUNCE_QUIT2 PLA_CANCEL +#define BOUNCE_DOWN PLA_DOWN +#define BOUNCE_DOWN_REPEAT PLA_DOWN_REPEAT +#define BOUNCE_UP PLA_UP +#define BOUNCE_UP_REPEAT PLA_UP_REPEAT +#endif #define BOUNCE_MODE PLA_SELECT #define LETTER_WIDTH 11 @@ -471,6 +482,10 @@ enum plugin_status plugin_start(const void* parameter) #if (CONFIG_KEYPAD == SAMSUNG_YH92X_PAD) || \ (CONFIG_KEYPAD == SAMSUNG_YH820_PAD) "[Rew] to stop"; +#elif (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) + "[Menu] to stop"; #else "[Off] to stop"; #endif diff --git a/apps/plugins/brickmania.c b/apps/plugins/brickmania.c index 4983d5a417..de65ce69e1 100644 --- a/apps/plugins/brickmania.c +++ b/apps/plugins/brickmania.c @@ -111,8 +111,7 @@ #elif CONFIG_KEYPAD == SANSA_C200_PAD || \ CONFIG_KEYPAD == SANSA_CLIP_PAD || \ -CONFIG_KEYPAD == SANSA_M200_PAD || \ -CONFIG_KEYPAD == SANSA_CONNECT_PAD +CONFIG_KEYPAD == SANSA_M200_PAD #define QUIT BUTTON_POWER #define LEFT BUTTON_LEFT #define RIGHT BUTTON_RIGHT @@ -122,6 +121,18 @@ CONFIG_KEYPAD == SANSA_CONNECT_PAD #define UP BUTTON_UP #define DOWN BUTTON_DOWN +#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD +#define QUIT BUTTON_POWER +#define LEFT BUTTON_LEFT +#define RIGHT BUTTON_RIGHT +#define SELECT BUTTON_SELECT +#define UP BUTTON_UP +#define DOWN BUTTON_DOWN + +#define SCROLL_FWD(x) ((x) & BUTTON_SCROLL_FWD) +#define SCROLL_BACK(x) ((x) & BUTTON_SCROLL_BACK) + + #elif CONFIG_KEYPAD == IRIVER_H10_PAD #define QUIT BUTTON_POWER #define LEFT BUTTON_LEFT @@ -2522,10 +2533,10 @@ enum plugin_status plugin_start(const void* parameter) #if LCD_DEPTH > 1 rb->lcd_set_backdrop(NULL); #endif -#ifdef HAVE_BACKLIGHT + /* Turn off backlight timeout */ backlight_ignore_timeout(); -#endif + /* now go ahead and have fun! */ rb->srand( *rb->current_tick ); brickmania_loadgame(); @@ -2554,9 +2565,9 @@ enum plugin_status plugin_start(const void* parameter) configfile_save(CONFIG_FILE_NAME,config,1,0); /* Restore user's original backlight setting */ rb->lcd_setfont(FONT_UI); -#ifdef HAVE_BACKLIGHT + /* Turn on backlight timeout (revert to settings) */ backlight_use_settings(); -#endif + return PLUGIN_OK; } diff --git a/apps/plugins/bubbles.c b/apps/plugins/bubbles.c index 88d7228d72..a64093492f 100644 --- a/apps/plugins/bubbles.c +++ b/apps/plugins/bubbles.c @@ -79,7 +79,6 @@ enum { #define ANGLE_STEP_REP 6 #define BUBBLES_QUIT1 PLA_EXIT -#define BUBBLES_QUIT2 PLA_CANCEL /* these are better off shooting with up */ #if (CONFIG_KEYPAD == SAMSUNG_YH820_PAD) \ @@ -92,10 +91,19 @@ enum { #define BUBBLES_FIRE PLA_UP #define BUBBLES_FIRE_REPEAT PLA_UP_REPEAT #define BUBBLES_PAUSE PLA_SELECT +#define BUBBLES_QUIT2 PLA_CANCEL +#elif (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define BUBBLES_FIRE PLA_SELECT +#define BUBBLES_FIRE_REPEAT PLA_SELECT_REPEAT +#define BUBBLES_PAUSE PLA_DOWN +#define BUBBLES_QUIT2 PLA_UP #else #define BUBBLES_FIRE PLA_SELECT #define BUBBLES_FIRE_REPEAT PLA_SELECT_REPEAT #define BUBBLES_PAUSE PLA_UP +#define BUBBLES_QUIT2 PLA_CANCEL #endif /* external bitmaps */ diff --git a/apps/plugins/calendar.c b/apps/plugins/calendar.c index 3299a81273..765b42ef59 100644 --- a/apps/plugins/calendar.c +++ b/apps/plugins/calendar.c @@ -39,14 +39,12 @@ #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) -#define CALENDAR_QUIT (BUTTON_SELECT|BUTTON_MENU) +#define CALENDAR_QUIT (BUTTON_MENU|BUTTON_REL) #define CALENDAR_SELECT (BUTTON_SELECT|BUTTON_REL) #define CALENDAR_NEXT_WEEK BUTTON_SCROLL_FWD #define CALENDAR_PREV_WEEK BUTTON_SCROLL_BACK #define CALENDAR_NEXT_DAY BUTTON_RIGHT #define CALENDAR_PREV_DAY BUTTON_LEFT -#define CALENDAR_NEXT_MONTH BUTTON_PLAY -#define CALENDAR_PREV_MONTH (BUTTON_MENU|BUTTON_REL) #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD) #define CALENDAR_QUIT BUTTON_POWER @@ -964,7 +962,7 @@ static bool view_events(int selected, struct shown *shown) while (!exit) { button = rb->get_action(CONTEXT_LIST, TIMEOUT_BLOCK); - rb->gui_synclist_do_button(&gui_memos, &button, LIST_WRAP_UNLESS_HELD); + rb->gui_synclist_do_button(&gui_memos, &button); switch (button) { @@ -1095,17 +1093,18 @@ enum plugin_status plugin_start(const void* parameter) case CALENDAR_QUIT: exit = true; break; - +#ifdef CALENDAR_NEXT_MONTH case CALENDAR_NEXT_MONTH: case CALENDAR_NEXT_MONTH | BUTTON_REPEAT: next_month(&shown, 0); break; - +#endif +#ifdef CALENDAR_PREV_MONTH case CALENDAR_PREV_MONTH: case CALENDAR_PREV_MONTH | BUTTON_REPEAT: prev_month(&shown, 0); break; - +#endif case CALENDAR_NEXT_WEEK: case CALENDAR_NEXT_WEEK | BUTTON_REPEAT: next_day(&shown, 7); diff --git a/apps/plugins/chessbox/chessbox_pgn.c b/apps/plugins/chessbox/chessbox_pgn.c index 0d9da441b1..bb35bec726 100644 --- a/apps/plugins/chessbox/chessbox_pgn.c +++ b/apps/plugins/chessbox/chessbox_pgn.c @@ -678,7 +678,6 @@ struct pgn_game_node* pgn_show_game_list(struct pgn_game_node* first_game){ if (rb->global_settings->talk_menu) rb->gui_synclist_set_voice_callback(&games_list, speak_game_selection); rb->gui_synclist_set_nb_items(&games_list, i); - rb->gui_synclist_limit_scroll(&games_list, true); rb->gui_synclist_select_item(&games_list, 0); rb->gui_synclist_draw(&games_list); @@ -687,9 +686,8 @@ struct pgn_game_node* pgn_show_game_list(struct pgn_game_node* first_game){ while (true) { curr_selection = rb->gui_synclist_get_sel_pos(&games_list); button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK); - if (rb->gui_synclist_do_button(&games_list,&button,LIST_WRAP_OFF)){ + if (rb->gui_synclist_do_button(&games_list, &button)) continue; - } switch (button) { case ACTION_STD_OK: return get_game_info(curr_selection, first_game); diff --git a/apps/plugins/chessbox/chessbox_pgn.h b/apps/plugins/chessbox/chessbox_pgn.h index 9d4f369ecc..7d0cb795cf 100644 --- a/apps/plugins/chessbox/chessbox_pgn.h +++ b/apps/plugins/chessbox/chessbox_pgn.h @@ -33,7 +33,7 @@ #define CB_PLAY (BUTTON_SELECT | BUTTON_PLAY) #define CB_LEVEL (BUTTON_SELECT | BUTTON_RIGHT) #define CB_RESTART (BUTTON_SELECT | BUTTON_LEFT) -#define CB_MENU (BUTTON_SELECT | BUTTON_MENU) +#define CB_MENU (BUTTON_SELECT | BUTTON_REPEAT) #define CB_SCROLL_UP (BUTTON_SCROLL_FWD|BUTTON_REPEAT) #define CB_SCROLL_DOWN (BUTTON_SCROLL_BACK|BUTTON_REPEAT) #define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT) diff --git a/apps/plugins/chopper.c b/apps/plugins/chopper.c index 392b840317..5c87e74e50 100644 --- a/apps/plugins/chopper.c +++ b/apps/plugins/chopper.c @@ -1083,10 +1083,10 @@ enum plugin_status plugin_start(const void* parameter) rb->lcd_set_foreground(LCD_WHITE); #endif -#ifdef HAVE_BACKLIGHT + /* Turn off backlight timeout */ backlight_ignore_timeout(); -#endif + rb->srand( *rb->current_tick ); @@ -1098,10 +1098,10 @@ enum plugin_status plugin_start(const void* parameter) configfile_save(CFG_FILE, config, 1, 0); rb->lcd_setfont(FONT_UI); -#ifdef HAVE_BACKLIGHT + /* Turn on backlight timeout (revert to settings) */ backlight_use_settings(); -#endif + return ret; } diff --git a/apps/plugins/clix.c b/apps/plugins/clix.c index 9cd66a8034..06813f3a4d 100644 --- a/apps/plugins/clix.c +++ b/apps/plugins/clix.c @@ -66,9 +66,7 @@ #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) -#define CLIX_BUTTON_QUIT (BUTTON_SELECT | BUTTON_MENU) -#define CLIX_BUTTON_UP BUTTON_MENU -#define CLIX_BUTTON_DOWN BUTTON_PLAY +#define CLIX_BUTTON_QUIT BUTTON_MENU #define CLIX_BUTTON_SCROLL_FWD BUTTON_SCROLL_FWD #define CLIX_BUTTON_SCROLL_BACK BUTTON_SCROLL_BACK #define CLIX_BUTTON_CLICK BUTTON_SELECT @@ -921,8 +919,10 @@ static int clix_handle_game(struct clix_game_state_t* state) case CLIX_BUTTON_SCROLL_BACK: case CLIX_BUTTON_SCROLL_BACK|BUTTON_REPEAT: #endif +#ifdef CLIX_BUTTON_UP case CLIX_BUTTON_UP: case CLIX_BUTTON_UP|BUTTON_REPEAT: +#endif if( state->y == 0 || state->board[ XYPOS( state->x, state->y - 1)] == CC_BLACK @@ -938,8 +938,10 @@ static int clix_handle_game(struct clix_game_state_t* state) case CLIX_BUTTON_SCROLL_FWD: case CLIX_BUTTON_SCROLL_FWD|BUTTON_REPEAT: #endif +#ifdef CLIX_BUTTON_DOWN case CLIX_BUTTON_DOWN: case CLIX_BUTTON_DOWN|BUTTON_REPEAT: +#endif if( state->y == (BOARD_HEIGHT - 1)) state->y = 0; else diff --git a/apps/plugins/clock/clock.c b/apps/plugins/clock/clock.c index d287c75598..c61b466aba 100644 --- a/apps/plugins/clock/clock.c +++ b/apps/plugins/clock/clock.c @@ -44,13 +44,19 @@ const struct button_mapping* plugin_contexts[]={ #define ACTION_COUNTER_TOGGLE PLA_SELECT #define ACTION_COUNTER_RESET PLA_SELECT_REPEAT -#define ACTION_MENU PLA_CANCEL #define ACTION_MODE_NEXT PLA_RIGHT #define ACTION_MODE_NEXT_REPEAT PLA_RIGHT_REPEAT #define ACTION_MODE_PREV PLA_LEFT #define ACTION_MODE_PREV_REPEAT PLA_LEFT_REPEAT +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define ACTION_MENU PLA_UP +#else +#define ACTION_MENU PLA_CANCEL #define ACTION_SKIN_NEXT PLA_UP #define ACTION_SKIN_NEXT_REPEAT PLA_UP_REPEAT +#endif #define ACTION_SKIN_PREV PLA_DOWN #define ACTION_SKIN_PREV_REPEAT PLA_DOWN_REPEAT @@ -165,10 +171,12 @@ enum plugin_status plugin_start(const void* parameter){ case ACTION_SKIN_PREV: clock_settings_skin_next(&clock_settings); break; +#if defined(ACTION_SKIN_NEXT) && defined(ACTION_SKIN_NEXT_REPEAT) case ACTION_SKIN_NEXT_REPEAT: case ACTION_SKIN_NEXT: clock_settings_skin_previous(&clock_settings); break; +#endif case ACTION_MENU: clock_draw_restore_colors(); exit_clock=main_menu(); diff --git a/apps/plugins/codebuster.c b/apps/plugins/codebuster.c index 956991575d..401ce6085f 100644 --- a/apps/plugins/codebuster.c +++ b/apps/plugins/codebuster.c @@ -438,6 +438,13 @@ enum plugin_status plugin_start(const void* parameter) { if (button == PLA_SELECT) break; +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) + if (button == PLA_UP) /* Menu button */ + button = PLA_CANCEL; +#endif + switch (button) { /* Exit */ diff --git a/apps/plugins/credits.c b/apps/plugins/credits.c index 9e43aab2a7..f4716651fd 100644 --- a/apps/plugins/credits.c +++ b/apps/plugins/credits.c @@ -21,7 +21,19 @@ #include "plugin.h" #include "lib/helper.h" - +#ifdef HAVE_REMOTE_LCD +#define REMOTE_WIDTH LCD_REMOTE_WIDTH +#define REMOTE_HEIGHT LCD_REMOTE_HEIGHT +#include "pluginbitmaps/remote_creditslogo.h" +#define REMOTE_LOGO_WIDTH BMPWIDTH_remote_creditslogo +#define REMOTE_LOGO_HEIGHT BMPHEIGHT_remote_creditslogo +#define REMOTE_LOGO (const fb_remote_data*)remote_creditslogo +#endif /* HAVE_REMOTE_LCD */ + +#define LOGO (const fb_data*)creditslogo +#include "pluginbitmaps/creditslogo.h" +#define LOGO_WIDTH BMPWIDTH_creditslogo +#define LOGO_HEIGHT BMPHEIGHT_creditslogo static const char* const credits[] = { #include "credits.raw" /* generated list of names from docs/CREDITS */ @@ -299,29 +311,78 @@ static void roll_credits(void) } } +int show_logo(void) +{ + unsigned char version[32]; + int font_h, ver_w; + rb->snprintf(version, sizeof(version), "Ver. %s", rb->rbversion); + ver_w = rb->font_getstringsize(version, NULL, &font_h, FONT_SYSFIXED); + rb->lcd_clear_display(); + rb->lcd_setfont(FONT_SYSFIXED); +#if defined(SANSA_CLIP) || defined(SANSA_CLIPV2) || defined(SANSA_CLIPPLUS) + /* display the logo in the blue area of the screen (bottom 48 pixels) */ + if (ver_w > LCD_WIDTH) + rb->lcd_puts_scroll(0, 0, version); + else + rb->lcd_putsxy((LCD_WIDTH/2) - (ver_w/2), 0, version); + rb->lcd_bitmap(LOGO, (LCD_WIDTH - LOGO_WIDTH) / 2, 16, + LOGO_WIDTH, LOGO_HEIGHT); +#else + rb->lcd_bitmap(LOGO, (LCD_WIDTH - LOGO_WIDTH) / 2, 10, + LOGO_WIDTH, LOGO_HEIGHT); + if (ver_w > LCD_WIDTH) + rb->lcd_puts_scroll(0, (LCD_HEIGHT-font_h) / font_h, version); + else + rb->lcd_putsxy((LCD_WIDTH/2) - (ver_w/2), LCD_HEIGHT-font_h, version); +#endif + rb->lcd_setfont(FONT_UI); + rb->lcd_update(); +#ifdef HAVE_REMOTE_LCD + rb->lcd_remote_clear_display(); + rb->lcd_remote_bitmap(REMOTE_LOGO, 0, 10, + REMOTE_LOGO_WIDTH, REMOTE_LOGO_HEIGHT); + rb->lcd_remote_setfont(FONT_SYSFIXED); + if (ver_w > LCD_REMOTE_WIDTH) + rb->lcd_remote_puts_scroll(0, (LCD_REMOTE_HEIGHT-font_h) / font_h, version); + else + rb->lcd_remote_putsxy((LCD_REMOTE_WIDTH/2) - (ver_w/2), + LCD_REMOTE_HEIGHT-font_h, version); + rb->lcd_remote_setfont(FONT_UI); + rb->lcd_remote_update(); +#endif + + return 0; +} + enum plugin_status plugin_start(const void* parameter) { (void)parameter; -#ifdef HAVE_BACKLIGHT + /* Turn off backlight timeout */ backlight_ignore_timeout(); -#endif -#if LCD_DEPTH>=16 +#if LCD_DEPTH >= 16 rb->lcd_set_foreground (LCD_WHITE); rb->lcd_set_background (LCD_BLACK); #endif - rb->show_logo(); - /* Show the logo for about 3 secs allowing the user to stop */ - if(!rb->action_userabort(3*HZ)) + show_logo(); + + /* Show the logo for about 5 secs allowing the user to stop */ + if(!rb->action_userabort(5*HZ)) + { + rb->lcd_scroll_stop(); roll_credits(); + } + +#ifdef HAVE_REMOTE_LCD + rb->lcd_remote_scroll_stop(); +#endif -#ifdef HAVE_BACKLIGHT /* Turn on backlight timeout (revert to settings) */ backlight_use_settings(); -#endif + return PLUGIN_OK; } diff --git a/apps/plugins/cube.c b/apps/plugins/cube.c index dfd7df8951..43318f5aee 100644 --- a/apps/plugins/cube.c +++ b/apps/plugins/cube.c @@ -52,12 +52,14 @@ #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) -#define CUBE_QUIT (BUTTON_SELECT | BUTTON_MENU) +#define CUBE_QUIT_PRE BUTTON_MENU +#define CUBE_QUIT (BUTTON_MENU | BUTTON_REL) #define CUBE_NEXT BUTTON_RIGHT #define CUBE_PREV BUTTON_LEFT #define CUBE_INC BUTTON_SCROLL_FWD #define CUBE_DEC BUTTON_SCROLL_BACK -#define CUBE_MODE BUTTON_MENU +#define CUBE_MODE_PRE BUTTON_MENU +#define CUBE_MODE (BUTTON_MENU | BUTTON_REPEAT) #define CUBE_PAUSE BUTTON_PLAY #define CUBE_HIGHSPEED_PRE BUTTON_SELECT #define CUBE_HIGHSPEED (BUTTON_SELECT | BUTTON_REL) @@ -729,6 +731,7 @@ enum plugin_status plugin_start(const void* parameter) int button; #if defined(CUBE_MODE_PRE) || \ + defined(CUBE_QUIT_PRE) || \ defined(CUBE_PAUSE_PRE) || \ defined(CUBE_HIGHSPEED_PRE) int lastbutton = BUTTON_NONE; @@ -903,6 +906,10 @@ enum plugin_status plugin_start(const void* parameter) case CUBE_RC_QUIT: #endif case CUBE_QUIT: +#ifdef CUBE_QUIT_PRE + if (lastbutton != CUBE_QUIT_PRE) + break; +#endif quit = true; break; @@ -911,6 +918,7 @@ enum plugin_status plugin_start(const void* parameter) break; } #if defined(CUBE_MODE_PRE) || \ + defined(CUBE_QUIT_PRE) || \ defined(CUBE_PAUSE_PRE) || \ defined(CUBE_HIGHSPEED_PRE) if (button != BUTTON_NONE) diff --git a/apps/plugins/demystify.c b/apps/plugins/demystify.c index 74537e94f8..cb8e4ddf72 100644 --- a/apps/plugins/demystify.c +++ b/apps/plugins/demystify.c @@ -37,26 +37,42 @@ #define MIN_POLYGONS 1 /* Key assignement */ -#define DEMYSTIFY_QUIT PLA_CANCEL #ifdef HAVE_SCROLLWHEEL +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define DEMYSTIFY_QUIT PLA_UP +#else +#define DEMYSTIFY_QUIT PLA_CANCEL +#endif + #define DEMYSTIFY_INCREASE_SPEED PLA_SCROLL_FWD #define DEMYSTIFY_DECREASE_SPEED PLA_SCROLL_BACK #define DEMYSTIFY_INCREASE_SPEED_REPEAT PLA_SCROLL_FWD_REPEAT #define DEMYSTIFY_DECREASE_SPEED_REPEAT PLA_SCROLL_BACK_REPEAT + +#define DEMYSTIFY_ADD_POLYGON PLA_RIGHT +#define DEMYSTIFY_REMOVE_POLYGON PLA_LEFT +#define DEMYSTIFY_ADD_POLYGON_REPEAT PLA_RIGHT_REPEAT +#define DEMYSTIFY_REMOVE_POLYGON_REPEAT PLA_LEFT_REPEAT + #else + +#define DEMYSTIFY_QUIT PLA_CANCEL + #define DEMYSTIFY_INCREASE_SPEED PLA_RIGHT #define DEMYSTIFY_DECREASE_SPEED PLA_LEFT #define DEMYSTIFY_INCREASE_SPEED_REPEAT PLA_RIGHT_REPEAT #define DEMYSTIFY_DECREASE_SPEED_REPEAT PLA_LEFT_REPEAT -#endif #define DEMYSTIFY_ADD_POLYGON PLA_UP #define DEMYSTIFY_REMOVE_POLYGON PLA_DOWN #define DEMYSTIFY_ADD_POLYGON_REPEAT PLA_UP_REPEAT #define DEMYSTIFY_REMOVE_POLYGON_REPEAT PLA_DOWN_REPEAT +#endif const struct button_mapping *plugin_contexts[] = {pla_main_ctx, #if defined(HAVE_REMOTE_LCD) @@ -262,12 +278,10 @@ static void polygons_draw(struct polygon_fifo * polygons, struct screen * displa static void cleanup(void) { -#ifdef HAVE_BACKLIGHT + backlight_use_settings(); -#ifdef HAVE_REMOTE_LCD remote_backlight_use_settings(); -#endif -#endif + } #ifdef HAVE_LCD_COLOR @@ -438,12 +452,10 @@ enum plugin_status plugin_start(const void* parameter) #if LCD_DEPTH > 1 rb->lcd_set_backdrop(NULL); #endif -#ifdef HAVE_BACKLIGHT + backlight_ignore_timeout(); -#ifdef HAVE_REMOTE_LCD remote_backlight_ignore_timeout(); -#endif -#endif + ret = plugin_main(); return ret; diff --git a/apps/plugins/dice.c b/apps/plugins/dice.c index 622c58d71d..7580697267 100644 --- a/apps/plugins/dice.c +++ b/apps/plugins/dice.c @@ -28,7 +28,14 @@ #define INITIAL_NB_DICES 1 #define INITIAL_NB_SIDES 2 /* corresponds to 6 sides in the array */ + +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define DICE_QUIT PLA_UP +#else #define DICE_QUIT PLA_CANCEL +#endif #define DICE_ROLL PLA_SELECT diff --git a/apps/plugins/doom/d_deh.c b/apps/plugins/doom/d_deh.c index 1a399e3b49..0a67aa0aad 100644 --- a/apps/plugins/doom/d_deh.c +++ b/apps/plugins/doom/d_deh.c @@ -63,7 +63,7 @@ char* strlwr(char* str) typedef struct { const byte *inp; // Pointer to string size_t size; // Bytes remaining in string - int fd; // Current file descriptor + int fd; // Current file descriptor } DEHFILE; // killough 10/98: emulate IO whether input really comes from a file or not @@ -2868,6 +2868,7 @@ boolean deh_GetData(char *s, char *k, uint_64_t *l, char **strval, int fpout) if (*t == '=') break; buffer[i] = *t; // copy it } + if (i == 0) i = 1; /* Just in case */ buffer[--i] = '\0'; // terminate the key before the '=' if (!*t) // end of string with no equal sign { diff --git a/apps/plugins/doom/i_video.c b/apps/plugins/doom/i_video.c index f5d07a8354..79f3212467 100644 --- a/apps/plugins/doom/i_video.c +++ b/apps/plugins/doom/i_video.c @@ -453,6 +453,9 @@ void I_ShutdownGraphics(void) #define DOOMBUTTON_MAP BUTTON_BOTTOMRIGHT #elif CONFIG_KEYPAD == SANSA_CONNECT_PAD +#define DOOMBUTTON_SCROLLWHEEL +#define DOOMBUTTON_SCROLLWHEEL_CC BUTTON_SCROLL_BACK +#define DOOMBUTTON_SCROLLWHEEL_CW BUTTON_SCROLL_FWD #define DOOMBUTTON_UP BUTTON_UP #define DOOMBUTTON_DOWN BUTTON_DOWN #define DOOMBUTTON_LEFT BUTTON_LEFT diff --git a/apps/plugins/doom/rockdoom.c b/apps/plugins/doom/rockdoom.c index 6594859c08..b68107f8aa 100644 --- a/apps/plugins/doom/rockdoom.c +++ b/apps/plugins/doom/rockdoom.c @@ -722,9 +722,9 @@ enum plugin_status plugin_start(const void* parameter) systemvol= rb->global_settings->volume-rb->global_settings->volume%mod; general_translucency = default_translucency; // phares -#ifdef HAVE_BACKLIGHT + backlight_ignore_timeout(); -#endif + #ifdef RB_PROFILE rb->profile_thread(); #endif @@ -738,9 +738,9 @@ enum plugin_status plugin_start(const void* parameter) #ifdef RB_PROFILE rb->profstop(); #endif -#ifdef HAVE_BACKLIGHT + backlight_use_settings(); -#endif + M_SaveDefaults (); I_Quit(); // Make SURE everything was closed out right diff --git a/apps/plugins/fft/fft.c b/apps/plugins/fft/fft.c index 35498227bf..4d36302ddf 100644 --- a/apps/plugins/fft/fft.c +++ b/apps/plugins/fft/fft.c @@ -40,13 +40,22 @@ GREY_INFO_STRUCT /* this set the context to use with PLA */ static const struct button_mapping *plugin_contexts[] = { pla_main_ctx }; -#define FFT_PREV_GRAPH PLA_LEFT -#define FFT_NEXT_GRAPH PLA_RIGHT -#define FFT_ORIENTATION PLA_CANCEL -#define FFT_WINDOW PLA_SELECT -#define FFT_AMP_SCALE PLA_UP -#define FFT_FREQ_SCALE PLA_DOWN -#define FFT_QUIT PLA_EXIT +#define FFT_PREV_GRAPH PLA_LEFT +#define FFT_NEXT_GRAPH PLA_RIGHT +#define FFT_ORIENTATION PLA_CANCEL +#define FFT_WINDOW PLA_SELECT_REL +#define FFT_AMP_SCALE PLA_SELECT_REPEAT +#define FFT_AMP_SCALE_PRE PLA_SELECT +#define FFT_FREQ_SCALE PLA_DOWN + + +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define FFT_QUIT PLA_UP +#else +#define FFT_QUIT PLA_EXIT +#endif #ifdef HAVE_LCD_COLOR #include "pluginbitmaps/fft_colors.h" @@ -1184,9 +1193,8 @@ static void fft_cleanup(void) #ifndef HAVE_LCD_COLOR grey_release(); #endif -#ifdef HAVE_BACKLIGHT + backlight_use_settings(); -#endif /* save settings if changed */ if (rb->memcmp(&fft, &fft_disk, sizeof(fft))) @@ -1237,9 +1245,8 @@ static bool fft_setup(void) mylcd_clear_display(); myosd_lcd_update(); #endif -#ifdef HAVE_BACKLIGHT + backlight_ignore_timeout(); -#endif #ifdef HAVE_ADJUSTABLE_CPU_FREQ rb->trigger_cpu_boost(); @@ -1259,6 +1266,10 @@ enum plugin_status plugin_start(const void* parameter) if(!fft_setup()) return PLUGIN_ERROR; +#if defined(FFT_AMP_SCALE_PRE) + int lastbutton = BUTTON_NONE; +#endif + while(run) { long delay = fft_draw(); @@ -1302,6 +1313,10 @@ enum plugin_status plugin_start(const void* parameter) break; case FFT_AMP_SCALE: +#ifdef FFT_AMP_SCALE_PRE + if (lastbutton != FFT_AMP_SCALE_PRE) + break; +#endif if (++fft.amp_scale >= FFT_MAX_AS) fft.amp_scale = FFT_MIN_AS; @@ -1330,6 +1345,11 @@ enum plugin_status plugin_start(const void* parameter) exit_on_usb(button); break; } + +#if defined(FFT_AMP_SCALE_PRE) + if (button != BUTTON_NONE) + lastbutton = button; +#endif } return PLUGIN_OK; diff --git a/apps/plugins/fire.c b/apps/plugins/fire.c index f3e6fb35e4..5cdf4a2d3a 100644 --- a/apps/plugins/fire.c +++ b/apps/plugins/fire.c @@ -56,10 +56,17 @@ const struct button_mapping* plugin_contexts[]= { }; #define FIRE_QUIT PLA_CANCEL -#define FIRE_QUIT2 PLA_EXIT #define FIRE_SWITCH_FLAMES_TYPE PLA_LEFT #define FIRE_SWITCH_FLAMES_MOVING PLA_RIGHT +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define FIRE_QUIT2 PLA_UP +#else +#define FIRE_QUIT2 PLA_EXIT +#endif + #ifdef HAVE_SCROLLWHEEL #define FIRE_INCREASE_MULT PLA_SCROLL_FWD #define FIRE_INCREASE_MULT_REP PLA_SCROLL_FWD_REPEAT @@ -279,10 +286,9 @@ static void cleanup(void *parameter) #ifndef HAVE_LCD_COLOR grey_release(); #endif -#ifdef HAVE_BACKLIGHT + /* Turn on backlight timeout (revert to settings) */ backlight_use_settings(); -#endif } @@ -371,10 +377,9 @@ enum plugin_status plugin_start(const void* parameter) #if LCD_DEPTH > 1 rb->lcd_set_backdrop(NULL); #endif -#ifdef HAVE_BACKLIGHT + /* Turn off backlight timeout */ backlight_ignore_timeout(); -#endif #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256) rb->lcd_set_mode(LCD_MODE_PAL256); diff --git a/apps/plugins/fireworks.c b/apps/plugins/fireworks.c index b7dad0d8ba..54a6d07c20 100644 --- a/apps/plugins/fireworks.c +++ b/apps/plugins/fireworks.c @@ -35,10 +35,17 @@ static const struct button_mapping *plugin_contexts[] = { pla_main_ctx }; /* We use PLA */ #define BTN_EXIT PLA_EXIT -#define BTN_MENU PLA_CANCEL #define BTN_FIRE PLA_SELECT #define BTN_FIRE_REPEAT PLA_SELECT_REPEAT +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define BTN_MENU PLA_UP +#else +#define BTN_MENU PLA_CANCEL +#endif + /* The lowdown on source terminology: * a ROCKET is launched from the LCD bottom. * FIREWORKs are ejected from the rocket when it explodes. */ @@ -358,9 +365,9 @@ enum plugin_status plugin_start(const void* parameter) /* set everything up.. no BL timeout, no backdrop, white-text-on-black-background. */ -#ifdef HAVE_BACKLIGHT + backlight_ignore_timeout(); -#endif + #if LCD_DEPTH > 1 rb->lcd_set_backdrop(NULL); rb->lcd_set_background(LCD_BLACK); @@ -524,10 +531,10 @@ enum plugin_status plugin_start(const void* parameter) break; } } -#ifdef HAVE_BACKLIGHT + /* Turn on backlight timeout (revert to settings) */ backlight_use_settings(); -#endif + #ifdef HAVE_ADJUSTABLE_CPU_FREQ rb->cpu_boost(false); #endif diff --git a/apps/plugins/flipit.c b/apps/plugins/flipit.c index c659cf5ba5..278c77e188 100644 --- a/apps/plugins/flipit.c +++ b/apps/plugins/flipit.c @@ -49,7 +49,7 @@ #define FLIPIT_DOWN BUTTON_PLAY #define FLIPIT_NEXT BUTTON_SCROLL_FWD #define FLIPIT_PREV BUTTON_SCROLL_BACK -#define FLIPIT_QUIT (BUTTON_SELECT | BUTTON_MENU) +#define FLIPIT_QUIT (BUTTON_SELECT | BUTTON_REPEAT) #define FLIPIT_SHUFFLE (BUTTON_SELECT | BUTTON_LEFT) #define FLIPIT_SOLVE (BUTTON_SELECT | BUTTON_PLAY) #define FLIPIT_STEP_BY_STEP (BUTTON_SELECT | BUTTON_RIGHT) @@ -841,7 +841,7 @@ enum plugin_status plugin_start(const void* parameter) #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) - rb->lcd_putsxy(2, 8, "[S-MENU] to stop"); + rb->lcd_putsxy(2, 8, "Long [SELECT] to stop"); rb->lcd_putsxy(2, 18, "[SELECT] toggle"); rb->lcd_putsxy(2, 28, "[S-LEFT] shuffle"); rb->lcd_putsxy(2, 38, "[S-PLAY] solution"); diff --git a/apps/plugins/fractals/fractal.h b/apps/plugins/fractals/fractal.h index 8e9446df0d..8432546c1e 100644 --- a/apps/plugins/fractals/fractal.h +++ b/apps/plugins/fractals/fractal.h @@ -40,7 +40,7 @@ #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) -#define FRACTAL_QUIT (BUTTON_SELECT | BUTTON_MENU) +#define FRACTAL_QUIT (BUTTON_SELECT | BUTTON_REPEAT) #define FRACTAL_UP BUTTON_MENU #define FRACTAL_DOWN BUTTON_PLAY #define FRACTAL_LEFT BUTTON_LEFT diff --git a/apps/plugins/imageviewer/image_decoder.c b/apps/plugins/imageviewer/image_decoder.c index eab1c01dbc..0c1776daaa 100644 --- a/apps/plugins/imageviewer/image_decoder.c +++ b/apps/plugins/imageviewer/image_decoder.c @@ -155,7 +155,10 @@ const struct image_decoder *load_decoder(struct loader_info *loader_info) goto error_close; } - if (lc_hdr->api_version != IMGDEC_API_VERSION) + if (lc_hdr->api_version != IMGDEC_API_VERSION || + hdr->img_api_size > sizeof(struct imgdec_api) || + hdr->plugin_api_version != PLUGIN_API_VERSION || + hdr->plugin_api_size > sizeof(struct plugin_api)) { rb->splashf(2*HZ, "%s decoder: Incompatible version.", name); goto error_close; diff --git a/apps/plugins/imageviewer/imageviewer.c b/apps/plugins/imageviewer/imageviewer.c index e30a98ef68..c77b22fdae 100644 --- a/apps/plugins/imageviewer/imageviewer.c +++ b/apps/plugins/imageviewer/imageviewer.c @@ -236,9 +236,9 @@ static bool set_option_dithering(void) } MENUITEM_FUNCTION(grayscale_item, 0, ID2P(LANG_GRAYSCALE), - set_option_grayscale, NULL, NULL, Icon_NOICON); + set_option_grayscale, NULL, Icon_NOICON); MENUITEM_FUNCTION(dithering_item, 0, ID2P(LANG_DITHERING), - set_option_dithering, NULL, NULL, Icon_NOICON); + set_option_dithering, NULL, Icon_NOICON); MAKE_MENU(display_menu, "Display Options", NULL, Icon_NOICON, &grayscale_item, &dithering_item); @@ -353,7 +353,7 @@ static int show_menu(void) /* return 1 to quit */ static int ask_and_get_audio_buffer(const char *filename) { int button; -#if defined(IMGVIEW_ZOOM_PRE) +#if defined(IMGVIEW_ZOOM_PRE) || defined(IMGVIEW_QUIT_PRE) int lastbutton = BUTTON_NONE; #endif rb->lcd_setfont(FONT_SYSFIXED); @@ -392,6 +392,10 @@ static int ask_and_get_audio_buffer(const char *filename) #endif #ifdef IMGVIEW_QUIT case IMGVIEW_QUIT: +#ifdef IMGVIEW_QUIT_PRE + if (lastbutton != IMGVIEW_QUIT_PRE) + break; +#endif #endif case IMGVIEW_MENU: return PLUGIN_OK; @@ -424,7 +428,7 @@ static int ask_and_get_audio_buffer(const char *filename) == SYS_USB_CONNECTED) return PLUGIN_USB_CONNECTED; } -#if defined(IMGVIEW_ZOOM_PRE) +#if defined(IMGVIEW_ZOOM_PRE) || defined(IMGVIEW_QUIT_PRE) if (button != BUTTON_NONE) lastbutton = button; #endif @@ -572,14 +576,19 @@ static void pan_view_down(struct image_info *info) } /* interactively scroll around the image */ -static int scroll_bmp(struct image_info *info) +static int scroll_bmp(struct image_info *info, bool initial_frame) { static long ss_timeout = 0; int button; #if defined(IMGVIEW_ZOOM_PRE) || defined(IMGVIEW_MENU_PRE) \ - || defined(IMGVIEW_SLIDE_SHOW_PRE) - int lastbutton = BUTTON_NONE; + || defined(IMGVIEW_SLIDE_SHOW_PRE) || defined(IMGVIEW_QUIT_PRE) + static int lastbutton; + if (initial_frame) + lastbutton = BUTTON_NONE; + +#else + (void) initial_frame; #endif if (!ss_timeout && iv_api.slideshow_enabled) @@ -745,6 +754,10 @@ static int scroll_bmp(struct image_info *info) #ifdef IMGVIEW_QUIT case IMGVIEW_QUIT: +#ifdef IMGVIEW_QUIT_PRE + if (lastbutton != IMGVIEW_QUIT_PRE) + break; +#endif return PLUGIN_OK; break; #endif @@ -756,7 +769,8 @@ static int scroll_bmp(struct image_info *info) break; } /* switch */ -#if defined(IMGVIEW_ZOOM_PRE) || defined(IMGVIEW_MENU_PRE) || defined(IMGVIEW_SLIDE_SHOW_PRE) +#if defined(IMGVIEW_ZOOM_PRE) || defined(IMGVIEW_MENU_PRE) ||\ + defined(IMGVIEW_SLIDE_SHOW_PRE) || defined(IMGVIEW_QUIT_PRE) if (button != BUTTON_NONE) lastbutton = button; #endif @@ -922,6 +936,7 @@ static int load_and_show(char* filename, struct image_info *info) /* used to loop through subimages in animated gifs */ int frame = 0; + bool initial_frame = true; do /* loop the image prepare and decoding when zoomed */ { status = imgdec->get_image(info, frame, ds); /* decode or fetch from cache */ @@ -954,7 +969,8 @@ static int load_and_show(char* filename, struct image_info *info) */ while (1) { - status = scroll_bmp(info); + status = scroll_bmp(info, initial_frame); + initial_frame = false; if (status == ZOOM_IN) { @@ -1064,10 +1080,8 @@ enum plugin_status plugin_start(const void* parameter) ARRAYLEN(config), IMGVIEW_SETTINGS_MINVERSION); rb->memcpy(&old_settings, &settings, sizeof (settings)); -#ifdef HAVE_BACKLIGHT /* Turn off backlight timeout */ backlight_ignore_timeout(); -#endif #if LCD_DEPTH > 1 rb->lcd_set_backdrop(NULL); @@ -1094,10 +1108,8 @@ enum plugin_status plugin_start(const void* parameter) rb->storage_spindown(rb->global_settings->disk_spindown); #endif -#ifdef HAVE_BACKLIGHT /* Turn on backlight timeout (revert to settings) */ backlight_use_settings(); -#endif #ifdef USEGSLIB grey_release(); /* deinitialize */ diff --git a/apps/plugins/imageviewer/imageviewer.h b/apps/plugins/imageviewer/imageviewer.h index 19b5db15bb..ac15df5960 100644 --- a/apps/plugins/imageviewer/imageviewer.h +++ b/apps/plugins/imageviewer/imageviewer.h @@ -136,14 +136,17 @@ struct image_decoder { int x, int y, int width, int height); }; -#define IMGDEC_API_VERSION (PLUGIN_API_VERSION << 4 | 0) +#define IMGDEC_API_VERSION 1 /* image decoder header */ struct imgdec_header { struct lc_header lc_hdr; /* must be the first */ const struct image_decoder *decoder; const struct plugin_api **api; + unsigned short plugin_api_version; + size_t plugin_api_size; const struct imgdec_api **img_api; + size_t img_api_size; }; #ifdef IMGDEC @@ -157,15 +160,18 @@ extern const struct image_decoder image_decoder; const struct imgdec_header __header \ __attribute__ ((section (".header")))= { \ { PLUGIN_MAGIC, TARGET_ID, IMGDEC_API_VERSION, \ - plugin_start_addr, plugin_end_addr }, &image_decoder, &rb, &iv }; + plugin_start_addr, plugin_end_addr, }, &image_decoder, \ + &rb, PLUGIN_API_VERSION, sizeof(struct plugin_api), \ + &iv, sizeof(struct imgdec_api) }; #else /* PLATFORM_HOSTED */ #define IMGDEC_HEADER \ const struct plugin_api *rb DATA_ATTR; \ const struct imgdec_api *iv DATA_ATTR; \ const struct imgdec_header __header \ __attribute__((visibility("default"))) = { \ - { PLUGIN_MAGIC, TARGET_ID, IMGDEC_API_VERSION, \ - NULL, NULL }, &image_decoder, &rb, &iv }; + { PLUGIN_MAGIC, TARGET_ID, IMGDEC_API_VERSION, NULL, NULL }, \ + &image_decoder, &rb, PLUGIN_API_VERSION, sizeof(struct plugin_api), \ + &iv, sizeof(struct imgdec_api), }; #endif /* CONFIG_PLATFORM */ #endif diff --git a/apps/plugins/imageviewer/imageviewer_button.h b/apps/plugins/imageviewer/imageviewer_button.h index b8b8c3baf7..d324f93292 100644 --- a/apps/plugins/imageviewer/imageviewer_button.h +++ b/apps/plugins/imageviewer/imageviewer_button.h @@ -53,8 +53,10 @@ #define IMGVIEW_RIGHT BUTTON_RIGHT #define IMGVIEW_NEXT (BUTTON_SELECT | BUTTON_RIGHT) #define IMGVIEW_PREVIOUS (BUTTON_SELECT | BUTTON_LEFT) -#define IMGVIEW_MENU (BUTTON_SELECT | BUTTON_MENU) -#define IMGVIEW_QUIT (BUTTON_SELECT | BUTTON_PLAY) +#define IMGVIEW_MENU_PRE BUTTON_SELECT +#define IMGVIEW_MENU (BUTTON_SELECT | BUTTON_REPEAT) +#define IMGVIEW_QUIT_PRE BUTTON_SELECT +#define IMGVIEW_QUIT (BUTTON_SELECT | BUTTON_REL) #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD #define IMGVIEW_ZOOM_PRE BUTTON_SELECT diff --git a/apps/plugins/imageviewer/jpeg/yuv2rgb.c b/apps/plugins/imageviewer/jpeg/yuv2rgb.c index 61d7fd6487..3e7f08d8bc 100644 --- a/apps/plugins/imageviewer/jpeg/yuv2rgb.c +++ b/apps/plugins/imageviewer/jpeg/yuv2rgb.c @@ -238,7 +238,7 @@ static fb_data (* const pixel_funcs[COLOUR_NUM_MODES][DITHER_NUM_MODES])(void) = }; /* These defines are used fornormal horizontal strides and vertical strides. */ -#if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE +#if LCD_STRIDEFORMAT == VERTICAL_STRIDE #define LCDADDR(x, y) (lcd_fb + LCD_HEIGHT*(x) + (y)) #define ROWENDOFFSET (width*LCD_HEIGHT) #define ROWOFFSET (1) diff --git a/apps/plugins/imageviewer/ppm/ppm_decoder.c b/apps/plugins/imageviewer/ppm/ppm_decoder.c index 4a86be1a3a..ccb208b80b 100644 --- a/apps/plugins/imageviewer/ppm/ppm_decoder.c +++ b/apps/plugins/imageviewer/ppm/ppm_decoder.c @@ -177,7 +177,7 @@ static int read_ppm_row(int fd, struct ppm_info *ppm, int row) int col; int r, g, b; #ifdef HAVE_LCD_COLOR -#if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE +#if LCD_STRIDEFORMAT == VERTICAL_STRIDE fb_data *dst = (fb_data *) ppm->buf + row; const int stride = ppm->x; #else diff --git a/apps/plugins/invadrox.c b/apps/plugins/invadrox.c index a164b95cf0..d130ab6108 100644 --- a/apps/plugins/invadrox.c +++ b/apps/plugins/invadrox.c @@ -785,7 +785,7 @@ static fb_data *lcd_fb; /* No standard get_pixel function yet, use this hack instead */ #if (LCD_DEPTH >= 8) -#if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE +#if LCD_STRIDEFORMAT == VERTICAL_STRIDE static inline fb_data get_pixel(int x, int y) { return lcd_fb[x*LCD_HEIGHT+y]; diff --git a/apps/plugins/jackpot.c b/apps/plugins/jackpot.c index 78f74568ca..fd878509cf 100644 --- a/apps/plugins/jackpot.c +++ b/apps/plugins/jackpot.c @@ -25,6 +25,13 @@ #include "lib/pluginlib_exit.h" +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define JACKPOT_QUIT PLA_UP +#else +#define JACKPOT_QUIT PLA_CANCEL +#endif const struct button_mapping* plugin_contexts[]={pla_main_ctx}; #define NB_PICTURES 9 @@ -248,7 +255,7 @@ enum plugin_status plugin_start(const void* parameter) plugin_contexts, ARRAYLEN(plugin_contexts)); switch ( action ) { - case PLA_CANCEL: + case JACKPOT_QUIT: return PLUGIN_OK; case PLA_SELECT: jackpot_play_turn(&game); diff --git a/apps/plugins/jewels.c b/apps/plugins/jewels.c index 3f209ae556..1536b785b4 100644 --- a/apps/plugins/jewels.c +++ b/apps/plugins/jewels.c @@ -49,9 +49,9 @@ #define JEWELS_PREV BUTTON_SCROLL_BACK #define JEWELS_NEXT BUTTON_SCROLL_FWD #define JEWELS_SELECT BUTTON_SELECT -#define JEWELS_CANCEL (BUTTON_SELECT | BUTTON_MENU) +#define JEWELS_CANCEL (BUTTON_SELECT | BUTTON_REPEAT) #define HK_SELECT "SELECT" -#define HK_CANCEL "SEL + MENU" +#define HK_CANCEL "Long SELECT" #elif (CONFIG_KEYPAD == IPOD_3G_PAD) #define JEWELS_LEFT BUTTON_LEFT diff --git a/apps/plugins/keybox.c b/apps/plugins/keybox.c index f8c6800a4d..cb2e23a94a 100644 --- a/apps/plugins/keybox.c +++ b/apps/plugins/keybox.c @@ -567,7 +567,7 @@ static int keybox(void) { rb->gui_synclist_draw(&kb_list); button = rb->get_action(CONTEXT_LIST, TIMEOUT_BLOCK); - if (rb->gui_synclist_do_button(&kb_list, &button, LIST_WRAP_UNLESS_HELD)) + if (rb->gui_synclist_do_button(&kb_list, &button)) continue; switch (button) @@ -659,7 +659,6 @@ enum plugin_status plugin_start(const void *parameter) rb->gui_synclist_set_title(&kb_list, "Keybox", NOICON); rb->gui_synclist_set_icon_callback(&kb_list, NULL); rb->gui_synclist_set_nb_items(&kb_list, 0); - rb->gui_synclist_limit_scroll(&kb_list, false); rb->gui_synclist_select_item(&kb_list, 0); init_ll(); diff --git a/apps/plugins/keyremap.c b/apps/plugins/keyremap.c index a4ce1c48e6..202d5fcfa4 100644 --- a/apps/plugins/keyremap.c +++ b/apps/plugins/keyremap.c @@ -42,8 +42,29 @@ #define KMFUSER "user_keyremap" #define MAX_BUTTON_COMBO 5 #define MAX_BUTTON_NAME 32 +#define MAX_MENU_NAME 64 #define TEST_COUNTDOWN_MS 1590 +struct context_flags { + char * name; + int flag; +}; + +/* flags added to context_name[] */ +static struct context_flags context_flags[] = { + {"UNKNOWN", 0},/* index 0 is an Error */ +#ifndef HAS_BUTTON_HOLD + {"LOCKED", CONTEXT_LOCKED}, +#endif + /*{"PLUGIN", CONTEXT_PLUGIN}, need a custom action list and a way to supply */ +#if BUTTON_REMOTE != 0 + {"REMOTE", CONTEXT_REMOTE}, +#ifndef HAS_BUTTON_HOLD + {"REMOTE_LOCKED", CONTEXT_REMOTE | CONTEXT_LOCKED}, +#endif +#endif /* BUTTON_REMOTE != 0 */ +}; + static struct keyremap_buffer_t { char * buffer; size_t buf_size; @@ -138,7 +159,7 @@ MENU_ITEM(M_DELCORE, "Remove Core Remap", 1), MENU_ITEM(M_EXIT, ID2P(LANG_MENU_QUIT), 0), MENU_ITEM(M_ACTIONS, "Actions", LAST_ACTION_PLACEHOLDER), MENU_ITEM(M_BUTTONS, "Buttons", -1), /* Set at runtime in plugin_start: */ -MENU_ITEM(M_CONTEXTS, "Contexts", LAST_CONTEXT_PLACEHOLDER ), +MENU_ITEM(M_CONTEXTS, "Contexts", LAST_CONTEXT_PLACEHOLDER * ARRAYLEN(context_flags)), MENU_ITEM(M_CONTEXT_EDIT, "", 5), #undef MENU_ITEM }; @@ -200,6 +221,47 @@ static void synclist_set_update(int id, int selected_item, int items, int sel_si synclist_set(id, selected_item, items, sel_size); } +/* returns the actual context & index of the flag is passed in *flagidx */ +static int ctx_strip_flagidx(int ctx, int *flagidx) +{ + int ctx_out = ctx % (LAST_CONTEXT_PLACEHOLDER); + *flagidx = 0; + if (ctx_out != ctx) + { + while (ctx >= LAST_CONTEXT_PLACEHOLDER) + { + (*flagidx)++; + ctx -= LAST_CONTEXT_PLACEHOLDER; + } + if (*flagidx >= (int)ARRAYLEN(context_flags)) + *flagidx = 0; /* unknown flag */ + + logf("%s ctx: (%d) %s flag idx: (%d) %s\n", __func__, + ctx, context_name(ctx), *flagidx, context_flags[*flagidx].name); + } + return ctx_out; +} + +/* combines context name and flag name using '_' to join them */ +static char *ctx_name_and_flag(int index) +{ + static char ctx_namebuf[MAX_MENU_NAME]; + char *ctx_name = "?"; + int flagidx; + int ctx = ctx_strip_flagidx(index, &flagidx); + if (flagidx == 0) + { + ctx_name = context_name(ctx); + } + else if (flagidx >= 0 && flagidx < (int)ARRAYLEN(context_flags)) + { + rb->snprintf(ctx_namebuf, sizeof(ctx_namebuf), "%s_%s", + context_name(ctx), context_flags[flagidx].name); + ctx_name = ctx_namebuf; + } + return ctx_name; +} + static int btnval_to_index(unsigned int btnvalue) { int index = -1; @@ -361,6 +423,7 @@ static int keyremap_map_is_valid(struct action_mapping_t *amap, int context) static struct button_mapping *keyremap_create_temp(int *entries) { + logf("%s()", __func__); struct button_mapping *tempkeymap; int action_offset = 1; /* start of action entries (ctx_count + 1)*/ int entry_count = 1;/* (ctx_count + ctx_count + act_count) */ @@ -390,8 +453,8 @@ static struct button_mapping *keyremap_create_temp(int *entries) } size_t keymap_bytes = (entry_count) * sizeof(struct button_mapping); *entries = entry_count; - logf("keyremap create temp entry count: %d", entry_count); - logf("keyremap bytes: %ld, avail: %ld", keymap_bytes, + logf("%s() entry count: %d", __func__, entry_count); + logf("keyremap bytes: %zu, avail: %zu", keymap_bytes, (keyremap_buffer.end - keyremap_buffer.front)); if (keyremap_buffer.front + keymap_bytes < keyremap_buffer.end) { @@ -401,6 +464,7 @@ static struct button_mapping *keyremap_create_temp(int *entries) for (i = 0; i < ctx_data.ctx_count; i++) { int actions_this_ctx = 0; + int flagidx; int context = ctx_data.ctx_map[i].context; /* how many actions are contained in each context? */ for (j = 0; j < ctx_data.act_count; j++) @@ -413,6 +477,10 @@ static struct button_mapping *keyremap_create_temp(int *entries) /*Don't save contexts with no actions */ if (actions_this_ctx == 0){ continue; } + /* convert context x flag to context | flag */ + context = ctx_strip_flagidx(ctx_data.ctx_map[i].context, &flagidx); + context |= context_flags[flagidx].flag; + entry->action_code = CORE_CONTEXT_REMAP(context); entry->button_code = action_offset; /* offset of first action entry */ entry->pre_button_code = actions_this_ctx; /* entries (excluding sentinel) */ @@ -431,6 +499,7 @@ static struct button_mapping *keyremap_create_temp(int *entries) { int actions_this_ctx = 0; int context = ctx_data.ctx_map[i].context; + for (int j = 0; j < ctx_data.act_count; j++) { if (keyremap_map_is_valid(&ctx_data.act_map[j], context) > 0) @@ -473,7 +542,7 @@ static int keyremap_save_current(const char *filename) struct button_mapping *keymap = keyremap_create_temp(&entry_count); - if (keymap == NULL || entry_count <= 3) + if (keymap == NULL || entry_count <= 3) /* there should be atleast 4 entries */ return status; keyset.crc32 = rb->crc_32(keymap, entry_count * sizeof(struct button_mapping), 0xFFFFFFFF); @@ -505,6 +574,7 @@ static void keyremap_save_user_keys(bool notify) if (keyremap_save_current(buf) == 0) { + logf("Error Saving"); if(notify) rb->splash(HZ *2, "Error Saving"); } @@ -519,11 +589,13 @@ static int keyremap_export_current(char *filenamebuf, size_t bufsz) int ctx_count = 0; size_t entrylen; - int entry_count = ctx_data.ctx_count + ctx_data.act_count + 1;;/* (ctx_count + ctx_count + act_count + 1) */ + int entry_count = ctx_data.ctx_count + ctx_data.act_count + 1; - if (entry_count <= 3) + if (entry_count < 3) /* the header is not counted should be at least 3 entries */ + { + logf("%s: Not enough entries", __func__); return 0; - + } int fd = rb->open(filenamebuf, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (fd < 0) @@ -613,13 +685,15 @@ static void keyremap_export_user_keys(void) static void keyremap_import_user_keys(void) { char buf[MAX_PATH]; - struct browse_context browse; - - rb->browse_context_init(&browse, SHOW_ALL, BROWSE_SELECTONLY, "Select Keymap", - Icon_Plugin, "/", NULL); - - browse.buf = buf; - browse.bufsize = sizeof(buf); + struct browse_context browse = { + .dirfilter = SHOW_ALL, + .flags = BROWSE_SELECTONLY, + .title = "Select Keymap", + .icon = Icon_Plugin, + .buf = buf, + .bufsize = sizeof(buf), + .root = "/", + }; if (rb->rockbox_browse(&browse) == GO_TO_PREVIOUS) { @@ -928,9 +1002,13 @@ next_line: { bufleft = bufsz - (pctx - filenamebuf); ctx = -1; - for (int i=0;i < LAST_CONTEXT_PLACEHOLDER;i++) + int ctx_x_flag_count = (LAST_CONTEXT_PLACEHOLDER + * ARRAYLEN(context_flags)); + + for (int i=0;i < ctx_x_flag_count ;i++) { - if (rb->strncasecmp(pctx, context_name(i), bufleft) == 0) + /* context x flag */ + if (rb->strncasecmp(pctx, ctx_name_and_flag(i), bufleft) == 0) { logf("ln: %d: Context Found: %s (%d)", line, pctx, i); if (keymap_add_context_entry(i) <= 0) @@ -1040,8 +1118,17 @@ static int keyremap_load_file(const char *filename) } if ((entry.action_code & CONTEXT_REMAPPED) == CONTEXT_REMAPPED) { - int context = (entry.action_code & ~CONTEXT_REMAPPED); + for (int i = ARRAYLEN(context_flags) - 1; i > 0; i--) /* don't check idx 0*/ + { + /* convert context | flag to context x flag */ + if ((context & context_flags[i].flag) == context_flags[i].flag) + { + logf("found ctx flag %s", context_flags[i].name); + context &= ~context_flags[i].flag; + context += i * LAST_CONTEXT_PLACEHOLDER; + } + } int offset = entry.button_code; int entries = entry.pre_button_code; if (offset == 0 || entries <= 0) @@ -1197,10 +1284,10 @@ static const char *menu_useract_items_cb(int selected_item, void* data, { if (ctx_data.act_count == 0) rb->snprintf(buf, buf_len, "%s$%s", - context_name(ctx_data.ctx_map[i].context), + ctx_name_and_flag(ctx_data.ctx_map[i].context), "Select$to add$actions"); else - rb->snprintf(buf, buf_len, ctxfmt, context_name(ctx_data.ctx_map[i].context)); + rb->snprintf(buf, buf_len, ctxfmt, ctx_name_and_flag(ctx_data.ctx_map[i].context)); return buf; } } @@ -1215,7 +1302,7 @@ static const char *menu_useract_items_cb(int selected_item, void* data, if (data != MENU_ID(M_EXPORTKEYS)) { pctxbuf = ctxbuf; - rb->snprintf(ctxbuf, sizeof(ctxbuf), ctxfmt, context_name(context)); + rb->snprintf(ctxbuf, sizeof(ctxbuf), ctxfmt, ctx_name_and_flag(context)); pctxbuf += szctx;//sizeof("CONTEXT") } struct button_mapping * bm = &ctx_data.act_map[i].map; @@ -1259,7 +1346,7 @@ static const char *test_keymap_name_cb(int selected_item, void* data, if (keytest.context >= 0) { if (selected_item == 0) - rb->snprintf(buf, buf_len, "< %s >", context_name(keytest.context)); + rb->snprintf(buf, buf_len, "< %s >", ctx_name_and_flag(keytest.context)); else if (selected_item == 1) { if (keytest.countdown >= 10) @@ -1300,7 +1387,7 @@ static const char* list_get_name_cb(int selected_item, void* data, } else if (data == MENU_ID(M_CONTEXTS)) { - return context_name(selected_item); + return ctx_name_and_flag(selected_item); } else if (data == MENU_ID(M_DELKEYS) || data == MENU_ID(M_LOADKEYS)) { @@ -1335,9 +1422,20 @@ static int list_voice_cb(int list_index, void* data) else rb->talk_spell(name, true); } + else if(data == MENU_ID(M_SETKEYS)) + { + char buf[MAX_MENU_NAME]; + int selcol = printcell_get_column_selected(); + const char* name = printcell_get_column_text(selcol, buf, sizeof(buf)); + long id = P2ID((const unsigned char *)name); + if(id>=0) + rb->talk_id(id, true); + else + rb->talk_spell(name, true); + } else { - char buf[64]; + char buf[MAX_MENU_NAME]; const char* name = list_get_name_cb(list_index, data, buf, sizeof(buf)); long id = P2ID((const unsigned char *)name); if(id>=0) @@ -1519,14 +1617,14 @@ int menu_action_setkeys(int *action, int selected_item, bool* exit, struct gui_s } else { - keyset.view_lastcol = printcell_increment_column(lists, 1, true); + keyset.view_lastcol = printcell_increment_column(1, true); *action = ACTION_NONE; } } } else if (*action == ACTION_STD_CANCEL) { - keyset.view_lastcol = printcell_increment_column(lists, -1, true); + keyset.view_lastcol = printcell_increment_column(-1, true); if (keyset.view_lastcol != keyset.view_columns - 1) { *action = ACTION_NONE; @@ -1950,9 +2048,8 @@ static void synclist_set(int id, int selected_item, int items, int sel_size) rb->gui_synclist_set_icon_callback(&lists,NULL); rb->gui_synclist_set_voice_callback(&lists, list_voice_cb); rb->gui_synclist_set_nb_items(&lists,items); - rb->gui_synclist_limit_scroll(&lists,true); rb->gui_synclist_select_item(&lists, selected_item); - printcell_enable(&lists, false, false); + printcell_enable(false); if (menu_id == MENU_ID(M_ROOT)) { @@ -1961,15 +2058,16 @@ static void synclist_set(int id, int selected_item, int items, int sel_size) } else if (menu_id == MENU_ID(M_SETKEYS)) { - printcell_enable(&lists, true, true); - keyset.view_columns = printcell_set_columns(&lists, ACTVIEW_HEADER, Icon_Rockbox); - int curcol = printcell_increment_column(&lists, 0, true); + keyset.view_columns = printcell_set_columns(&lists, NULL, + ACTVIEW_HEADER, Icon_Rockbox); + printcell_enable(true); + int curcol = printcell_get_column_selected(); if (keyset.view_lastcol >= keyset.view_columns) keyset.view_lastcol = -1; /* restore column position */ while (keyset.view_lastcol > -1 && curcol != keyset.view_lastcol) { - curcol = printcell_increment_column(&lists, 1, true); + curcol = printcell_increment_column(1, true); } keyset.view_lastcol = curcol; } @@ -1979,9 +2077,8 @@ static void synclist_set(int id, int selected_item, int items, int sel_size) PEEK_MENU_ID(id); lang_strlcpy(menu_title, mainitem(id)->name, sizeof(menu_title)); rb->gui_synclist_set_title(&lists, menu_title, Icon_Submenu_Entered); - /* if (menu_title[0] == '$'){ printcell_enable(&lists, true, true); } */ + /* if (menu_title[0] == '$'){ printcell_enable(true); } */ } - } static void keyremap_set_buffer(void* buffer, size_t buf_size) @@ -2055,7 +2152,7 @@ enum plugin_status plugin_start(const void* parameter) redraw = true; ret = menu_action_cb(&action, selected_item, &exit, &lists); - if (rb->gui_synclist_do_button(&lists,&action,LIST_WRAP_UNLESS_HELD)) + if (rb->gui_synclist_do_button(&lists, &action)) continue; selected_item = rb->gui_synclist_get_sel_pos(&lists); diff --git a/apps/plugins/lamp.c b/apps/plugins/lamp.c index 6c9ae6626d..5aa06f4d2d 100644 --- a/apps/plugins/lamp.c +++ b/apps/plugins/lamp.c @@ -58,7 +58,14 @@ static const struct button_mapping *plugin_contexts[] = { pla_main_ctx }; #define LAMP_EXIT PLA_EXIT + +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define LAMP_EXIT2 PLA_UP +#else #define LAMP_EXIT2 PLA_CANCEL +#endif #ifdef HAVE_LCD_COLOR @@ -103,9 +110,8 @@ enum plugin_status plugin_start(const void* parameter) int current_brightness = MAX_BRIGHTNESS_SETTING; backlight_brightness_set(MAX_BRIGHTNESS_SETTING); #endif /* HAVE_BACKLIGHT_BRIGHTNESS */ -#ifdef HAVE_BUTTONLIGHT_BRIGHTNESS + buttonlight_brightness_set(MAX_BRIGHTNESS_SETTING); -#endif /* HAVE_BUTTONLIGHT_BRIGHTNESS */ #ifdef HAVE_LCD_INVERT #ifdef HAVE_NEGATIVE_LCD @@ -116,9 +122,8 @@ enum plugin_status plugin_start(const void* parameter) #endif /* HAVE_LCD_INVERT */ backlight_force_on(); -#ifdef HAVE_BUTTON_LIGHT buttonlight_force_on(); -#endif /* HAVE_BUTTON_LIGHT */ + rb->lcd_clear_display(); rb->lcd_update(); @@ -207,20 +212,17 @@ enum plugin_status plugin_start(const void* parameter) /* restore */ backlight_use_settings(); -#ifdef HAVE_BUTTON_LIGHT + buttonlight_use_settings(); -#endif /* HAVE_BUTTON_LIGHT */ #ifdef HAVE_LCD_INVERT rb->lcd_set_invert_display(rb->global_settings->invert); #endif /* HAVE_LCD_INVERT */ -#ifdef HAVE_BACKLIGHT_BRIGHTNESS + backlight_brightness_use_setting(); -#endif /* HAVE_BACKLIGHT_BRIGHTNESS */ -#ifdef HAVE_BUTTONLIGHT_BRIGHTNESS + buttonlight_brightness_use_setting(); -#endif /* HAVE_BUTTONLIGHT_BRIGHTNESS */ #if LCD_DEPTH > 1 rb->lcd_set_background(bg_color); diff --git a/apps/plugins/lastfm_scrobbler.c b/apps/plugins/lastfm_scrobbler.c index 7bd213b6d2..1530ff7ae7 100644 --- a/apps/plugins/lastfm_scrobbler.c +++ b/apps/plugins/lastfm_scrobbler.c @@ -21,11 +21,56 @@ * ****************************************************************************/ /* Scrobbler Plugin -Audioscrobbler spec at: +Audioscrobbler spec at: (use wayback machine) http://www.audioscrobbler.net/wiki/Portable_Player_Logging +* EXCERPT: +* The first lines of .scrobbler.log should be header lines, indicated by the leading '#' character: + +#AUDIOSCROBBLER/1.1 +#TZ/[UNKNOWN|UTC] +#CLIENT/<IDENTIFICATION STRING> + +Where 1.1 is the version for this file format + + If the device knows what timezone it is in, + it must convert all logged times to UTC (aka GMT+0) + eg: #TZ/UTC + If the device knows the time, but not the timezone + eg: #TZ/UNKNOWN + +<IDENTIFICATION STRING> should be replaced by the name/model of the hardware device + and the revision of the software producing the log file. + +After the header lines, simply append one line of text for every song + that is played or skipped. + +The following fields comprise each line, and are tab (\t) + separated (strip any tab characters from the data): + + - artist name + - album name (optional) + - track name + - track position on album (optional) + - song duration in seconds + - rating (L if listened at least 50% or S if skipped) + - unix timestamp when song started playing + - MusicBrainz Track ID (optional) +lines should be terminated with \n +Example +(listened to enter sandman, skipped cowboys, listened to the pusher) : + #AUDIOSCROBBLER/1.0 + #TZ/UTC + #CLIENT/Rockbox h3xx 1.1 + Metallica Metallica Enter Sandman 1 365 L 1143374412 62c2e20a?-559e-422f-a44c-9afa7882f0c4? + Portishead Roseland NYC Live Cowboys 2 312 S 1143374777 db45ed76-f5bf-430f-a19f-fbe3cd1c77d3 + Steppenwolf Live The Pusher 12 350 L 1143374779 58ddd581-0fcc-45ed-9352-25255bf80bfb? + If the data for optional fields is not available to you, leave the field blank (\t\t). + All strings should be written as UTF-8, although the file does not use a BOM. + All fields except those marked (optional) above are required. */ #include "plugin.h" +#include "lib/configfile.h" #ifndef UNTAGGED #define UNTAGGED "<UNTAGGED>" @@ -39,22 +84,35 @@ http://www.audioscrobbler.net/wiki/Portable_Player_Logging /****************** constants ******************/ #define EV_EXIT MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0xFF) -#define EV_OTHINSTANCE MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0xFE) +#define EV_FLUSHCACHE MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0xFE) +#define EV_USER_ERROR MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0xFD) #define EV_STARTUP MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x01) #define EV_TRACKCHANGE MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x02) #define EV_TRACKFINISH MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x03) -#define SCROBBLER_VERSION "1.1" +#define ERR_NONE (0) +#define ERR_WRITING_FILE (-1) +#define ERR_ENTRY_LENGTH (-2) +#define ERR_WRITING_DATA (-3) /* increment this on any code change that effects output */ +#define SCROBBLER_VERSION "1.1" + #define SCROBBLER_REVISION " $Revision$" -#define SCROBBLER_MAX_CACHE 32 +#define SCROBBLER_BAD_ENTRY "# FAILED - " + /* longest entry I've had is 323, add a safety margin */ -#define SCROBBLER_CACHE_LEN 512 +#define SCROBBLER_CACHE_LEN (512) +#define SCROBBLER_MAX_CACHE (32 * SCROBBLER_CACHE_LEN) + +#define SCROBBLER_MAX_TRACK_MRU (32) /* list of hashes to detect repeats */ #define ITEM_HDR "#ARTIST #ALBUM #TITLE #TRACKNUM #LENGTH #RATING #TIMESTAMP #MUSICBRAINZ_TRACKID\n" +#define CFG_FILE "/lastfm_scrobbler.cfg" +#define CFG_VER 1 + #if CONFIG_RTC static time_t timestamp; #define BASE_FILENAME HOME_DIR "/.scrobbler.log" @@ -63,161 +121,212 @@ static time_t timestamp; #define record_timestamp() ((void)(timestamp = rb->mktime(rb->get_time()))) #else /* !CONFIG_RTC */ #define HDR_STR_TIMELESS " Timeless" -#define BASE_FILENAME ".scrobbler-timeless.log" +#define BASE_FILENAME HOME_DIR "/.scrobbler-timeless.log" #define get_timestamp() (0l) #define record_timestamp() ({}) #endif /* CONFIG_RTC */ #define THREAD_STACK_SIZE 4*DEFAULT_STACK_SIZE -#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ - (CONFIG_KEYPAD == IRIVER_H300_PAD) -#define SCROBBLE_OFF BUTTON_OFF -#define SCROBBLE_OFF_TXT "STOP" -#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ - (CONFIG_KEYPAD == IPOD_3G_PAD) || \ - (CONFIG_KEYPAD == IPOD_1G2G_PAD) -#define SCROBBLE_OFF BUTTON_MENU -#define SCROBBLE_OFF_TXT "MENU" -#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD || \ - CONFIG_KEYPAD == AGPTEK_ROCKER_PAD -#define SCROBBLE_OFF BUTTON_POWER -#define SCROBBLE_OFF_TXT "POWER" -#elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \ - (CONFIG_KEYPAD == SANSA_C200_PAD) || \ - (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \ - (CONFIG_KEYPAD == SANSA_M200_PAD) -#define SCROBBLE_OFF BUTTON_POWER -#define SCROBBLE_OFF_TXT "POWER" -#elif (CONFIG_KEYPAD == SANSA_FUZE_PAD) -#define SCROBBLE_OFF BUTTON_HOME -#define SCROBBLE_OFF_TXT "HOME" -#elif (CONFIG_KEYPAD == IRIVER_H10_PAD || \ - CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD || \ - CONFIG_KEYPAD == SONY_NWZ_PAD || \ - CONFIG_KEYPAD == XDUOO_X3_PAD || \ - CONFIG_KEYPAD == IHIFI_770_PAD || \ - CONFIG_KEYPAD == IHIFI_800_PAD || \ - CONFIG_KEYPAD == XDUOO_X3II_PAD || \ - CONFIG_KEYPAD == XDUOO_X20_PAD || \ - CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD || \ - CONFIG_KEYPAD == EROSQ_PAD) -#define SCROBBLE_OFF BUTTON_POWER -#define SCROBBLE_OFF_TXT "POWER" -#elif CONFIG_KEYPAD == GIGABEAT_PAD -#define SCROBBLE_OFF BUTTON_POWER -#define SCROBBLE_OFF_TXT "POWER" -#elif CONFIG_KEYPAD == GIGABEAT_S_PAD \ - || CONFIG_KEYPAD == SAMSUNG_YPR0_PAD \ - || CONFIG_KEYPAD == CREATIVE_ZEN_PAD -#define SCROBBLE_OFF BUTTON_BACK -#define SCROBBLE_OFF_TXT "BACK" -#elif CONFIG_KEYPAD == MROBE500_PAD -#define SCROBBLE_OFF BUTTON_POWER -#define SCROBBLE_OFF_TXT "POWER" -#elif CONFIG_KEYPAD == MROBE100_PAD -#define SCROBBLE_OFF BUTTON_POWER -#define SCROBBLE_OFF_TXT "POWER" -#elif CONFIG_KEYPAD == IAUDIO_M3_PAD -#define SCROBBLE_OFF BUTTON_REC -#define BATTERY_RC_OFF BUTTON_RC_REC -#define SCROBBLE_OFF_TXT "REC" -#elif CONFIG_KEYPAD == COWON_D2_PAD -#define SCROBBLE_OFF BUTTON_POWER -#define SCROBBLE_OFF_TXT "POWER" -#elif CONFIG_KEYPAD == CREATIVEZVM_PAD -#define SCROBBLE_OFF BUTTON_BACK -#define SCROBBLE_OFF_TXT "BACK" -#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD -#define SCROBBLE_OFF BUTTON_POWER -#define SCROBBLE_OFF_TXT "POWER" -#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD -#define SCROBBLE_OFF BUTTON_POWER -#define SCROBBLE_OFF_TXT "POWER" -#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD -#define SCROBBLE_OFF BUTTON_POWER -#define SCROBBLE_OFF_TXT "POWER" -#elif CONFIG_KEYPAD == ONDAVX747_PAD -#define SCROBBLE_OFF BUTTON_POWER -#define SCROBBLE_OFF_TXT "POWER" -#elif CONFIG_KEYPAD == ONDAVX777_PAD -#define SCROBBLE_OFF BUTTON_POWER -#define SCROBBLE_OFF_TXT "POWER" -#elif (CONFIG_KEYPAD == SAMSUNG_YH820_PAD) || \ - (CONFIG_KEYPAD == SAMSUNG_YH92X_PAD) -#define SCROBBLE_OFF BUTTON_RIGHT -#define SCROBBLE_OFF_TXT "RIGHT" -#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD -#define SCROBBLE_OFF BUTTON_REC -#define SCROBBLE_OFF_TXT "REC" -#elif CONFIG_KEYPAD == MPIO_HD200_PAD -#define SCROBBLE_OFF BUTTON_REC -#define SCROBBLE_OFF_TXT "REC" -#elif CONFIG_KEYPAD == MPIO_HD300_PAD -#define SCROBBLE_OFF BUTTON_REC -#define SCROBBLE_OFF_TXT "REC" -#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD -#define SCROBBLE_OFF BUTTON_POWER -#define SCROBBLE_OFF_TXT "POWER" -#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD -#define SCROBBLE_OFF BUTTON_POWER -#define SCROBBLE_OFF_TXT "POWER" -#elif (CONFIG_KEYPAD == HM60X_PAD) || (CONFIG_KEYPAD == HM801_PAD) -#define SCROBBLE_OFF BUTTON_POWER -#define SCROBBLE_OFF_TXT "POWER" -#elif CONFIG_KEYPAD == DX50_PAD -#define SCROBBLE_OFF BUTTON_POWER_LONG -#define SCROBBLE_OFF_TXT "Power Long" -#elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD -#define SCROBBLE_OFF BUTTON_POWER -#define SCROBBLE_OFF_TXT "Power" -#elif CONFIG_KEYPAD == FIIO_M3K_PAD -#define SCROBBLE_OFF BUTTON_POWER -#define SCROBBLE_OFF_TXT "Power" -#elif CONFIG_KEYPAD == SHANLING_Q1_PAD -/* use touchscreen */ -#else -#error "No keymap defined!" -#endif -#if defined(HAVE_TOUCHSCREEN) -#ifndef SCROBBLE_OFF -#define SCROBBLE_OFF BUTTON_TOPLEFT -#endif -#ifndef SCROBBLE_OFF_TXT -#define SCROBBLE_OFF_TXT "TOPLEFT" -#endif -#endif /****************** prototypes ******************/ -int plugin_main(const void* parameter); /* main loop */ enum plugin_status plugin_start(const void* parameter); /* entry */ - +void play_tone(unsigned int frequency, unsigned int duration); /****************** globals ******************/ -unsigned char **language_strings; /* for use with str() macro; must be init */ /* communication to the worker thread */ static struct { bool exiting; /* signal to the thread that we want to exit */ unsigned int id; /* worker thread id */ - struct event_queue queue; /* thread event queue */ + struct event_queue queue; /* thread event queue */ + struct queue_sender_list queue_send; long stack[THREAD_STACK_SIZE / sizeof(long)]; } gThread; -static struct +struct cache_entry { + size_t len; + uint32_t crc; + char buf[ ]; +}; + +static struct scrobbler_cache +{ + int entries; char *buf; - int pos; + size_t pos; size_t size; bool pending; bool force_flush; + struct mutex mtx; } gCache; +static struct scrobbler_cfg +{ + int uniqct; + int savepct; + int minms; + int beeplvl; + bool playback; + bool verbose; +} gConfig; + +static struct configdata config[] = +{ + #define MAX_MRU (SCROBBLER_MAX_TRACK_MRU) + {TYPE_INT, 0, MAX_MRU, { .int_p = &gConfig.uniqct }, "UniqCt", NULL}, + {TYPE_INT, 0, 100, { .int_p = &gConfig.savepct }, "SavePct", NULL}, + {TYPE_INT, 0, 10000, { .int_p = &gConfig.minms }, "MinMs", NULL}, + {TYPE_BOOL, 0, 1, { .bool_p = &gConfig.playback }, "Playback", NULL}, + {TYPE_BOOL, 0, 1, { .bool_p = &gConfig.verbose }, "Verbose", NULL}, + {TYPE_INT, 0, 10, { .int_p = &gConfig.beeplvl }, "BeepLvl", NULL}, + #undef MAX_MRU +}; +const int gCfg_sz = sizeof(config)/sizeof(*config); + +/****************** config functions *****************/ +static void config_set_defaults(void) +{ + gConfig.uniqct = SCROBBLER_MAX_TRACK_MRU; + gConfig.savepct = 50; + gConfig.minms = 500; + gConfig.playback = false; + gConfig.verbose = true; + gConfig.beeplvl = 10; +} + +static int config_settings_menu(void) +{ + int selection = 0; + + static uint32_t crc = 0; + + struct viewport parentvp[NB_SCREENS]; + FOR_NB_SCREENS(l) + { + rb->viewport_set_defaults(&parentvp[l], l); + rb->viewport_set_fullscreen(&parentvp[l], l); + } + + #define MENUITEM_STRINGLIST_CUSTOM(name, str, callback, ... ) \ + static const char *name##_[] = {__VA_ARGS__}; \ + static const struct menu_callback_with_desc name##__ = \ + {callback,str, Icon_NOICON}; \ + struct menu_item_ex name = \ + {MT_RETURN_ID|MENU_HAS_DESC| \ + MENU_ITEM_COUNT(sizeof( name##_)/sizeof(*name##_)), \ + { .strings = name##_},{.callback_and_desc = & name##__}}; + + MENUITEM_STRINGLIST_CUSTOM(settings_menu, ID2P(LANG_SETTINGS), NULL, + ID2P(LANG_RESUME_PLAYBACK), + "Save Threshold", + "Minimum Elapsed", + "Verbose", + "Beep Level", + "Unique Track MRU", + ID2P(LANG_REVERT_TO_DEFAULT_SETTINGS), + ID2P(VOICE_BLANK), + ID2P(LANG_CANCEL_0), + ID2P(LANG_SAVE_EXIT)); + + #undef MENUITEM_STRINGLIST_CUSTOM + + const int items = MENU_GET_COUNT(settings_menu.flags); + const unsigned int flags = settings_menu.flags & (~MENU_ITEM_COUNT(MENU_COUNT_MASK)); + if (crc == 0) + { + crc = rb->crc_32(&gConfig, sizeof(struct scrobbler_cfg), 0xFFFFFFFF); + } + + do { + if (crc == rb->crc_32(&gConfig, sizeof(struct scrobbler_cfg), 0xFFFFFFFF)) + { + /* hide save item -- there are no changes to save */ + settings_menu.flags = flags|MENU_ITEM_COUNT((items - 1)); + } + else + { + settings_menu.flags = flags|MENU_ITEM_COUNT(items); + } + selection=rb->do_menu(&settings_menu,&selection, parentvp, true); + switch(selection) { + + case 0: /* resume playback on plugin start */ + rb->set_bool(rb->str(LANG_RESUME_PLAYBACK), &gConfig.playback); + break; + case 1: /* % of track played to indicate listened status */ + rb->set_int("Save Threshold", "%", UNIT_PERCENT, + &gConfig.savepct, NULL, 10, 0, 100, NULL ); + break; + case 2: /* tracks played less than this will not be logged */ + rb->set_int("Minimum Elapsed", "ms", UNIT_MS, + &gConfig.minms, NULL, 100, 0, 10000, NULL ); + break; + case 3: /* suppress non-error messages */ + rb->set_bool("Verbose", &gConfig.verbose); + break; + case 4: /* set volume of start-up beep */ + rb->set_int("Beep Level", "", UNIT_INT, + &gConfig.beeplvl, NULL, 1, 0, 10, NULL); + play_tone(1500, 100); + break; + case 5: /* keep a list of tracks to prevent repeat [Skipped] entries */ + rb->set_int("Unique Track MRU Size", "", UNIT_INT, + &gConfig.uniqct, NULL, 1, 0, SCROBBLER_MAX_TRACK_MRU, NULL); + break; + case 6: /* set defaults */ + { + const struct text_message prompt = { + (const char*[]){ ID2P(LANG_AUDIOSCROBBLER), + ID2P(LANG_REVERT_TO_DEFAULT_SETTINGS)}, 2}; + if(rb->gui_syncyesno_run(&prompt, NULL, NULL) == YESNO_YES) + { + config_set_defaults(); + if (gConfig.verbose) + rb->splash(HZ, ID2P(LANG_REVERT_TO_DEFAULT_SETTINGS)); + } + break; + } + case 7: /*sep*/ + continue; + case 8: /* Cancel */ + return -1; + break; + case 9: /* Save & exit */ + { + int res = configfile_save(CFG_FILE, config, gCfg_sz, CFG_VER); + if (res >= 0) + { + crc = rb->crc_32(&gConfig, sizeof(struct scrobbler_cfg), 0xFFFFFFFF); + logf("SCROBBLER: cfg saved %s %d bytes", CFG_FILE, gCfg_sz); + return PLUGIN_OK; + } + logf("SCROBBLER: cfg FAILED (%d) %s", res, CFG_FILE); + return PLUGIN_ERROR; + } + case MENU_ATTACHED_USB: + return PLUGIN_USB_CONNECTED; + default: + return PLUGIN_OK; + } + } while ( selection >= 0 ); + return 0; +} + /****************** helper fuctions ******************/ +void play_tone(unsigned int frequency, unsigned int duration) +{ + if (gConfig.beeplvl > 0) + rb->beep_play(frequency, duration, 100 * gConfig.beeplvl); +} -int scrobbler_init(void) +int scrobbler_init_cache(void) { + memset(&gCache, 0, sizeof(struct scrobbler_cache)); gCache.buf = rb->plugin_get_buffer(&gCache.size); - size_t reqsz = SCROBBLER_MAX_CACHE*SCROBBLER_CACHE_LEN; + /* we need to reserve the space we want for our use in TSR plugins since + * someone else could call plugin_get_buffer() and corrupt our memory */ + size_t reqsz = SCROBBLER_MAX_CACHE; gCache.size = PLUGIN_BUFFER_SIZE - rb->plugin_reserve_buffer(reqsz); if (gCache.size < reqsz) @@ -225,14 +334,80 @@ int scrobbler_init(void) logf("SCROBBLER: OOM , %ld < req:%ld", gCache.size, reqsz); return -1; } - - gCache.pos = 0; - gCache.pending = false; gCache.force_flush = true; - logf("Scrobbler Initialized"); + rb->mutex_init(&gCache.mtx); + logf("SCROBBLER: Initialized"); return 1; } +static inline size_t cache_get_entry_size(int str_len) +{ + /* entry_sz consists of the cache entry + str_len + \0NULL terminator */ + return str_len + 1 + sizeof(struct cache_entry); +} + +static inline const char* str_chk_valid(const char *s, const char *alt) +{ + return (s != NULL ? s : alt); +} + +static bool track_is_unique(uint32_t hash1, uint32_t hash2) +{ + bool is_unique = false; + static uint8_t mru_len = 0; + + struct hash64 { uint32_t hash1; uint32_t hash2; }; + + static struct hash64 hash_mru[SCROBBLER_MAX_TRACK_MRU]; + struct hash64 i = {0}; + struct hash64 itmp; + uint8_t mru; + + if (mru_len > gConfig.uniqct) + mru_len = gConfig.uniqct; + + if (gConfig.uniqct < 1) + return true; + + /* Search in MRU */ + for (mru = 0; mru < mru_len; mru++) + { + /* Items shifted >> 1 */ + itmp = i; + i = hash_mru[mru]; + hash_mru[mru] = itmp; + + /* Found in MRU */ + if ((i.hash1 == hash1) && (i.hash2 == hash2)) + { + logf("SCROBBLER: hash [%x, %x] found in MRU @ %d", i.hash1, i.hash2, mru); + goto Found; + } + } + + /* Add MRU entry */ + is_unique = true; + if (mru_len < SCROBBLER_MAX_TRACK_MRU && mru_len < gConfig.uniqct) + { + hash_mru[mru_len] = i; + mru_len++; + } + else + { + logf("SCROBBLER: hash [%x, %x] evicted from MRU", i.hash1, i.hash2); + } + + i = (struct hash64){.hash1 = hash1, .hash2 = hash2}; + logf("SCROBBLER: hash [%x, %x] added to MRU[%d]", i.hash1, i.hash2, mru_len); + +Found: + + /* Promote MRU item to top of MRU */ + hash_mru[0] = i; + + return is_unique; +} + static void get_scrobbler_filename(char *path, size_t size) { int used; @@ -241,7 +416,7 @@ static void get_scrobbler_filename(char *path, size_t size) if (used >= (int)size) { - logf("%s: not enough buffer space for log file", __func__); + logf("%s: not enough buffer space for log filename", __func__); rb->memset(path, 0, size); } } @@ -252,6 +427,9 @@ static void scrobbler_write_cache(void) int fd; logf("%s", __func__); char scrobbler_file[MAX_PATH]; + + rb->mutex_lock(&gCache.mtx); + get_scrobbler_filename(scrobbler_file, sizeof(scrobbler_file)); /* If the file doesn't exist, create it. @@ -261,6 +439,7 @@ static void scrobbler_write_cache(void) fd = rb->open(scrobbler_file, O_RDWR | O_CREAT, 0666); if(fd >= 0) { + /* write file header */ rb->fdprintf(fd, "#AUDIOSCROBBLER/" SCROBBLER_VERSION "\n" "#TZ/UNKNOWN\n" "#CLIENT/Rockbox " TARGET_NAME SCROBBLER_REVISION @@ -275,38 +454,72 @@ static void scrobbler_write_cache(void) } } + int entries = gCache.entries; + size_t used = gCache.pos; + size_t pos = 0; + /* clear even if unsuccessful - we don't want to overflow the buffer */ + gCache.pos = 0; + gCache.entries = 0; + /* write the cache entries */ fd = rb->open(scrobbler_file, O_WRONLY | O_APPEND); if(fd >= 0) { - logf("SCROBBLER: writing %d entries", gCache.pos); - /* copy data to temporary storage in case data moves during I/O */ - char temp_buf[SCROBBLER_CACHE_LEN]; - for ( i=0; i < gCache.pos; i++ ) + logf("SCROBBLER: writing %d entries", entries); + /* copy cached data to storage */ + uint32_t prev_crc = 0x0; + uint32_t crc; + size_t entry_sz, len; + bool err = false; + + for (i = 0; i < entries && pos < used; i++) { - logf("SCROBBLER: write %d", i); - char* scrobbler_buf = gCache.buf; - ssize_t len = rb->strlcpy(temp_buf, scrobbler_buf+(SCROBBLER_CACHE_LEN*i), - sizeof(temp_buf)); - if (rb->write(fd, temp_buf, len) != len) + logf("SCROBBLER: write %d read pos [%ld]", i, pos); + + struct cache_entry *entry = (struct cache_entry*)&gCache.buf[pos]; + + entry_sz = cache_get_entry_size(entry->len); + crc = rb->crc_32(entry->buf, entry->len, 0xFFFFFFFF) ^ prev_crc; + prev_crc = crc; + + len = rb->strlen(entry->buf); + logf("SCROBBLER: write entry %d sz [%ld] len [%ld]", i, entry_sz, len); + + if (len != entry->len || crc != entry->crc) /* the entry is corrupted */ + { + rb->write(fd, SCROBBLER_BAD_ENTRY, sizeof(SCROBBLER_BAD_ENTRY)-1); + logf("SCROBBLER: Bad entry %d", i); + if(!err) + { + rb->queue_post(&gThread.queue, EV_USER_ERROR, ERR_WRITING_DATA); + err = true; + } + } + + logf("SCROBBLER: writing %s", entry->buf); + + if (rb->write(fd, entry->buf, len) != (ssize_t)len) break; + + if (entry->buf[len - 1] != '\n') + rb->write(fd, "\n", 1); /* ensure newline termination */ + + pos += entry_sz; } rb->close(fd); } else { logf("SCROBBLER: error writing file"); + rb->queue_post(&gThread.queue, EV_USER_ERROR, ERR_WRITING_FILE); } - - /* clear even if unsuccessful - don't want to overflow the buffer */ - gCache.pos = 0; + rb->mutex_unlock(&gCache.mtx); } #if USING_STORAGE_CALLBACK static void scrobbler_flush_callback(void) { - (void) gCache.force_flush; - if(gCache.pos <= 0) + if(gCache.pos == 0) return; #if (CONFIG_STORAGE & STORAGE_ATA) else @@ -321,69 +534,127 @@ static void scrobbler_flush_callback(void) } #endif -static inline char* str_chk_valid(char *s, char *alt) +static unsigned long scrobbler_get_threshold(unsigned long length) { - return (s != NULL ? s : alt); + /* length is assumed to be in miliseconds */ + return length / 100 * gConfig.savepct; +} + +static int create_log_entry(const struct mp3entry *id, + struct cache_entry *entry, int *trk_info_len) +{ + #define SEP "\t" + #define EOL "\n" + char* artist = id->artist ? id->artist : id->albumartist; + char rating = 'S'; /* Skipped */ + if (id->elapsed >= scrobbler_get_threshold(id->length)) + rating = 'L'; /* Listened */ + + char tracknum[11] = { "" }; + + if (id->tracknum > 0) + rb->snprintf(tracknum, sizeof (tracknum), "%d", id->tracknum); + + int ret = rb->snprintf(entry->buf, + SCROBBLER_CACHE_LEN, + "%s"SEP"%s"SEP"%s"SEP"%s"SEP"%d%n"SEP"%c"SEP"%ld"SEP"%s"EOL"", + str_chk_valid(artist, UNTAGGED), + str_chk_valid(id->album, ""), + str_chk_valid(id->title, id->path), + tracknum, + (int)(id->length / 1000), + trk_info_len, /* receives len of the string written so far */ + rating, + get_timestamp(), + str_chk_valid(id->mb_track_id, "")); + + #undef SEP + #undef EOL + return ret; } static void scrobbler_add_to_cache(const struct mp3entry *id) { - static uint32_t last_crc = 0; int trk_info_len = 0; - if ( gCache.pos >= SCROBBLER_MAX_CACHE ) - scrobbler_write_cache(); + if (id->elapsed < (unsigned long) gConfig.minms) + { + logf("SCROBBLER: skipping entry < %d ms: %s", gConfig.minms, id->path); + return; + } - char rating = 'S'; /* Skipped */ - char* scrobbler_buf = gCache.buf; + rb->mutex_lock(&gCache.mtx); - logf("SCROBBLER: add_to_cache[%d]", gCache.pos); + /* not enough room left to guarantee next entry will fit so flush the cache */ + if ( gCache.pos > SCROBBLER_MAX_CACHE - SCROBBLER_CACHE_LEN ) + scrobbler_write_cache(); - if (id->elapsed > id->length / 2) - rating = 'L'; /* Listened */ + logf("SCROBBLER: add_to_cache[%d] write pos[%ld]", gCache.entries, gCache.pos); + /* use prev_crc to allow whole buffer to be checked for consistency */ + static uint32_t prev_crc = 0x0; + if (gCache.pos == 0) + prev_crc = 0x0; - char tracknum[11] = { "" }; + void *buf = &gCache.buf[gCache.pos]; + memset(buf, 0, SCROBBLER_CACHE_LEN); - if (id->tracknum > 0) - rb->snprintf(tracknum, sizeof (tracknum), "%d", id->tracknum); + struct cache_entry *entry = buf; - char* artist = id->artist ? id->artist : id->albumartist; + int ret = create_log_entry(id, entry, &trk_info_len); - int ret = rb->snprintf(&scrobbler_buf[(SCROBBLER_CACHE_LEN*gCache.pos)], - SCROBBLER_CACHE_LEN, - "%s\t%s\t%s\t%s\t%d\t%c%n\t%ld\t%s\n", - str_chk_valid(artist, UNTAGGED), - str_chk_valid(id->album, ""), - str_chk_valid(id->title, ""), - tracknum, - (int)(id->length / 1000), - rating, - &trk_info_len, - get_timestamp(), - str_chk_valid(id->mb_track_id, "")); - - if ( ret >= SCROBBLER_CACHE_LEN ) + if (ret <= 0 || (size_t) ret >= SCROBBLER_CACHE_LEN) { logf("SCROBBLER: entry too long:"); logf("SCROBBLER: %s", id->path); + rb->queue_post(&gThread.queue, EV_USER_ERROR, ERR_ENTRY_LENGTH); } - else + else if (ret > 0) { - uint32_t crc = rb->crc_32(&scrobbler_buf[(SCROBBLER_CACHE_LEN*gCache.pos)], - trk_info_len, 0xFFFFFFFF); - if (crc != last_crc) + /* first generate a crc over the static portion of the track info data + this and a crc of the filename will be used to detect repeat entries + */ + static uint32_t last_crc = 0; + uint32_t crc_entry = rb->crc_32(entry->buf, trk_info_len, 0xFFFFFFFF); + uint32_t crc_path = rb->crc_32(id->path, rb->strlen(id->path), 0xFFFFFFFF); + bool is_unique = track_is_unique(crc_entry, crc_path); + bool is_listened = (id->elapsed >= scrobbler_get_threshold(id->length)); + + if (is_unique || is_listened) { - last_crc = crc; - logf("Added %s", scrobbler_buf); - gCache.pos++; + /* finish calculating the CRC of the whole entry */ + const void *src = entry->buf + trk_info_len; + entry->crc = rb->crc_32(src, ret - trk_info_len, crc_entry) ^ prev_crc; + prev_crc = entry->crc; + entry->len = ret; + + /* since Listened entries are written regardless + make sure this isn't a direct repeat */ + if ((entry->crc ^ crc_path) != last_crc) + { + + if (is_listened) + last_crc = (entry->crc ^ crc_path); + else + last_crc = 0; + + size_t entry_sz = cache_get_entry_size(ret); + + logf("SCROBBLER: Added (#%d) sz[%ld] len[%d], %s", + gCache.entries, entry_sz, ret, entry->buf); + + gCache.entries++; + /* increase pos by string len + null terminator + sizeof entry */ + gCache.pos += entry_sz; + #if USING_STORAGE_CALLBACK - rb->register_storage_idle_func(scrobbler_flush_callback); + rb->register_storage_idle_func(scrobbler_flush_callback); #endif + } } else logf("SCROBBLER: skipping repeat entry: %s", id->path); } - + rb->mutex_unlock(&gCache.mtx); } static void scrobbler_flush_cache(void) @@ -404,16 +675,14 @@ static void scrobbler_flush_cache(void) } } -static void scrobbler_change_event(unsigned short id, void *ev_data) +static void track_change_event(unsigned short id, void *ev_data) { (void)id; logf("%s", __func__); struct mp3entry *id3 = ((struct track_event *)ev_data)->id3; - /* check if track was resumed > %50 played ( likely got saved ) - check for blank artist or track name */ - if ((id3->elapsed > id3->length / 2) - || (!id3->artist && !id3->albumartist) || !id3->title) + /* check if track was resumed > %threshold played ( likely got saved ) */ + if ((id3->elapsed > scrobbler_get_threshold(id3->length))) { gCache.pending = false; logf("SCROBBLER: skipping file %s", id3->path); @@ -425,6 +694,7 @@ static void scrobbler_change_event(unsigned short id, void *ev_data) gCache.pending = true; } } + #ifdef ROCKBOX_HAS_LOGF static const char* track_event_info(struct track_event* te) { @@ -439,34 +709,39 @@ static const char* track_event_info(struct track_event* te) * TEF_REWIND = 0x4, interpret as rewind, id3->elapsed is the position before the seek back to 0 */ - logf("flag %d", te->flags); + logf("SCROBBLER: flag %d", te->flags); return strflags[te->flags&0x7]; } - #endif -static void scrobbler_finish_event(unsigned short id, void *ev_data) + +static void track_finish_event(unsigned short id, void *ev_data) { (void)id; struct track_event *te = ((struct track_event *)ev_data); - struct mp3entry *id3 = te->id3; logf("%s %s %s", __func__, gCache.pending?"True":"False", track_event_info(te)); /* add entry using the currently ending track */ if (gCache.pending && (te->flags & TEF_CURRENT) && !(te->flags & TEF_REWIND)) { gCache.pending = false; - if (id3->elapsed*2 >= id3->length) - scrobbler_add_to_cache(te->id3); - else - { - logf("%s Discarding < 50%% played", __func__); - } + scrobbler_add_to_cache(te->id3); } +} +/****************** main thread + helpers ******************/ +static void events_unregister(void) +{ + /* we don't want any more events */ + rb->remove_event(PLAYBACK_EVENT_TRACK_CHANGE, track_change_event); + rb->remove_event(PLAYBACK_EVENT_TRACK_FINISH, track_finish_event); +} +static void events_register(void) +{ + rb->add_event(PLAYBACK_EVENT_TRACK_CHANGE, track_change_event); + rb->add_event(PLAYBACK_EVENT_TRACK_FINISH, track_finish_event); } -/****************** main thread + helper ******************/ void thread(void) { bool in_usb = false; @@ -487,7 +762,8 @@ void thread(void) in_usb = false; /*fall through*/ case EV_STARTUP: - rb->beep_play(1500, 100, 1000); + events_register(); + play_tone(1500, 100); break; case SYS_POWEROFF: case SYS_REBOOT: @@ -495,15 +771,27 @@ void thread(void) /*fall through*/ case EV_EXIT: #if USING_STORAGE_CALLBACK - rb->unregister_storage_idle_func(scrobbler_flush_callback, !in_usb); + rb->unregister_storage_idle_func(scrobbler_flush_callback, false); #else if (!in_usb) scrobbler_flush_cache(); #endif + events_unregister(); return; - case EV_OTHINSTANCE: + case EV_FLUSHCACHE: scrobbler_flush_cache(); - rb->splashf(HZ * 2, "%s Cache Flushed", str(LANG_AUDIOSCROBBLER)); + rb->queue_reply(&gThread.queue, 0); + break; + case EV_USER_ERROR: + if (!in_usb) + { + if (ev.data == ERR_WRITING_FILE) + rb->splash(HZ, "SCROBBLER: error writing log"); + else if (ev.data == ERR_ENTRY_LENGTH) + rb->splash(HZ, "SCROBBLER: error entry too long"); + else if (ev.data == ERR_WRITING_DATA) + rb->splash(HZ, "SCROBBLER: error bad entry data"); + } break; default: logf("default %ld", ev.id); @@ -514,12 +802,13 @@ void thread(void) void thread_create(void) { - /* put the thread's queue in the bcast list */ + /* put the thread's queue in the broadcast list */ rb->queue_init(&gThread.queue, true); gThread.id = rb->create_thread(thread, gThread.stack, sizeof(gThread.stack), 0, "Last.Fm_TSR" IF_PRIO(, PRIORITY_BACKGROUND) IF_COP(, CPU)); + rb->queue_enable_queue_send(&gThread.queue, &gThread.queue_send, gThread.id); rb->queue_post(&gThread.queue, EV_STARTUP, 0); rb->yield(); } @@ -527,79 +816,85 @@ void thread_create(void) void thread_quit(void) { if (!gThread.exiting) { + gThread.exiting = true; rb->queue_post(&gThread.queue, EV_EXIT, 0); rb->thread_wait(gThread.id); - /* we don't want any more events */ - rb->remove_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event); - rb->remove_event(PLAYBACK_EVENT_TRACK_FINISH, scrobbler_finish_event); /* remove the thread's queue from the broadcast list */ rb->queue_delete(&gThread.queue); - gThread.exiting = true; } } -/* callback to end the TSR plugin, called before a new one gets loaded */ -static bool exit_tsr(bool reenter) +/* callback to end the TSR plugin, called before a new plugin gets loaded */ +static int plugin_exit_tsr(bool reenter) { - logf("%s", __func__); - bool is_exit = false; - int button; - if (reenter) - { - logf(" reenter other instance "); - rb->queue_post(&gThread.queue, EV_OTHINSTANCE, 0); - return false; /* dont let it start again */ - } - rb->lcd_clear_display(); - rb->lcd_puts_scroll(0, 0, "Scrobbler is currently running."); - rb->lcd_puts_scroll(0, 1, "Press " SCROBBLE_OFF_TXT " to exit"); - rb->lcd_puts_scroll(0, 2, "Anything else will resume"); - - rb->lcd_update(); - rb->button_clear_queue(); - while (1) + MENUITEM_STRINGLIST(menu, ID2P(LANG_AUDIOSCROBBLER), NULL, ID2P(LANG_SETTINGS), + "Flush Cache", "Exit Plugin", ID2P(LANG_BACK)); + + const struct text_message quit_prompt = { + (const char*[]){ ID2P(LANG_AUDIOSCROBBLER), + "is currently running.", + "Quit scrobbler?" }, 3 + }; + + while(true) { - button = rb->button_get(true); - if (IS_SYSEVENT(button)) - continue; - if (button == SCROBBLE_OFF) + int result = reenter ? rb->do_menu(&menu, NULL, NULL, false) : 2; + switch(result) { - rb->queue_post(&gThread.queue, EV_EXIT, 0); - rb->thread_wait(gThread.id); - /* remove the thread's queue from the broadcast list */ - rb->queue_delete(&gThread.queue); - is_exit = true; - } - else is_exit = false; + case 0: /* settings */ + config_settings_menu(); + break; + case 1: /* flush cache */ + if (gCache.entries > 0) + { + rb->queue_send(&gThread.queue, EV_FLUSHCACHE, 0); + if (gConfig.verbose) + rb->splashf(2*HZ, "%s Cache Flushed", rb->str(LANG_AUDIOSCROBBLER)); + } + break; - break; + case 2: /* exit plugin - quit */ + if(rb->gui_syncyesno_run(&quit_prompt, NULL, NULL) == YESNO_YES) + { + scrobbler_flush_cache(); + thread_quit(); + return (reenter ? PLUGIN_TSR_TERMINATE : PLUGIN_TSR_SUSPEND); + } + /* Fall Through */ + case 3: /* back to menu */ + return PLUGIN_TSR_CONTINUE; + } } - FOR_NB_SCREENS(idx) - rb->screens[idx]->scroll_stop(); - - if (is_exit) - thread_quit(); - - return is_exit; } /****************** main ******************/ - -int plugin_main(const void* parameter) +static int plugin_main(const void* parameter) { - (void)parameter; + struct scrobbler_cfg cfg; + rb->memcpy(&cfg, &gConfig, sizeof(struct scrobbler_cfg)); /* store settings */ + + /* Resume plugin ? -- silences startup */ + if (parameter == rb->plugin_tsr) + { + gConfig.beeplvl = 0; + gConfig.playback = false; + gConfig.verbose = false; + } rb->memset(&gThread, 0, sizeof(gThread)); - rb->splashf(HZ / 2, "%s Started",str(LANG_AUDIOSCROBBLER)); - logf("%s: %s Started", __func__, str(LANG_AUDIOSCROBBLER)); + if (gConfig.verbose) + rb->splashf(HZ / 2, "%s Started",rb->str(LANG_AUDIOSCROBBLER)); + logf("%s: %s Started", __func__, rb->str(LANG_AUDIOSCROBBLER)); - rb->plugin_tsr(exit_tsr); /* stay resident */ + rb->plugin_tsr(plugin_exit_tsr); /* stay resident */ - rb->add_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event); - rb->add_event(PLAYBACK_EVENT_TRACK_FINISH, scrobbler_finish_event); thread_create(); + rb->memcpy(&gConfig, &cfg, sizeof(struct scrobbler_cfg)); /*restore settings */ - return 0; + if (gConfig.playback) + return PLUGIN_GOTO_WPS; + + return PLUGIN_OK; } /***************** Plugin Entry Point *****************/ @@ -609,9 +904,20 @@ enum plugin_status plugin_start(const void* parameter) /* now go ahead and have fun! */ if (rb->usb_inserted() == true) return PLUGIN_USB_CONNECTED; - language_strings = rb->language_strings; - if (scrobbler_init() < 0) + + if (scrobbler_init_cache() < 0) return PLUGIN_ERROR; + + config_set_defaults(); + + if (configfile_load(CFG_FILE, config, gCfg_sz, CFG_VER) < 0) + { + /* If the loading failed, save a new config file */ + configfile_save(CFG_FILE, config, gCfg_sz, CFG_VER); + if (gConfig.verbose) + rb->splash(HZ, ID2P(LANG_REVERT_TO_DEFAULT_SETTINGS)); + } + int ret = plugin_main(parameter); - return (ret==0) ? PLUGIN_OK : PLUGIN_ERROR; + return ret; } diff --git a/apps/plugins/lastfm_scrobbler_viewer.c b/apps/plugins/lastfm_scrobbler_viewer.c new file mode 100644 index 0000000000..c8b125c293 --- /dev/null +++ b/apps/plugins/lastfm_scrobbler_viewer.c @@ -0,0 +1,1033 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// __ \_/ ___\| |/ /| __ \ / __ \ \/ / + * Jukebox | | ( (__) ) \___| ( | \_\ ( (__) ) ( + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2023 William Wilgus + * + * 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" +#include "lang_enum.h" + +#include "lib/printcell_helper.h" + +#include "lib/configfile.h" +#define CFG_FILE "/lastfm_scrobbler_viewer.cfg" +#define TMP_FILE ""PLUGIN_DATA_DIR "/lscrobbler_viewer_%d.tmp" +#define CFG_VER 1 + +#ifdef ROCKBOX_HAS_LOGF +#define logf rb->logf +#else +#define logf(...) do { } while(0) +#endif + +/*#ARTIST #ALBUM #TITLE #TRACKNUM #LENGTH #RATING #TIMESTAMP #MUSICBRAINZ_TRACKID*/ + +#define SCROBBLE_HDR_FMT "$*%d$%s$*%d$%s$*%d$%s$Track#$Length$Rating$TimeStamp$TrackId" +//#define SCROBBLE_HDR "$*128$Artist$*128$Album$*128$Title$Track#$Length$Rating$TimeStamp$TrackId" + +#define SCROBBLER_MIN_COLUMNS (6) /* a valid scrobbler file should have at least this many columns */ + +#define GOTO_ACTION_DEFAULT_HANDLER (PLUGIN_OK + 1) +#define CANCEL_CONTEXT_MENU (PLUGIN_OK + 2) +#define QUIT_CONTEXT_MENU (PLUGIN_OK + 3) +/* global lists, for everything */ +static struct gui_synclist lists; + +/* printcell data for the current file */ +struct printcell_data_t { + int view_columns; + int view_lastcol; + + int items_buffered; + int items_total; + int fd_cur; + char *filename; + + char *buf; + size_t buf_size; + off_t buf_used; + char header[PRINTCELL_MAXLINELEN]; + +}; + +enum e_find_type { + FIND_ALL = 0, + FIND_EXCLUDE, + FIND_EXCLUDE_CASE, + FIND_EXCLUDE_ANY, + FIND_INCLUDE, + FIND_INCLUDE_CASE, + FIND_INCLUDE_ANY, + FIND_CUSTOM, +}; + +static void synclist_set(int selected_item, int items, int sel_size, struct printcell_data_t *pc_data); +static void pc_data_set_header(struct printcell_data_t *pc_data); + +static void browse_file(char *buf, size_t bufsz) +{ + struct browse_context browse = { + .dirfilter = SHOW_ALL, + .flags = BROWSE_SELECTONLY, + .title = "Select a scrobbler log file", + .icon = Icon_Playlist, + .buf = buf, + .bufsize = bufsz, + .root = "/", + }; + + if (rb->rockbox_browse(&browse) != GO_TO_PREVIOUS) + { + buf[0] = '\0'; + } +} + +static struct plugin_config +{ + bool separator; + bool talk; + int col_width; + int hidecol_flags; +} gConfig; + +static struct configdata config[] = +{ + {TYPE_BOOL, 0, 1, { .bool_p = &gConfig.separator }, "Cell Separator", NULL}, + {TYPE_BOOL, 0, 1, { .bool_p = &gConfig.talk }, "Voice", NULL}, + {TYPE_INT, 32, LCD_WIDTH, { .int_p = &gConfig.col_width }, "Cell Width", NULL}, + {TYPE_INT, INT_MIN, INT_MAX, { .int_p = &gConfig.hidecol_flags }, "Hidden Columns", NULL}, +}; +const int gCfg_sz = sizeof(config)/sizeof(*config); +/****************** config functions *****************/ +static void config_set_defaults(void) +{ + gConfig.col_width = MIN(LCD_WIDTH, 128); + gConfig.hidecol_flags = 0; + gConfig.separator = true; + gConfig.talk = rb->global_settings->talk_menu; +} + +static void config_save(void) +{ + configfile_save(CFG_FILE, config, gCfg_sz, CFG_VER); +} + +static int config_settings_menu(struct printcell_data_t *pc_data) +{ + int selection = 0; + + struct viewport parentvp[NB_SCREENS]; + FOR_NB_SCREENS(l) + { + rb->viewport_set_defaults(&parentvp[l], l); + rb->viewport_set_fullscreen(&parentvp[l], l); + } + + MENUITEM_STRINGLIST(settings_menu, ID2P(LANG_SETTINGS), NULL, + ID2P(LANG_LIST_SEPARATOR), + "Cell Width", + ID2P(LANG_VOICE), + ID2P(VOICE_BLANK), + ID2P(VOICE_BLANK), + ID2P(LANG_CANCEL_0), + ID2P(LANG_SAVE_EXIT)); + + do { + selection=rb->do_menu(&settings_menu,&selection, parentvp, true); + switch(selection) { + + case 0: + rb->set_bool(rb->str(LANG_LIST_SEPARATOR), &gConfig.separator); + break; + case 1: + rb->set_int("Cell Width", "", UNIT_INT, + &gConfig.col_width, NULL, 1, 32, LCD_WIDTH, NULL ); + break; + case 2: + rb->set_bool(rb->str(LANG_VOICE), &gConfig.talk); + break; + case 3: + continue; + case 4: /*sep*/ + continue; + case 5: + return -1; + break; + case 6: + { + pc_data_set_header(pc_data); + synclist_set(0, pc_data->items_total, 1, pc_data); + int res = configfile_save(CFG_FILE, config, gCfg_sz, CFG_VER); + if (res >= 0) + { + logf("Cfg saved %s %d bytes", CFG_FILE, gCfg_sz); + return PLUGIN_OK; + } + logf("Cfg FAILED (%d) %s", res, CFG_FILE); + return PLUGIN_ERROR; + } + case MENU_ATTACHED_USB: + return PLUGIN_USB_CONNECTED; + default: + return PLUGIN_OK; + } + } while ( selection >= 0 ); + return 0; +} + +/* open file pass back file descriptor and return file size */ +static size_t file_open(const char *filename, int *fd) +{ + size_t fsize = 0; + + if (filename && fd) + { + *fd = rb->open(filename, O_RDONLY); + if (*fd >= 0) + { + fsize = rb->filesize(*fd); + } + } + return fsize; +} + +static const char* list_get_name_cb(int selected_item, void* data, + char* buf, size_t buf_len) +{ + const int slush_pos = 32; /* entries around the current entry to keep buffered */ + /* keep track of the last position in the buffer */ + static int buf_line_num = 0; + static off_t buf_last_pos = 0; + /* keep track of the last position in the file */ + static int file_line_num = 0; + static off_t file_last_seek = 0; + + if (selected_item < 0) + { + logf("[%s] Reset positions", __func__); + buf_line_num = 0; + buf_last_pos = 0; + file_line_num = 0; + file_last_seek = 0; + return ""; + } + + int line_num; + struct printcell_data_t *pc_data = (struct printcell_data_t*) data; + bool found = false; + + if (pc_data->buf && selected_item < pc_data->items_buffered) + { + int buf_pos; + + if (buf_line_num > selected_item || buf_last_pos >= pc_data->buf_used + || buf_line_num < 0) + { + logf("[%s] Set pos buffer 0", __func__); + buf_line_num = 0; + buf_last_pos = 0; + } + buf_pos = buf_last_pos; + line_num = buf_line_num; + + while (buf_pos < pc_data->buf_used + && line_num < pc_data->items_buffered) + { + size_t len = rb->strlen(&pc_data->buf[buf_pos]); + if(line_num == selected_item) + { + rb->strlcpy(buf, &pc_data->buf[buf_pos], MIN(buf_len, len)); + logf("(%d) in buffer: %s", line_num, buf); + found = true; + break; + } + else + { + buf_pos += len + 1; /* need to go past the NULL terminator */ + line_num++; + + if (buf_line_num + slush_pos < selected_item) + { + logf("[%s] Set pos buffer %d", __func__, line_num); + buf_line_num = line_num; + buf_last_pos = buf_pos; + } + } + } + } + + /* didn't find the item try the file */ + if(!found && pc_data->fd_cur >= 0) + { + int fd = pc_data->fd_cur; + + if (file_line_num < 0 || file_line_num > selected_item) + { + logf("[%s] Set seek file 0", __func__); + file_line_num = 0; + file_last_seek = 0; + } + + rb->lseek(fd, file_last_seek, SEEK_SET); + line_num = file_line_num; + + while ((rb->read_line(fd, buf, buf_len)) > 0) + { + if(buf[0] == '#') + continue; + if(line_num == selected_item) + { + logf("(%d) in file: %s", line_num, buf); + found = true; + break; + } + else + { + line_num++; + + if (file_line_num + slush_pos < selected_item) + { + logf("[%s] Set seek file %d", __func__, line_num); + file_line_num = line_num; + file_last_seek = rb->lseek(fd, 0, SEEK_CUR); + } + } + } + } + + if(!found) + { + logf("(%d) Not Found!", selected_item); + buf_line_num = -1; + file_line_num = -1; + buf[0] = '\0'; + } + return buf; +} + +static int list_voice_cb(int list_index, void* data) +{ + (void) list_index; + struct printcell_data_t *pc_data = (struct printcell_data_t*) data; + if (!gConfig.talk) + return -1; + + int selcol = printcell_get_column_selected(); + char buf[MAX_PATH]; + char* name; + long id; + + if (pc_data->view_lastcol != selcol) + { + name = printcell_get_title_text(selcol, buf, sizeof(buf)); + + id = P2ID((const unsigned char *)name); + + if(id>=0) + rb->talk_id(id, true); + else if (selcol >= 0) + { + switch (selcol) + { + case 0: + rb->talk_id(LANG_ID3_ARTIST, true); + break; + case 1: + rb->talk_id(LANG_ID3_ALBUM, true); + break; + case 2: + rb->talk_id(LANG_ID3_TITLE, true); + break; + case 3: + rb->talk_id(LANG_ID3_TRACKNUM, true); + break; + case 4: + rb->talk_id(LANG_ID3_LENGTH, true); + break; + + default: + rb->talk_spell(name, true); + break; + } + } + else + rb->talk_id(LANG_ALL, true); + + rb->talk_id(VOICE_PAUSE, true); + } + + name = printcell_get_column_text(selcol, buf, sizeof(buf)); + + id = P2ID((const unsigned char *)name); + + if(id>=0) + rb->talk_id(id, true); + else if (selcol >= 0) + rb->talk_spell(name, true); + + return 0; +} + +static enum themable_icons list_icon_cb(int selected_item, void *data) +{ + struct printcell_data_t *pc_data = (struct printcell_data_t*) data; + if (lists.selected_item == selected_item) + { + if (pc_data->view_lastcol < 0) + return Icon_Config; + return Icon_Audio; + } + return Icon_NOICON; +} + +/* load file entries into pc_data buffer, file should already be opened + * and will be closed if the whole file was buffered */ +static int file_load_entries(struct printcell_data_t *pc_data) +{ + int items = 0; + int count = 0; + int buffered = 0; + unsigned int pos = 0; + bool comment = false; + char ch; + int fd = pc_data->fd_cur; + if (fd < 0) + return 0; + + rb->lseek(fd, 0, SEEK_SET); + + while (rb->read(fd, &ch, 1) > 0) + { + if (count++ == 0 && ch == '#') /* skip comments */ + comment = true; + else if (!comment && ch != '\r' && pc_data->buf_size > pos) + pc_data->buf[pos++] = ch; + + if (items == 0 && pos > PRINTCELL_MAXLINELEN * 2) + break; + + if (ch == '\n') + { + if (!comment) + { + pc_data->buf[pos] = '\0'; + if (pc_data->buf_size > pos) + { + pos++; + buffered++; + } + items++; + } + comment = false; + count = 0; + rb->yield(); + } + } + + logf("[%s] items: %d buffered: %d", __func__, items, buffered); + + pc_data->items_total = items; + pc_data->items_buffered = buffered; + pc_data->buf[pos] = '\0'; + pc_data->buf_used = pos; + + if (items == buffered) /* whole file fit into buffer; close file */ + { + rb->close(pc_data->fd_cur); + pc_data->fd_cur = -1; + } + + list_get_name_cb(-1, NULL, NULL, 0); /* prime name cb */ + return items; +} + +static int filter_items(struct printcell_data_t *pc_data, + enum e_find_type find_type, int col) +{ + /* saves filtered items to a temp file and loads it */ + int fd; + bool reload = false; + char buf[PRINTCELL_MAXLINELEN]; + char find_exclude_buf[PRINTCELL_MAXLINELEN]; + int selcol = printcell_get_column_selected(); + char *find_exclude = printcell_get_column_text(selcol, find_exclude_buf, + sizeof(find_exclude_buf)); + const char colsep = '\t'; + int find_len = rb->strlen(find_exclude); + + if (find_type == FIND_CUSTOM || find_len == 0) + { + int option = 0; + struct opt_items find_types[] = { + {"Exclude", -1}, {"Exclude Case Sensitive", -1}, + {"Exclude Any", -1}, {"Include", -1}, + {"Include Case Sensitive", -1}, {"Include Any", -1} + }; + if (rb->set_option("Find Type", &option, INT, + find_types, 6, NULL)) + { + return 0; + } + switch (option) + { + case 0: + find_type = FIND_EXCLUDE; + break; + case 1: + find_type = FIND_EXCLUDE_CASE; + break; + case 2: + find_type = FIND_EXCLUDE_ANY; + break; + case 3: + find_type = FIND_INCLUDE; + break; + case 4: + find_type = FIND_INCLUDE_CASE; + break; + case 5: + find_type = FIND_INCLUDE_ANY; + break; + default: + find_type = FIND_ALL; + break; + } + + /* copy data to beginning of buf */ + rb->memmove(find_exclude_buf, find_exclude, find_len); + find_exclude_buf[find_len] = '\0'; + + if (rb->kbd_input(find_exclude_buf, sizeof(find_exclude_buf), NULL) < 0) + return -1; + find_exclude = find_exclude_buf; + find_len = rb->strlen(find_exclude); + } + + char tmp_filename[MAX_PATH]; + static int tmp_num = 0; + rb->snprintf(tmp_filename, sizeof(tmp_filename), TMP_FILE, tmp_num); + tmp_num++; + + fd = rb->open(tmp_filename, O_RDWR | O_CREAT | O_TRUNC, 0666); + if(fd >= 0) + { + rb->splash_progress_set_delay(HZ * 5); + for (int i = 0; i < pc_data->items_total; i++) + { + rb->splash_progress(i, pc_data->items_total, "Filtering..."); + const char * data = list_get_name_cb(i, pc_data, buf, sizeof(buf)); + + if (find_type != FIND_ALL) + { + int index = col; + + if (index < 0) + index = 0; + if (find_len > 0) + { + char *bcol = buf; + while (*bcol != '\0' && index > 0) + { + if (*bcol == colsep) + index--; + bcol++; + } + if (index > 0) + continue; + + if (find_type == FIND_EXCLUDE) + { + if (rb->strncasecmp(bcol, find_exclude, find_len) == 0) + { + logf("[%s] exclude [%s]", find_exclude, bcol); + continue; + } + } + else if (find_type == FIND_INCLUDE) + { + if (rb->strncasecmp(bcol, find_exclude, find_len) != 0) + { + logf("%s include %s", find_exclude, bcol); + continue; + } + } + else if (find_type == FIND_EXCLUDE_CASE) + { + if (rb->strncmp(bcol, find_exclude, find_len) == 0) + { + logf("[%s] exclude case [%s]", find_exclude, bcol); + continue; + } + } + else if (find_type == FIND_INCLUDE_CASE) + { + if (rb->strncmp(bcol, find_exclude, find_len) != 0) + { + logf("%s include case %s", find_exclude, bcol); + continue; + } + } + else if (find_type == FIND_EXCLUDE_ANY) + { + bool found = false; + while (*bcol != '\0' && *bcol != colsep) + { + if (rb->strncasecmp(bcol, find_exclude, find_len) == 0) + { + logf("[%s] exclude any [%s]", find_exclude, bcol); + found = true; + break; + } + bcol++; + } + if (found) + continue; + } + else if (find_type == FIND_INCLUDE_ANY) + { + bool found = false; + while (*bcol != '\0' && *bcol != colsep) + { + if (rb->strncasecmp(bcol, find_exclude, find_len) == 0) + { + found = true; + logf("[%s] include any [%s]", find_exclude, bcol); + break; + } + bcol++; + } + if (!found) + continue; + } + } + } + int len = rb->strlen(data); + if (len > 0) + { + logf("writing [%d bytes][%s]", len + 1, data); + rb->write(fd, data, len); + rb->write(fd, "\n", 1); + } + } + reload = true; + } + + if (reload) + { + if (pc_data->fd_cur >= 0) + rb->close(pc_data->fd_cur); + + pc_data->fd_cur = fd; + int items = file_load_entries(pc_data); + if (items >= 0) + { + lists.selected_item = 0; + rb->gui_synclist_set_nb_items(&lists, items); + } + } + logf("Col text '%s'", find_exclude); + logf("text '%s'", find_exclude_buf); + + return pc_data->items_total; +} + +static int scrobbler_context_menu(struct printcell_data_t *pc_data) +{ + struct viewport parentvp[NB_SCREENS]; + FOR_NB_SCREENS(l) + { + rb->viewport_set_defaults(&parentvp[l], l); + rb->viewport_set_fullscreen(&parentvp[l], l); + } + + int col = printcell_get_column_selected(); + int selection = 0; + int items = 0; + uint32_t visible = printcell_get_column_visibility(-1); + bool hide_col = PRINTCELL_COLUMN_IS_VISIBLE(visible, col); + + char namebuf[PRINTCELL_MAXLINELEN]; + enum e_find_type find_type = FIND_ALL; + + char *colname = pc_data->filename; + if (col >= 0) + colname = printcell_get_title_text(col, namebuf, sizeof(namebuf)); + +#define MENUITEM_STRINGLIST_CUSTOM(name, str, callback, ... ) \ + const char *name##_[] = {__VA_ARGS__}; \ + const struct menu_callback_with_desc name##__ = \ + {callback,str, Icon_NOICON}; \ + const struct menu_item_ex name = \ + {MT_RETURN_ID|MENU_HAS_DESC| \ + MENU_ITEM_COUNT(sizeof( name##_)/sizeof(*name##_)), \ + { .strings = name##_},{.callback_and_desc = & name##__}}; + + const char *menu_item[4]; + + menu_item[0]= hide_col ? "Hide":"Show"; + menu_item[1]= "Exclude"; + menu_item[2]= "Include"; + menu_item[3]= "Custom Filter"; + + if (col == -1) + { + menu_item[0]= hide_col ? "Hide All":"Show All"; + menu_item[1]= "Open"; + menu_item[2]= "Reload"; + menu_item[3]= ID2P(LANG_SETTINGS); + } + + MENUITEM_STRINGLIST_CUSTOM(context_menu, colname, NULL, + menu_item[0], + menu_item[1], + menu_item[2], + menu_item[3], + ID2P(VOICE_BLANK), + ID2P(LANG_CANCEL_0), + ID2P(LANG_MENU_QUIT)); + +#undef MENUITEM_STRINGLIST_CUSTOM + do { + selection=rb->do_menu(&context_menu,&selection, parentvp, true); + switch(selection) { + + case 0: + { + printcell_set_column_visible(col, !hide_col); + if (hide_col) + { + do + { + col = printcell_increment_column(1, true); + } while (col >= 0 && printcell_get_column_visibility(col) == 1); + pc_data->view_lastcol = col; + } + gConfig.hidecol_flags = printcell_get_column_visibility(-1); + break; + } + case 1: /* Exclude / Open */ + { + if (col == -1)/*Open*/ + { + char buf[MAX_PATH]; + browse_file(buf, sizeof(buf)); + if (rb->file_exists(buf)) + { + rb->strlcpy(pc_data->filename, buf, MAX_PATH); + if (pc_data->fd_cur >= 0) + rb->close(pc_data->fd_cur); + if (file_open(pc_data->filename, &pc_data->fd_cur) > 0) + items = file_load_entries(pc_data); + if (items >= 0) + synclist_set(0, items, 1, pc_data); + } + else + rb->splash(HZ *2, "Error Opening"); + + return CANCEL_CONTEXT_MENU; + } + + find_type = FIND_EXCLUDE; + } + /* fall-through */ + case 2: /* Include / Reload */ + { + if (col == -1) /*Reload*/ + { + if (pc_data->fd_cur >= 0) + rb->close(pc_data->fd_cur); + if (file_open(pc_data->filename, &pc_data->fd_cur) > 0) + items = file_load_entries(pc_data); + if (items >= 0) + rb->gui_synclist_set_nb_items(&lists, items); + return CANCEL_CONTEXT_MENU; + } + + if (find_type == FIND_ALL) + find_type = FIND_INCLUDE; + /* fall-through */ + } + case 3: /*Custom Filter / Settings */ + { + if (col == -1)/*Settings*/ + return config_settings_menu(pc_data); + + if (find_type == FIND_ALL) + find_type = FIND_CUSTOM; + items = filter_items(pc_data, find_type, col); + + if (items >= 0) + rb->gui_synclist_set_nb_items(&lists, items); + break; + } + case 4: /*sep*/ + continue; + case 5: + return CANCEL_CONTEXT_MENU; + break; + case 6: /* Quit */ + return QUIT_CONTEXT_MENU; + break; + case MENU_ATTACHED_USB: + return PLUGIN_USB_CONNECTED; + default: + return PLUGIN_OK; + } + } while ( selection < 0 ); + return 0; +} + +static void cleanup(void *parameter) +{ + struct printcell_data_t *pc_data = (struct printcell_data_t*) parameter; + if (pc_data->fd_cur >= 0) + rb->close(pc_data->fd_cur); + pc_data->fd_cur = -1; +} + +static void menu_action_printcell(int *action, int selected_item, bool* exit, struct gui_synclist *lists) +{ + (void) exit; + struct printcell_data_t *pc_data = (struct printcell_data_t*) lists->data; + if (*action == ACTION_STD_OK) + { + if (selected_item < lists->nb_items) + { + pc_data->view_lastcol = printcell_increment_column(1, true); + *action = ACTION_NONE; + } + } + else if (*action == ACTION_STD_CANCEL) + { + pc_data->view_lastcol = printcell_increment_column(-1, true); + if (pc_data->view_lastcol != pc_data->view_columns - 1) + { + *action = ACTION_NONE; + } + } + else if (*action == ACTION_STD_CONTEXT) + { + int ctxret = scrobbler_context_menu(pc_data); + if (ctxret == QUIT_CONTEXT_MENU) + *exit = true; + } +} + +int menu_action_cb(int *action, int selected_item, bool* exit, struct gui_synclist *lists) +{ + + menu_action_printcell(action, selected_item, exit, lists); + + if (rb->default_event_handler_ex(*action, cleanup, lists->data) == SYS_USB_CONNECTED) + { + *exit = true; + return PLUGIN_USB_CONNECTED; + } + return PLUGIN_OK; +} + +static int count_max_columns(int items, char delimeter, + int expected_cols, struct printcell_data_t *pc_data) +{ + int max_cols = 0; + int cols = 0; + char buf[PRINTCELL_MAXLINELEN]; + for (int i = 0; i < items; i++) + { + const char *txt = list_get_name_cb(i, pc_data, buf, sizeof(buf)); + while (*txt != '\0') + { + if (*txt == delimeter) + { + cols++; + if (cols == expected_cols) + { + max_cols = cols; + break; + } + } + txt++; + } + + if(max_cols < expected_cols && i > 32) + break; + + if (cols > max_cols) + max_cols = cols; + cols = 0; + } + return max_cols; +} + +static void synclist_set(int selected_item, int items, int sel_size, struct printcell_data_t *pc_data) +{ + if (items <= 0) + return; + if (selected_item < 0) + selected_item = 0; + + rb->gui_synclist_init(&lists,list_get_name_cb, + pc_data, false, sel_size, NULL); + + rb->gui_synclist_set_icon_callback(&lists, list_icon_cb); + rb->gui_synclist_set_voice_callback(&lists, list_voice_cb); + rb->gui_synclist_set_nb_items(&lists,items); + rb->gui_synclist_select_item(&lists, selected_item); + + struct printcell_settings pcs = {.cell_separator = gConfig.separator, + .title_delimeter = '$', + .text_delimeter = '\t', + .hidecol_flags = gConfig.hidecol_flags}; + + pc_data->view_columns = printcell_set_columns(&lists, &pcs, + pc_data->header, Icon_Rockbox); + printcell_enable(true); + + + int max_cols = count_max_columns(items, pcs.text_delimeter, + SCROBBLER_MIN_COLUMNS, pc_data); + if (max_cols < SCROBBLER_MIN_COLUMNS) /* not a scrobbler file? */ + { + rb->gui_synclist_set_voice_callback(&lists, NULL); + pc_data->view_columns = printcell_set_columns(&lists, NULL, + "$*512$", Icon_Questionmark); + } + + int curcol = printcell_get_column_selected(); + while (curcol >= 0) + curcol = printcell_increment_column(-1, false); + + if (pc_data->view_lastcol >= pc_data->view_columns) + pc_data->view_lastcol = -1; + + /* restore column position */ + while (pc_data->view_lastcol > -1 && curcol != pc_data->view_lastcol) + { + curcol = printcell_increment_column(1, true); + } + pc_data->view_lastcol = curcol; + list_voice_cb(0, pc_data); +} + +static void pc_data_set_header(struct printcell_data_t *pc_data) +{ + int col_w = gConfig.col_width; + rb->snprintf(pc_data->header, PRINTCELL_MAXLINELEN, + SCROBBLE_HDR_FMT, col_w, rb->str(LANG_ID3_ARTIST), + col_w, rb->str(LANG_ID3_ALBUM), + col_w, rb->str(LANG_ID3_TITLE)); +} + +enum plugin_status plugin_start(const void* parameter) +{ + int ret = PLUGIN_OK; + int selected_item = -1; + int action; + int items = 0; +#if CONFIG_RTC + static char filename[MAX_PATH] = HOME_DIR "/.scrobbler.log"; +#else /* !CONFIG_RTC */ + static char filename[MAX_PATH] = HOME_DIR "/.scrobbler-timeless.log"; +#endif /* CONFIG_RTC */ + bool redraw = true; + bool exit = false; + + static struct printcell_data_t printcell_data; + + if (parameter) + { + rb->strlcpy(filename, (const char*)parameter, MAX_PATH); + filename[MAX_PATH - 1] = '\0'; + } + + if (!rb->file_exists(filename)) + { + browse_file(filename, sizeof(filename)); + if (!rb->file_exists(filename)) + { + rb->splash(HZ, "No Scrobbler file Goodbye."); + return PLUGIN_ERROR; + } + + } + + config_set_defaults(); + if (configfile_load(CFG_FILE, config, gCfg_sz, CFG_VER) < 0) + { + /* If the loading failed, save a new config file */ + config_set_defaults(); + configfile_save(CFG_FILE, config, gCfg_sz, CFG_VER); + + rb->splash(HZ, ID2P(LANG_REVERT_TO_DEFAULT_SETTINGS)); + } + + rb->memset(&printcell_data, 0, sizeof (struct printcell_data_t)); + printcell_data.fd_cur = -1; + printcell_data.view_lastcol = -1; + + if (rb->file_exists(filename)) + { + if (file_open(filename, &printcell_data.fd_cur) == 0) + printcell_data.fd_cur = -1; + else + { + size_t buf_size; + printcell_data.buf = rb->plugin_get_buffer(&buf_size); + printcell_data.buf_size = buf_size; + printcell_data.buf_used = 0; + printcell_data.filename = filename; + items = file_load_entries(&printcell_data); + } + } + int col_w = gConfig.col_width; + rb->snprintf(printcell_data.header, PRINTCELL_MAXLINELEN, + SCROBBLE_HDR_FMT, col_w, rb->str(LANG_ID3_ARTIST), + col_w, rb->str(LANG_ID3_ALBUM), + col_w, rb->str(LANG_ID3_TITLE)); + + if (!exit && items > 0) + { + synclist_set(0, items, 1, &printcell_data); + rb->gui_synclist_draw(&lists); + + while (!exit) + { + action = rb->get_action(CONTEXT_LIST, HZ / 10); + + if (action == ACTION_NONE) + { + if (redraw) + { + action = ACTION_REDRAW; + redraw = false; + } + } + else + redraw = true; + + ret = menu_action_cb(&action, selected_item, &exit, &lists); + if (rb->gui_synclist_do_button(&lists, &action)) + continue; + selected_item = rb->gui_synclist_get_sel_pos(&lists); + + } + } + config_save(); + cleanup(&printcell_data); + return ret; +} diff --git a/apps/plugins/lib/SOURCES b/apps/plugins/lib/SOURCES index bff9017404..09a8b1c5ed 100644 --- a/apps/plugins/lib/SOURCES +++ b/apps/plugins/lib/SOURCES @@ -69,3 +69,9 @@ kbd_helper.c #ifdef HAVE_TOUCHSCREEN pluginlib_touchscreen.c #endif + +id3.c + +#ifdef HAVE_TAGCACHE +mul_id3.c +#endif diff --git a/apps/plugins/lib/bmp_smooth_scale.c b/apps/plugins/lib/bmp_smooth_scale.c index c5f258cdbf..378ff96448 100644 --- a/apps/plugins/lib/bmp_smooth_scale.c +++ b/apps/plugins/lib/bmp_smooth_scale.c @@ -78,7 +78,7 @@ void smooth_resize_bitmap(struct bitmap *src_bmp, struct bitmap *dest_bmp) fb_data *sptr, *dptr; int x, y, end; int val_y = 0, val_x; -#if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE +#if LCD_STRIDEFORMAT == VERTICAL_STRIDE const int sw = src_bmp->height; const int sh = src_bmp->width; const int dw = dest_bmp->height; diff --git a/apps/plugins/lib/helper.c b/apps/plugins/lib/helper.c index 018c1616c8..92d9ec905e 100644 --- a/apps/plugins/lib/helper.c +++ b/apps/plugins/lib/helper.c @@ -58,7 +58,12 @@ void backlight_use_settings(void) backlight_timeout_plugged); #endif /* CONFIG_CHARGING */ } -#endif /* HAVE_BACKLIGHT */ +#else /* HAVE_BACKLIGHT */ +/* DUMMY FUNCTIONS */ +void backlight_force_on(void){} +void backlight_ignore_timeout(void){} +void backlight_use_settings(void){} +#endif /* !HAVE_BACKLIGHT */ #ifdef HAVE_SW_POWEROFF static bool original_sw_poweroff_state = true; @@ -73,7 +78,11 @@ void sw_poweroff_restore(void) { rb->button_set_sw_poweroff_state(original_sw_poweroff_state); } -#endif +#else /* HAVE_SW_POWEROFF */ +/* DUMMY FUNCTIONS */ +void sw_poweroff_disable(void){} +void sw_poweroff_restore(void){} +#endif /* !HAVE_SW_POWEROFF */ #ifdef HAVE_REMOTE_LCD /* Force the backlight on */ @@ -106,7 +115,12 @@ void remote_backlight_use_settings(void) remote_backlight_timeout_plugged); #endif /* CONFIG_CHARGING */ } -#endif /* HAVE_REMOTE_LCD */ +#else /* HAVE_REMOTE_LCD */ +/* DUMMY FUNCTIONS */ +void remote_backlight_force_on(void){} +void remote_backlight_ignore_timeout(void){} +void remote_backlight_use_settings(void){} +#endif /* !HAVE_REMOTE_LCD */ #ifdef HAVE_BUTTON_LIGHT /* Force the buttonlight on */ @@ -133,7 +147,13 @@ void buttonlight_use_settings(void) { rb->buttonlight_set_timeout(rb->global_settings->buttonlight_timeout); } -#endif /* HAVE_BUTTON_LIGHT */ +#else /* HAVE_BUTTON_LIGHT */ +/* DUMMY FUNCTIONS */ +void buttonlight_force_on(void){} +void buttonlight_force_off(void){} +void buttonlight_ignore_timeout(void){} +void buttonlight_use_settings(void){} +#endif /* !HAVE_BUTTON_LIGHT */ #ifdef HAVE_BACKLIGHT_BRIGHTNESS void backlight_brightness_set(int brightness) @@ -145,7 +165,15 @@ void backlight_brightness_use_setting(void) { rb->backlight_set_brightness(rb->global_settings->brightness); } -#endif /* HAVE_BACKLIGHT_BRIGHTNESS */ +#else /* HAVE_BACKLIGHT_BRIGHTNESS */ +/* DUMMY FUNCTIONS */ +void backlight_brightness_set(int brightness) +{ + (void)brightness; +} +void backlight_brightness_use_setting(void){} + +#endif /* !HAVE_BACKLIGHT_BRIGHTNESS */ #ifdef HAVE_BUTTONLIGHT_BRIGHTNESS void buttonlight_brightness_set(int brightness) @@ -157,4 +185,12 @@ void buttonlight_brightness_use_setting(void) { rb->buttonlight_set_brightness(rb->global_settings->buttonlight_brightness); } -#endif /* HAVE_BUTTONLIGHT_BRIGHTNESS */ +#else /* HAVE_BUTTONLIGHT_BRIGHTNESS */ +/* DUMMY FUNCTIONS */ +void buttonlight_brightness_set(int brightness) +{ + (void)brightness; +} + +void buttonlight_brightness_use_setting(void){} +#endif /* !HAVE_BUTTONLIGHT_BRIGHTNESS */ diff --git a/apps/plugins/lib/helper.h b/apps/plugins/lib/helper.h index 00ad8ac087..6aee4dc581 100644 --- a/apps/plugins/lib/helper.h +++ b/apps/plugins/lib/helper.h @@ -23,6 +23,16 @@ #include "plugin.h" +#ifndef MAX_BRIGHTNESS_SETTING +#define MAX_BRIGHTNESS_SETTING 0 +#endif +#ifndef MIN_BRIGHTNESS_SETTING +#define MIN_BRIGHTNESS_SETTING 0 +#endif +#ifndef DEFAULT_BRIGHTNESS_SETTING +#define DEFAULT_BRIGHTNESS_SETTING 0 +#endif + int talk_val(long n, int unit, bool enqueue); /** @@ -32,39 +42,29 @@ void backlight_force_on(void); void backlight_ignore_timeout(void); void backlight_use_settings(void); -#ifdef HAVE_SW_POWEROFF /** * Disable and restore software poweroff (i.e. holding PLAY on iPods). * Only call _restore() if _disable() was called earlier! */ void sw_poweroff_disable(void); void sw_poweroff_restore(void); -#endif -#ifdef HAVE_REMOTE_LCD void remote_backlight_force_on(void); void remote_backlight_ignore_timeout(void); void remote_backlight_use_settings(void); -#endif -#ifdef HAVE_BUTTON_LIGHT void buttonlight_force_on(void); void buttonlight_force_off(void); void buttonlight_ignore_timeout(void); void buttonlight_use_settings(void); -#endif /** * Backlight brightness adjustment settings */ -#ifdef HAVE_BACKLIGHT_BRIGHTNESS void backlight_brightness_set(int brightness); void backlight_brightness_use_setting(void); -#endif -#ifdef HAVE_BUTTONLIGHT_BRIGHTNESS void buttonlight_brightness_set(int brightness); void buttonlight_brightness_use_setting(void); -#endif /* HAVE_BUTTONLIGHT_BRIGHTNESS */ #endif /* _LIB_HELPER_H_ */ diff --git a/apps/plugins/lib/highscore.c b/apps/plugins/lib/highscore.c index 3aae955bfc..04faf27891 100644 --- a/apps/plugins/lib/highscore.c +++ b/apps/plugins/lib/highscore.c @@ -124,11 +124,16 @@ void highscore_show(int position, struct highscore *scores, int num_scores, bool show_level) { int i, w, h; -#ifdef HAVE_LCD_COLOR +#if defined(HAVE_LCD_COLOR) || LCD_DEPTH >= 2 unsigned bgcolor = rb->lcd_get_background(); unsigned fgcolor = rb->lcd_get_foreground(); +#ifdef HAVE_LCD_COLOR rb->lcd_set_background(LCD_BLACK); rb->lcd_set_foreground(LCD_WHITE); +#else + rb->lcd_set_background(LCD_WHITE); + rb->lcd_set_foreground(LCD_BLACK); +#endif #endif rb->lcd_clear_display(); @@ -173,7 +178,7 @@ void highscore_show(int position, struct highscore *scores, int num_scores, rb->button_clear_queue(); rb->button_get(true); rb->lcd_setfont(FONT_SYSFIXED); -#ifdef HAVE_LCD_COLOR +#if defined(HAVE_LCD_COLOR) || LCD_DEPTH >= 2 rb->lcd_set_background(bgcolor); rb->lcd_set_foreground(fgcolor); #endif diff --git a/apps/plugins/lib/id3.c b/apps/plugins/lib/id3.c new file mode 100644 index 0000000000..b0202b1d9c --- /dev/null +++ b/apps/plugins/lib/id3.c @@ -0,0 +1,39 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2023 Christian Soffke + * + * 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" + +/* Fills mp3entry with metadata retrieved from RAM, if possible, or by reading from + * the file directly. Note that the tagcache only stores a subset of metadata and + * will thus not return certain properties of the file, such as frequency, size, or + * codec. + */ +bool retrieve_id3(struct mp3entry *id3, const char* file) +{ +#if defined (HAVE_TAGCACHE) && defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) + if (rb->tagcache_fill_tags(id3, file)) + { + rb->strlcpy(id3->path, file, sizeof(id3->path)); + return true; + } +#endif + + return !rb->mp3info(id3, file); +} diff --git a/apps/plugins/lib/id3.h b/apps/plugins/lib/id3.h new file mode 100644 index 0000000000..6ae1688798 --- /dev/null +++ b/apps/plugins/lib/id3.h @@ -0,0 +1,26 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2023 Christian Soffke + * + * 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. + * + ****************************************************************************/ +#ifndef ID3_H +#define ID3_H + +bool retrieve_id3(struct mp3entry *id3, const char* file); + +#endif /* ID3_H */ diff --git a/apps/plugins/lib/mul_id3.c b/apps/plugins/lib/mul_id3.c new file mode 100644 index 0000000000..edf44f7282 --- /dev/null +++ b/apps/plugins/lib/mul_id3.c @@ -0,0 +1,174 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2023 Christian Soffke + * + * 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" +#include "mul_id3.h" + +struct multiple_tracks_id3 { + unsigned long long filesize; + unsigned long long length; + unsigned long frequency; + unsigned int artist_hash; + unsigned int composer_hash; + unsigned int albumartist_hash; + unsigned int grouping_hash; + unsigned int comment_hash; + unsigned int album_hash; + unsigned int genre_hash; + unsigned int codectype; + unsigned int bitrate; + int year; + bool vbr; +}; + +static struct multiple_tracks_id3 mul_id3; + + +/* Calculate modified FNV hash of string + * has good avalanche behaviour and uniform distribution + * see http://home.comcast.net/~bretm/hash/ */ +static unsigned int mfnv(char *str) +{ + const unsigned int p = 16777619; + unsigned int hash = 0x811C9DC5; // 2166136261; + + if (!str) + return 0; + + while(*str) + hash = (hash ^ *str++) * p; + hash += hash << 13; + hash ^= hash >> 7; + hash += hash << 3; + hash ^= hash >> 17; + hash += hash << 5; + return hash; +} + +static void init_mul_id3(void) +{ + mul_id3.artist_hash = 0; + mul_id3.album_hash = 0; + mul_id3.genre_hash = 0; + mul_id3.composer_hash = 0; + mul_id3.albumartist_hash = 0; + mul_id3.grouping_hash = 0; + mul_id3.comment_hash = 0; + mul_id3.codectype = 0; + mul_id3.vbr = false; + mul_id3.bitrate = 0; + mul_id3.frequency = 0; + mul_id3.length = 0; + mul_id3.filesize = 0; + mul_id3.year = 0; +} + +void collect_id3(struct mp3entry *id3, bool is_first_track) +{ + if (is_first_track) + { + init_mul_id3(); + mul_id3.artist_hash = mfnv(id3->artist); + mul_id3.album_hash = mfnv(id3->album); + mul_id3.genre_hash = mfnv(id3->genre_string); + mul_id3.composer_hash = mfnv(id3->composer); + mul_id3.albumartist_hash = mfnv(id3->albumartist); + mul_id3.grouping_hash = mfnv(id3->grouping); + mul_id3.comment_hash = mfnv(id3->comment); + mul_id3.codectype = id3->codectype; + mul_id3.vbr = id3->vbr; + mul_id3.bitrate = id3->bitrate; + mul_id3.frequency = id3->frequency; + mul_id3.year = id3->year; + } + else + { + if (mul_id3.artist_hash && (mfnv(id3->artist) != mul_id3.artist_hash)) + mul_id3.artist_hash = 0; + if (mul_id3.album_hash && (mfnv(id3->album) != mul_id3.album_hash)) + mul_id3.album_hash = 0; + if (mul_id3.genre_hash && (mfnv(id3->genre_string) != mul_id3.genre_hash)) + mul_id3.genre_hash = 0; + if (mul_id3.composer_hash && (mfnv(id3->composer) != mul_id3.composer_hash)) + mul_id3.composer_hash = 0; + if (mul_id3.albumartist_hash && (mfnv(id3->albumartist) != + mul_id3.albumartist_hash)) + mul_id3.albumartist_hash = 0; + if (mul_id3.grouping_hash && (mfnv(id3->grouping) != mul_id3.grouping_hash)) + mul_id3.grouping_hash = 0; + if (mul_id3.comment_hash && (mfnv(id3->comment) != mul_id3.comment_hash)) + mul_id3.comment_hash = 0; + + if (mul_id3.codectype && (id3->codectype != mul_id3.codectype)) + mul_id3.codectype = AFMT_UNKNOWN; + if (mul_id3.bitrate && (id3->bitrate != mul_id3.bitrate || + id3->vbr != mul_id3.vbr)) + mul_id3.bitrate = 0; + if (mul_id3.frequency && (id3->frequency != mul_id3.frequency)) + mul_id3.frequency = 0; + if (mul_id3.year && (id3->year != mul_id3.year)) + mul_id3.year = 0; + } + mul_id3.length += id3->length; + mul_id3.filesize += id3->filesize; +} + +/* (!) Note scale factor applied to returned metadata: + * - Unit for filesize will be KiB instead of Bytes + * - Unit for length will be s instead of ms + * + * Use result only as input for browse_id3, + * with the track_ct parameter set to > 1. + */ +void finalize_id3(struct mp3entry *id3) +{ + id3->path[0] = '\0'; + id3->title = NULL; + if (!mul_id3.artist_hash) + id3->artist = NULL; + if (!mul_id3.album_hash) + id3->album = NULL; + if (!mul_id3.genre_hash) + id3->genre_string = NULL; + if (!mul_id3.composer_hash) + id3->composer = NULL; + if (!mul_id3.albumartist_hash) + id3->albumartist = NULL; + if (!mul_id3.grouping_hash) + id3->grouping = NULL; + if (!mul_id3.comment_hash) + id3->comment = NULL; + id3->disc_string = NULL; + id3->track_string = NULL; + id3->year_string = NULL; + id3->year = mul_id3.year; + mul_id3.length /= 1000; + mul_id3.filesize >>= 10; + id3->length = mul_id3.length > ULONG_MAX ? 0 : mul_id3.length; + id3->filesize = mul_id3.filesize > INT_MAX ? 0 : mul_id3.filesize; + id3->frequency = mul_id3.frequency; + id3->bitrate = mul_id3.bitrate; + id3->codectype = mul_id3.codectype; + id3->vbr = mul_id3.vbr; + id3->discnum = 0; + id3->tracknum = 0; + id3->track_level = 0; + id3->album_level = 0; +} diff --git a/apps/plugins/lib/mul_id3.h b/apps/plugins/lib/mul_id3.h new file mode 100644 index 0000000000..d08095de5c --- /dev/null +++ b/apps/plugins/lib/mul_id3.h @@ -0,0 +1,27 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2023 Christian Soffke + * + * 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. + * + ****************************************************************************/ +#ifndef MUL_ID3_H +#define MUL_ID3_H + +void collect_id3(struct mp3entry *id3, bool is_first_track); +void finalize_id3(struct mp3entry *id3); + +#endif /* MUL_ID3_H */ diff --git a/apps/plugins/lib/osd.c b/apps/plugins/lib/osd.c index 7d6e10a410..99f77da7dc 100644 --- a/apps/plugins/lib/osd.c +++ b/apps/plugins/lib/osd.c @@ -106,10 +106,10 @@ static struct osd grey_osd; # error Unknown 2-bit format; please define macros # endif /* LCD_PIXELFORMAT */ #elif LCD_DEPTH == 16 -# if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE +# if LCD_STRIDEFORMAT == VERTICAL_STRIDE # define _OSD_HEIGHT2BYTES(h) ((h)*2) # define _OSD_BYTES2HEIGHT(b) ((b)/2) -# else /* !defined(LCD_STRIDEFORMAT) || LCD_STRIDEFORMAT != VERTICAL_STRIDE */ +# else /* LCD_STRIDEFORMAT != VERTICAL_STRIDE */ # define _OSD_WIDTH2BYTES(w) ((w)*2) # define _OSD_BYTES2WIDTH(b) ((b)/2) # endif /* end stride type selection */ @@ -160,7 +160,7 @@ static void * _osd_lcd_init_buffers(struct osd *osd, unsigned flags, rb->viewport_set_fullscreen(&osd->vp, SCREEN_MAIN); -#if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE +#if LCD_STRIDEFORMAT == VERTICAL_STRIDE int colbytes = _OSD_HEIGHT2BYTES(LCD_HEIGHT); int bytecols = *bufsize / colbytes; int w = _OSD_BYTES2WIDTH(bytecols); @@ -193,7 +193,7 @@ static void * _osd_lcd_init_buffers(struct osd *osd, unsigned flags, w = _OSD_BYTES2WIDTH(_OSD_WIDTH2BYTES(w)); osd->lcd_bitmap_stride = _OSD_BYTES2HEIGHT(_OSD_HEIGHT2BYTES(LCD_HEIGHT)); osd->back_bitmap_stride = h; -#else /* !defined(LCD_STRIDEFORMAT) || LCD_STRIDEFORMAT != VERTICAL_STRIDE */ +#else /* LCD_STRIDEFORMAT != VERTICAL_STRIDE */ int rowbytes = _OSD_WIDTH2BYTES(LCD_WIDTH); int byterows = *bufsize / rowbytes; int w = _OSD_BYTES2WIDTH(rowbytes); diff --git a/apps/plugins/lib/overlay.c b/apps/plugins/lib/overlay.c index 0ecc1bf3e7..065273534e 100644 --- a/apps/plugins/lib/overlay.c +++ b/apps/plugins/lib/overlay.c @@ -83,9 +83,8 @@ enum plugin_status run_overlay(const void* parameter, goto error_close; } - - if (hdr->api_version > PLUGIN_API_VERSION - || hdr->api_version < PLUGIN_MIN_API_VERSION) + if (hdr->api_version != PLUGIN_API_VERSION || + p_hdr->api_size > sizeof(struct plugin_api)) { rb->splashf(2*HZ, "%s overlay: Incompatible version.", name); goto error_close; diff --git a/apps/plugins/lib/playback_control.c b/apps/plugins/lib/playback_control.c index 363033b1f2..3e97916400 100644 --- a/apps/plugins/lib/playback_control.c +++ b/apps/plugins/lib/playback_control.c @@ -65,21 +65,21 @@ static bool nexttrack(void) static bool volume(void) { const struct settings_list* vol = - rb->find_setting(&rb->global_settings->volume, NULL); + rb->find_setting(&rb->global_settings->volume); return rb->option_screen((struct settings_list*)vol, parentvp, false, "Volume"); } static bool shuffle(void) { const struct settings_list* shuffle = - rb->find_setting(&rb->global_settings->playlist_shuffle, NULL); + rb->find_setting(&rb->global_settings->playlist_shuffle); return rb->option_screen((struct settings_list*)shuffle, parentvp, false, "Shuffle"); } static bool repeat_mode(void) { const struct settings_list* repeat = - rb->find_setting(&rb->global_settings->repeat_mode, NULL); + rb->find_setting(&rb->global_settings->repeat_mode); int old_repeat = rb->global_settings->repeat_mode; rb->option_screen((struct settings_list*)repeat, parentvp, false, "Repeat"); @@ -91,19 +91,19 @@ static bool repeat_mode(void) return false; } MENUITEM_FUNCTION(prevtrack_item, 0, ID2P(LANG_PREVTRACK), - prevtrack, NULL, NULL, Icon_NOICON); + prevtrack, NULL, Icon_NOICON); MENUITEM_FUNCTION(playpause_item, 0, ID2P(LANG_PLAYPAUSE), - play, NULL, NULL, Icon_NOICON); + play, NULL, Icon_NOICON); MENUITEM_FUNCTION(stop_item, 0, ID2P(LANG_STOP_PLAYBACK), - stop, NULL, NULL, Icon_NOICON); + stop, NULL, Icon_NOICON); MENUITEM_FUNCTION(nexttrack_item, 0, ID2P(LANG_NEXTTRACK), - nexttrack, NULL, NULL, Icon_NOICON); + nexttrack, NULL, Icon_NOICON); MENUITEM_FUNCTION(volume_item, 0, ID2P(LANG_CHANGE_VOLUME), - volume, NULL, NULL, Icon_NOICON); + volume, NULL, Icon_NOICON); MENUITEM_FUNCTION(shuffle_item, 0, ID2P(LANG_CHANGE_SHUFFLE_MODE), - shuffle, NULL, NULL, Icon_NOICON); + shuffle, NULL, Icon_NOICON); MENUITEM_FUNCTION(repeat_mode_item, 0, ID2P(LANG_CHANGE_REPEAT_MODE), - repeat_mode, NULL, NULL, Icon_NOICON); + repeat_mode, NULL, Icon_NOICON); MAKE_MENU(playback_control_menu, ID2P(LANG_PLAYBACK_CONTROL), NULL, Icon_NOICON, &prevtrack_item, &playpause_item, &stop_item, &nexttrack_item, &volume_item, &shuffle_item, &repeat_mode_item); diff --git a/apps/plugins/lib/pluginlib_bmp.c b/apps/plugins/lib/pluginlib_bmp.c index f3edfbf425..82f84b05af 100644 --- a/apps/plugins/lib/pluginlib_bmp.c +++ b/apps/plugins/lib/pluginlib_bmp.c @@ -94,7 +94,7 @@ int save_bmp_file( char* filename, struct bitmap *bm ) */ void simple_resize_bitmap(struct bitmap *src, struct bitmap *dst) { -#if defined(LCD_STRIDEFORMAT) && (LCD_STRIDEFORMAT == VERTICAL_STRIDE) +#if LCD_STRIDEFORMAT == VERTICAL_STRIDE const int srcw = src->height; const int srch = src->width; const int dstw = dst->height; diff --git a/apps/plugins/lib/printcell_helper.c b/apps/plugins/lib/printcell_helper.c index 328f74e318..48b8b2c9d2 100644 --- a/apps/plugins/lib/printcell_helper.c +++ b/apps/plugins/lib/printcell_helper.c @@ -22,10 +22,6 @@ #include "plugin.h" #include "lib/printcell_helper.h" -#ifndef PRINTCELL_MAX_COLUMNS -#define PRINTCELL_MAX_COLUMNS 16 -#endif - #define COLUMN_ENDLEN 3 #define TITLE_FLAG 0xFF #define SELECTED_FLAG 0x1 @@ -37,48 +33,54 @@ #endif struct printcell_info_t { - int offw[NB_SCREENS]; - int iconw[NB_SCREENS]; - int selcol_offw[NB_SCREENS]; - int totalcolw[NB_SCREENS]; - int firstcolxw[NB_SCREENS]; - uint16_t colw[NB_SCREENS][PRINTCELL_MAX_COLUMNS]; - int ncols; - int selcol; - int selcol_index; - char title[PRINTCELL_MAXLINELEN]; - bool separator; + struct gui_synclist *gui_list; /* list to display */ + int offw[NB_SCREENS]; /* padding between column boundries and text */ + int iconw[NB_SCREENS]; /* width of an icon */ + int selcol_offw[NB_SCREENS]; /* offset width calculated for selected item */ + int totalcolw[NB_SCREENS]; /* total width of all columns */ + int firstcolxw[NB_SCREENS]; /* first column x + width, save recalculating */ + int ncols; /* number of columns */ + int selcol; /* selected column (-1 to ncols-1) */ + uint32_t hidecol_flags; /*bits 0-31 set bit to 1 to hide a column (1<<col#) */ + uint16_t colw[NB_SCREENS][PRINTCELL_MAX_COLUMNS]; /* width of title text + or MIN(or user defined width / screen width) */ + char title[PRINTCELL_MAXLINELEN]; /* title buffer */ + char titlesep; /* character that separates title column items (ex '$') */ + char colsep; /* character that separates text column items (ex ',') */ + bool separator; /* draw grid */ }; + static struct printcell_info_t printcell; -static void parse_dsptext(int ncols, const char *dsp_text, char* buffer, uint16_t *sidx) +static void parse_dsptext(char splitchr, int ncols, const char *dsp_text, + char* buffer, size_t bufsz, uint16_t *sidx) { /*Internal function loads sidx with split offsets indexing - the buffer of null terminated strings, splits on '$' + the buffer of null terminated strings, splits on 'splitchr' _assumptions_: dsp_text[len - 1] = \0, - buffer[PRINTCELL_MAXLINELEN], sidx[PRINTCELL_MAX_COLUMNS] */ int i = 0; - int j = 0; - int ch = '$'; /* first column $ is optional */ - if (*dsp_text == '$') + size_t j = 0; + int ch = splitchr; /* first column $ is optional */ + if (*dsp_text == splitchr) dsp_text++; /* add null to the start of the text buffer */ buffer[j++] = '\0'; do { - if (ch == '$') + if (ch == splitchr) { - sidx[i] = j; - if (*dsp_text == '$') /* $$ escaped user must want to display $*/ - buffer[j++] = *dsp_text++; - while (*dsp_text != '\0' && *dsp_text != '$' && j < PRINTCELL_MAXLINELEN - 1) + sidx[i] = j; /* save start index and copy next column to the buffer */ + while (*dsp_text != '\0' && *dsp_text != splitchr && j < (bufsz - 1)) + { buffer[j++] = *dsp_text++; + } buffer[j++] = '\0'; + i++; - if (i >= ncols || j >= (PRINTCELL_MAXLINELEN - 1)) + if (i >= ncols || j >= (bufsz - 1)) break; } ch = *dsp_text++; @@ -146,23 +148,39 @@ static inline void set_cell_width(struct viewport *vp, int max_w, int new_w) static inline int printcells(struct screen *display, char* buffer, uint16_t *sidx, struct line_desc *linedes, struct viewport *vp, int vp_w, int separator, - int x, int y, int offw, int selected_flag, bool scroll) + int x, int y, int offw, int selected_flag, int last_col, + bool scroll, bool is_title) { /* Internal function prints remaining cells */ int text_offset = offw + offw; - int ncols = printcell.ncols; int screen = display->screen_type; int height = linedes->height; int selsep = (selected_flag == 0) ? 0: separator; uint16_t *screencolwidth = printcell.colw[screen]; - for(int i = 1; i < ncols; i++) + for(int i = 1; i <= last_col; i++) { int ny = y; int nw = screencolwidth[i] + text_offset; + int offx = 0; + + if (i == last_col || x + nw >= vp_w - offw + 1) + { /* not enough space for next column use up excess */ + if (nw < (vp_w - x)) + { + if (is_title) + offx = ((vp_w - x) - nw) / 2; + nw = vp_w - x; + } + } + + if (!PRINTCELL_COLUMN_IS_VISIBLE(printcell.hidecol_flags, i)) + nw = 0; + int nx = x + nw; char *buftext; - if (nx > 0 && x < vp_w) + + if (nx > 0 && nw > offw && x < vp_w) { set_cell_width(vp, vp_w, nx); @@ -173,11 +191,15 @@ static inline int printcells(struct screen *display, char* buffer, } else { + if (vp_w < x + text_offset) + { + scroll = false; + } linedes->scroll = scroll; linedes->separator_height = separator; } buftext = &buffer[sidx[i]]; - display->put_line(x + offw, ny, linedes, "$t", buftext); + display->put_line(x + offw + offx, ny, linedes, "$t", buftext); vp->width += COLUMN_ENDLEN + 1; draw_selector(display, linedes, selected_flag, i, separator, x, ny, nw, height); } @@ -192,12 +214,18 @@ static inline int calcvisible(int screen, int vp_w, int text_offset, int sbwidth uint16_t *screencolwidth = printcell.colw[screen]; int screenicnwidth = printcell.iconw[screen]; int offset = 0; - int selcellw = screencolwidth[printcell.selcol] + text_offset; + int selcellw = 0; + if (printcell.selcol >= 0) + selcellw = screencolwidth[printcell.selcol] + text_offset; int maxw = vp_w - (sbwidth + selcellw + 1); for (int i = printcell.selcol - 1; i >= 0; i--) { int cw = screencolwidth[i] + text_offset; + + if (!PRINTCELL_COLUMN_IS_VISIBLE(printcell.hidecol_flags, i)) + cw = 0; + if (i == 0) cw += screenicnwidth; if (offset > 0 || cw > maxw) @@ -234,7 +262,7 @@ static void printcell_listdraw_fn(struct list_putlineinfo_t *list_info) bool show_cursor = list_info->show_cursor; bool have_icons = list_info->have_icons; struct line_desc *linedes = list_info->linedes; - char *dsp_text = list_info->dsp_text; + const char *dsp_text = list_info->dsp_text; struct viewport *vp = list_info->vp; int line = list_info->line; @@ -255,15 +283,30 @@ static void printcell_listdraw_fn(struct list_putlineinfo_t *list_info) separator = 1; int nx = x; + int last_col = printcell.ncols - 1; + int hidden_w = 0; int nw, colxw; - + char *buftext; printcell_buffer[0] = '\0'; - parse_dsptext(printcell.ncols, dsp_text, printcell_buffer, sidx); - char *buftext = &printcell_buffer[sidx[0]]; + uint16_t *screencolwidth = printcell.colw[screen]; + if (printcell.hidecol_flags > 0) + { + for (int i = 0; i < printcell.ncols; i++) + { + if (PRINTCELL_COLUMN_IS_VISIBLE(printcell.hidecol_flags, i)) + last_col = i; + else + hidden_w += (screencolwidth[i] + text_offset); + } + } if (is_title) { + parse_dsptext(printcell.titlesep, printcell.ncols, dsp_text, + printcell_buffer, sizeof(printcell_buffer), sidx); + + buftext = &printcell_buffer[sidx[0]]; /* set to first column text */ int sbwidth = 0; if (rb->global_settings->scrollbar == SCROLLBAR_LEFT) sbwidth = rb->global_settings->scrollbar_width; @@ -276,6 +319,9 @@ static void printcell_listdraw_fn(struct list_putlineinfo_t *list_info) nx -= printcell.selcol_offw[screen]; nw = screencolwidth[0] + printcell.iconw[screen] + text_offset; + + if (!PRINTCELL_COLUMN_IS_VISIBLE(printcell.hidecol_flags, 0)) + nw = printcell.iconw[screen] - 1; nw += sbwidth; colxw = nx + nw; @@ -299,16 +345,21 @@ static void printcell_listdraw_fn(struct list_putlineinfo_t *list_info) } else { + parse_dsptext(printcell.colsep, printcell.ncols, dsp_text, + printcell_buffer, sizeof(printcell_buffer), sidx); + + buftext = &printcell_buffer[sidx[0]]; /* set to first column text */ int cursor = Icon_NOICON; nx -= printcell.selcol_offw[screen]; if (selected_flag & SELECTED_FLAG) { - printcell.selcol_index = sidx[printcell.selcol]; /* save the item offset*/ cursor = Icon_Cursor; /* limit length of selection if columns don't reach end */ int maxw = nx + printcell.totalcolw[screen] + printcell.iconw[screen]; maxw += text_offset * printcell.ncols; + maxw -= hidden_w; + if (vp_w > maxw) vp->width = maxw; /* display a blank line first to draw selector across all cells */ @@ -358,7 +409,7 @@ static void printcell_listdraw_fn(struct list_putlineinfo_t *list_info) nx += nw; /* display remaining cells */ printcells(display, printcell_buffer, sidx, linedes, vp, vp_w, separator, - nx, y, col_offset_width, selected_flag, scroll_items); + nx, y, col_offset_width, selected_flag, last_col, scroll_items, is_title); /* draw a line at the bottom of the list */ if (separator > 0 && line == list->nb_items - 1) @@ -371,14 +422,17 @@ static void printcell_listdraw_fn(struct list_putlineinfo_t *list_info) vp->width = vp_w; } -void printcell_enable(struct gui_synclist *gui_list, bool enable, bool separator) +void printcell_enable(bool enable) { - printcell.separator = separator; + if (!printcell.gui_list) + return; + struct gui_synclist *gui_list = printcell.gui_list; #ifdef HAVE_LCD_COLOR static int list_sep_color = INT_MIN; if (enable) { - list_sep_color = rb->global_settings->list_separator_color; + if (list_sep_color == INT_MIN) + list_sep_color = rb->global_settings->list_separator_color; rb->global_settings->list_separator_color = rb->global_settings->fg_color; gui_list->callback_draw_item = printcell_listdraw_fn; } @@ -398,8 +452,11 @@ void printcell_enable(struct gui_synclist *gui_list, bool enable, bool separator } -int printcell_increment_column(struct gui_synclist *gui_list, int increment, bool wrap) +int printcell_increment_column(int increment, bool wrap) { + if (!printcell.gui_list) + return -1; + struct gui_synclist *gui_list = printcell.gui_list; int item = printcell.selcol + increment; int imin = -1; int imax = printcell.ncols - 1; @@ -419,36 +476,94 @@ int printcell_increment_column(struct gui_synclist *gui_list, int increment, boo FOR_NB_SCREENS(n) /* offset needs recalculated */ printcell.selcol_offw[n] = 0; printcell.selcol = item; - printcell.selcol_index = 0; + rb->gui_synclist_draw(gui_list); + rb->gui_synclist_speak_item(gui_list); } return item; } +int printcell_get_column_selected(void) +{ + if (!printcell.gui_list) + return -1; + return printcell.selcol; +} + +uint32_t printcell_get_column_visibility(int col) +{ + if (col >= 0) + return (PRINTCELL_COLUMN_IS_VISIBLE(printcell.hidecol_flags, col) ? 0:1); + else /* return flag of all columns */ + return printcell.hidecol_flags; +} + +void printcell_set_column_visible(int col, bool visible) +{ + /* visible columns have 0 for the column bit hidden columns have the bit set */ + if (col >= 0) + { + if (visible) + printcell.hidecol_flags &= ~(PRINTCELL_COLUMN_FLAG(col)); + else + printcell.hidecol_flags |= PRINTCELL_COLUMN_FLAG(col); + } + else + { + if (visible) /* set to everything visible */ + printcell.hidecol_flags = 0; + else /* set to everything hidden */ + printcell.hidecol_flags = ((uint32_t)-1); + } +} + int printcell_set_columns(struct gui_synclist *gui_list, - char * title, enum themable_icons icon) + struct printcell_settings * pcs, + char * title, enum themable_icons icon) { + if (title == NULL) title = "$PRINTCELL NOT SETUP"; + + if (pcs == NULL) /* DEFAULTS */ + { +#if LCD_DEPTH > 1 + /* If line sep is set to automatic then outline cells */ + bool sep = (rb->global_settings->list_separator_height < 0); +#else + bool sep = (rb->global_settings->cursor_style == 0); +#endif + pcs = &(struct printcell_settings){ .cell_separator = sep, + .title_delimeter = '$', + .text_delimeter = '$', + .hidecol_flags = 0}; + } + uint16_t sidx[PRINTCELL_MAX_COLUMNS]; /* starting position of column in title string */ int width, height, user_minwidth; int i = 0; - int j = 0; - int ch = '$'; /* first column $ is optional */ - + size_t j = 0; rb->memset(&printcell, 0, sizeof(struct printcell_info_t)); + printcell.gui_list = gui_list; + printcell.separator = pcs->cell_separator; + printcell.titlesep = pcs->title_delimeter; + printcell.colsep = pcs->text_delimeter; + printcell.hidecol_flags = pcs->hidecol_flags; + + int ch = printcell.titlesep; /* first column $ is optional */ + FOR_NB_SCREENS(n) { rb->screens[n]->getstringsize("W", &width, &height); printcell.offw[n] = width; /* set column text offset */ } - if (*title == '$') + if (*title == printcell.titlesep) title++; do { - if (ch == '$') + if (ch == printcell.titlesep) { printcell.title[j++] = ch; user_minwidth = 0; @@ -460,7 +575,7 @@ int printcell_set_columns(struct gui_synclist *gui_list, user_minwidth = 10*user_minwidth + *title - '0'; title++; } - if (*title != '$') /* user forgot $ or wants to display '*' */ + if (*title != printcell.titlesep) /* user forgot titlesep or wants to display '*' */ { title = dspst; user_minwidth = 0; @@ -470,17 +585,25 @@ int printcell_set_columns(struct gui_synclist *gui_list, } sidx[i] = j; - if (*title == '$') /* $$ escaped user must want to display $*/ - printcell.title[j++] = *title++; - while (*title != '\0' && *title != '$' && j < PRINTCELL_MAXLINELEN - 1) + while (*title != '\0' + && *title != printcell.titlesep + && j < PRINTCELL_MAXLINELEN - 1) + { printcell.title[j++] = *title++; + } FOR_NB_SCREENS(n) { - rb->screens[n]->getstringsize(&printcell.title[sidx[i]], &width, &height); + rb->screens[n]->getstringsize(&printcell.title[sidx[i]], + &width, &height); + if (width < user_minwidth) width = user_minwidth; + + if (width > LCD_WIDTH) + width = LCD_WIDTH; + printcell.colw[n][i] = width; printcell.totalcolw[n] += width; } @@ -492,37 +615,67 @@ int printcell_set_columns(struct gui_synclist *gui_list, printcell.ncols = i; printcell.title[j] = '\0'; printcell.selcol = -1; - printcell.selcol_index = 0; rb->gui_synclist_set_title(gui_list, printcell.title, icon); return printcell.ncols; } -char *printcell_get_selected_column_text(struct gui_synclist *gui_list, char *buf, size_t bufsz) +char *printcell_get_title_text(int selcol, char *buf, size_t bufsz) { - int selected = gui_list->selected_item; - int index = printcell.selcol_index - 1; + /* note offsets are calculated everytime this function is called + * shouldn't be used in hot code paths */ + int index = 0; + buf[0] = '\0'; + if (selcol < 0) /* return entire string incld col formatting '$'*/ + return printcell.title; + + if (selcol < printcell.ncols) + { + uint16_t sidx[PRINTCELL_MAX_COLUMNS]; /*indexes zero terminated strings in buffer*/ + parse_dsptext(printcell.titlesep, selcol + 1, printcell.title, buf, bufsz, sidx); + index = sidx[selcol]; + } + return &buf[index]; +} - if (index < 0) - index = 0; +char *printcell_get_column_text(int selcol, char *buf, size_t bufsz) +{ + int index = 0; char *bpos; + struct gui_synclist *gui_list = printcell.gui_list; - if (gui_list->callback_get_item_name(selected, gui_list->data, buf, bufsz) == buf) + if (gui_list && gui_list->callback_draw_item == printcell_listdraw_fn) { - bpos = &buf[index]; - if (printcell.selcol < 0) /* return entire string incld col formatting '$'*/ - return bpos; - while(bpos < &buf[bufsz - 1]) + int col = selcol; + int item = gui_list->selected_item; + void *data = gui_list->data; + + if (col < printcell.ncols + && gui_list->callback_get_item_name(item, data, buf, bufsz) == buf) { - if (*bpos == '$' || *bpos == '\0') - goto success; - bpos++; + bpos = buf; + if (col < 0) /* return entire string incld col formatting '$'*/ + { + return bpos; + } + bpos++; /* Skip sep/NULL */ + + while(bpos < &buf[bufsz - 1]) + { + if (*bpos == printcell.colsep || *bpos == '\0') + { + if (col-- == 0) + goto success; + index = bpos - buf + 1; /* Skip sep/NULL */ + } + bpos++; + } } } /*failure*/ - bpos = buf; - index = 0; + bpos = buf; + index = 0; success: - *bpos = '\0'; - return &buf[index]; + *bpos = '\0'; + return &buf[index]; } diff --git a/apps/plugins/lib/printcell_helper.h b/apps/plugins/lib/printcell_helper.h index adc98e5a5f..f58e73c0a5 100644 --- a/apps/plugins/lib/printcell_helper.h +++ b/apps/plugins/lib/printcell_helper.h @@ -21,25 +21,67 @@ #ifndef _PRINTCELL_LIST_H_ #define _PRINTCELL_LIST_H_ +#ifndef PRINTCELL_MAX_COLUMNS +#define PRINTCELL_MAX_COLUMNS 16 /* Max 32 (hidecol_flags)*/ +#endif + #define PRINTCELL_MAXLINELEN MAX_PATH +#define PC_COL_FLAG(col) ((uint32_t)(col >= 0 \ + && col < PRINTCELL_MAX_COLUMNS) ? 1u<<col : -1u) + +#define PRINTCELL_COLUMN_IS_VISIBLE(flag, col) ((flag & PC_COL_FLAG(col)) == 0) +#define PRINTCELL_COLUMN_FLAG(col) (PC_COL_FLAG(col)) -/* sets the printcell function enabled */ -void printcell_enable(struct gui_synclist *gui_list, bool enable, bool separator); +struct printcell_settings +{ + bool cell_separator; + char title_delimeter; + char text_delimeter; + uint32_t hidecol_flags; +}; -/* sets title and calculates cell widths each column is identified by '$' character - ex 3 columns title = "Col1$Col2$Col3" also accepts $*WIDTH$ - ex 3 columns varying width title = "$*64$Col1$*128$Col2$Col3 - returns number of columns +/* Printcell initialization - Sets title and calculates cell widths +* by default each column is identified by '$' character +* ex 3 columns title = "Col1$Col2$Col3" also accepts $*WIDTH$ +* ex 3 columns varying width title = "$*64$Col1$*128$Col2$Col3 +* supplying struct printcell_settings pcs allows changing default settings +* supply NULL to use defaults +* +* Returns number of columns */ -int printcell_set_columns(struct gui_synclist *gui_list, - char * title, enum themable_icons icon); +int printcell_set_columns(struct gui_synclist *gui_list, + struct printcell_settings * pcs, + char * title, enum themable_icons icon); + +/* Sets the printcell function enabled (use after initializing with set_column) + * Note you should call printcell_enable(false) if the list might be reused */ +void printcell_enable(bool enable); -/* increments the current selected column negative increment is allowed - returns the selected column +/* Increments the current selected column negative increment is allowed + returns the selected column range: -1(no selection) to ncols - 1 */ -int printcell_increment_column(struct gui_synclist *gui_list, int increment, bool wrap); +int printcell_increment_column(int increment, bool wrap); + +/* Return index of the currently selected column (-1 to ncols - 1) */ +int printcell_get_column_selected(void); + +/* Return the text of currently selected column buffer should be sized + * for max item len, buf[PRINTCELL_MAXLINELEN] is a safe bet */ +char *printcell_get_column_text(int selcol, char *buf, size_t bufsz); -/* return the text of currently selected column buffer should be sized +/* Return the text of currently selected column title should be sized * for max item len, buf[PRINTCELL_MAXLINELEN] is a safe bet */ -char *printcell_get_selected_column_text(struct gui_synclist *gui_list, char *buf, size_t bufsz); +char *printcell_get_title_text(int selcol, char *buf, size_t bufsz); + + +/* Hide or show a specified column - supply col = -1 to affect all columns */ +void printcell_set_column_visible(int col, bool visible); + +/* Return visibility of a specified column +* returns (1 visible or 0 hidden) +* if supply col == -1 a flag with visibility of all columns will be returned +* NOTE: flag denotes a hidden column by a 1 in the column bit (1 << col#) +* PRINTCELL_COLUMN_IS_VISIBLE(flag,col) macro will convert to bool +*/ +uint32_t printcell_get_column_visibility(int col); #endif /*_PRINTCELL_LIST_H_*/ diff --git a/apps/plugins/lib/wrappers.h b/apps/plugins/lib/wrappers.h index b6fbd51a39..761854fa05 100644 --- a/apps/plugins/lib/wrappers.h +++ b/apps/plugins/lib/wrappers.h @@ -53,6 +53,7 @@ #define strlen rb->strlen #define strlcpy rb->strlcpy #define strrchr rb->strrchr +#define fix_path_part rb->fix_path_part #endif diff --git a/apps/plugins/lib/xlcd_scroll.c b/apps/plugins/lib/xlcd_scroll.c index 5ac4a366e8..906f4eaae1 100644 --- a/apps/plugins/lib/xlcd_scroll.c +++ b/apps/plugins/lib/xlcd_scroll.c @@ -30,7 +30,7 @@ static const unsigned short patterns[4] = {0xFFFF, 0xFF00, 0x00FF, 0x0000}; #endif -#if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE +#if LCD_STRIDEFORMAT == VERTICAL_STRIDE void xlcd_scroll_left(int count) { /*size_t dst_stride;*/ @@ -668,4 +668,4 @@ void xlcd_scroll_down(int count) } #endif /* LCD_PIXELFORMAT, LCD_DEPTH */ -#endif /* defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE */ +#endif /* LCD_STRIDEFORMAT == VERTICAL_STRIDE */ diff --git a/apps/plugins/logo.c b/apps/plugins/logo.c index 984a65aa34..9df73a9d0b 100644 --- a/apps/plugins/logo.c +++ b/apps/plugins/logo.c @@ -49,15 +49,27 @@ static const struct button_mapping *plugin_contexts[] /* We use PLA */ #define LP_QUIT PLA_EXIT -#define LP_QUIT2 PLA_CANCEL #define LP_DEC_X PLA_LEFT #define LP_DEC_X_REPEAT PLA_LEFT_REPEAT #define LP_INC_X PLA_RIGHT #define LP_INC_X_REPEAT PLA_RIGHT_REPEAT + +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define LP_QUIT2 PLA_UP +#define LP_DEC_Y PLA_SCROLL_BACK +#define LP_DEC_Y_REPEAT PLA_SCROLL_BACK_REPEAT +#define LP_INC_Y PLA_SCROLL_FWD +#define LP_INC_Y_REPEAT PLA_SCROLL_FWD_REPEAT +#else +#define LP_QUIT2 PLA_CANCEL #define LP_DEC_Y PLA_DOWN #define LP_DEC_Y_REPEAT PLA_DOWN_REPEAT #define LP_INC_Y PLA_UP #define LP_INC_Y_REPEAT PLA_UP_REPEAT +#endif + enum plugin_status plugin_start(const void* parameter) { int button; diff --git a/apps/plugins/lrcplayer.c b/apps/plugins/lrcplayer.c index f42b96b5b3..de31733671 100644 --- a/apps/plugins/lrcplayer.c +++ b/apps/plugins/lrcplayer.c @@ -643,22 +643,6 @@ static void init_time_tag(void) * /ddd.lrc */ -/* taken from apps/recorder/albumart.c */ -static void fix_filename(char* name) -{ - static const char invalid_chars[] = "*/:<>?\\|"; - - while (1) - { - if (*name == 0) - return; - if (*name == '"') - *name = '\''; - else if (rb->strchr(invalid_chars, *name)) - *name = '_'; - name++; - } -} static bool find_lrc_file_helper(const char *base_dir) { char fname[MAX_PATH]; @@ -678,7 +662,7 @@ static bool find_lrc_file_helper(const char *base_dir) if (current.id3->title && rb->strcmp(names[0], current.id3->title)) { rb->strlcpy(fname, current.id3->title, sizeof(fname)); - fix_filename(fname); + rb->fix_path_part(fname, 0, sizeof(fname) - 1); names[1] = fname; } @@ -2078,8 +2062,7 @@ static int timetag_editor(void) while (!exit) { button = rb->get_action(CONTEXT_TREE, TIMEOUT_BLOCK); - if (rb->gui_synclist_do_button(&gui_editor, &button, - LIST_WRAP_UNLESS_HELD)) + if (rb->gui_synclist_do_button(&gui_editor, &button)) continue; switch (button) @@ -2437,7 +2420,6 @@ static bool lrc_debug_menu(void) { struct simplelist_info info; rb->simplelist_info_init(&info, "Debug Menu", 6, NULL); - info.hide_selection = true; info.scroll_all = true; info.get_name = lrc_debug_data; return rb->simplelist_show_list(&info); @@ -2643,16 +2625,10 @@ static int handle_button(void) ff_rewind(0, false); break; case ACTION_WPS_VOLDOWN: - limit = rb->sound_min(SOUND_VOLUME); - if (--rb->global_settings->volume < limit) - rb->global_settings->volume = limit; - rb->sound_set(SOUND_VOLUME, rb->global_settings->volume); + rb->adjust_volume(-1); break; case ACTION_WPS_VOLUP: - limit = rb->sound_max(SOUND_VOLUME); - if (++rb->global_settings->volume > limit) - rb->global_settings->volume = limit; - rb->sound_set(SOUND_VOLUME, rb->global_settings->volume); + rb->adjust_volume(1); break; case ACTION_WPS_CONTEXT: ret = LRC_GOTO_EDITOR; diff --git a/apps/plugins/lua/rocklib.c b/apps/plugins/lua/rocklib.c index cadc8be6ac..8efaaab169 100644 --- a/apps/plugins/lua/rocklib.c +++ b/apps/plugins/lua/rocklib.c @@ -930,12 +930,6 @@ RB_WRAP(restart_lua) return -1; } -RB_WRAP(show_logo) -{ - rb->show_logo(); - return 0; -} - RB_WRAP(mem_stats) { /* used, allocd, free = rb.mem_stats() */ @@ -1032,7 +1026,6 @@ static const luaL_Reg rocklib[] = /* MISC */ RB_FUNC(restart_lua), - RB_FUNC(show_logo), RB_FUNC(mem_stats), {NULL, NULL} diff --git a/apps/plugins/lua/rocklib_events.c b/apps/plugins/lua/rocklib_events.c index 1c13a6758f..52e87f3d61 100644 --- a/apps/plugins/lua/rocklib_events.c +++ b/apps/plugins/lua/rocklib_events.c @@ -253,7 +253,9 @@ static int lua_rev_callback(lua_State *L, struct cb_data *evt) lua_pushlightuserdata(L, evt->data); lua_status = lua_resume(L, 2); /* call the saved function */ - if (lua_status == LUA_YIELD) /* coroutine.yield() disallowed */ + if (lua_status == LUA_SUCCESS) + lua_settop(L, 0); /* eat any value(s) returned */ + else if (lua_status == LUA_YIELD) /* coroutine.yield() disallowed */ luaL_where(L, 1); /* push error string on stack */ return lua_status; @@ -421,7 +423,7 @@ static void init_event_thread(bool init, struct event_data *ev_data) 0, EVENT_THREAD IF_PRIO(, PRIORITY_SYSTEM) - IF_COP(, COP)); + IF_COP(, CPU)); /* Timer is used to poll waiting events */ if (!rb->timer_register(1, NULL, EV_TIMER_FREQ, rev_timer_isr IF_COP(, CPU))) diff --git a/apps/plugins/lua/rocklib_img.c b/apps/plugins/lua/rocklib_img.c index b0ca769ca4..68e5325ce0 100644 --- a/apps/plugins/lua/rocklib_img.c +++ b/apps/plugins/lua/rocklib_img.c @@ -380,7 +380,7 @@ static inline fb_data* rli_get_element(struct rocklua_image* img, int x, int y) pixel_to_native(x, y, &x, &y); -#if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE +#if LCD_STRIDEFORMAT == VERTICAL_STRIDE /* column major address */ size_t data_address = (stride * (x - 1)) + (y - 1); diff --git a/apps/plugins/main_menu_config.c b/apps/plugins/main_menu_config.c index 9f651094b1..a5488ed2c0 100644 --- a/apps/plugins/main_menu_config.c +++ b/apps/plugins/main_menu_config.c @@ -188,7 +188,7 @@ enum plugin_status plugin_start(const void* parameter) { cur_sel = rb->gui_synclist_get_sel_pos(&list); action = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK); - if (rb->gui_synclist_do_button(&list,&action,LIST_WRAP_UNLESS_HELD)) + if (rb->gui_synclist_do_button(&list, &action)) continue; switch (action) diff --git a/apps/plugins/matrix.c b/apps/plugins/matrix.c index 1b2f6d465a..6e96aae10c 100644 --- a/apps/plugins/matrix.c +++ b/apps/plugins/matrix.c @@ -52,6 +52,14 @@ /* this set the context to use with PLA */ static const struct button_mapping *plugin_contexts[] = { pla_main_ctx }; +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define MATRIX_EXIT2 PLA_UP +#else +#define MATRIX_EXIT2 PLA_CANCEL +#endif + #ifdef HAVE_SCROLLWHEEL #define MATRIX_SLEEP_MORE PLA_SCROLL_BACK #define MATRIX_SLEEP_MORE_REPEAT PLA_SCROLL_BACK_REPEAT @@ -65,7 +73,6 @@ static const struct button_mapping *plugin_contexts[] = { pla_main_ctx }; #endif /* HAVE_SCROLLWHEEL */ #define MATRIX_PAUSE PLA_SELECT #define MATRIX_EXIT PLA_EXIT -#define MATRIX_EXIT2 PLA_CANCEL #define SLEEP HZ/50 diff --git a/apps/plugins/maze.c b/apps/plugins/maze.c index 20d5c82495..ebb83ab15c 100644 --- a/apps/plugins/maze.c +++ b/apps/plugins/maze.c @@ -37,11 +37,14 @@ /* key assignments */ -#if (CONFIG_KEYPAD == IPOD_3G_PAD) +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) # define MAZE_NEW (BUTTON_SELECT | BUTTON_REPEAT) # define MAZE_NEW_PRE BUTTON_SELECT # define MAZE_QUIT BUTTON_MENU -# define MAZE_SOLVE (BUTTON_SELECT | BUTTON_PLAY) +# define MAZE_SOLVE (BUTTON_SELECT | BUTTON_REL) +# define MAZE_SOLVE_PRE BUTTON_SELECT # define MAZE_RIGHT BUTTON_RIGHT # define MAZE_RIGHT_REPEAT BUTTON_RIGHT|BUTTON_REPEAT # define MAZE_LEFT BUTTON_LEFT @@ -491,17 +494,15 @@ static void maze_move_player_left(struct maze* maze) enum plugin_status plugin_start(const void* parameter) { int button; -#ifdef MAZE_NEW_PRE +#if defined(MAZE_NEW_PRE) || defined(MAZE_SOLVE_PRE) int lastbutton = BUTTON_NONE; #endif int quit = 0; struct maze maze; (void)parameter; -#ifdef HAVE_BACKLIGHT /* Turn off backlight timeout */ backlight_ignore_timeout(); -#endif /* Seed the RNG */ rb->srand(*rb->current_tick); @@ -546,6 +547,10 @@ enum plugin_status plugin_start(const void* parameter) maze_draw(&maze, rb->screens[i]); break; case MAZE_SOLVE: +#ifdef MAZE_SOLVE_PRE + if(lastbutton != MAZE_SOLVE_PRE) + break; +#endif maze_solve(&maze); FOR_NB_SCREENS(i) maze_draw(&maze, rb->screens[i]); @@ -585,14 +590,13 @@ enum plugin_status plugin_start(const void* parameter) } break; } -#ifdef MAZE_NEW_PRE +#if defined(MAZE_NEW_PRE) || defined(MAZE_SOLVE_PRE) if( button != BUTTON_NONE ) lastbutton = button; #endif } /* Turn on backlight timeout (revert to settings) */ -#ifdef HAVE_BACKLIGHT backlight_use_settings(); -#endif + return ((quit == 1) ? PLUGIN_OK : PLUGIN_USB_CONNECTED); } diff --git a/apps/plugins/mazezam.c b/apps/plugins/mazezam.c index cd7b6e22a8..1183f8f502 100644 --- a/apps/plugins/mazezam.c +++ b/apps/plugins/mazezam.c @@ -27,7 +27,9 @@ /* Include standard plugin macro */ -#if (CONFIG_KEYPAD == IPOD_3G_PAD) +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) # define MAZEZAM_MENU BUTTON_MENU # define MAZEZAM_RIGHT BUTTON_RIGHT # define MAZEZAM_LEFT BUTTON_LEFT @@ -256,9 +258,7 @@ static void store_lcd_settings(void) ******************************************************************************/ static void restore_lcd_settings(void) { /* Turn on backlight timeout (revert to settings) */ -#ifdef HAVE_BACKLIGHT backlight_use_settings(); -#endif /* Restore the old settings */ #if LCD_DEPTH > 1 @@ -272,10 +272,9 @@ static void restore_lcd_settings(void) { * Adjust the LCD settings to suit MazezaM levels ******************************************************************************/ static void plugin_lcd_settings(void) { -#ifdef HAVE_BACKLIGHT /* Turn off backlight timeout */ backlight_ignore_timeout(); -#endif + /* Set the new settings */ #ifdef HAVE_LCD_COLOR rb->lcd_set_background(MAZEZAM_BG_COLOR); diff --git a/apps/plugins/metronome.c b/apps/plugins/metronome.c index 157d116ff9..9d61c067fd 100644 --- a/apps/plugins/metronome.c +++ b/apps/plugins/metronome.c @@ -82,7 +82,13 @@ enum metronome_errors #define MET_SYNC #endif +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define METRONOME_QUIT PLA_UP +#else #define METRONOME_QUIT PLA_EXIT +#endif #ifdef HAVE_SCROLLWHEEL #define METRONOME_VOL_UP PLA_SCROLL_FWD diff --git a/apps/plugins/mikmod/mikmod.c b/apps/plugins/mikmod/mikmod.c index 6622b5fdb6..65633c0ad1 100644 --- a/apps/plugins/mikmod/mikmod.c +++ b/apps/plugins/mikmod/mikmod.c @@ -710,7 +710,6 @@ static void mm_errorhandler(void) static int playfile(char* filename) { - int vol = 0; int button; int retval = PLUGIN_OK; bool changingpos = false; @@ -789,13 +788,8 @@ static int playfile(char* filename) } break; } - vol = rb->global_settings->volume; - if (vol < rb->sound_max(SOUND_VOLUME)) - { - vol++; - rb->sound_set(SOUND_VOLUME, vol); - rb->global_settings->volume = vol; - } + + rb->adjust_volume(1); break; case ACTION_WPS_VOLDOWN: @@ -808,13 +802,8 @@ static int playfile(char* filename) } break; } - vol = rb->global_settings->volume; - if (vol > rb->sound_min(SOUND_VOLUME)) - { - vol--; - rb->sound_set(SOUND_VOLUME, vol); - rb->global_settings->volume = vol; - } + + rb->adjust_volume(-1); break; case ACTION_WPS_SKIPPREV: diff --git a/apps/plugins/mosaique.c b/apps/plugins/mosaique.c index caf5346dc5..cf3f42521a 100644 --- a/apps/plugins/mosaique.c +++ b/apps/plugins/mosaique.c @@ -37,10 +37,17 @@ static const struct button_mapping *plugin_contexts[] = { pla_main_ctx }; #define MOSAIQUE_QUIT PLA_EXIT -#define MOSAIQUE_QUIT2 PLA_CANCEL -#define MOSAIQUE_SPEED PLA_UP +#define MOSAIQUE_SPEED PLA_RIGHT #define MOSAIQUE_RESTART PLA_SELECT +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define MOSAIQUE_QUIT2 PLA_UP +#else +#define MOSAIQUE_QUIT2 PLA_CANCEL +#endif + enum plugin_status plugin_start(const void* parameter) { int button; diff --git a/apps/plugins/mpegplayer/libmpeg2/idct_arm.S b/apps/plugins/mpegplayer/libmpeg2/idct_arm.S index 97a87a8b59..90eb5031c7 100644 --- a/apps/plugins/mpegplayer/libmpeg2/idct_arm.S +++ b/apps/plugins/mpegplayer/libmpeg2/idct_arm.S @@ -43,8 +43,8 @@ ldrsh r7, [r0, #12] /* d2 */ ldrsh r8, [r0, #14] /* d3 */ orrs r9, r2, r3 - orreqs r9, r4, r5 - orreqs r9, r6, r7 + orrseq r9, r4, r5 + orrseq r9, r6, r7 cmpeq r8, #0 bne 2f mov r1, r1, asl #15 @@ -320,7 +320,7 @@ mpeg2_idct_copy: mpeg2_idct_add: cmp r0, #129 mov r0, r1 - ldreqsh r1, [r0, #0] + ldrsheq r1, [r0, #0] bne 1f and r1, r1, #0x70 cmp r1, #0x40 diff --git a/apps/plugins/mpegplayer/libmpeg2/idct_armv6.S b/apps/plugins/mpegplayer/libmpeg2/idct_armv6.S index dc53cbd7bd..a259721410 100644 --- a/apps/plugins/mpegplayer/libmpeg2/idct_armv6.S +++ b/apps/plugins/mpegplayer/libmpeg2/idct_armv6.S @@ -19,6 +19,7 @@ * ****************************************************************************/ +#include "config.h" .global mpeg2_idct_copy .type mpeg2_idct_copy, %function @@ -228,7 +229,7 @@ mpeg2_idct_copy: mpeg2_idct_add: cmp r0, #129 mov r0, r1 - ldreqsh r1, [r0, #0] + ldrsheq r1, [r0, #0] bne 1f and r1, r1, #0x70 cmp r1, #0x40 @@ -260,7 +261,7 @@ mpeg2_idct_add: strd r4, [r1] @ r4, r5 add r1, r1, r2 cmp r0, r3 - ldrlod r8, [r1] @ r8, r9 + ldrdlo r8, [r1] @ r8, r9 blo 2b ldmfd sp!, {r4-r11, pc} @@ -291,7 +292,7 @@ mpeg2_idct_add: strd r0, [r2] @ r0, r1 add r2, r2, r3 cmp r2, r12 - ldrlod r0, [r2] @ r0, r1 + ldrdlo r0, [r2] @ r0, r1 blo 4b ldmfd sp!, {r4, pc} diff --git a/apps/plugins/mpegplayer/mpeg_misc.h b/apps/plugins/mpegplayer/mpeg_misc.h index e04db0e19d..233b815493 100644 --- a/apps/plugins/mpegplayer/mpeg_misc.h +++ b/apps/plugins/mpegplayer/mpeg_misc.h @@ -53,12 +53,14 @@ enum state_enum #define CMP_3_CONST(_a, _b) \ ({ int _x; \ asm volatile ( \ + BEGIN_ARM_ASM_SYNTAX_UNIFIED \ "ldrb %[x], [%[a], #0] \n" \ "eors %[x], %[x], %[b0] \n" \ - "ldreqb %[x], [%[a], #1] \n" \ - "eoreqs %[x], %[x], %[b1] \n" \ - "ldreqb %[x], [%[a], #2] \n" \ - "eoreqs %[x], %[x], %[b2] \n" \ + "ldrbeq %[x], [%[a], #1] \n" \ + "eorseq %[x], %[x], %[b1] \n" \ + "ldrbeq %[x], [%[a], #2] \n" \ + "eorseq %[x], %[x], %[b2] \n" \ + END_ARM_ASM_SYNTAX_UNIFIED \ : [x]"=&r"(_x) \ : [a]"r"(_a), \ [b0]"i"(((_b) >> 24) & 0xff), \ @@ -70,14 +72,16 @@ enum state_enum #define CMP_4_CONST(_a, _b) \ ({ int _x; \ asm volatile ( \ + BEGIN_ARM_ASM_SYNTAX_UNIFIED \ "ldrb %[x], [%[a], #0] \n" \ "eors %[x], %[x], %[b0] \n" \ - "ldreqb %[x], [%[a], #1] \n" \ - "eoreqs %[x], %[x], %[b1] \n" \ - "ldreqb %[x], [%[a], #2] \n" \ - "eoreqs %[x], %[x], %[b2] \n" \ - "ldreqb %[x], [%[a], #3] \n" \ - "eoreqs %[x], %[x], %[b3] \n" \ + "ldrbeq %[x], [%[a], #1] \n" \ + "eorseq %[x], %[x], %[b1] \n" \ + "ldrbeq %[x], [%[a], #2] \n" \ + "eorseq %[x], %[x], %[b2] \n" \ + "ldrbeq %[x], [%[a], #3] \n" \ + "eorseq %[x], %[x], %[b3] \n" \ + END_ARM_ASM_SYNTAX_UNIFIED \ : [x]"=&r"(_x) \ : [a]"r"(_a), \ [b0]"i"(((_b) >> 24) & 0xff), \ diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c index e66b4df146..654a348959 100644 --- a/apps/plugins/mpegplayer/mpegplayer.c +++ b/apps/plugins/mpegplayer/mpegplayer.c @@ -1215,10 +1215,9 @@ static void osd_lcd_enable_hook(unsigned short id, void* param) static void osdbacklight_hw_on_video_mode(bool video_on) { if (video_on) { -#ifdef HAVE_BACKLIGHT /* Turn off backlight timeout */ backlight_ignore_timeout(); -#endif + #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) rb->remove_event(LCD_EVENT_ACTIVATION, osd_lcd_enable_hook); #endif @@ -1226,10 +1225,8 @@ static void osdbacklight_hw_on_video_mode(bool video_on) #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) rb->add_event(LCD_EVENT_ACTIVATION, osd_lcd_enable_hook); #endif -#ifdef HAVE_BACKLIGHT /* Revert to user's backlight settings */ backlight_use_settings(); -#endif } } diff --git a/apps/plugins/open_plugins.c b/apps/plugins/open_plugins.c index 3a0c34d8d6..b608aff789 100644 --- a/apps/plugins/open_plugins.c +++ b/apps/plugins/open_plugins.c @@ -87,14 +87,23 @@ static size_t pathbasename(const char *name, const char **nameptr) *nameptr = q; return r - q; } +static int op_entry_checksum(void) +{ + if (op_entry.checksum != open_plugin_csum + + (op_entry.lang_id <= OPEN_PLUGIN_LANG_INVALID ? 0 : LANG_LAST_INDEX_IN_ARRAY)) + { + return 0; + } + return 1; +} static bool op_entry_read(int fd, int selected_item, off_t data_sz) { rb->memset(&op_entry, 0, op_entry_sz); op_entry.lang_id = -1; - return ((selected_item >= 0) && + return ((selected_item >= 0) && (fd >= 0) && (rb->lseek(fd, selected_item * op_entry_sz, SEEK_SET) >= 0) && - (rb->read(fd, &op_entry, data_sz) == data_sz)); + (rb->read(fd, &op_entry, data_sz) == data_sz) && op_entry_checksum() > 0); } static bool op_entry_read_name(int fd, int selected_item) @@ -102,15 +111,6 @@ static bool op_entry_read_name(int fd, int selected_item) return op_entry_read(fd, selected_item, op_name_sz); } -static int op_entry_checksum(void) -{ - if (op_entry.checksum != open_plugin_csum) - { - return 0; - } - return 1; -} - static int op_entry_read_opx(const char *path) { int ret = -1; @@ -174,7 +174,8 @@ failure: static void op_entry_set_checksum(void) { - op_entry.checksum = open_plugin_csum; + op_entry.checksum = open_plugin_csum + + (op_entry.lang_id <= OPEN_PLUGIN_LANG_INVALID ? 0 : LANG_LAST_INDEX_IN_ARRAY); } static void op_entry_set_name(void) @@ -188,17 +189,20 @@ static void op_entry_set_name(void) static int op_entry_set_path(void) { int ret = 0; - struct browse_context browse; char tmp_buf[OPEN_PLUGIN_BUFSZ+1]; if (op_entry.path[0] == '\0') rb->strcpy(op_entry.path, PLUGIN_DIR"/"); - rb->browse_context_init(&browse, SHOW_ALL, BROWSE_SELECTONLY, rb->str(LANG_ADD), - Icon_Plugin, op_entry.path, NULL); - - browse.buf = tmp_buf; - browse.bufsize = OPEN_PLUGIN_BUFSZ; + struct browse_context browse = { + .dirfilter = SHOW_ALL, + .flags = BROWSE_SELECTONLY | BROWSE_DIRFILTER, + .title = rb->str(LANG_ADD), + .icon = Icon_Plugin, + .root = op_entry.path, + .buf = tmp_buf, + .bufsize = sizeof(tmp_buf), + }; if (rb->rockbox_browse(&browse) == GO_TO_PREVIOUS) { @@ -212,7 +216,6 @@ static int op_entry_set_path(void) static int op_entry_set_param_path(void) { int ret = 0; - struct browse_context browse; char tmp_buf[OPEN_PLUGIN_BUFSZ+1]; if (op_entry.param[0] == '\0') @@ -220,11 +223,15 @@ static int op_entry_set_param_path(void) else rb->strcpy(tmp_buf, op_entry.param); - rb->browse_context_init(&browse, SHOW_ALL, BROWSE_SELECTONLY, "", - Icon_Plugin, tmp_buf, NULL); - - browse.buf = tmp_buf; - browse.bufsize = OPEN_PLUGIN_BUFSZ; + struct browse_context browse = { + .dirfilter = SHOW_ALL, + .flags = BROWSE_SELECTONLY | BROWSE_DIRFILTER, + .title = rb->str(LANG_PARAMETER), + .icon = Icon_Plugin, + .root = tmp_buf, + .buf = tmp_buf, + .bufsize = sizeof(tmp_buf), + }; if (rb->rockbox_browse(&browse) == GO_TO_PREVIOUS) { @@ -405,6 +412,7 @@ static uint32_t op_entry_add_path(const char *key, const char *plugin, const cha { rb->close(fd_tmp); rb->close(fd_dat); + fd_dat = -1; rb->remove(OPEN_PLUGIN_DAT); rb->rename(OPEN_PLUGIN_DAT ".tmp", OPEN_PLUGIN_DAT); } @@ -461,12 +469,12 @@ static void op_entry_remove(int selection) static void op_entry_remove_empty(void) { bool resave = false; - if (fd_dat && rb->lseek(fd_dat, 0, SEEK_SET) == 0) + if (fd_dat >= 0 && rb->lseek(fd_dat, 0, SEEK_SET) == 0) { while (resave == false && rb->read(fd_dat, &op_entry, op_entry_sz) == op_entry_sz) { - if (op_entry.hash == 0) + if (op_entry.hash == 0 || !op_entry_checksum()) resave = true; } } @@ -482,6 +490,7 @@ static void op_entry_remove_empty(void) { rb->close(fd_tmp); rb->close(fd_dat); + fd_dat = -1; rb->remove(OPEN_PLUGIN_DAT); rb->rename(OPEN_PLUGIN_DAT ".tmp", OPEN_PLUGIN_DAT); } @@ -623,7 +632,6 @@ static void synclist_set(char* menu_id, int selection, int items, int sel_size) rb->gui_synclist_set_icon_callback(&lists,NULL); rb->gui_synclist_set_voice_callback(&lists, list_voice_cb); rb->gui_synclist_set_nb_items(&lists,items); - rb->gui_synclist_limit_scroll(&lists,true); rb->gui_synclist_select_item(&lists, selection); list_voice_cb(selection, menu_id); } @@ -682,7 +690,7 @@ static void edit_menu(int selection) { action = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK); - if (rb->gui_synclist_do_button(&lists,&action,LIST_WRAP_UNLESS_HELD)) + if (rb->gui_synclist_do_button(&lists, &action)) continue; selected_item = rb->gui_synclist_get_sel_pos(&lists); switch (action) @@ -840,6 +848,12 @@ reopen_datfile: }/* OP_EXT */ } + for (int i = items - 1; i > 0 && !exit; i--) + { + if (!op_entry_read(fd_dat, i, op_entry_sz)) + items--; + } + if (items < 1 && !exit) { char* cur_filename = rb->plugin_get_current_filename(); @@ -865,7 +879,7 @@ reopen_datfile: { action = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK); - if (rb->gui_synclist_do_button(&lists,&action,LIST_WRAP_UNLESS_HELD)) + if (rb->gui_synclist_do_button(&lists, &action)) continue; selection = rb->gui_synclist_get_sel_pos(&lists); switch (action) @@ -892,6 +906,7 @@ reopen_datfile: } break; case ACTION_STD_CANCEL: + case ACTION_STD_MENU: { selection = -2; exit = true; diff --git a/apps/plugins/oscilloscope.c b/apps/plugins/oscilloscope.c index ae84e14f7f..00d03fb03e 100644 --- a/apps/plugins/oscilloscope.c +++ b/apps/plugins/oscilloscope.c @@ -47,12 +47,14 @@ #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) -#define OSCILLOSCOPE_QUIT (BUTTON_SELECT | BUTTON_MENU) -#define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_PLAY) +#define OSCILLOSCOPE_QUIT BUTTON_MENU +#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_SELECT +#define OSCILLOSCOPE_GRAPHMODE (BUTTON_SELECT | BUTTON_REL) +#define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_SELECT +#define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_REPEAT) #define OSCILLOSCOPE_ADVMODE (BUTTON_SELECT | BUTTON_RIGHT) #define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_LEFT) -#define OSCILLOSCOPE_GRAPHMODE BUTTON_MENU -#define OSCILLOSCOPE_PAUSE BUTTON_PLAY +#define OSCILLOSCOPE_PAUSE BUTTON_PLAY | BUTTON_REL #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT #define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_FWD @@ -1939,10 +1941,9 @@ static void osc_cleanup(void) rb->lcd_set_foreground(LCD_DEFAULT_FG); rb->lcd_set_background(LCD_DEFAULT_BG); #endif -#ifdef HAVE_BACKLIGHT + /* Turn on backlight timeout (revert to settings) */ backlight_use_settings(); -#endif /* save settings if changed */ if (rb->memcmp(&osc, &osc_disk, sizeof(osc))) @@ -1975,10 +1976,9 @@ static void osc_setup(void) mixer_sampr = rb->mixer_get_frequency(); #endif -#ifdef HAVE_BACKLIGHT /* Turn off backlight timeout */ backlight_ignore_timeout(); -#endif + graphmode_setup(); } diff --git a/apps/plugins/otp.c b/apps/plugins/otp.c index 4d302563fb..356e1e5eb6 100644 --- a/apps/plugins/otp.c +++ b/apps/plugins/otp.c @@ -208,17 +208,16 @@ static int base32_encode(const uint8_t *data, int length, uint8_t *result, static bool browse( char *dst, int dst_size, const char *start ) { - struct browse_context browse; - - rb->browse_context_init(&browse, SHOW_ALL, - BROWSE_SELECTONLY|BROWSE_NO_CONTEXT_MENU, - NULL, NOICON, start, NULL); - - browse.buf = dst; - browse.bufsize = dst_size; + struct browse_context browse = { + .dirfilter = SHOW_ALL, + .flags = BROWSE_SELECTONLY | BROWSE_NO_CONTEXT_MENU, + .icon = Icon_NOICON, + .root = start, + .buf = dst, + .bufsize = dst_size, + }; rb->rockbox_browse(&browse); - return (browse.flags & BROWSE_SELECTED); } diff --git a/apps/plugins/pacbox/pacbox.c b/apps/plugins/pacbox/pacbox.c index 71c9751cad..9434aed743 100755 --- a/apps/plugins/pacbox/pacbox.c +++ b/apps/plugins/pacbox/pacbox.c @@ -809,8 +809,8 @@ enum plugin_status plugin_start(const void* parameter) #ifdef HAVE_ADJUSTABLE_CPU_FREQ rb->cpu_boost(false); #endif -#ifdef HAVE_BACKLIGHT + backlight_use_settings(); -#endif + return PLUGIN_OK; } diff --git a/apps/plugins/pdbox/PDa/src/m_obj.c b/apps/plugins/pdbox/PDa/src/m_obj.c index d06caa12fd..8d4947f202 100644 --- a/apps/plugins/pdbox/PDa/src/m_obj.c +++ b/apps/plugins/pdbox/PDa/src/m_obj.c @@ -272,6 +272,9 @@ static int outlet_eventno; recursion */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Warray-bounds" +#if __GNUC__ >= 13 +#pragma GCC diagnostic ignored "-Wdangling-pointer" +#endif void outlet_setstacklim(void) { char c; diff --git a/apps/plugins/pdbox/pdbox.c b/apps/plugins/pdbox/pdbox.c index f21913788b..08236bfeba 100644 --- a/apps/plugins/pdbox/pdbox.c +++ b/apps/plugins/pdbox/pdbox.c @@ -229,7 +229,7 @@ enum plugin_status plugin_start(const void* parameter) 0, /* FIXME Which flags? */ "PD core" IF_PRIO(, PRIORITY_REALTIME) - IF_COP(, COP)); + IF_COP(, CPU)); gui_thread_id = rb->create_thread(&gui_thread, diff --git a/apps/plugins/pegbox.c b/apps/plugins/pegbox.c index cb6361547d..8b88aad052 100644 --- a/apps/plugins/pegbox.c +++ b/apps/plugins/pegbox.c @@ -65,7 +65,7 @@ (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) #define PEGBOX_SELECT (BUTTON_SELECT|BUTTON_RIGHT) -#define PEGBOX_QUIT (BUTTON_SELECT|BUTTON_PLAY) +#define PEGBOX_QUIT (BUTTON_SELECT|BUTTON_REPEAT) #define PEGBOX_RESTART (BUTTON_SELECT|BUTTON_LEFT) #define PEGBOX_LVL_UP (BUTTON_SELECT|BUTTON_MENU) #define PEGBOX_UP BUTTON_MENU @@ -74,7 +74,7 @@ #define PEGBOX_LEFT BUTTON_LEFT #define SELECT_TEXT "SELECT+RIGHT" -#define QUIT_TEXT "SELECT+PLAY" +#define QUIT_TEXT "Long SELECT" #define RESTART_TEXT "SELECT+LEFT" #define LVL_UP_TEXT "SELECT+MENU" #define LVL_DOWN_TEXT "-" diff --git a/apps/plugins/periodic_table.c b/apps/plugins/periodic_table.c index b77dd07432..2dd84baacd 100644 --- a/apps/plugins/periodic_table.c +++ b/apps/plugins/periodic_table.c @@ -619,7 +619,6 @@ enum plugin_status plugin_start(const void* parameter) switch (button) { case PERIODIC_KEY_SELECT: - break; case PERIODIC_KEY_MENU: return PLUGIN_OK; break; diff --git a/apps/plugins/pictureflow/pictureflow.c b/apps/plugins/pictureflow/pictureflow.c index a2782b6a2b..b21faf1dd8 100644 --- a/apps/plugins/pictureflow/pictureflow.c +++ b/apps/plugins/pictureflow/pictureflow.c @@ -33,6 +33,7 @@ #include "lib/grey.h" #include "lib/mylcd.h" #include "lib/feature_wrappers.h" +#include "lib/id3.h" /******************************* Globals ***********************************/ static fb_data *lcd_fb; @@ -44,6 +45,7 @@ static fb_data *lcd_fb; #if PF_PLAYBACK_CAPABLE #include "lib/playback_control.h" +#include "lib/mul_id3.h" #endif #define PF_PREV ACTION_STD_PREV @@ -151,8 +153,12 @@ const struct button_mapping pf_context_buttons[] = {PF_QUIT, BUTTON_POWER, BUTTON_NONE}, #elif (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ || (CONFIG_KEYPAD == IPOD_3G_PAD) \ - || (CONFIG_KEYPAD == IPOD_4G_PAD) \ - || (CONFIG_KEYPAD == MPIO_HD300_PAD) + || (CONFIG_KEYPAD == IPOD_4G_PAD) + {PF_MENU, BUTTON_MENU|BUTTON_REPEAT, BUTTON_MENU}, + {PF_QUIT, BUTTON_MENU|BUTTON_REL, BUTTON_MENU}, + {PF_SORTING_NEXT, BUTTON_SELECT|BUTTON_MENU, BUTTON_NONE}, + {PF_SORTING_PREV, BUTTON_SELECT|BUTTON_PLAY, BUTTON_NONE}, +#elif CONFIG_KEYPAD == MPIO_HD300_PAD {PF_QUIT, BUTTON_MENU|BUTTON_REPEAT, BUTTON_MENU}, #elif CONFIG_KEYPAD == IAUDIO_M3_PAD {PF_QUIT, BUTTON_RC_REC, BUTTON_NONE}, @@ -268,7 +274,6 @@ typedef fb_data pix_t; /* some magic numbers for cache_version. */ #define CACHE_REBUILD 0 -#define CACHE_UPDATE 1 /* Error return values */ #define SUCCESS 0 @@ -306,6 +311,8 @@ struct pf_config_t bool resize; bool show_fps; + + bool update_albumart; }; struct pf_index_t { @@ -511,6 +518,7 @@ static struct configdata config[] = { TYPE_ENUM, 0, 2, { .int_p = &pf_cfg.year_sort_order }, "year order", year_sort_order_conf }, { TYPE_BOOL, 0, 1, { .bool_p = &pf_cfg.show_year }, "show year", NULL }, + { TYPE_BOOL, 0, 1, { .bool_p = &pf_cfg.update_albumart }, "update albumart", NULL } }; #define CONFIG_NUM_ITEMS (sizeof(config) / sizeof(struct configdata)) @@ -532,6 +540,7 @@ static PFreal offsetX; static PFreal offsetY; static int number_of_slides; static bool is_initial_slide = true; +static bool show_tracks_while_browsing = false; static struct pf_slide_cache pf_sldcache; @@ -552,6 +561,8 @@ static struct pf_index_t pf_idx; static struct pf_track_t pf_tracks; +static struct mp3entry id3; + void reset_track_list(void); static bool thread_is_running; @@ -624,7 +635,7 @@ static inline void buf_ctx_unlock(void) buf_ctx_locked = false; } -static bool check_database(bool prompt) +static bool check_database(void) { bool needwarn = true; int spin = 5; @@ -642,9 +653,7 @@ static bool check_database(bool prompt) needwarn = false; rb->splash(0, ID2P(LANG_TAGCACHE_BUSY)); } - else if (!prompt) - return false; - else if (rb->action_userabort(HZ/5)) + else return false; rb->yield(); @@ -667,9 +676,10 @@ static bool confirm_quit(void) return true; } -static void config_save(int cache_version) +static void config_save(int cache_version, bool update_albumart) { pf_cfg.cache_version = cache_version; + pf_cfg.update_albumart = update_albumart; configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); } @@ -684,12 +694,13 @@ static void config_set_defaults(struct pf_config_t *cfg) cfg->last_album = 0; cfg->backlight_mode = 0; cfg->resize = true; - cfg->cache_version = 0; + cfg->cache_version = CACHE_REBUILD; cfg->show_album_name = (LCD_HEIGHT > 100) - ? ALBUM_NAME_TOP : ALBUM_NAME_BOTTOM; + ? ALBUM_AND_ARTIST_BOTTOM : ALBUM_NAME_BOTTOM; cfg->sort_albums_by = SORT_BY_ARTIST_AND_NAME; cfg->year_sort_order = ASCENDING; cfg->show_year = false; + cfg->update_albumart = false; } static inline PFreal fmul(PFreal a, PFreal b) @@ -959,6 +970,7 @@ const struct custom_format format_transposed = { static const struct button_mapping* get_context_map(int context) { + context &= ~CONTEXT_LOCKED; return pf_contexts[context & ~CONTEXT_PLUGIN]; } @@ -1923,17 +1935,10 @@ static int pf_tcs_retrieve_track_title(int string_index, int disc_num, int track if (rb->strcmp(UNTAGGED, tcs.result) == 0) { /* show filename instead of <untaggged> */ - if (!rb->tagcache_retrieve(&tcs, tcs.idx_id, tag_filename, + if (!rb->tagcache_retrieve(&tcs, tcs.idx_id, tag_virt_basename, file_name, MAX_PATH)) return 0; track_title = file_name; - if (track_title) - { - /* if filename remove the '/' */ - track_title = rb->strrchr(track_title, PATH_SEPCH); - if (track_title) - track_title++; - } } if (!track_title) @@ -2067,15 +2072,11 @@ static inline void free_borrowed_tracks(void) static bool get_albumart_for_index_from_db(const int slide_index, char *buf, int buflen) { - if ( slide_index == -1 ) - { - rb->strlcpy( buf, EMPTY_SLIDE, buflen ); - } + bool ret; if (tcs.valid || !rb->tagcache_search(&tcs, tag_filename)) return false; - bool result; /* find the first track of the album */ rb->tagcache_search_add_filter(&tcs, tag_album, pf_idx.album_index[slide_index].seek); @@ -2083,36 +2084,12 @@ static bool get_albumart_for_index_from_db(const int slide_index, char *buf, rb->tagcache_search_add_filter(&tcs, tag_albumartist, pf_idx.album_index[slide_index].artist_seek); - if ( rb->tagcache_get_next(&tcs) ) { - struct mp3entry id3; - int fd; + ret = rb->tagcache_get_next(&tcs) && + retrieve_id3(&id3, tcs.result) && + search_albumart_files(&id3, ":", buf, buflen); -#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) - if (rb->tagcache_fill_tags(&id3, tcs.result)) - { - rb->strlcpy(id3.path, tcs.result, sizeof(id3.path)); - } - else -#endif - { - fd = rb->open(tcs.result, O_RDONLY); - if (fd) { - rb->get_metadata(&id3, fd, tcs.result); - rb->close(fd); - } - } - - if ( search_albumart_files(&id3, ":", buf, buflen) ) - result = true; - else - result = false; - } - else { - /* did not find a matching track */ - result = false; - } rb->tagcache_search_finish(&tcs); - return result; + return ret; } /** @@ -2209,6 +2186,9 @@ static unsigned int mfnv(char *str) const unsigned int p = 16777619; unsigned int hash = 0x811C9DC5; // 2166136261; + if (!str) + return 0; + while(*str) hash = (hash ^ *str++) * p; hash += hash << 13; @@ -2250,8 +2230,6 @@ static bool incremental_albumart_cache(bool verbose) unsigned int hash_artist, hash_album; unsigned int format = FORMAT_NATIVE; - bool update = (pf_cfg.cache_version == CACHE_UPDATE); - if (pf_cfg.resize) format |= FORMAT_RESIZE|FORMAT_KEEP_ASPECT; @@ -2263,8 +2241,6 @@ static bool incremental_albumart_cache(bool verbose) aa_cache.inspected++; if (aa_cache.idx >= pf_idx.album_ct) { aa_cache.idx = 0; } /* Rollover */ - if (!get_albumart_for_index_from_db(idx, aa_cache.file, sizeof(aa_cache.file))) - goto aa_failure; //rb->strcpy(aa_cache.file, EMPTY_SLIDE_BMP); hash_artist = mfnv(get_album_artist(idx)); hash_album = mfnv(get_album_name(idx)); @@ -2272,13 +2248,15 @@ static bool incremental_albumart_cache(bool verbose) rb->snprintf(aa_cache.pfraw_file, sizeof(aa_cache.pfraw_file), CACHE_PREFIX "/%x%x.pfraw", hash_album, hash_artist); - if(rb->file_exists(aa_cache.pfraw_file)) { - if(update) { - aa_cache.slides++; - goto aa_success; - } + if(pf_cfg.update_albumart && rb->file_exists(aa_cache.pfraw_file)) { + aa_cache.slides++; + goto aa_success; } + if (!get_albumart_for_index_from_db(idx, aa_cache.file, sizeof(aa_cache.file))) + goto aa_failure; //rb->strcpy(aa_cache.file, EMPTY_SLIDE_BMP); + + aa_cache.input_bmp.data = aa_cache.buf; aa_cache.input_bmp.width = DISPLAY_WIDTH; aa_cache.input_bmp.height = DISPLAY_HEIGHT; @@ -2316,6 +2294,8 @@ aa_success: configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); free_all_slide_prio(0); + if (pf_state == pf_idle) + rb->queue_post(&thread_q, EV_WAKEUP, 0); } if(verbose)/* direct interaction with user */ @@ -3096,7 +3076,7 @@ static void render_slide(struct slide_data *slide, const int alpha) const pix_t *ptr = &src[column * bmp->height]; -#if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE +#if LCD_STRIDEFORMAT == VERTICAL_STRIDE #define PIXELSTEP_Y 1 #define LCDADDR(x, y) (&buffer[BUFFER_HEIGHT*(x) + (y)]) #else @@ -3169,19 +3149,19 @@ static inline void set_current_slide(const int slide_index) { int old_center_index = center_index; step = 0; - center_index = fbound(slide_index, 0, number_of_slides - 1); + center_index = fbound(0, slide_index, number_of_slides - 1); if (old_center_index != center_index) { rb->queue_remove_from_head(&thread_q, EV_WAKEUP); rb->queue_post(&thread_q, EV_WAKEUP, 0); } target = center_index; - slide_frame = slide_index << 16; + slide_frame = center_index << 16; reset_slides(); } -static void interrupt_cover_out_animation(void); +static void skip_animation_to_idle_state(void); static bool sort_albums(int new_sorting, bool from_settings) { int i, album_idx, artist_idx; @@ -3215,7 +3195,7 @@ static bool sort_albums(int new_sorting, bool from_settings) if (pf_state == pf_show_tracks || pf_state == pf_cover_in || pf_state == pf_cover_out) - interrupt_cover_out_animation(); + skip_animation_to_idle_state(); else if (pf_state == pf_scrolling) set_current_slide(target); pf_state = pf_idle; @@ -3225,6 +3205,12 @@ static bool sort_albums(int new_sorting, bool from_settings) { #ifdef USEGSLIB grey_show(false); +#if LCD_DEPTH > 1 + rb->lcd_set_background(N_BRIGHT(0)); + rb->lcd_set_foreground(N_BRIGHT(255)); +#endif + rb->lcd_clear_display(); + rb->lcd_update(); #endif rb->splash(HZ, sort_options[pf_cfg.sort_albums_by]); #ifdef USEGSLIB @@ -3255,7 +3241,10 @@ static bool sort_albums(int new_sorting, bool from_settings) if(!rb->strcmp(pf_idx.album_names + album_idx, current_album_name) && !rb->strcmp(pf_idx.artist_names + artist_idx, current_album_artist)) + { set_current_slide(i); + pf_cfg.last_album = i; + } } return true; } @@ -3269,6 +3258,8 @@ static void start_animation(void) pf_state = pf_scrolling; } +static void update_scroll_animation(void); + /** Go to the previous slide */ @@ -3282,6 +3273,8 @@ static void show_previous_slide(void) } else if ( step > 0 ) { target = center_index; step = (target <= center_slide.slide_index) ? -1 : 1; + if (step < 0) + update_scroll_animation(); } else { target = fmax(0, center_index - 2); } @@ -3301,6 +3294,8 @@ static void show_next_slide(void) } else if ( step < 0 ) { target = center_index; step = (target < center_slide.slide_index) ? -1 : 1; + if (step > 0) + update_scroll_animation(); } else { target = fmin(center_index + 2, number_of_slides - 1); } @@ -3477,16 +3472,29 @@ static void cleanup(void) rb->cpu_boost(false); #endif end_pf_thread(); -#ifdef HAVE_BACKLIGHT + /* Turn on backlight timeout (revert to settings) */ backlight_use_settings(); -#endif #ifdef USEGSLIB grey_release(); #endif } +static void skip_animation_to_show_tracks(void); +static void adjust_album_display_for_setting(int old_val, int new_val) +{ + if (old_val == new_val) + return; + + reset_track_list(); + recalc_offsets(); + reset_slides(); + + if (pf_state == pf_show_tracks) + skip_animation_to_show_tracks(); +} + /** Shows the settings menu */ @@ -3542,11 +3550,10 @@ static int settings_menu(void) selection=rb->do_menu(&settings_menu,&selection, NULL, false); switch(selection) { case 0: + old_val = pf_cfg.show_album_name; rb->set_option(rb->str(LANG_SHOW_ALBUM_TITLE), &pf_cfg.show_album_name, INT, album_name_options, 5, NULL); - reset_track_list(); - recalc_offsets(); - reset_slides(); + adjust_album_display_for_setting(old_val, pf_cfg.show_album_name); break; case 1: rb->set_bool(rb->str(LANG_SHOW_YEAR_IN_ALBUM_TITLE), &pf_cfg.show_year); @@ -3568,38 +3575,40 @@ static int settings_menu(void) pf_cfg.year_sort_order = old_val; break; case 4: + old_val = pf_cfg.show_fps; rb->set_bool(rb->str(LANG_DISPLAY_FPS), &pf_cfg.show_fps); - reset_track_list(); + if (old_val != pf_cfg.show_fps) + reset_track_list(); break; case 5: + old_val = pf_cfg.slide_spacing; rb->set_int(rb->str(LANG_SPACING), "", 1, &pf_cfg.slide_spacing, NULL, 1, 0, 100, NULL ); - recalc_offsets(); - reset_slides(); + adjust_album_display_for_setting(old_val, pf_cfg.slide_spacing); break; case 6: + old_val = pf_cfg.center_margin; rb->set_int(rb->str(LANG_CENTRE_MARGIN), "", 1, &pf_cfg.center_margin, NULL, 1, 0, 80, NULL ); - recalc_offsets(); - reset_slides(); + adjust_album_display_for_setting(old_val, pf_cfg.center_margin); break; case 7: + old_val = pf_cfg.num_slides; rb->set_int(rb->str(LANG_NUMBER_OF_SLIDES), "", 1, &pf_cfg.num_slides, NULL, 1, 1, MAX_SLIDES_COUNT, NULL ); - recalc_offsets(); - reset_slides(); + adjust_album_display_for_setting(old_val, pf_cfg.num_slides); break; case 8: + old_val = pf_cfg.zoom; rb->set_int(rb->str(LANG_ZOOM), "", 1, &pf_cfg.zoom, NULL, 1, 10, 300, NULL ); - recalc_offsets(); - reset_slides(); + adjust_album_display_for_setting(old_val, pf_cfg.zoom); break; case 9: @@ -3609,6 +3618,7 @@ static int settings_menu(void) break; /* fallthrough if changed, since cache needs to be rebuilt */ case 10: + pf_cfg.update_albumart = false; pf_cfg.cache_version = CACHE_REBUILD; rb->remove(EMPTY_SLIDE); configfile_save(CONFIG_FILE, config, @@ -3616,7 +3626,8 @@ static int settings_menu(void) rb->splash(HZ, ID2P(LANG_CACHE_REBUILT_NEXT_RESTART)); break; case 11: - pf_cfg.cache_version = CACHE_UPDATE; + pf_cfg.update_albumart = true; + pf_cfg.cache_version = CACHE_REBUILD; rb->remove(EMPTY_SLIDE); configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); @@ -3642,45 +3653,67 @@ static int settings_menu(void) Show the main menu */ enum { + PF_SHOW_TRACKS_WHILE_BROWSING, + PF_GOTO_LAST_ALBUM, PF_GOTO_WPS, #if PF_PLAYBACK_CAPABLE - PF_MENU_CLEAR_PLAYLIST, PF_MENU_PLAYBACK_CONTROL, #endif PF_MENU_SETTINGS, - PF_MENU_RETURN, PF_MENU_QUIT, }; static int main_menu(void) { int selection = 0; - int result; + int result, curr_album; #if LCD_DEPTH > 1 rb->lcd_set_foreground(N_BRIGHT(255)); #endif MENUITEM_STRINGLIST(main_menu, "PictureFlow Main Menu", NULL, + ID2P(LANG_SHOW_TRACKS_WHILE_BROWSING), + ID2P(LANG_GOTO_LAST_ALBUM), ID2P(LANG_GOTO_WPS), #if PF_PLAYBACK_CAPABLE - ID2P(LANG_CLEAR_PLAYLIST), ID2P(LANG_PLAYBACK_CONTROL), #endif ID2P(LANG_SETTINGS), - ID2P(LANG_RETURN), ID2P(LANG_MENU_QUIT)); while (1) { switch (rb->do_menu(&main_menu,&selection, NULL, false)) { + case PF_SHOW_TRACKS_WHILE_BROWSING: + if (pf_state != pf_show_tracks) + { + if (pf_state == pf_scrolling) + set_current_slide(target); + + skip_animation_to_show_tracks(); + } + show_tracks_while_browsing = true; + return 0; + case PF_GOTO_LAST_ALBUM: + if (pf_state == pf_scrolling) + curr_album = target; + else + curr_album = center_index; + + if (pf_state == pf_show_tracks) + free_borrowed_tracks(); + if (pf_state == pf_show_tracks || + pf_state == pf_cover_in || + pf_state == pf_cover_out) + skip_animation_to_idle_state(); + + set_current_slide(pf_cfg.last_album); + pf_cfg.last_album = curr_album; + + pf_state = pf_idle; + return 0; case PF_GOTO_WPS: /* WPS */ return -2; #if PF_PLAYBACK_CAPABLE - case PF_MENU_CLEAR_PLAYLIST: - if(rb->warn_on_pl_erase() && rb->playlist_remove_all_tracks(NULL) == 0) { - rb->playlist_create(NULL, NULL); - rb->splash(HZ*2, ID2P(LANG_PLAYLIST_CLEARED)); - } - break; case PF_MENU_PLAYBACK_CONTROL: /* Playback Control */ playback_control(NULL); break; @@ -3689,8 +3722,6 @@ static int main_menu(void) result = settings_menu(); if ( result != 0 ) return result; break; - case PF_MENU_RETURN: - return 0; case PF_MENU_QUIT: return -1; @@ -3703,21 +3734,33 @@ static int main_menu(void) } } +#define ZOOMIN_FRAME_COUNT 19 +#define ZOOMIN_FRAME_DIST -5 +#define ZOOMIN_FRAME_ANGLE 1 +#define ZOOMIN_FRAME_FADE 13 + +#define ROTATE_FRAME_COUNT 15 +#define ROTATE_FRAME_ANGLE 16 + +#define KEYFRAME_COUNT ZOOMIN_FRAME_COUNT + ROTATE_FRAME_COUNT + /** Animation step for zooming into the current cover */ static void update_cover_in_animation(void) { cover_animation_keyframe++; - if( cover_animation_keyframe < 20 ) { - center_slide.distance-=5; - center_slide.angle+=1; - extra_fade += 13; - } - else if( cover_animation_keyframe < 35 ) { - center_slide.angle+=16; + + if(cover_animation_keyframe <= ZOOMIN_FRAME_COUNT) + { + center_slide.distance += ZOOMIN_FRAME_DIST; + center_slide.angle += ZOOMIN_FRAME_ANGLE; + extra_fade += ZOOMIN_FRAME_FADE; } - else { + else if(cover_animation_keyframe <= KEYFRAME_COUNT) + center_slide.angle += ROTATE_FRAME_ANGLE; + else + { cover_animation_keyframe = 0; pf_state = pf_show_tracks; } @@ -3729,36 +3772,40 @@ static void update_cover_in_animation(void) static void update_cover_out_animation(void) { cover_animation_keyframe++; - if( cover_animation_keyframe <= 15 ) { - center_slide.angle-=16; - } - else if( cover_animation_keyframe < 35 ) { - center_slide.distance+=5; - center_slide.angle-=1; - extra_fade -= 13; + + if(cover_animation_keyframe <= ROTATE_FRAME_COUNT) + center_slide.angle -= ROTATE_FRAME_ANGLE; + else if(cover_animation_keyframe <= KEYFRAME_COUNT) + { + center_slide.distance -= ZOOMIN_FRAME_DIST; + center_slide.angle -= ZOOMIN_FRAME_ANGLE; + extra_fade -= ZOOMIN_FRAME_FADE; } - else { + else + { cover_animation_keyframe = 0; pf_state = pf_idle; } } /** - Skip steps for zooming into the current cover + Immediately show tracks and skip any animation frames */ -static void interrupt_cover_in_animation(void) +static void skip_animation_to_show_tracks(void) { pf_state = pf_show_tracks; cover_animation_keyframe = 0; - extra_fade = 13 * 19; - center_slide.distance = -5 * 19; - center_slide.angle = 19 + (15 * 16); + + extra_fade = ZOOMIN_FRAME_COUNT * ZOOMIN_FRAME_FADE; + center_slide.distance = ZOOMIN_FRAME_COUNT * ZOOMIN_FRAME_DIST; + center_slide.angle = (ZOOMIN_FRAME_COUNT * ZOOMIN_FRAME_ANGLE) + + (ROTATE_FRAME_COUNT * ROTATE_FRAME_ANGLE); } /** - Skip steps for zooming out the current cover + Immediately transition to idle state and skip any animation frames */ -static void interrupt_cover_out_animation(void) +static void skip_animation_to_idle_state(void) { pf_state = pf_idle; cover_animation_keyframe = 0; @@ -3767,21 +3814,12 @@ static void interrupt_cover_out_animation(void) } /** - Stop zooming out the current cover and start zooming in + Change direction during cover in/out animation */ -static void revert_cover_out_animation(void) +static void reverse_animation(void) { - pf_state = pf_cover_in; - cover_animation_keyframe = 34 - cover_animation_keyframe; -} - -/** - Stop zooming into the current cover and start zooming out -*/ -static void revert_cover_in_animation(void) -{ - pf_state = pf_cover_out; - cover_animation_keyframe = 34 - cover_animation_keyframe; + pf_state = pf_state == pf_cover_out ? pf_cover_in : pf_cover_out; + cover_animation_keyframe = KEYFRAME_COUNT - cover_animation_keyframe; } /** @@ -3888,7 +3926,10 @@ static void show_track_list(void) { mylcd_clear_display(); if ( center_slide.slide_index != pf_tracks.cur_idx ) { - show_track_list_loading(); +#ifdef HAVE_TC_RAMCACHE + if (!rb->tagcache_is_in_ram()) +#endif + show_track_list_loading(); create_track_index(center_slide.slide_index); if (pf_tracks.count == 0) { @@ -3909,7 +3950,7 @@ static void show_track_list(void) for (; track_i < pf_tracks.list_visible + pf_tracks.list_start; track_i++) { char *trackname = get_track_name(track_i); - if ( track_i == pf_tracks.sel ) { + if (track_i == pf_tracks.sel && !show_tracks_while_browsing) { if (pf_tracks.sel != pf_tracks.last_sel) { set_scroll_line(trackname, PF_SCROLL_TRACK); pf_tracks.last_sel = pf_tracks.sel; @@ -3961,7 +4002,7 @@ static void select_next_album(void) free_borrowed_tracks(); target = center_index + 1; set_current_slide(target); - interrupt_cover_in_animation(); + skip_animation_to_show_tracks(); } } @@ -3971,13 +4012,50 @@ static void select_prev_album(void) free_borrowed_tracks(); target = center_index - 1; set_current_slide(target); - interrupt_cover_in_animation(); + skip_animation_to_show_tracks(); } } #if PF_PLAYBACK_CAPABLE +static int show_id3_info(const char *selected_file) +{ + int i; + unsigned long last_tick; + const char *file_name; + bool is_multiple_tracks = insert_whole_album && pf_tracks.count > 1; + + last_tick = *(rb->current_tick) + HZ/2; + rb->splash_progress_set_delay(HZ / 2); /* wait 1/2 sec before progress */ + i = 0; + do { + file_name = i == 0 ? selected_file : get_track_filename(i); + if (rb->mp3info(&id3, file_name)) + return 0; -static bool playlist_insert(int position, bool queue, bool create_new) + if (is_multiple_tracks) + { + rb->splash_progress(i, pf_tracks.count, + "%s (%s)", rb->str(LANG_WAIT), rb->str(LANG_OFF_ABORT)); + if (TIME_AFTER(*(rb->current_tick), last_tick + HZ/4)) + { + if (rb->action_userabort(TIMEOUT_NOBLOCK)) + return 0; + last_tick = *(rb->current_tick); + } + + collect_id3(&id3, i == 0); + rb->yield(); + } + } while (++i < pf_tracks.count && is_multiple_tracks); + + if (is_multiple_tracks) + finalize_id3(&id3); + + return rb->browse_id3(&id3, 0, 0, NULL, i) ? PLUGIN_USB_CONNECTED : 0; +} + + +static bool pf_current_playlist_insert(int position, bool queue, bool create_new) { if (position == PLAYLIST_REPLACE) { @@ -4008,11 +4086,52 @@ static bool playlist_insert(int position, bool queue, bool create_new) return true; } + +static int pf_add_to_playlist(const char* playlist, bool new_playlist) +{ + int fd; + int result = 0; + + if (new_playlist) + fd = rb->open_utf8(playlist, O_CREAT|O_WRONLY|O_TRUNC); + else + fd = rb->open(playlist, O_CREAT|O_WRONLY|O_APPEND, 0666); + + if(fd < 0) + return -1; + + rb->reload_directory(); + + if (!insert_whole_album) + { + if (rb->fdprintf(fd, "%s\n", get_track_filename(pf_tracks.sel)) <= 0) + result = -1; + } + else + { + int i = 0; + do { + if (rb->fdprintf(fd, "%s\n", get_track_filename(i)) <= 0) + { + result = -1; + break; + } + rb->yield(); + } while(++i < pf_tracks.count); + } + rb->close(fd); + return result; +} + + static bool track_list_ready(void) { if (pf_state != pf_show_tracks) { - rb->splash(0, ID2P(LANG_WAIT)); +#ifdef HAVE_TC_RAMCACHE + if (!rb->tagcache_is_in_ram()) +#endif + rb->splash(0, ID2P(LANG_WAIT)); create_track_index(center_slide.slide_index); if (pf_tracks.count == 0) { @@ -4024,14 +4143,8 @@ static bool track_list_ready(void) return true; } -/** - Brings up "Current Playlist" menu with first - track of selection. - Onplay menu code calls back playlist_insert for - adding all of the tracks. -*/ -static void show_current_playlist_menu(void) +static bool context_menu_ready(void) { #ifdef USEGSLIB grey_show(false); @@ -4043,16 +4156,26 @@ static void show_current_playlist_menu(void) #ifdef USEGSLIB grey_show(true); #endif - return; + return false; } - insert_whole_album = pf_state != pf_show_tracks; +#if LCD_DEPTH > 1 +#ifdef USEGSLIB + rb->lcd_set_foreground(N_BRIGHT(0)); + rb->lcd_set_background(N_BRIGHT(255)); +#endif +#endif + insert_whole_album = (pf_state != pf_show_tracks) || show_tracks_while_browsing; FOR_NB_SCREENS(i) rb->viewportmanager_theme_enable(i, true, NULL); - rb->onplay_show_playlist_menu(get_track_filename(pf_tracks.sel), - &playlist_insert); + + return true; +} + +static void context_menu_cleanup(void) +{ FOR_NB_SCREENS(i) rb->viewportmanager_theme_undo(i, false); - if (insert_whole_album) + if (pf_state != pf_show_tracks) free_borrowed_tracks(); #ifdef USEGSLIB grey_show(true); @@ -4061,6 +4184,60 @@ static void show_current_playlist_menu(void) } +static int context_menu(void) +{ + char album_name[MAX_PATH]; + char *file_name = get_track_filename(show_tracks_while_browsing ? 0 : pf_tracks.sel); + int attr = FILE_ATTR_AUDIO; + + enum { + PF_CURRENT_PLAYLIST = 0, + PF_CATALOG, + PF_ID3_INFO + }; + MENUITEM_STRINGLIST(context_menu, ID2P(LANG_ONPLAY_MENU_TITLE), NULL, + ID2P(LANG_PLAYING_NEXT), + ID2P(LANG_ADD_TO_PL), + ID2P(LANG_MENU_SHOW_ID3_INFO)); + + while (1) { + switch (rb->do_menu(&context_menu, + NULL, NULL, false)) { + + case PF_CURRENT_PLAYLIST: + if (insert_whole_album && pf_tracks.count > 1) + { + attr = ATTR_DIRECTORY; + file_name = NULL; + } + rb->onplay_show_playlist_menu(file_name, attr, &pf_current_playlist_insert); + return 0; + case PF_CATALOG: + if (insert_whole_album) + { + /* add a leading slash so that catalog_add_to_a_playlist + later prefills the name when creating a new playlist */ + rb->snprintf(album_name, MAX_PATH, "/%s", get_album_name(center_index)); + rb->fix_path_part(album_name, 1, sizeof(album_name) - 2); + file_name = album_name; + attr = ATTR_DIRECTORY; + } + + rb->onplay_show_playlist_cat_menu(file_name, attr, &pf_add_to_playlist); + return 0; + case PF_ID3_INFO: + return show_id3_info(file_name); + case MENU_ATTACHED_USB: + return PLUGIN_USB_CONNECTED; + default: + return 0; + + } + } +} + + + /* * Puts selected album's tracks into a newly created playlist and starts playing */ @@ -4093,7 +4270,7 @@ static bool start_playback(bool return_to_WPS) if (shuffle || center_slide.slide_index != old_playlist || (old_shuffle != shuffle)) { - if (!playlist_insert(PLAYLIST_REPLACE, false, true)) + if (!pf_current_playlist_insert(PLAYLIST_REPLACE, false, true)) { #ifdef USEGSLIB grey_show(true); @@ -4104,7 +4281,7 @@ static bool start_playback(bool return_to_WPS) start_index = rb->playlist_shuffle(*rb->current_tick, pf_tracks.sel); } rb->playlist_start(start_index, 0, 0); - rb->playlist_get_current()->num_inserted_tracks = 0; /* prevent warn_on_pl_erase */ + rb->playlist_set_modified(NULL, false); old_shuffle = shuffle; #ifdef USEGSLIB if (!return_to_WPS) @@ -4204,32 +4381,15 @@ static void draw_album_text(void) static void set_initial_slide(const char* selected_file) { - if (selected_file == NULL) + if (selected_file) + set_current_slide(retrieve_id3(&id3, selected_file) ? + id3_get_index(&id3) : + pf_cfg.last_album); + else set_current_slide(rb->audio_status() ? id3_get_index(rb->audio_current_track()) : pf_cfg.last_album); - else - { - struct mp3entry id3; -#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) - if (rb->tagcache_fill_tags(&id3, selected_file)) - set_current_slide(id3_get_index(&id3)); - else -#endif - { - int fd = rb->open(selected_file, O_RDONLY); - if (fd >= 0) - { - if (rb->get_metadata(&id3, fd, selected_file)) - set_current_slide(id3_get_index(&id3)); - else - set_current_slide(pf_cfg.last_album); - rb->close(fd); - } - else - set_current_slide(pf_cfg.last_album); - } - } + } /** @@ -4264,14 +4424,11 @@ static int pictureflow_main(const char* selected_file) config_set_defaults(&pf_cfg); configfile_load(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); - if(pf_cfg.auto_wps == 0) - draw_splashscreen(pf_idx.buf, pf_idx.buf_sz); - if(pf_cfg.backlight_mode == 0) { - /* Turn off backlight timeout */ + #ifdef HAVE_BACKLIGHT + if(pf_cfg.backlight_mode == 0) backlight_ignore_timeout(); #endif - } rb->mutex_init(&buf_ctx_mutex); @@ -4319,13 +4476,13 @@ static int pictureflow_main(const char* selected_file) pf_idx.buf_sz -= aa_bufsz; if (!create_empty_slide(pf_cfg.cache_version != CACHE_VERSION)) { - config_save(CACHE_REBUILD); + config_save(CACHE_REBUILD, false); error_wait("Could not load the empty slide"); return PLUGIN_ERROR; } if ((pf_cfg.cache_version != CACHE_VERSION) && !create_albumart_cache()) { - config_save(CACHE_REBUILD); + config_save(CACHE_REBUILD, false); error_wait("Could not create album art cache"); } else if(aa_cache.inspected < pf_idx.album_ct) { rb->splash(HZ * 2, "Updating album art cache in background"); @@ -4333,7 +4490,7 @@ static int pictureflow_main(const char* selected_file) if (pf_cfg.cache_version != CACHE_VERSION) { - config_save(CACHE_VERSION); + config_save(CACHE_VERSION, pf_cfg.update_albumart); } rb->buflib_init(&buf_ctx, (void *)pf_idx.buf, pf_idx.buf_sz); @@ -4407,6 +4564,7 @@ static int pictureflow_main(const char* selected_file) instant_update = true; break; case pf_cover_out: + show_tracks_while_browsing = false; update_cover_out_animation(); render_all_slides(); instant_update = true; @@ -4415,8 +4573,14 @@ static int pictureflow_main(const char* selected_file) show_track_list(); break; case pf_idle: + show_tracks_while_browsing = false; render_all_slides(); - incremental_albumart_cache(false); + if (aa_cache.inspected < pf_idx.album_ct) + { + buf_ctx_lock(); + incremental_albumart_cache(false); + buf_ctx_unlock(); + } break; } @@ -4442,7 +4606,8 @@ static int pictureflow_main(const char* selected_file) rb->snprintf(fpstxt, sizeof(fpstxt), "%d %%", progress_pct); } - if (pf_cfg.show_album_name == ALBUM_NAME_TOP) + if (pf_cfg.show_album_name == ALBUM_NAME_TOP || + pf_cfg.show_album_name == ALBUM_AND_ARTIST_TOP) fpstxt_y = LCD_HEIGHT - rb->screens[SCREEN_MAIN]->getcharheight(); else @@ -4471,15 +4636,17 @@ static int pictureflow_main(const char* selected_file) case PF_WPS: return PLUGIN_GOTO_WPS; case PF_BACK: - if ( pf_state == pf_show_tracks ) + if (show_tracks_while_browsing) + show_tracks_while_browsing = false; + else if (pf_state == pf_show_tracks) { pf_state = pf_cover_out; free_borrowed_tracks(); } else if (pf_state == pf_cover_in) - revert_cover_in_animation(); + reverse_animation(); else if (pf_state == pf_cover_out) - interrupt_cover_out_animation(); + skip_animation_to_idle_state(); else if (pf_state == pf_idle || pf_state == pf_scrolling) return PLUGIN_OK; break; @@ -4504,11 +4671,16 @@ static int pictureflow_main(const char* selected_file) case PF_NEXT: case PF_NEXT_REPEAT: if ( pf_state == pf_show_tracks ) - select_next_track(); + { + if (show_tracks_while_browsing) + select_next_album(); + else + select_next_track(); + } else if (pf_state == pf_cover_in) - interrupt_cover_in_animation(); + skip_animation_to_show_tracks(); else if (pf_state == pf_cover_out) - interrupt_cover_out_animation(); + skip_animation_to_idle_state(); if ( pf_state == pf_idle || pf_state == pf_scrolling ) show_next_slide(); @@ -4517,11 +4689,16 @@ static int pictureflow_main(const char* selected_file) case PF_PREV: case PF_PREV_REPEAT: if ( pf_state == pf_show_tracks ) - select_prev_track(); + { + if (show_tracks_while_browsing) + select_prev_album(); + else + select_prev_track(); + } else if (pf_state == pf_cover_in) - interrupt_cover_in_animation(); + skip_animation_to_show_tracks(); else if (pf_state == pf_cover_out) - interrupt_cover_out_animation(); + skip_animation_to_idle_state(); if ( pf_state == pf_idle || pf_state == pf_scrolling ) show_previous_slide(); @@ -4557,21 +4734,30 @@ static int pictureflow_main(const char* selected_file) } else if ( pf_state == pf_show_tracks ) select_prev_album(); + else if (pf_state == pf_cover_in) + reverse_animation(); + else if (pf_state == pf_cover_out) + skip_animation_to_idle_state(); break; #if PF_PLAYBACK_CAPABLE case PF_CONTEXT: - if (pf_cfg.auto_wps != 0 && - (pf_state == pf_idle || pf_state == pf_scrolling || - pf_state == pf_show_tracks || pf_state == pf_cover_out)) { - + if (pf_state == pf_idle || pf_state == pf_scrolling || + pf_state == pf_show_tracks || pf_state == pf_cover_out) + { if ( pf_state == pf_scrolling) { set_current_slide(target); pf_state = pf_idle; - } else if (pf_state == pf_cover_out) - interrupt_cover_out_animation(); + } + else if (pf_state == pf_cover_out) + skip_animation_to_idle_state(); - show_current_playlist_menu(); + if (context_menu_ready()) + { + ret = context_menu(); + context_menu_cleanup(); + if ( ret != 0 ) return ret; + } } break; #endif @@ -4594,19 +4780,22 @@ static int pictureflow_main(const char* selected_file) pf_state = pf_cover_in; } else if (pf_state == pf_cover_out) - revert_cover_out_animation(); + reverse_animation(); else if (pf_state == pf_cover_in) - interrupt_cover_in_animation(); + skip_animation_to_show_tracks(); + else if (pf_state == pf_show_tracks) + { + if (show_tracks_while_browsing) + show_tracks_while_browsing = false; #if PF_PLAYBACK_CAPABLE - else if (pf_state == pf_show_tracks) { - if(pf_cfg.auto_wps != 0) { + else if(pf_cfg.auto_wps != 0) { if (start_playback(true)) return PLUGIN_GOTO_WPS; } else start_playback(false); - } #endif + } break; default: exit_on_usb(button); @@ -4627,17 +4816,12 @@ enum plugin_status plugin_start(const void *parameter) void * buf; size_t buf_size; - bool prompt = (parameter && (((char *) parameter)[0] == ACTIVITY_MAINMENU)); bool file_id3 = (parameter && (((char *) parameter)[0] == '/')); - if (!check_database(prompt)) + if (!check_database()) { - if (prompt) - return PLUGIN_OK; - else - error_wait("Please enable database"); - - return PLUGIN_ERROR; + error_wait("Please enable database"); + return PLUGIN_OK; } atexit(cleanup); @@ -4677,7 +4861,10 @@ enum plugin_status plugin_start(const void *parameter) ret = file_id3 ? pictureflow_main(file) : pictureflow_main(NULL); if ( ret == PLUGIN_OK || ret == PLUGIN_GOTO_WPS) { - pf_cfg.last_album = center_index; + if (pf_state == pf_scrolling) + pf_cfg.last_album = target; + else + pf_cfg.last_album = center_index; if (configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION)) { diff --git a/apps/plugins/pitch_detector.c b/apps/plugins/pitch_detector.c index 4ae43b3236..e9b1fb11b0 100644 --- a/apps/plugins/pitch_detector.c +++ b/apps/plugins/pitch_detector.c @@ -1013,6 +1013,11 @@ static void record_and_get_pitch(void) break; case PLA_CANCEL: +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) + case PLA_UP: +#endif rb->pcm_stop_recording(); quit = main_menu(); if(!quit) diff --git a/apps/plugins/plasma.c b/apps/plugins/plasma.c index f944d3d775..cdb6e66569 100644 --- a/apps/plugins/plasma.c +++ b/apps/plugins/plasma.c @@ -140,10 +140,10 @@ static void cleanup(void) #ifndef HAVE_LCD_COLOR grey_release(); #endif -#ifdef HAVE_BACKLIGHT + /* Turn on backlight timeout (revert to settings) */ backlight_use_settings(); -#endif + #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256) rb->lcd_set_mode(LCD_MODE_RGB565); #endif @@ -268,6 +268,11 @@ int main(void) switch(action) { +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) + case PLA_UP: +#endif case PLA_EXIT: case PLA_CANCEL: return PLUGIN_OK; @@ -277,7 +282,11 @@ int main(void) case PLA_SCROLL_FWD: case PLA_SCROLL_FWD_REPEAT: #endif +#if (CONFIG_KEYPAD != IPOD_1G2G_PAD) \ + && (CONFIG_KEYPAD != IPOD_3G_PAD) \ + && (CONFIG_KEYPAD != IPOD_4G_PAD) case PLA_UP: +#endif case PLA_UP_REPEAT: ++plasma_frequency; wave_table_generate(); @@ -321,10 +330,10 @@ enum plugin_status plugin_start(const void* parameter) #if LCD_DEPTH > 1 rb->lcd_set_backdrop(NULL); #endif -#ifdef HAVE_BACKLIGHT + /* Turn off backlight timeout */ backlight_ignore_timeout(); -#endif + #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256) rb->lcd_set_mode(LCD_MODE_PAL256); #endif diff --git a/apps/plugins/pong.c b/apps/plugins/pong.c index b49fec2459..17e6e6ed73 100644 --- a/apps/plugins/pong.c +++ b/apps/plugins/pong.c @@ -750,10 +750,9 @@ enum plugin_status plugin_start(const void* parameter) this to avoid the compiler warning about it */ (void)parameter; -#ifdef HAVE_BACKLIGHT /* Turn off backlight timeout */ backlight_ignore_timeout(); -#endif + /* Clear screen */ rb->lcd_clear_display(); @@ -792,9 +791,9 @@ enum plugin_status plugin_start(const void* parameter) rb->lcd_clear_display(); } } -#ifdef HAVE_BACKLIGHT + /* Turn on backlight timeout (revert to settings) */ backlight_use_settings(); -#endif + return (game == 0) ? PLUGIN_OK : PLUGIN_USB_CONNECTED; } diff --git a/apps/plugins/properties.c b/apps/plugins/properties.c index e5f00e307b..53af4c5bab 100644 --- a/apps/plugins/properties.c +++ b/apps/plugins/properties.c @@ -20,32 +20,47 @@ ****************************************************************************/ #include "plugin.h" +#ifdef HAVE_TAGCACHE +#include "lib/mul_id3.h" +#endif + #if !defined(ARRAY_SIZE) #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0])) #endif +struct dir_stats { + char dirname[MAX_PATH]; + int len; + unsigned int dir_count; + unsigned int file_count; + unsigned long long byte_count; +}; + enum props_types { PROPS_FILE = 0, PROPS_ID3, + PROPS_MUL_ID3, PROPS_DIR }; static int props_type = PROPS_FILE; static struct mp3entry id3; +#ifdef HAVE_TAGCACHE +static int mul_id3_count; +#endif -char str_filename[MAX_PATH]; -char str_dirname[MAX_PATH]; -char str_size[64]; -char str_dircount[64]; -char str_filecount[64]; -char str_date[64]; -char str_time[64]; +static char str_filename[MAX_PATH]; +static char str_dirname[MAX_PATH]; +static char str_size[64]; +static char str_dircount[64]; +static char str_filecount[64]; +static char str_date[64]; +static char str_time[64]; -unsigned nseconds; -unsigned long nsize; -int32_t size_unit; -struct tm tm; +static unsigned long nsize; +static int32_t size_unit; +static struct tm tm; #define NUM_FILE_PROPERTIES 5 static const unsigned char* const props_file[] = @@ -111,14 +126,8 @@ static bool file_properties(const char* selected_file) rb->snprintf(str_time, sizeof str_time, "%02d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec); - int fd = rb->open(selected_file, O_RDONLY); - if (fd >= 0) - { - if (rb->get_metadata(&id3, fd, selected_file)) - props_type = PROPS_ID3; - - rb->close(fd); - } + if (!rb->mp3info(&id3, selected_file)) + props_type = PROPS_ID3; found = true; break; } @@ -128,15 +137,7 @@ static bool file_properties(const char* selected_file) return found; } -typedef struct { - char dirname[MAX_PATH]; - int len; - unsigned int dc; - unsigned int fc; - unsigned long long bc; -} DPS; - -static bool _dir_properties(DPS *dps) +static bool _dir_properties(struct dir_stats *stats) { /* recursively scan directories in search of files and informs the user of the progress */ @@ -147,11 +148,11 @@ static bool _dir_properties(DPS *dps) struct dirent* entry; result = true; - dirlen = rb->strlen(dps->dirname); - dir = rb->opendir(dps->dirname); + dirlen = rb->strlen(stats->dirname); + dir = rb->opendir(stats->dirname); if (!dir) { - rb->splashf(HZ*2, "%s", dps->dirname); + rb->splashf(HZ*2, "%s", stats->dirname); return false; /* open error */ } @@ -160,7 +161,7 @@ static bool _dir_properties(DPS *dps) { struct dirinfo info = rb->dir_get_info(dir, entry); /* append name to current directory */ - rb->snprintf(dps->dirname+dirlen, dps->len-dirlen, "/%s", + rb->snprintf(stats->dirname+dirlen, stats->len-dirlen, "/%s", entry->d_name); if (info.attribute & ATTR_DIRECTORY) @@ -169,29 +170,30 @@ static bool _dir_properties(DPS *dps) !rb->strcmp((char *)entry->d_name, "..")) continue; /* skip these */ - dps->dc++; /* new directory */ + stats->dir_count++; /* new directory */ if (*rb->current_tick - lasttick > (HZ/8)) { unsigned log; lasttick = *rb->current_tick; rb->lcd_clear_display(); rb->lcd_puts(0,0,"SCANNING..."); - rb->lcd_puts(0,1,dps->dirname); - rb->lcd_putsf(0,2,"Directories: %d", dps->dc); - rb->lcd_putsf(0,3,"Files: %d", dps->fc); - log = human_size_log(dps->bc); - rb->lcd_putsf(0,4,"Size: %lu %cB", (unsigned long)(dps->bc >> (10*log)), + rb->lcd_puts(0,1,stats->dirname); + rb->lcd_putsf(0,2,"Directories: %d", stats->dir_count); + rb->lcd_putsf(0,3,"Files: %d", stats->file_count); + log = human_size_log(stats->byte_count); + rb->lcd_putsf(0,4,"Size: %lu %s", + (unsigned long)(stats->byte_count >> (10*log)), rb->str(units[log])); rb->lcd_update(); } /* recursion */ - result = _dir_properties(dps); + result = _dir_properties(stats); } else { - dps->fc++; /* new file */ - dps->bc += info.size; + stats->file_count++; /* new file */ + stats->byte_count += info.size; } if(ACTION_STD_CANCEL == rb->get_action(CONTEXT_STD,TIMEOUT_NOBLOCK)) result = false; @@ -201,17 +203,17 @@ static bool _dir_properties(DPS *dps) return result; } -static bool dir_properties(const char* selected_file, DPS *dps) +static bool dir_properties(const char* selected_file, struct dir_stats *stats) { unsigned log; - rb->strlcpy(dps->dirname, selected_file, MAX_PATH); + rb->strlcpy(stats->dirname, selected_file, MAX_PATH); #ifdef HAVE_ADJUSTABLE_CPU_FREQ rb->cpu_boost(true); #endif - if (!_dir_properties(dps)) + if (!_dir_properties(stats)) { #ifdef HAVE_ADJUSTABLE_CPU_FREQ rb->cpu_boost(false); @@ -224,10 +226,10 @@ static bool dir_properties(const char* selected_file, DPS *dps) #endif rb->strlcpy(str_dirname, selected_file, MAX_PATH); - rb->snprintf(str_dircount, sizeof str_dircount, "%d", dps->dc); - rb->snprintf(str_filecount, sizeof str_filecount, "%d", dps->fc); - log = human_size_log(dps->bc); - nsize = (long) (dps->bc >> (log*10)); + rb->snprintf(str_dircount, sizeof str_dircount, "%d", stats->dir_count); + rb->snprintf(str_filecount, sizeof str_filecount, "%d", stats->file_count); + log = human_size_log(stats->byte_count); + nsize = (long) (stats->byte_count >> (log*10)); size_unit = units[log]; rb->snprintf(str_size, sizeof str_size, "%ld %s", nsize, rb->str(size_unit)); return true; @@ -255,7 +257,7 @@ static const char * get_props(int selected_item, void* data, static int speak_property_selection(int selected_item, void *data) { - DPS *dps = data; + struct dir_stats *stats = data; int32_t id = P2ID((props_type == PROPS_DIR ? props_dir : props_file)[selected_item]); rb->talk_id(id, false); switch (id) @@ -295,10 +297,10 @@ static int speak_property_selection(int selected_item, void *data) rb->talk_time(&tm, true); break; case LANG_PROPERTIES_SUBDIRS: - rb->talk_number(dps->dc, true); + rb->talk_number(stats->dir_count, true); break; case LANG_PROPERTIES_FILES: - rb->talk_number(dps->fc, true); + rb->talk_number(stats->file_count, true); break; default: rb->talk_spell(props_file[selected_item + 1], true); @@ -307,33 +309,49 @@ static int speak_property_selection(int selected_item, void *data) return 0; } -enum plugin_status plugin_start(const void* parameter) +static int browse_file_or_dir(struct dir_stats *stats) { struct gui_synclist properties_lists; int button; - bool quit = false, usb = false; - const char *file = parameter; - if(!parameter) return PLUGIN_ERROR; -#ifdef HAVE_TOUCHSCREEN - rb->touchscreen_set_mode(rb->global_settings->touch_mode); -#endif - static DPS dps = { - .len = MAX_PATH, - .dc = 0, - .fc = 0, - .bc = 0, - }; + rb->gui_synclist_init(&properties_lists, &get_props, stats, false, 2, NULL); + rb->gui_synclist_set_title(&properties_lists, + rb->str(props_type == PROPS_DIR ? + LANG_PROPERTIES_DIRECTORY_PROPERTIES : + LANG_PROPERTIES_FILE_PROPERTIES), + NOICON); + rb->gui_synclist_set_icon_callback(&properties_lists, NULL); + if (rb->global_settings->talk_menu) + rb->gui_synclist_set_voice_callback(&properties_lists, speak_property_selection); + rb->gui_synclist_set_nb_items(&properties_lists, + 2 * (props_type == PROPS_FILE ? NUM_FILE_PROPERTIES : + NUM_DIR_PROPERTIES)); + rb->gui_synclist_select_item(&properties_lists, 0); + rb->gui_synclist_draw(&properties_lists); + rb->gui_synclist_speak_item(&properties_lists); + + while(true) + { + button = rb->get_action(CONTEXT_LIST, HZ); + /* HZ so the status bar redraws corectly */ + if (rb->gui_synclist_do_button(&properties_lists,&button)) + continue; + switch(button) + { + case ACTION_STD_CANCEL: + return false; + default: + if (rb->default_event_handler(button) == SYS_USB_CONNECTED) + return true; + break; + } + } +} - /* determine if it's a file or a directory */ - bool found = false; +static bool determine_file_or_dir(void) +{ DIR* dir; struct dirent* entry; - char* ptr = rb->strrchr(file, '/') + 1; - int dirlen = (ptr - file); - - rb->strlcpy(str_dirname, file, dirlen + 1); - rb->snprintf(str_filename, sizeof str_filename, "%s", file+dirlen); dir = rb->opendir(str_dirname); if (dir) @@ -344,76 +362,95 @@ enum plugin_status plugin_start(const void* parameter) { struct dirinfo info = rb->dir_get_info(dir, entry); props_type = info.attribute & ATTR_DIRECTORY ? PROPS_DIR : PROPS_FILE; - found = true; - break; + rb->closedir(dir); + return true; } } rb->closedir(dir); } - /* now we know if it's a file or a dir or maybe something failed */ + return false; +} - if(!found) - { - /* weird: we couldn't find the entry. This Should Never Happen (TM) */ - rb->splashf(0, "File/Dir not found: %s", file); - rb->action_userabort(TIMEOUT_BLOCK); - return PLUGIN_OK; - } +#ifdef HAVE_TAGCACHE +bool mul_id3_add(const char *file_name) +{ + if (rb->mp3info(&id3, file_name)) + return false; - /* get the info depending on its_a_dir */ - if(!(props_type == PROPS_DIR ? dir_properties(file, &dps) : file_properties(file))) + collect_id3(&id3, mul_id3_count == 0); + mul_id3_count++; + + return true; +} +#endif + +enum plugin_status plugin_start(const void* parameter) +{ + static struct dir_stats stats = { - /* something went wrong (to do: tell user what it was (nesting,...) */ - rb->splash(0, ID2P(LANG_PROPERTIES_FAIL)); - rb->action_userabort(TIMEOUT_BLOCK); - return PLUGIN_OK; - } + .len = MAX_PATH, + .dir_count = 0, + .file_count = 0, + .byte_count = 0, + }; - FOR_NB_SCREENS(i) - rb->viewportmanager_theme_enable(i, true, NULL); + const char *file = parameter; + if(!parameter) + return PLUGIN_ERROR; + +#ifdef HAVE_TOUCHSCREEN + rb->touchscreen_set_mode(rb->global_settings->touch_mode); +#endif - if (props_type == PROPS_ID3) - usb = rb->browse_id3(&id3, 0, 0); +#ifdef HAVE_TAGCACHE + if (!rb->strcmp(file, MAKE_ACT_STR(ACTIVITY_DATABASEBROWSER))) /* db table selected */ + { + props_type = PROPS_MUL_ID3; + mul_id3_count = 0; + + if (!rb->tagtree_subentries_do_action(&mul_id3_add) || mul_id3_count == 0) + return PLUGIN_ERROR; + else if (mul_id3_count > 1) /* otherwise, the retrieved id3 can be used as-is */ + finalize_id3(&id3); + } else +#endif + if (file[0] == '/') /* single track selected */ { - rb->gui_synclist_init(&properties_lists, &get_props, &dps, false, 2, NULL); - rb->gui_synclist_set_title(&properties_lists, - rb->str(props_type == PROPS_DIR ? - LANG_PROPERTIES_DIRECTORY_PROPERTIES : - LANG_PROPERTIES_FILE_PROPERTIES), - NOICON); - rb->gui_synclist_set_icon_callback(&properties_lists, NULL); - if (rb->global_settings->talk_menu) - rb->gui_synclist_set_voice_callback(&properties_lists, speak_property_selection); - rb->gui_synclist_set_nb_items(&properties_lists, - 2 * (props_type == PROPS_FILE ? NUM_FILE_PROPERTIES : - NUM_DIR_PROPERTIES)); - rb->gui_synclist_limit_scroll(&properties_lists, true); - rb->gui_synclist_select_item(&properties_lists, 0); - rb->gui_synclist_draw(&properties_lists); - rb->gui_synclist_speak_item(&properties_lists); - - while(!quit) + const char* file_name = rb->strrchr(file, '/') + 1; + int dirlen = (file_name - file); + + rb->strlcpy(str_dirname, file, dirlen + 1); + rb->snprintf(str_filename, sizeof str_filename, "%s", file+dirlen); + + if(!determine_file_or_dir()) { - button = rb->get_action(CONTEXT_LIST, HZ); - /* HZ so the status bar redraws corectly */ - if (rb->gui_synclist_do_button(&properties_lists,&button,LIST_WRAP_UNLESS_HELD)) - continue; - switch(button) - { - case ACTION_STD_CANCEL: - quit = true; - break; - default: - if (rb->default_event_handler(button) == SYS_USB_CONNECTED) - { - quit = true; - usb = true; - } - break; - } + /* weird: we couldn't find the entry. This Should Never Happen (TM) */ + rb->splashf(0, "File/Dir not found: %s", file); + rb->action_userabort(TIMEOUT_BLOCK); + return PLUGIN_OK; + } + + /* get the info depending on its_a_dir */ + if(!(props_type == PROPS_DIR ? dir_properties(file, &stats) : file_properties(file))) + { + /* something went wrong (to do: tell user what it was (nesting,...) */ + rb->splash(0, ID2P(LANG_PROPERTIES_FAIL)); + rb->action_userabort(TIMEOUT_BLOCK); + return PLUGIN_OK; } } + else + return PLUGIN_ERROR; + + FOR_NB_SCREENS(i) + rb->viewportmanager_theme_enable(i, true, NULL); + + bool usb = props_type == PROPS_ID3 ? rb->browse_id3(&id3, 0, 0, &tm, 1) : +#ifdef HAVE_TAGCACHE + props_type == PROPS_MUL_ID3 ? rb->browse_id3(&id3, 0, 0, NULL, mul_id3_count) : +#endif + browse_file_or_dir(&stats); FOR_NB_SCREENS(i) rb->viewportmanager_theme_undo(i, false); diff --git a/apps/plugins/puzzles/rockbox.c b/apps/plugins/puzzles/rockbox.c index 6e34adb1db..e175429075 100644 --- a/apps/plugins/puzzles/rockbox.c +++ b/apps/plugins/puzzles/rockbox.c @@ -1465,7 +1465,7 @@ static void rb_blitter_free(void *handle, blitter *bl) static void rb_blitter_save(void *handle, blitter *bl, int x, int y) { /* no viewport offset */ -#if defined(LCD_STRIDEFORMAT) && (LCD_STRIDEFORMAT == VERTICAL_STRIDE) +#if LCD_STRIDEFORMAT == VERTICAL_STRIDE #error no vertical stride #else if(bl && bl->bmp.data) @@ -2450,7 +2450,6 @@ static int list_choose(const char *list_str, const char *title, int sel) rb->gui_synclist_init(&list, &config_choices_formatter, (void*)list_str, false, 1, NULL); rb->gui_synclist_set_icon_callback(&list, NULL); rb->gui_synclist_set_nb_items(&list, n); - rb->gui_synclist_limit_scroll(&list, false); rb->gui_synclist_select_item(&list, sel); @@ -2459,7 +2458,7 @@ static int list_choose(const char *list_str, const char *title, int sel) { rb->gui_synclist_draw(&list); int button = rb->get_action(CONTEXT_LIST, TIMEOUT_BLOCK); - if(rb->gui_synclist_do_button(&list, &button, LIST_WRAP_UNLESS_HELD)) + if(rb->gui_synclist_do_button(&list, &button)) continue; switch(button) { @@ -2664,7 +2663,6 @@ static bool config_menu(void) rb->gui_synclist_init(&list, &config_formatter, config, false, 1, NULL); rb->gui_synclist_set_icon_callback(&list, NULL); rb->gui_synclist_set_nb_items(&list, n); - rb->gui_synclist_limit_scroll(&list, false); rb->gui_synclist_select_item(&list, 0); @@ -2674,7 +2672,7 @@ static bool config_menu(void) { rb->gui_synclist_draw(&list); int button = rb->get_action(CONTEXT_LIST, TIMEOUT_BLOCK); - if(rb->gui_synclist_do_button(&list, &button, LIST_WRAP_UNLESS_HELD)) + if(rb->gui_synclist_do_button(&list, &button)) continue; switch(button) { @@ -2750,7 +2748,6 @@ static int do_preset_menu(struct preset_menu *menu, char *title, int selected) rb->gui_synclist_init(&list, &preset_formatter, menu, false, 1, NULL); rb->gui_synclist_set_icon_callback(&list, NULL); rb->gui_synclist_set_nb_items(&list, menu->n_entries); - rb->gui_synclist_limit_scroll(&list, false); rb->gui_synclist_select_item(&list, selected); @@ -2760,7 +2757,7 @@ static int do_preset_menu(struct preset_menu *menu, char *title, int selected) { rb->gui_synclist_draw(&list); int button = rb->get_action(CONTEXT_LIST, TIMEOUT_BLOCK); - if(rb->gui_synclist_do_button(&list, &button, LIST_WRAP_UNLESS_HELD)) + if(rb->gui_synclist_do_button(&list, &button)) continue; switch(button) { @@ -3393,9 +3390,7 @@ static void shutdown_tlsf(void) static void exit_handler(void) { -#ifdef HAVE_SW_POWEROFF sw_poweroff_restore(); -#endif unload_fonts(); shutdown_tlsf(); @@ -3655,9 +3650,7 @@ static void puzzles_main(void) { rb_atexit(exit_handler); -#ifdef HAVE_SW_POWEROFF sw_poweroff_disable(); -#endif init_default_settings(); init_fonttab(); diff --git a/apps/plugins/random_folder_advance_config.c b/apps/plugins/random_folder_advance_config.c index 2c9fb411ac..5688ff93d3 100644 --- a/apps/plugins/random_folder_advance_config.c +++ b/apps/plugins/random_folder_advance_config.c @@ -311,14 +311,13 @@ static int edit_list(void) rb->gui_synclist_init(&lists,list_get_name_cb,0, false, 1, NULL); rb->gui_synclist_set_icon_callback(&lists,NULL); rb->gui_synclist_set_nb_items(&lists,list->count); - rb->gui_synclist_limit_scroll(&lists,true); rb->gui_synclist_select_item(&lists, 0); while (!exit) { rb->gui_synclist_draw(&lists); button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK); - if (rb->gui_synclist_do_button(&lists,&button,LIST_WRAP_UNLESS_HELD)) + if (rb->gui_synclist_do_button(&lists, &button)) continue; selection = rb->gui_synclist_get_sel_pos(&lists); switch (button) diff --git a/apps/plugins/rb_info.c b/apps/plugins/rb_info.c index e0ec117dfb..a89cc658cc 100644 --- a/apps/plugins/rb_info.c +++ b/apps/plugins/rb_info.c @@ -335,6 +335,17 @@ static int list_voice_cb(int list_index, void* data) rb->talk_spell(name, true); } } + else if (data == MENU_ID(M_TESTPUT)) + { + char buf[64]; + const char* name = printcell_get_column_text(printcell_get_column_selected(), + buf, sizeof(buf)); + long id = P2ID((const unsigned char *)name); + if(id>=0) + rb->talk_id(id, true); + else + rb->talk_spell(name, true); + } else { char buf[64]; @@ -354,12 +365,12 @@ int menu_action_cb(int *action, int selected_item, bool* exit, struct gui_syncli { if (*action == ACTION_STD_OK) { - printcell_increment_column(lists, 1, true); + printcell_increment_column(1, true); *action = ACTION_NONE; } else if (*action == ACTION_STD_CANCEL) { - if (printcell_increment_column(lists, -1, true) != testput_cols - 1) + if (printcell_increment_column(-1, true) != testput_cols - 1) { *action = ACTION_NONE; } @@ -368,7 +379,8 @@ int menu_action_cb(int *action, int selected_item, bool* exit, struct gui_syncli { char buf[PRINTCELL_MAXLINELEN]; char* bufp = buf; - bufp = printcell_get_selected_column_text(lists, bufp, PRINTCELL_MAXLINELEN); + int selcol = printcell_get_column_selected(); + bufp = printcell_get_column_text(selcol, bufp, PRINTCELL_MAXLINELEN); rb->splashf(HZ * 2, "Item: %s", bufp); } } @@ -428,20 +440,13 @@ int menu_action_cb(int *action, int selected_item, bool* exit, struct gui_syncli if (cur->menuid == MENU_ID(M_TESTPUT)) { - //rb->gui_list_screen_scroll_out_of_view(true); synclist_set(cur->menuid, 0, cur->items, 1); -#if LCD_DEPTH > 1 - /* If line sep is set to automatic then outline cells */ - bool showlinesep = (rb->global_settings->list_separator_height < 0); -#else - bool showlinesep = (rb->global_settings->cursor_style == 0); -#endif - printcell_enable(lists, true, showlinesep); + printcell_enable(true); //lists->callback_draw_item = test_listdraw_fn; } else { - printcell_enable(lists, false, false); + printcell_enable(false); synclist_set(cur->menuid, 1, cur->items, 1); } rb->gui_synclist_draw(lists); @@ -473,9 +478,8 @@ int menu_action_cb(int *action, int selected_item, bool* exit, struct gui_syncli { if (lists->data == MENU_ID(M_TESTPUT)) { - //rb->gui_list_screen_scroll_out_of_view(false); //lists->callback_draw_item = NULL; - printcell_enable(lists, false, false); + printcell_enable(false); } if (lists->data != MENU_ID(M_ROOT)) { @@ -507,7 +511,8 @@ static void synclist_set(char* menu_id, int selected_item, int items, int sel_si menu_id, false, sel_size, NULL); if (menu_id == MENU_ID(M_TESTPUT)) { - testput_cols = printcell_set_columns(&lists, TESTPUT_HEADER, Icon_Rockbox); + testput_cols = printcell_set_columns(&lists, NULL, + TESTPUT_HEADER, Icon_Rockbox); } else { @@ -516,7 +521,6 @@ static void synclist_set(char* menu_id, int selected_item, int items, int sel_si rb->gui_synclist_set_icon_callback(&lists,NULL); rb->gui_synclist_set_voice_callback(&lists, list_voice_cb); rb->gui_synclist_set_nb_items(&lists,items); - rb->gui_synclist_limit_scroll(&lists,true); rb->gui_synclist_select_item(&lists, selected_item); } @@ -560,11 +564,11 @@ enum plugin_status plugin_start(const void* parameter) else redraw = true; ret = menu_action_cb(&action, selected_item, &exit, &lists); - if (rb->gui_synclist_do_button(&lists,&action,LIST_WRAP_UNLESS_HELD)) + if (rb->gui_synclist_do_button(&lists, &action)) continue; selected_item = rb->gui_synclist_get_sel_pos(&lists); } } - + printcell_enable(false); return ret; } diff --git a/apps/plugins/resistor.c b/apps/plugins/resistor.c index d32ac3fad9..4461dc0dea 100644 --- a/apps/plugins/resistor.c +++ b/apps/plugins/resistor.c @@ -574,9 +574,8 @@ static void display_helpfile(void) static void led_resistance_calc(void) { -#ifdef HAVE_BACKLIGHT backlight_ignore_timeout(); -#endif + int voltage_menu_selection, button_press, j, k, l, foreward_current = 0; int fwd_current_selection = 0; bool quit = false; @@ -769,9 +768,8 @@ static void led_resistance_calc(void) default: quit = true; -#ifdef HAVE_BACKLIGHT backlight_use_settings(); -#endif + break; } } @@ -784,9 +782,8 @@ static void led_resistance_calc(void) static void resistance_to_color(void) { -#ifdef HAVE_BACKLIGHT backlight_ignore_timeout(); -#endif + int menu_selection; int menu_selection_tol; int button_press; @@ -910,9 +907,9 @@ static void resistance_to_color(void) break; default: quit = true; -#ifdef HAVE_BACKLIGHT + backlight_use_settings(); -#endif + break; } } @@ -924,9 +921,8 @@ static void resistance_to_color(void) static void color_to_resistance(void) { -#ifdef HAVE_BACKLIGHT backlight_ignore_timeout(); -#endif + bool quit = false; int button_input = 0; @@ -995,9 +991,7 @@ static void color_to_resistance(void) case PLA_SELECT: default: quit = true; -#ifdef HAVE_BACKLIGHT backlight_use_settings(); -#endif break; } } diff --git a/apps/plugins/robotfindskitten.c b/apps/plugins/robotfindskitten.c index 4f228423b6..31c419e33d 100644 --- a/apps/plugins/robotfindskitten.c +++ b/apps/plugins/robotfindskitten.c @@ -469,7 +469,13 @@ static char* messages[] = #define RFK_VERSION "v1.4142135.406" +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +# define RFK_QUIT PLA_SELECT_REPEAT +#else # define RFK_QUIT PLA_CANCEL +#endif # define RFK_RIGHT PLA_RIGHT # define RFK_LEFT PLA_LEFT # define RFK_UP PLA_UP diff --git a/apps/plugins/rockblox.c b/apps/plugins/rockblox.c index 927710b37b..a0105a1ffb 100644 --- a/apps/plugins/rockblox.c +++ b/apps/plugins/rockblox.c @@ -33,7 +33,7 @@ (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) -#define ROCKBLOX_OFF (BUTTON_MENU | BUTTON_SELECT) +#define ROCKBLOX_OFF (BUTTON_SELECT | BUTTON_REPEAT) #define ROCKBLOX_ROTATE_CCW BUTTON_SCROLL_BACK #define ROCKBLOX_ROTATE_CCW2 (BUTTON_MENU | BUTTON_REL) #define ROCKBLOX_ROTATE_CW BUTTON_SCROLL_FWD @@ -41,6 +41,7 @@ #define ROCKBLOX_RIGHT BUTTON_RIGHT #define ROCKBLOX_DOWN BUTTON_PLAY #define ROCKBLOX_RESTART (BUTTON_SELECT | BUTTON_PLAY) +#define ROCKBLOX_DROP_PRE BUTTON_SELECT #define ROCKBLOX_DROP (BUTTON_SELECT | BUTTON_REL) #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ @@ -1498,16 +1499,13 @@ static int rockblox_loop (void) #ifdef HAS_BUTTON_HOLD if (rb->button_hold ()) { /* Turn on backlight timeout (revert to settings) */ -#ifdef HAVE_BACKLIGHT backlight_use_settings(); -#endif rb->splash(0, "Paused"); while (rb->button_hold ()) rb->sleep(HZ/10); -#ifdef HAVE_BACKLIGHT /* Turn off backlight timeout */ backlight_ignore_timeout(); -#endif + /* get rid of the splash text */ rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT); show_details (); @@ -1677,10 +1675,9 @@ enum plugin_status plugin_start (const void *parameter) rb->lcd_setfont (FONT_SYSFIXED); -#ifdef HAVE_BACKLIGHT /* Turn off backlight timeout */ backlight_ignore_timeout(); -#endif + load_game(); resume_file = resume; @@ -1728,9 +1725,8 @@ enum plugin_status plugin_start (const void *parameter) /* Save user's HighScore */ highscore_save(SCORE_FILE, highscores, NUM_SCORES); -#ifdef HAVE_BACKLIGNT + backlight_use_settings(); -#endif return PLUGIN_OK; } diff --git a/apps/plugins/rockblox1d.c b/apps/plugins/rockblox1d.c index 6a2b013c44..6d535bbcd7 100644 --- a/apps/plugins/rockblox1d.c +++ b/apps/plugins/rockblox1d.c @@ -28,7 +28,14 @@ static const struct button_mapping *plugin_contexts[] = { pla_main_ctx }; #define ONEDROCKBLOX_DOWN PLA_DOWN #define ONEDROCKBLOX_DOWN_REPEAT PLA_DOWN_REPEAT #define ONEDROCKBLOX_QUIT PLA_EXIT + +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define ONEDROCKBLOX_QUIT2 PLA_UP +#else #define ONEDROCKBLOX_QUIT2 PLA_CANCEL +#endif #define mrand(max) (short)(rb->rand()%max) diff --git a/apps/plugins/rockboy/menu.c b/apps/plugins/rockboy/menu.c index 6fafdc11a6..7fd7aabdc8 100644 --- a/apps/plugins/rockboy/menu.c +++ b/apps/plugins/rockboy/menu.c @@ -83,9 +83,8 @@ int do_user_menu(void) { rb->lcd_set_mode(LCD_MODE_RGB565); #endif -#ifdef HAVE_BACKLIGHT backlight_use_settings(); -#endif + /* Clean out the button Queue */ while (rb->button_get(false) != BUTTON_NONE) rb->yield(); @@ -139,10 +138,9 @@ int do_user_menu(void) { rb->lcd_set_mode(LCD_MODE_PAL256); #endif -#ifdef HAVE_BACKLIGHT /* ignore backlight time out */ backlight_ignore_timeout(); -#endif + return ret; } @@ -430,7 +428,7 @@ static void do_opt_menu(void) options.dirty=1; /* Assume that the settings have been changed */ struct viewport *parentvp = NULL; - const struct settings_list* vol = rb->find_setting(&rb->global_settings->volume, NULL); + const struct settings_list* vol = rb->find_setting(&rb->global_settings->volume); while(!done) { diff --git a/apps/plugins/rockboy/rockboy.c b/apps/plugins/rockboy/rockboy.c index 2c5c6e4dbf..2d0c349507 100644 --- a/apps/plugins/rockboy/rockboy.c +++ b/apps/plugins/rockboy/rockboy.c @@ -602,10 +602,9 @@ enum plugin_status plugin_start(const void* parameter) rb->lcd_set_mode(LCD_MODE_PAL256); #endif -#ifdef HAVE_BACKLIGHT /* ignore backlight time out */ backlight_ignore_timeout(); -#endif + gnuboy_main(parameter); #ifdef HAVE_WHEEL_POSITION @@ -616,9 +615,7 @@ enum plugin_status plugin_start(const void* parameter) rb->lcd_set_mode(LCD_MODE_RGB565); #endif -#ifdef HAVE_BACKLIGHT backlight_use_settings(); -#endif if(!rb->audio_status()) rockboy_pcm_close(); diff --git a/apps/plugins/rocklife.c b/apps/plugins/rocklife.c index 99297abd0f..c4c7842fe0 100644 --- a/apps/plugins/rocklife.c +++ b/apps/plugins/rocklife.c @@ -70,7 +70,13 @@ #define ROCKLIFE_INIT PLA_DOWN #define ROCKLIFE_NEXT PLA_RIGHT #define ROCKLIFE_NEXT_REP PLA_RIGHT_REPEAT +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define ROCKLIFE_QUIT PLA_UP +#else #define ROCKLIFE_QUIT PLA_CANCEL +#endif #define ROCKLIFE_STATUS PLA_LEFT #define PATTERN_RANDOM 0 @@ -474,9 +480,8 @@ enum plugin_status plugin_start(const void* parameter) char *ptemp; (void)(parameter); -#ifdef HAVE_BACKLIGHT backlight_ignore_timeout(); -#endif + #if LCD_DEPTH > 1 rb->lcd_set_backdrop(NULL); #ifdef HAVE_LCD_COLOR @@ -580,8 +585,7 @@ enum plugin_status plugin_start(const void* parameter) rb->yield(); } -#ifdef HAVE_BACKLIGHT backlight_use_settings(); -#endif + return usb? PLUGIN_USB_CONNECTED: PLUGIN_OK; } diff --git a/apps/plugins/rockpaint.c b/apps/plugins/rockpaint.c index 09fa2c8c5f..cba1701eb6 100644 --- a/apps/plugins/rockpaint.c +++ b/apps/plugins/rockpaint.c @@ -1084,15 +1084,15 @@ static bool callback_show_item(char *name, int attr, struct tree_context *tc) static bool browse( char *dst, int dst_size, const char *start ) { - struct browse_context browse; - - rb->browse_context_init(&browse, SHOW_ALL, - BROWSE_SELECTONLY|BROWSE_NO_CONTEXT_MENU, - NULL, NOICON, start, NULL); - - browse.callback_show_item = callback_show_item; - browse.buf = dst; - browse.bufsize = dst_size; + struct browse_context browse = { + .dirfilter = SHOW_ALL, + .flags = BROWSE_SELECTONLY | BROWSE_NO_CONTEXT_MENU, + .icon = Icon_NOICON, + .root = start, + .buf = dst, + .bufsize = dst_size, + .callback_show_item = callback_show_item, + }; rb->rockbox_browse(&browse); diff --git a/apps/plugins/sdl/SDL_mixer/timidity/playmidi.c b/apps/plugins/sdl/SDL_mixer/timidity/playmidi.c index 1638732dc5..38f7109b13 100644 --- a/apps/plugins/sdl/SDL_mixer/timidity/playmidi.c +++ b/apps/plugins/sdl/SDL_mixer/timidity/playmidi.c @@ -21,6 +21,8 @@ #include "tables.h" +/* ROCKBOX HACK: avoid a conflict with adjust_volume() in misc.h */ +#define adjust_volume adjust_midi_volume static int opt_expression_curve = 2; static int opt_volume_curve = 2; diff --git a/apps/plugins/sdl/main.c b/apps/plugins/sdl/main.c index 6efb072faf..7220c7cfd9 100644 --- a/apps/plugins/sdl/main.c +++ b/apps/plugins/sdl/main.c @@ -64,9 +64,8 @@ void cleanup(void) if(audiobuf) memset(audiobuf, 0, 4); /* clear */ -#ifdef HAVE_BACKLIGHT backlight_use_settings(); -#endif + #ifdef HAVE_ADJUSTABLE_CPU_FREQ rb->cpu_boost(false); #endif @@ -219,9 +218,9 @@ enum plugin_status plugin_start(const void *param) #ifdef HAVE_ADJUSTABLE_CPU_FREQ rb->cpu_boost(true); #endif -#ifdef HAVE_BACKLIGHT + backlight_ignore_timeout(); -#endif + /* set the real exit handler */ #undef rb_atexit rb_atexit(cleanup); diff --git a/apps/plugins/sdl/src/audio/rockbox/SDL_rockboxaudio.c b/apps/plugins/sdl/src/audio/rockbox/SDL_rockboxaudio.c index cb72687d48..ac268b4a19 100644 --- a/apps/plugins/sdl/src/audio/rockbox/SDL_rockboxaudio.c +++ b/apps/plugins/sdl/src/audio/rockbox/SDL_rockboxaudio.c @@ -132,38 +132,42 @@ static void ROCKBOXAUD_WaitAudio(_THIS) } /* when this is called, SDL wants us to play the samples in mixbuf */ -static void ROCKBOXAUD_PlayAudio(_THIS) +static void +ROCKBOXAUD_PlayAudio(_THIS) { /* There are two cases in which we should be called: * - There is an empty buffer (marked with status = 0) * - There are more than two buffers marked as playing, meaning at least one is stale. */ - int idx = -1; /* Find the next empty or stale buffer and fill. */ - for(int i = 1; i < this->hidden->n_buffers; ++i) + for(int i = 1; i <= this->hidden->n_buffers; ++i) { - idx = (this->hidden->current_playing + i) % this->hidden->n_buffers; + int idx = (this->hidden->current_playing + i) % this->hidden->n_buffers; /* Empty or stale. */ if(this->hidden->status[idx] == 0 || - this->hidden->status[idx] == 2) - break; - } - if(idx < 0) - return; + this->hidden->status[idx] == 2) { + + LOGF("found empty buffer: %d (status: %d)", idx, this->hidden->status[idx]); + + /* probably premature optimization here */ + char *dst = (char*)this->hidden->rb_buf[idx], *src = this->hidden->mixbuf; + int size = this->spec.size / 2; + memcpy(dst, src, size); - /* probably premature optimization here */ - char *dst = (char*)this->hidden->rb_buf[idx], *src = this->hidden->mixbuf; - int size = this->hidden->mixlen / 2; - memcpy(dst, src, size); + this->hidden->status[idx] = 1; + rb->yield(); - this->hidden->status[idx] = 1; - rb->yield(); + memcpy(dst + size, src + size, this->spec.size - size); - memcpy(dst + size, src + size, this->hidden->mixlen - size); + LOGF("filled buffer %d (status %d %d %d %d)", idx, this->hidden->status[0], this->hidden->status[1], this->hidden->status[2], this->hidden->status[3]); + + return; + } + } - //LOGF("filled buffer %d (status %d %d %d)", idx, this->hidden->status[0], this->hidden->status[1], this->hidden->status[2]); + LOGF("WARNING: PlayDevice could not find buffer to fill; DROPPING SAMPLES!"); } static SDL_AudioDevice *ROCKBOXAUD_CreateDevice(int devindex) diff --git a/apps/plugins/shopper.c b/apps/plugins/shopper.c index 7129291c10..25a484a31e 100644 --- a/apps/plugins/shopper.c +++ b/apps/plugins/shopper.c @@ -304,7 +304,6 @@ enum plugin_status plugin_start(const void* parameter) /* now dump it in the list */ rb->gui_synclist_init(&lists,list_get_name_cb,0, false, 1, NULL); rb->gui_synclist_set_icon_callback(&lists, list_get_icon_cb); - rb->gui_synclist_limit_scroll(&lists,true); create_view(&lists); rb->gui_synclist_set_nb_items(&lists,view_item_count); rb->gui_synclist_select_item(&lists, 0); @@ -316,7 +315,7 @@ enum plugin_status plugin_start(const void* parameter) rb->gui_synclist_draw(&lists); cur_sel = rb->gui_synclist_get_sel_pos(&lists); button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK); - if (rb->gui_synclist_do_button(&lists,&button,LIST_WRAP_UNLESS_HELD)) + if (rb->gui_synclist_do_button(&lists, &button)) continue; switch (button) { diff --git a/apps/plugins/shortcuts/shortcuts_view.c b/apps/plugins/shortcuts/shortcuts_view.c index f4c4b58bc1..2a7970bebe 100644 --- a/apps/plugins/shortcuts/shortcuts_view.c +++ b/apps/plugins/shortcuts/shortcuts_view.c @@ -59,13 +59,8 @@ enum sc_list_action_type draw_sc_list(struct gui_synclist *gui_sc) /* user input */ button = rb->get_action(CONTEXT_LIST, HZ); /* HZ so the status bar redraws corectly */ - if (rb->gui_synclist_do_button(gui_sc, &button, - LIST_WRAP_UNLESS_HELD)) { - /* automatic handling of user input. - * _UNLESS_HELD can be _ON or _OFF also - * selection changed, so redraw */ + if (rb->gui_synclist_do_button(gui_sc, &button)) continue; - } switch (button) { /* process the user input */ case ACTION_STD_OK: return SCLA_SELECT; @@ -115,7 +110,6 @@ int list_sc(void) rb->gui_synclist_set_title(&gui_sc, (user_file?"Shortcuts (sealed)":"Shortcuts (editable)"), NOICON); rb->gui_synclist_set_nb_items(&gui_sc, sc_file.entry_cnt); - rb->gui_synclist_limit_scroll(&gui_sc, false); rb->gui_synclist_select_item(&gui_sc, 0); /* Draw the prepared widget to the LCD now */ diff --git a/apps/plugins/sliding_puzzle.c b/apps/plugins/sliding_puzzle.c index a34cb77669..33d2bb68f6 100644 --- a/apps/plugins/sliding_puzzle.c +++ b/apps/plugins/sliding_puzzle.c @@ -36,7 +36,7 @@ #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) -#define PUZZLE_QUIT (BUTTON_SELECT | BUTTON_MENU) +#define PUZZLE_QUIT (BUTTON_SELECT | BUTTON_REPEAT) #define PUZZLE_LEFT BUTTON_LEFT #define PUZZLE_RIGHT BUTTON_RIGHT #define PUZZLE_UP BUTTON_MENU @@ -468,8 +468,8 @@ static const char * initial_bmp_path=NULL; static const char * get_albumart_bmp_path(void) { struct mp3entry* track = rb->audio_current_track(); - - if (!track || !track->path || track->path[0] == '\0') + /* Note rb->audio_current_track->path should never be null */ + if (!track || track->path[0] == '\0') return NULL; if (!rb->search_albumart_files(track, "", albumart_path, MAX_PATH ) ) @@ -848,7 +848,7 @@ enum plugin_status plugin_start( #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \ (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) - rb->lcd_putsxy(0, 18, "[S-MENU] to stop"); + rb->lcd_putsxy(0, 18, "Long [SELECT] to stop"); rb->lcd_putsxy(0, 28, "[S-LEFT] shuffle"); rb->lcd_putsxy(0, 38, "[S-RIGHT] change pic"); #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ diff --git a/apps/plugins/snake.c b/apps/plugins/snake.c index 25c89b264b..359077c9fa 100644 --- a/apps/plugins/snake.c +++ b/apps/plugins/snake.c @@ -55,12 +55,12 @@ dir is the current direction of the snake - 0=up, 1=right, 2=down, 3=left; #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) -#define SNAKE_QUIT (BUTTON_SELECT|BUTTON_MENU) +#define SNAKE_QUIT (BUTTON_SELECT|BUTTON_REPEAT) #define SNAKE_LEFT BUTTON_LEFT #define SNAKE_RIGHT BUTTON_RIGHT #define SNAKE_UP BUTTON_MENU #define SNAKE_DOWN BUTTON_PLAY -#define SNAKE_PLAYPAUSE BUTTON_SELECT +#define SNAKE_PLAYPAUSE (BUTTON_SELECT|BUTTON_REL) #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD) #define SNAKE_QUIT BUTTON_POWER diff --git a/apps/plugins/snake2.c b/apps/plugins/snake2.c index 094fd854eb..7a43b235b7 100644 --- a/apps/plugins/snake2.c +++ b/apps/plugins/snake2.c @@ -181,8 +181,8 @@ Head and Tail are stored #define SNAKE2_RIGHT BUTTON_RIGHT #define SNAKE2_UP BUTTON_MENU #define SNAKE2_DOWN BUTTON_PLAY -#define SNAKE2_QUIT (BUTTON_SELECT | BUTTON_MENU) -#define SNAKE2_PLAYPAUSE BUTTON_SELECT +#define SNAKE2_QUIT (BUTTON_SELECT | BUTTON_REPEAT) +#define SNAKE2_PLAYPAUSE (BUTTON_SELECT | BUTTON_REL) #define SNAKE2_PLAYPAUSE_TEXT "Select" #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD) diff --git a/apps/plugins/snow.c b/apps/plugins/snow.c index 10b41c972b..c7d7ad31d8 100644 --- a/apps/plugins/snow.c +++ b/apps/plugins/snow.c @@ -30,8 +30,14 @@ static const struct button_mapping *plugin_contexts[] = { pla_main_ctx }; /* PLA definitions */ #define SNOW_QUIT PLA_EXIT -#define SNOW_QUIT2 PLA_CANCEL +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define SNOW_QUIT2 PLA_UP +#else +#define SNOW_QUIT2 PLA_CANCEL +#endif static short particles[NUM_PARTICLES][2]; #if LCD_WIDTH >= 160 diff --git a/apps/plugins/sokoban.c b/apps/plugins/sokoban.c index 247663a5c2..bf61db7d88 100644 --- a/apps/plugins/sokoban.c +++ b/apps/plugins/sokoban.c @@ -125,7 +125,7 @@ #define SOKOBAN_RIGHT BUTTON_RIGHT #define SOKOBAN_UP BUTTON_MENU #define SOKOBAN_DOWN BUTTON_PLAY -#define SOKOBAN_MENU (BUTTON_SELECT | BUTTON_MENU) +#define SOKOBAN_MENU (BUTTON_SELECT | BUTTON_REPEAT) #define SOKOBAN_UNDO_PRE BUTTON_SELECT #define SOKOBAN_UNDO (BUTTON_SELECT | BUTTON_REL) #define SOKOBAN_REDO (BUTTON_SELECT | BUTTON_PLAY) diff --git a/apps/plugins/solitaire.c b/apps/plugins/solitaire.c index ebc042f6db..874d872d95 100644 --- a/apps/plugins/solitaire.c +++ b/apps/plugins/solitaire.c @@ -56,7 +56,7 @@ #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) -# define SOL_QUIT (BUTTON_SELECT | BUTTON_MENU) +# define SOL_QUIT (BUTTON_SELECT | BUTTON_REPEAT) # define SOL_UP BUTTON_SCROLL_BACK # define SOL_DOWN BUTTON_SCROLL_FWD # define SOL_LEFT_PRE BUTTON_LEFT diff --git a/apps/plugins/spacerocks.c b/apps/plugins/spacerocks.c index 8203fad612..36729f8453 100644 --- a/apps/plugins/spacerocks.c +++ b/apps/plugins/spacerocks.c @@ -51,10 +51,10 @@ #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) -#define AST_PAUSE (BUTTON_SELECT | BUTTON_PLAY) -#define AST_QUIT (BUTTON_SELECT | BUTTON_MENU) -#define AST_THRUST BUTTON_MENU -#define AST_HYPERSPACE BUTTON_PLAY +#define AST_PAUSE BUTTON_PLAY +#define AST_QUIT BUTTON_MENU +#define AST_THRUST BUTTON_RIGHT +#define AST_HYPERSPACE BUTTON_LEFT #define AST_LEFT BUTTON_SCROLL_BACK #define AST_RIGHT BUTTON_SCROLL_FWD #define AST_FIRE BUTTON_SELECT @@ -259,8 +259,8 @@ #define AST_QUIT BUTTON_POWER #define AST_THRUST BUTTON_UP #define AST_HYPERSPACE BUTTON_DOWN -#define AST_LEFT BUTTON_LEFT -#define AST_RIGHT BUTTON_RIGHT +#define AST_LEFT BUTTON_SCROLL_BACK +#define AST_RIGHT BUTTON_SCROLL_FWD #define AST_FIRE BUTTON_SELECT #elif (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD) @@ -2128,10 +2128,10 @@ enum plugin_status plugin_start(const void* parameter) #endif /* universal font */ rb->lcd_setfont(FONT_SYSFIXED); -#ifdef HAVE_BACKLIGHT + /* Turn off backlight timeout */ backlight_ignore_timeout(); -#endif + highscore_load(SCORE_FILE, highscores, NUM_SCORES); rb->srand(*rb->current_tick); @@ -2143,10 +2143,9 @@ enum plugin_status plugin_start(const void* parameter) rb->lcd_setfont(FONT_UI); highscore_save(SCORE_FILE, highscores, NUM_SCORES); -#ifdef HAVE_BACKLIGHT + /* Turn on backlight timeout (revert to settings) */ backlight_use_settings(); -#endif return ret; } diff --git a/apps/plugins/speedread.c b/apps/plugins/speedread.c index 42634fb536..7a9ab61e7c 100644 --- a/apps/plugins/speedread.c +++ b/apps/plugins/speedread.c @@ -141,9 +141,9 @@ static void cleanup(void) { if(custom_font != FONT_UI) rb->font_unload(custom_font); -#ifdef HAVE_BACKLIGHT + backlight_use_settings(); -#endif + } /* returns height of drawn area */ @@ -302,9 +302,8 @@ static void begin_anim(void) static void init_drawing(void) { -#ifdef HAVE_BACKLIGHT backlight_ignore_timeout(); -#endif + atexit(cleanup); rb->lcd_set_background(OUTSIDE_COLOR); @@ -483,16 +482,19 @@ static void load_font(void) static void font_menu(void) { /* taken from text_viewer */ - struct browse_context browse; char font[MAX_PATH], name[MAX_FILENAME+10]; - rb->snprintf(name, sizeof(name), "%s.fnt", rb->global_settings->font_file); - rb->browse_context_init(&browse, SHOW_FONT, - BROWSE_SELECTONLY|BROWSE_NO_CONTEXT_MENU, - "Font", Icon_Menu_setting, FONT_DIR, name); - browse.buf = font; - browse.bufsize = sizeof(font); + struct browse_context browse = { + .dirfilter = SHOW_FONT, + .flags = BROWSE_SELECTONLY | BROWSE_NO_CONTEXT_MENU, + .title = rb->str(LANG_CUSTOM_FONT), + .icon = Icon_Menu_setting, + .root = FONT_DIR, + .selected = name, + .buf = font, + .bufsize = sizeof(font), + }; rb->rockbox_browse(&browse); diff --git a/apps/plugins/star.c b/apps/plugins/star.c index 874afc1cf1..59cefa2c15 100644 --- a/apps/plugins/star.c +++ b/apps/plugins/star.c @@ -80,7 +80,7 @@ (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) -#define STAR_QUIT (BUTTON_SELECT | BUTTON_MENU) +#define STAR_QUIT (BUTTON_SELECT | BUTTON_REPEAT) #define STAR_LEFT BUTTON_LEFT #define STAR_RIGHT BUTTON_RIGHT #define STAR_UP BUTTON_MENU @@ -91,7 +91,7 @@ #define STAR_LEVEL_DOWN (BUTTON_SELECT | BUTTON_LEFT) #define STAR_LEVEL_REPEAT (BUTTON_SELECT | BUTTON_PLAY) #define STAR_TOGGLE_CONTROL_NAME "SELECT" -#define STAR_QUIT_NAME "S + MENU" +#define STAR_QUIT_NAME "Long SELECT" #define STAR_LEVEL_UP_NAME "S >" #define STAR_LEVEL_DOWN_NAME "S <" #define STAR_LEVEL_REPEAT_NAME "S + PLAY" diff --git a/apps/plugins/starfield.c b/apps/plugins/starfield.c index 7fc400d0ee..239b7c1396 100644 --- a/apps/plugins/starfield.c +++ b/apps/plugins/starfield.c @@ -27,11 +27,21 @@ static const struct button_mapping *plugin_contexts[] = { pla_main_ctx }; /* Key assignement */ #define STARFIELD_QUIT PLA_EXIT +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define STARFIELD_QUIT2 PLA_UP +#define STARFIELD_INCREASE_ZMOVE PLA_SCROLL_FWD +#define STARFIELD_INCREASE_ZMOVE_REPEAT PLA_SCROLL_FWD_REPEAT +#define STARFIELD_DECREASE_ZMOVE PLA_SCROLL_BACK +#define STARFIELD_DECREASE_ZMOVE_REPEAT PLA_SCROLL_BACK_REPEAT +#else #define STARFIELD_QUIT2 PLA_CANCEL #define STARFIELD_INCREASE_ZMOVE PLA_UP #define STARFIELD_INCREASE_ZMOVE_REPEAT PLA_UP_REPEAT #define STARFIELD_DECREASE_ZMOVE PLA_DOWN #define STARFIELD_DECREASE_ZMOVE_REPEAT PLA_DOWN_REPEAT +#endif #define STARFIELD_INCREASE_NB_STARS PLA_RIGHT #define STARFIELD_INCREASE_NB_STARS_REPEAT PLA_RIGHT_REPEAT #define STARFIELD_DECREASE_NB_STARS PLA_LEFT @@ -324,14 +334,14 @@ enum plugin_status plugin_start(const void* parameter) int ret; (void)parameter; -#ifdef HAVE_BACKLIGHT + /* Turn off backlight timeout */ backlight_ignore_timeout(); -#endif + ret = plugin_main(); -#ifdef HAVE_BACKLIGHT + /* Turn on backlight timeout (revert to settings) */ backlight_use_settings(); -#endif + return ret; } diff --git a/apps/plugins/stats.c b/apps/plugins/stats.c index 19ccd9f452..b48259a0e4 100644 --- a/apps/plugins/stats.c +++ b/apps/plugins/stats.c @@ -29,7 +29,15 @@ static bool cancel; /* we use PLA */ #define STATS_STOP PLA_EXIT + +#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) \ + || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define STATS_STOP2 PLA_UP +#else #define STATS_STOP2 PLA_CANCEL +#endif + /* this set the context to use with PLA */ static const struct button_mapping *plugin_contexts[] = { pla_main_ctx }; @@ -149,7 +157,7 @@ static void traversedir(char* location, char* name) lasttick = *rb->current_tick; button = pluginlib_getaction(TIMEOUT_NOBLOCK, plugin_contexts, ARRAYLEN(plugin_contexts)); - if (button == STATS_STOP) { + if (button == STATS_STOP || button == STATS_STOP2) { cancel = true; break; } diff --git a/apps/plugins/superdom.c b/apps/plugins/superdom.c index 50027a30c6..6969f76165 100644 --- a/apps/plugins/superdom.c +++ b/apps/plugins/superdom.c @@ -1450,7 +1450,6 @@ static int show_inventory(void) { struct simplelist_info info; rb->simplelist_info_init(&info, "Inventory", 9, NULL); - info.hide_selection = true; info.get_name = inventory_data; if(rb->simplelist_show_list(&info)) { diff --git a/apps/plugins/test_disk.c b/apps/plugins/test_disk.c index 1429668556..fee6c4d0b0 100644 --- a/apps/plugins/test_disk.c +++ b/apps/plugins/test_disk.c @@ -467,10 +467,9 @@ enum plugin_status plugin_start(const void* parameter) rb->srand(*rb->current_tick); -#ifdef HAVE_BACKLIGHT /* Turn off backlight timeout */ backlight_ignore_timeout(); -#endif + while(!quit) { @@ -489,9 +488,8 @@ enum plugin_status plugin_start(const void* parameter) } /* Turn on backlight timeout (revert to settings) */ -#ifdef HAVE_BACKLIGHT backlight_use_settings(); -#endif + rb->rmdir(testbasedir); return PLUGIN_OK; diff --git a/apps/plugins/test_fps.c b/apps/plugins/test_fps.c index ddf938ac25..2f4e9bb13e 100644 --- a/apps/plugins/test_fps.c +++ b/apps/plugins/test_fps.c @@ -401,9 +401,9 @@ enum plugin_status plugin_start(const void* parameter) #if (CONFIG_PLATFORM & PLATFORM_NATIVE) cpu_freq = *rb->cpu_frequency; /* remember CPU frequency */ #endif -#ifdef HAVE_BACKLIGHT + backlight_ignore_timeout(); -#endif + time_main_update(); rb->sleep(HZ); #if defined(HAVE_LCD_COLOR) && (MEMORYSIZE > 2) @@ -424,9 +424,9 @@ enum plugin_status plugin_start(const void* parameter) (cpu_freq + 500000) / 1000000); log_text(str); #endif -#ifdef HAVE_BACKLIGHT + backlight_use_settings(); -#endif + /* wait until user closes plugin */ plugin_quit(); diff --git a/apps/plugins/test_gfx.c b/apps/plugins/test_gfx.c index 7734179159..60e2836463 100644 --- a/apps/plugins/test_gfx.c +++ b/apps/plugins/test_gfx.c @@ -495,9 +495,9 @@ enum plugin_status plugin_start(const void* parameter) rb->lcd_set_backdrop(NULL); rb->lcd_clear_display(); #endif -#ifdef HAVE_BACKLIGHT + backlight_ignore_timeout(); -#endif + rb->splashf(0, "LCD driver performance test, please wait %d sec", 7*4*DURATION/HZ); init_rand_table(); @@ -522,9 +522,9 @@ enum plugin_status plugin_start(const void* parameter) (cpu_freq + 500000) / 1000000); #endif rb->close(log_fd); -#ifdef HAVE_BACKLIGHT + backlight_use_settings(); -#endif + #ifdef TEST_GREYLIB grey_release(); #endif diff --git a/apps/plugins/test_grey.c b/apps/plugins/test_grey.c index 121cbad051..07fda1b9c6 100644 --- a/apps/plugins/test_grey.c +++ b/apps/plugins/test_grey.c @@ -123,9 +123,9 @@ enum plugin_status plugin_start(const void* parameter) } for (i = 0; i <= STEPS; i++) input_levels[i] = lcd_levels[i] = (255 * i + (STEPS/2)) / STEPS; -#ifdef HAVE_BACKLIGHT + backlight_ignore_timeout(); -#endif + grey_set_background(0); /* set background to black */ grey_clear_display(); grey_show(true); @@ -221,8 +221,8 @@ enum plugin_status plugin_start(const void* parameter) } grey_release(); -#ifdef HAVE_BACKLIGHT + backlight_use_settings(); -#endif + return PLUGIN_OK; } diff --git a/apps/plugins/test_usb.c b/apps/plugins/test_usb.c new file mode 100644 index 0000000000..28ef8f7e5f --- /dev/null +++ b/apps/plugins/test_usb.c @@ -0,0 +1,137 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2022 Aidan MacDonald + * + * 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" +#include "logf.h" + +#undef DEBUGF +#define DEBUGF(...) +//#define DEBUGF printf + +#define EV_EXIT MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0xFF) + +unsigned char stack[DEFAULT_STACK_SIZE]; +struct event_queue queue; +int thread_id; +const char* state = "none"; +const char* prev_state = "none"; + +static void main_loop(void) +{ + bool exiting = false; + struct queue_event ev; + + while(true) { + rb->queue_wait(&queue, &ev); + + /* events that are handled whether exiting or not */ + switch(ev.id) { + case EV_EXIT: + return; + } + + if(exiting) + continue; + + /* events handled only when not exiting */ + switch(ev.id) { + case SYS_USB_CONNECTED: + prev_state = state; + state = "connected"; + logf("test_usb: connect ack %ld", *rb->current_tick); + DEBUGF("test_usb: connect ack %ld\n", *rb->current_tick); + rb->usb_acknowledge(SYS_USB_CONNECTED_ACK); + break; + + case SYS_USB_DISCONNECTED: + prev_state = state; + state = "disconnected"; + logf("test_usb: disconnect %ld", *rb->current_tick); + DEBUGF("test_usb: disconnect %ld\n", *rb->current_tick); + break; + + case SYS_POWEROFF: + case SYS_REBOOT: + prev_state = state; + state = "exiting"; + exiting = true; + break; + } + } +} + +static void kill_tsr(void) +{ + rb->queue_post(&queue, EV_EXIT, 0); + rb->thread_wait(thread_id); + rb->queue_delete(&queue); +} + +static int exit_tsr(bool reenter) +{ + MENUITEM_STRINGLIST(menu, "USB test menu", NULL, + "Status", "Stop plugin", "Back"); + + while(true) { + int result = reenter ? rb->do_menu(&menu, NULL, NULL, false) : 1; + switch(result) { + case 0: + rb->splashf(HZ, "State: %s", state); + rb->splashf(HZ, "Prev: %s", prev_state); + break; + case 1: + rb->splashf(HZ, "Stopping USB test thread"); + kill_tsr(); + return (reenter ? PLUGIN_TSR_TERMINATE : PLUGIN_TSR_SUSPEND); + case 2: + return PLUGIN_TSR_CONTINUE; + } + } +} + +static void run_tsr(void) +{ + rb->queue_init(&queue, true); + thread_id = rb->create_thread(main_loop, stack, sizeof(stack), + 0, "test_usb TSR" + IF_PRIO(, PRIORITY_BACKGROUND) + IF_COP(, CPU)); + rb->plugin_tsr(exit_tsr); +} + +enum plugin_status plugin_start(const void* parameter) +{ + bool resume = (parameter == rb->plugin_tsr); + + MENUITEM_STRINGLIST(menu, "USB test menu", NULL, + "Start", "Quit"); + + switch(!resume ? rb->do_menu(&menu, NULL, NULL, false) : 0) { + case 0: + run_tsr(); + rb->splashf(HZ, "USB test thread started"); + return PLUGIN_OK; + case 1: + return PLUGIN_OK; + default: + return PLUGIN_ERROR; + } +} diff --git a/apps/plugins/test_viewports.c b/apps/plugins/test_viewports.c index 2bada01f79..6eff0249a2 100644 --- a/apps/plugins/test_viewports.c +++ b/apps/plugins/test_viewports.c @@ -130,7 +130,7 @@ static void *test_address_fn(int x, int y) struct frame_buffer_t *fb = vp0.buffer; /* LCD_STRIDEFORMAT & LCD_NATIVE_STRIDE macros allow Horiz screens to work with RB */ -#if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE +#if LCD_STRIDEFORMAT == VERTICAL_STRIDE size_t element = (x * LCD_NATIVE_STRIDE(fb->stride)) + y; #else size_t element = (y * LCD_NATIVE_STRIDE(fb->stride)) + x; @@ -249,9 +249,11 @@ enum plugin_status plugin_start(const void* parameter) rb->button_get(true); + rb->screens[SCREEN_MAIN]->scroll_stop(); /* Restore the default viewport */ rb->screens[SCREEN_MAIN]->set_viewport(NULL); #ifdef HAVE_REMOTE_LCD + rb->screens[SCREEN_REMOTE]->scroll_stop(); rb->screens[SCREEN_REMOTE]->set_viewport(NULL); #endif diff --git a/apps/plugins/text_editor.c b/apps/plugins/text_editor.c index 0cbb61c774..8740606c58 100644 --- a/apps/plugins/text_editor.c +++ b/apps/plugins/text_editor.c @@ -214,7 +214,6 @@ static void setup_lists(struct gui_synclist *lists, int sel) rb->gui_synclist_init(lists,list_get_name_cb,0, false, 1, NULL); rb->gui_synclist_set_icon_callback(lists,NULL); rb->gui_synclist_set_nb_items(lists,line_count); - rb->gui_synclist_limit_scroll(lists,true); rb->gui_synclist_select_item(lists, sel); rb->gui_synclist_draw(lists); } @@ -395,7 +394,7 @@ enum plugin_status plugin_start(const void* parameter) rb->gui_synclist_draw(&lists); cur_sel = rb->gui_synclist_get_sel_pos(&lists); button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK); - if (rb->gui_synclist_do_button(&lists,&button,LIST_WRAP_UNLESS_HELD)) + if (rb->gui_synclist_do_button(&lists, &button)) continue; switch (button) { diff --git a/apps/plugins/text_viewer/tv_menu.c b/apps/plugins/text_viewer/tv_menu.c index 53e0adaf67..1cc471e207 100644 --- a/apps/plugins/text_viewer/tv_menu.c +++ b/apps/plugins/text_viewer/tv_menu.c @@ -51,10 +51,9 @@ static bool tv_horizontal_scroll_mode_setting(void) } MENUITEM_FUNCTION(horizontal_scrollbar_item, 0, "Scrollbar", - tv_horizontal_scrollbar_setting, - NULL, NULL, Icon_NOICON); + tv_horizontal_scrollbar_setting, NULL, Icon_NOICON); MENUITEM_FUNCTION(horizontal_scroll_mode_item, 0, "Scroll Mode", - tv_horizontal_scroll_mode_setting, NULL, NULL, Icon_NOICON); + tv_horizontal_scroll_mode_setting, NULL, Icon_NOICON); MAKE_MENU(horizontal_scroll_menu, "Horizontal", NULL, Icon_NOICON, &horizontal_scrollbar_item, @@ -103,16 +102,14 @@ static bool tv_narrow_mode_setting(void) } MENUITEM_FUNCTION(vertical_scrollbar_item, 0, "Scrollbar", - tv_vertical_scrollbar_setting, - NULL, NULL, Icon_NOICON); + tv_vertical_scrollbar_setting, NULL, Icon_NOICON); MENUITEM_FUNCTION(vertical_scroll_mode_item, 0, "Scroll Mode", - tv_vertical_scroll_mode_setting, NULL, NULL, Icon_NOICON); -MENUITEM_FUNCTION(overlap_page_mode_item, 0, "Overlap Pages", tv_overlap_page_mode_setting, - NULL, NULL, Icon_NOICON); + tv_vertical_scroll_mode_setting, NULL, Icon_NOICON); +MENUITEM_FUNCTION(overlap_page_mode_item, 0, "Overlap Pages", tv_overlap_page_mode_setting, NULL, Icon_NOICON); MENUITEM_FUNCTION(autoscroll_speed_item, 0, "Auto-Scroll Speed", - tv_autoscroll_speed_setting, NULL, NULL, Icon_NOICON); + tv_autoscroll_speed_setting, NULL, Icon_NOICON); MENUITEM_FUNCTION(narrow_mode_item, 0, "Left/Right Key (Narrow mode)", - tv_narrow_mode_setting, NULL, NULL, Icon_NOICON); + tv_narrow_mode_setting, NULL, Icon_NOICON); MAKE_MENU(vertical_scroll_menu, "Vertical", NULL, Icon_NOICON, &vertical_scrollbar_item, @@ -203,16 +200,19 @@ static bool tv_statusbar_setting(void) static bool tv_font_setting(void) { - struct browse_context browse; char font[MAX_PATH], name[MAX_FILENAME+10]; - rb->snprintf(name, sizeof(name), "%s.fnt", new_prefs.font_name); - rb->browse_context_init(&browse, SHOW_FONT, - BROWSE_SELECTONLY|BROWSE_NO_CONTEXT_MENU, - "Font", Icon_Menu_setting, FONT_DIR, name); - browse.buf = font; - browse.bufsize = sizeof(font); + struct browse_context browse = { + .dirfilter = SHOW_FONT, + .flags = BROWSE_SELECTONLY | BROWSE_NO_CONTEXT_MENU, + .title = "Font", /* XXX: Translate? */ + .icon = Icon_Menu_setting, + .root = FONT_DIR, + .selected = name, + .buf = font, + .bufsize = sizeof(font), + }; rb->rockbox_browse(&browse); @@ -240,29 +240,29 @@ static bool tv_night_mode_setting(void) } #endif -MENUITEM_FUNCTION(encoding_item, 0, "Encoding", tv_encoding_setting, - NULL, NULL, Icon_NOICON); -MENUITEM_FUNCTION(word_wrap_item, 0, "Word Wrap", tv_word_wrap_setting, - NULL, NULL, Icon_NOICON); -MENUITEM_FUNCTION(line_mode_item, 0, "Line Mode", tv_line_mode_setting, - NULL, NULL, Icon_NOICON); -MENUITEM_FUNCTION(windows_item, 0, "Screens Per Page", tv_windows_setting, - NULL, NULL, Icon_NOICON); -MENUITEM_FUNCTION(alignment_item, 0, "Alignment", tv_alignment_setting, - NULL, NULL, Icon_NOICON); -MENUITEM_FUNCTION(header_item, 0, "Show Header", tv_header_setting, - NULL, NULL, Icon_NOICON); -MENUITEM_FUNCTION(footer_item, 0, "Show Footer", tv_footer_setting, - NULL, NULL, Icon_NOICON); -MENUITEM_FUNCTION(statusbar_item, 0, "Show Statusbar", tv_statusbar_setting, - NULL, NULL, Icon_NOICON); -MENUITEM_FUNCTION(font_item, 0, "Font", tv_font_setting, - NULL, NULL, Icon_NOICON); -MENUITEM_FUNCTION(indent_spaces_item, 0, "Indent Spaces", tv_indent_spaces_setting, - NULL, NULL, Icon_NOICON); +MENUITEM_FUNCTION(encoding_item, 0, "Encoding", + tv_encoding_setting, NULL, Icon_NOICON); +MENUITEM_FUNCTION(word_wrap_item, 0, "Word Wrap", + tv_word_wrap_setting, NULL, Icon_NOICON); +MENUITEM_FUNCTION(line_mode_item, 0, "Line Mode", + tv_line_mode_setting, NULL, Icon_NOICON); +MENUITEM_FUNCTION(windows_item, 0, "Screens Per Page", + tv_windows_setting, NULL, Icon_NOICON); +MENUITEM_FUNCTION(alignment_item, 0, "Alignment", + tv_alignment_setting, NULL, Icon_NOICON); +MENUITEM_FUNCTION(header_item, 0, "Show Header", + tv_header_setting, NULL, Icon_NOICON); +MENUITEM_FUNCTION(footer_item, 0, "Show Footer", + tv_footer_setting, NULL, Icon_NOICON); +MENUITEM_FUNCTION(statusbar_item, 0, "Show Statusbar", + tv_statusbar_setting, NULL, Icon_NOICON); +MENUITEM_FUNCTION(font_item, 0, "Font", + tv_font_setting, NULL, Icon_NOICON); +MENUITEM_FUNCTION(indent_spaces_item, 0, "Indent Spaces", + tv_indent_spaces_setting, NULL, Icon_NOICON); #ifdef HAVE_LCD_COLOR -MENUITEM_FUNCTION(night_mode_item, 0, "Night Mode", tv_night_mode_setting, - NULL, NULL, Icon_NOICON); +MENUITEM_FUNCTION(night_mode_item, 0, "Night Mode", + tv_night_mode_setting, NULL, Icon_NOICON); #endif MAKE_MENU(option_menu, "Viewer Options", NULL, Icon_NOICON, diff --git a/apps/plugins/vbrfix.c b/apps/plugins/vbrfix.c index 88f0a6579e..79fa134499 100644 --- a/apps/plugins/vbrfix.c +++ b/apps/plugins/vbrfix.c @@ -150,7 +150,7 @@ static bool vbr_fix(const char *selected_file) xingupdate(0); rc = rb->mp3info(&entry, selected_file); - if(rc < 0) { + if(rc) { fileerror(rc); return true; } @@ -258,6 +258,8 @@ static bool vbr_fix(const char *selected_file) } else { + rb->close(fd); + /* Not a VBR file */ DEBUGF("Not a VBR file\n"); rb->splash(HZ*2, ID2P(LANG_NOT_A_VBR_FILE)); diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config index 8d266966d0..c0b76d45d5 100644 --- a/apps/plugins/viewers.config +++ b/apps/plugins/viewers.config @@ -105,4 +105,5 @@ shopper,viewers/shopper,1 lnk,viewers/windows_lnk,- #ifdef HAVE_TAGCACHE *,demos/pictureflow,- +log,viewers/lastfm_scrobbler_viewer,4 #endif diff --git a/apps/plugins/vu_meter.c b/apps/plugins/vu_meter.c index 356a7fdd93..39deae6947 100644 --- a/apps/plugins/vu_meter.c +++ b/apps/plugins/vu_meter.c @@ -20,6 +20,8 @@ #include "plugin.h" #include "fixedpoint.h" #include "lib/playback_control.h" +#include "lib/helper.h" +#include "lib/pluginlib_exit.h" @@ -910,6 +912,12 @@ static void digital_meter(void) { rb->lcd_hline(0,LCD_WIDTH-1,half_height+3); } +static void vu_meter_cleanup(void) +{ + /* Turn on backlight timeout (revert to settings) */ + backlight_use_settings(); +} + enum plugin_status plugin_start(const void* parameter) { int button; #if defined(VUMETER_HELP_PRE) || defined(VUMETER_MENU_PRE) @@ -920,12 +928,17 @@ enum plugin_status plugin_start(const void* parameter) { calc_scales(); + atexit(vu_meter_cleanup); + load_settings(); rb->lcd_setfont(FONT_SYSFIXED); #ifdef HAVE_LCD_COLOR screen_foreground = rb->lcd_get_foreground(); #endif + /* Turn off backlight timeout */ + backlight_ignore_timeout(); + while (1) { rb->lcd_clear_display(); diff --git a/apps/plugins/wormlet.c b/apps/plugins/wormlet.c index 162cea6208..abdb6a4725 100644 --- a/apps/plugins/wormlet.c +++ b/apps/plugins/wormlet.c @@ -54,7 +54,7 @@ static long max_cycle; #define BTN_DIR_LEFT BUTTON_LEFT #define BTN_DIR_RIGHT BUTTON_RIGHT #define BTN_STARTPAUSE (BUTTON_SELECT|BUTTON_REL) -#define BTN_QUIT (BUTTON_SELECT|BUTTON_MENU) +#define BTN_QUIT (BUTTON_SELECT|BUTTON_REPEAT) #define BTN_STOPRESET (BUTTON_SELECT|BUTTON_PLAY) #elif (CONFIG_KEYPAD == IRIVER_H300_PAD) || (CONFIG_KEYPAD == IRIVER_H100_PAD) @@ -2428,10 +2428,9 @@ static bool launch_wormlet(void) rb->lcd_clear_display(); -#ifdef HAVE_BACKLIGHT /* Turn off backlight timeout */ backlight_ignore_timeout(); -#endif + /* start the game */ while (game_result == 1) game_result = run(); @@ -2439,10 +2438,10 @@ static bool launch_wormlet(void) switch (game_result) { case 2: -#ifdef HAVE_BACKLIGHT + /* Turn on backlight timeout (revert to settings) */ backlight_use_settings(); -#endif + return false; break; } diff --git a/apps/plugins/xobox.c b/apps/plugins/xobox.c index b8b1964db4..336d92bd4e 100644 --- a/apps/plugins/xobox.c +++ b/apps/plugins/xobox.c @@ -42,10 +42,10 @@ (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) -#define QUIT (BUTTON_SELECT | BUTTON_MENU) +#define QUIT (BUTTON_SELECT | BUTTON_REPEAT) #define LEFT BUTTON_LEFT #define RIGHT BUTTON_RIGHT -#define PAUSE BUTTON_SELECT +#define PAUSE (BUTTON_SELECT | BUTTON_REL) #define MENU_UP BUTTON_SCROLL_FWD #define MENU_DOWN BUTTON_SCROLL_BACK #define UP BUTTON_MENU @@ -1297,10 +1297,9 @@ enum plugin_status plugin_start (const void *parameter) rb->lcd_set_backdrop(NULL); #endif -#ifdef HAVE_BACKLIGHT /* Turn off backlight timeout */ backlight_ignore_timeout(); -#endif + highscore_load(SCORE_FILE, highscores, NUM_SCORES); if (!load_game()) { @@ -1310,10 +1309,10 @@ enum plugin_status plugin_start (const void *parameter) randomize (); ret = xobox_loop (); -#ifdef HAVE_BACKLIGHT + /* Turn on backlight timeout (revert to settings) */ backlight_use_settings(); -#endif + rb->lcd_setfont (FONT_UI); highscore_save(SCORE_FILE, highscores, NUM_SCORES); diff --git a/apps/plugins/xworld/engine.c b/apps/plugins/xworld/engine.c index b09e320078..d99d9df6c6 100644 --- a/apps/plugins/xworld/engine.c +++ b/apps/plugins/xworld/engine.c @@ -293,7 +293,7 @@ void engine_processInput(struct Engine* e) { e->sys->input.save = false; } if (e->sys->input.fastMode) { - e->vm._fastMode = !&e->vm._fastMode; + e->vm._fastMode = !e->vm._fastMode; e->sys->input.fastMode = false; } if (e->sys->input.stateSlot != 0) { diff --git a/apps/plugins/xworld/sys.c b/apps/plugins/xworld/sys.c index c57da9456b..e20322258d 100644 --- a/apps/plugins/xworld/sys.c +++ b/apps/plugins/xworld/sys.c @@ -122,9 +122,8 @@ void exit_handler(void) #ifdef HAVE_ADJUSTABLE_CPU_FREQ rb->cpu_boost(false); #endif -#ifdef HAVE_BACKLIGHT + backlight_use_settings(); -#endif } static bool sys_do_help(void) @@ -287,7 +286,7 @@ static void do_sound_settings(struct System* sys) case 2: { const struct settings_list* vol = - rb->find_setting(&rb->global_settings->volume, NULL); + rb->find_setting(&rb->global_settings->volume); rb->option_screen((struct settings_list*)vol, NULL, false, "Volume"); break; } @@ -428,9 +427,8 @@ void sys_menu(struct System* sys) void sys_init(struct System* sys, const char* title) { (void) title; -#ifdef HAVE_BACKLIGHT + backlight_ignore_timeout(); -#endif rb_atexit(exit_handler); save_sys = sys; rb->memset(&sys->input, 0, sizeof(sys->input)); @@ -496,7 +494,7 @@ void sys_copyRect(struct System* sys, uint16_t x, uint16_t y, uint16_t w, uint16 for (int i = 0; i < w / 2; ++i) { uint8_t pix1 = *(buf + i) >> 4; uint8_t pix2 = *(buf + i) & 0xF; -#if defined(LCD_STRIDEFORMAT) && (LCD_STRIDEFORMAT == VERTICAL_STRIDE) +#if LCD_STRIDEFORMAT == VERTICAL_STRIDE framebuffer[( (h * 2) ) * 320 + i] = sys->palette[pix1]; framebuffer[( (h * 2) + 1) * 320 + i] = sys->palette[pix2]; #else @@ -515,7 +513,7 @@ void sys_copyRect(struct System* sys, uint16_t x, uint16_t y, uint16_t w, uint16 for (int i = 0; i < w / 2; ++i) { uint8_t pix1 = *(buf + i) >> 4; uint8_t pix2 = *(buf + i) & 0xF; -#if defined(LCD_STRIDEFORMAT) && (LCD_STRIDEFORMAT == VERTICAL_STRIDE) +#if LCD_STRIDEFORMAT == VERTICAL_STRIDE framebuffer[(200 - h * 2 ) * 320 + ( 320 - i )] = sys->palette[pix1]; framebuffer[(200 - h * 2 - 1) * 320 + ( 320 - i )] = sys->palette[pix2]; #else @@ -531,7 +529,7 @@ void sys_copyRect(struct System* sys, uint16_t x, uint16_t y, uint16_t w, uint16 else { int next = 0; -#if defined(LCD_STRIDEFORMAT) && (LCD_STRIDEFORMAT == VERTICAL_STRIDE) +#if LCD_STRIDEFORMAT == VERTICAL_STRIDE for(int x = 0; x < w / 2; ++x) { for(int y = 0; y < h; ++y) @@ -565,7 +563,7 @@ void sys_copyRect(struct System* sys, uint16_t x, uint16_t y, uint16_t w, uint16 struct bitmap in_bmp; if(sys->settings.rotation_option) { -#if defined(LCD_STRIDEFORMAT) && (LCD_STRIDEFORMAT == VERTICAL_STRIDE) +#if LCD_STRIDEFORMAT == VERTICAL_STRIDE in_bmp.width = 320; in_bmp.height = 200; #else @@ -575,7 +573,7 @@ void sys_copyRect(struct System* sys, uint16_t x, uint16_t y, uint16_t w, uint16 } else { -#if defined(LCD_STRIDEFORMAT) && (LCD_STRIDEFORMAT == VERTICAL_STRIDE) +#if LCD_STRIDEFORMAT == VERTICAL_STRIDE in_bmp.width = 200; in_bmp.height = 320; #else @@ -600,7 +598,7 @@ void sys_copyRect(struct System* sys, uint16_t x, uint16_t y, uint16_t w, uint16 } else { -#if defined(LCD_STRIDEFORMAT) && (LCD_STRIDEFORMAT == VERTICAL_STRIDE) +#if LCD_STRIDEFORMAT == VERTICAL_STRIDE for(int x = 0; x < 320; ++x) { for(int y = 0; y < 200; ++y) |