diff options
Diffstat (limited to 'apps/onplay.c')
-rw-r--r-- | apps/onplay.c | 1039 |
1 files changed, 440 insertions, 599 deletions
diff --git a/apps/onplay.c b/apps/onplay.c index d72f592f2e..ba06d13183 100644 --- a/apps/onplay.c +++ b/apps/onplay.c @@ -63,12 +63,16 @@ #include "viewport.h" #include "pathfuncs.h" #include "shortcuts.h" +#include "misc.h" static int context; static const char *selected_file = NULL; static char selected_file_path[MAX_PATH]; static int selected_file_attr = 0; static int onplay_result = ONPLAY_OK; +static bool in_queue_submenu = false; +static bool (*ctx_current_playlist_insert)(int position, bool queue, bool create_new); +static int (*ctx_add_to_playlist)(const char* playlist, bool new_playlist); extern struct menu_item_ex file_menu; /* settings_menu.c */ /* redefine MAKE_MENU so the MENU_EXITAFTERTHISMENU flag can be added easily */ @@ -125,8 +129,8 @@ static bool clipboard_clip(struct clipboard *clip, const char *path, unsigned int attr, unsigned int flags) { /* if it fits it clips */ - if (strlcpy(clip->path, path, sizeof (clip->path)) - < sizeof (clip->path)) { + if (strmemccpy(clip->path, path, sizeof (clip->path)) != NULL) + { clip->attr = attr; clip->flags = flags; return true; @@ -142,16 +146,25 @@ static bool clipboard_clip(struct clipboard *clip, const char *path, /* interface function. */ /* ----------------------------------------------------------------------- */ + +static int bookmark_load_menu_wrapper(void) +{ + if (get_current_activity() == ACTIVITY_CONTEXTMENU) /* get rid of parent activity */ + pop_current_activity_without_refresh(); /* when called from ctxt menu */ + + return bookmark_load_menu(); +} + static int bookmark_menu_callback(int action, const struct menu_item_ex *this_item, struct gui_synclist *this_list); MENUITEM_FUNCTION(bookmark_create_menu_item, 0, ID2P(LANG_BOOKMARK_MENU_CREATE), - bookmark_create_menu, NULL, + bookmark_create_menu, bookmark_menu_callback, Icon_Bookmark); MENUITEM_FUNCTION(bookmark_load_menu_item, 0, ID2P(LANG_BOOKMARK_MENU_LIST), - bookmark_load_menu, NULL, + bookmark_load_menu_wrapper, bookmark_menu_callback, Icon_Bookmark); MAKE_ONPLAYMENU(bookmark_menu, ID2P(LANG_BOOKMARK_MENU), bookmark_menu_callback, Icon_Bookmark, @@ -187,261 +200,6 @@ static int bookmark_menu_callback(int action, return action; } -/* playing_time screen context */ -struct playing_time_info { - int curr_playing; /* index of currently playing track in playlist */ - int nb_tracks; /* how many tracks in playlist */ - /* seconds before and after current position, and total. Datatype - allows for values up to 68years. If I had kept it in ms - though, it would have overflowed at 24days, which takes - something like 8.5GB at 32kbps, and so we could conceivably - have playlists lasting longer than that. */ - long secs_bef, secs_aft, secs_ttl; - long trk_secs_bef, trk_secs_aft, trk_secs_ttl; - /* kilobytes played before and after current pos, and total. - Kilobytes because bytes would overflow. Data type range is up - to 2TB. */ - long kbs_bef, kbs_aft, kbs_ttl; -}; - -/* list callback for playing_time screen */ -static const char * playing_time_get_or_speak_info(int selected_item, void * data, - char *buf, size_t buffer_len, - bool say_it) -{ - struct playing_time_info *pti = (struct playing_time_info *)data; - switch(selected_item) { - case 0: { /* elapsed and total time */ - char timestr1[25], timestr2[25]; - format_time_auto(timestr1, sizeof(timestr1), pti->secs_bef, - UNIT_SEC, false); - format_time_auto(timestr2, sizeof(timestr2), pti->secs_ttl, - UNIT_SEC, false); - long elapsed_perc; /* percentage of duration elapsed */ - if (pti->secs_ttl == 0) - elapsed_perc = 0; - else if (pti->secs_ttl <= 0xFFFFFF) - elapsed_perc = pti->secs_bef *100 / pti->secs_ttl; - else /* sacrifice some precision to avoid overflow */ - elapsed_perc = (pti->secs_bef>>7) *100 /(pti->secs_ttl>>7); - snprintf(buf, buffer_len, str(LANG_PLAYTIME_ELAPSED), - timestr1, timestr2, elapsed_perc); - if (say_it) - talk_ids(false, LANG_PLAYTIME_ELAPSED, - TALK_ID(pti->secs_bef, UNIT_TIME), - VOICE_OF, - TALK_ID(pti->secs_ttl, UNIT_TIME), - VOICE_PAUSE, - TALK_ID(elapsed_perc, UNIT_PERCENT)); - break; - } - case 1: { /* playlist remaining time */ - char timestr[25]; - format_time_auto(timestr, sizeof(timestr), pti->secs_aft, - UNIT_SEC, false); - snprintf(buf, buffer_len, str(LANG_PLAYTIME_REMAINING), - timestr); - if (say_it) - talk_ids(false, LANG_PLAYTIME_REMAINING, - TALK_ID(pti->secs_aft, UNIT_TIME)); - break; - } - case 2: { /* track elapsed and duration */ - char timestr1[25], timestr2[25]; - format_time_auto(timestr1, sizeof(timestr1), pti->trk_secs_bef, - UNIT_SEC, false); - format_time_auto(timestr2, sizeof(timestr2), pti->trk_secs_ttl, - UNIT_SEC, false); - long elapsed_perc; /* percentage of duration elapsed */ - if (pti->trk_secs_ttl == 0) - elapsed_perc = 0; - else if (pti->trk_secs_ttl <= 0xFFFFFF) - elapsed_perc = pti->trk_secs_bef *100 / pti->trk_secs_ttl; - else /* sacrifice some precision to avoid overflow */ - elapsed_perc = (pti->trk_secs_bef>>7) *100 /(pti->trk_secs_ttl>>7); - snprintf(buf, buffer_len, str(LANG_PLAYTIME_TRK_ELAPSED), - timestr1, timestr2, elapsed_perc); - if (say_it) - talk_ids(false, LANG_PLAYTIME_TRK_ELAPSED, - TALK_ID(pti->trk_secs_bef, UNIT_TIME), - VOICE_OF, - TALK_ID(pti->trk_secs_ttl, UNIT_TIME), - VOICE_PAUSE, - TALK_ID(elapsed_perc, UNIT_PERCENT)); - break; - } - case 3: { /* track remaining time */ - char timestr[25]; - format_time_auto(timestr, sizeof(timestr), pti->trk_secs_aft, - UNIT_SEC, false); - snprintf(buf, buffer_len, str(LANG_PLAYTIME_TRK_REMAINING), - timestr); - if (say_it) - talk_ids(false, LANG_PLAYTIME_TRK_REMAINING, - TALK_ID(pti->trk_secs_aft, UNIT_TIME)); - break; - } - case 4: { /* track index */ - int track_perc = (pti->curr_playing+1) *100 / pti->nb_tracks; - snprintf(buf, buffer_len, str(LANG_PLAYTIME_TRACK), - pti->curr_playing + 1, pti->nb_tracks, track_perc); - if (say_it) - talk_ids(false, LANG_PLAYTIME_TRACK, - TALK_ID(pti->curr_playing+1, UNIT_INT), - VOICE_OF, - TALK_ID(pti->nb_tracks, UNIT_INT), - VOICE_PAUSE, - TALK_ID(track_perc, UNIT_PERCENT)); - break; - } - case 5: { /* storage size */ - char str1[10], str2[10], str3[10]; - output_dyn_value(str1, sizeof(str1), pti->kbs_ttl, kibyte_units, 3, true); - output_dyn_value(str2, sizeof(str2), pti->kbs_bef, kibyte_units, 3, true); - output_dyn_value(str3, sizeof(str3), pti->kbs_aft, kibyte_units, 3, true); - snprintf(buf, buffer_len, str(LANG_PLAYTIME_STORAGE), - str1,str2,str3); - if (say_it) { - talk_id(LANG_PLAYTIME_STORAGE, false); - output_dyn_value(NULL, 0, pti->kbs_ttl, kibyte_units, 3, true); - talk_ids(true, VOICE_PAUSE, VOICE_PLAYTIME_DONE); - output_dyn_value(NULL, 0, pti->kbs_bef, kibyte_units, 3, true); - talk_id(LANG_PLAYTIME_REMAINING, true); - output_dyn_value(NULL, 0, pti->kbs_aft, kibyte_units, 3, true); - } - break; - } - case 6: { /* Average track file size */ - char str[10]; - long avg_track_size = pti->kbs_ttl /pti->nb_tracks; - output_dyn_value(str, sizeof(str), avg_track_size, kibyte_units, 3, true); - snprintf(buf, buffer_len, str(LANG_PLAYTIME_AVG_TRACK_SIZE), - str); - if (say_it) { - talk_id(LANG_PLAYTIME_AVG_TRACK_SIZE, false); - output_dyn_value(NULL, 0, avg_track_size, kibyte_units, 3, true); - } - break; - } - case 7: { /* Average bitrate */ - /* Convert power of 2 kilobytes to power of 10 kilobits */ - long avg_bitrate = pti->kbs_ttl / pti->secs_ttl *1024 *8 /1000; - snprintf(buf, buffer_len, str(LANG_PLAYTIME_AVG_BITRATE), - avg_bitrate); - if (say_it) - talk_ids(false, LANG_PLAYTIME_AVG_BITRATE, - TALK_ID(avg_bitrate, UNIT_KBIT)); - break; - } - } - return buf; -} - -static const char * playing_time_get_info(int selected_item, void * data, - char *buffer, size_t buffer_len) -{ - return playing_time_get_or_speak_info(selected_item, data, - buffer, buffer_len, false); -} - -static int playing_time_speak_info(int selected_item, void * data) -{ - static char buffer[MAX_PATH]; - playing_time_get_or_speak_info(selected_item, data, - buffer, MAX_PATH, true); - return 0; -} - -/* playing time screen: shows total and elapsed playlist duration and - other stats */ -static bool playing_time(void) -{ - unsigned long talked_tick = current_tick; - struct playing_time_info pti; - struct playlist_track_info pltrack; - struct mp3entry id3; - int i, fd, ret; - - pti.nb_tracks = playlist_amount(); - playlist_get_resume_info(&pti.curr_playing); - struct mp3entry *curr_id3 = audio_current_track(); - if (pti.curr_playing == -1 || !curr_id3) - return false; - pti.secs_bef = pti.trk_secs_bef = curr_id3->elapsed/1000; - pti.secs_aft = pti.trk_secs_aft - = (curr_id3->length -curr_id3->elapsed)/1000; - pti.kbs_bef = curr_id3->offset/1024; - pti.kbs_aft = (curr_id3->filesize -curr_id3->offset)/1024; - - splash(0, ID2P(LANG_WAIT)); - - /* Go through each file in the playlist and get its stats. For - huge playlists this can take a while... The reference position - is the position at the moment this function was invoked, - although playback continues forward. */ - for (i = 0; i < pti.nb_tracks; i++) { - /* Show a splash while we are loading. */ - splashf(0, str(LANG_LOADING_PERCENT), - i*100/pti.nb_tracks, str(LANG_OFF_ABORT)); - /* Voice equivalent */ - if (TIME_AFTER(current_tick, talked_tick+5*HZ)) { - talked_tick = current_tick; - talk_ids(false, LANG_LOADING_PERCENT, - TALK_ID(i*100/pti.nb_tracks, UNIT_PERCENT)); - } - if (action_userabort(TIMEOUT_NOBLOCK)) - goto exit; - - if (i == pti.curr_playing) - continue; - - if (playlist_get_track_info(NULL, i, &pltrack) < 0) - goto error; - if ((fd = open(pltrack.filename, O_RDONLY)) < 0) - goto error; - ret = get_metadata(&id3, fd, pltrack.filename); - close(fd); - if (!ret) - goto error; - - if (i < pti.curr_playing) { - pti.secs_bef += id3.length/1000; - pti.kbs_bef += id3.filesize/1024; - } else { - pti.secs_aft += id3.length/1000; - pti.kbs_aft += id3.filesize/1024; - } - } - - pti.secs_ttl = pti.secs_bef +pti.secs_aft; - pti.trk_secs_ttl = pti.trk_secs_bef +pti.trk_secs_aft; - pti.kbs_ttl = pti.kbs_bef +pti.kbs_aft; - - struct gui_synclist pt_lists; - int key; - - gui_synclist_init(&pt_lists, &playing_time_get_info, &pti, true, 1, NULL); - if (global_settings.talk_menu) - gui_synclist_set_voice_callback(&pt_lists, playing_time_speak_info); - gui_synclist_set_nb_items(&pt_lists, 8); - gui_synclist_draw(&pt_lists); -/* gui_syncstatusbar_draw(&statusbars, true); */ - gui_synclist_speak_item(&pt_lists); - while (true) { -/* gui_syncstatusbar_draw(&statusbars, false); */ - if (list_do_action(CONTEXT_LIST, HZ/2, - &pt_lists, &key, LIST_WRAP_UNLESS_HELD) == 0 - && key!=ACTION_NONE && key!=ACTION_UNKNOWN) - { - talk_force_shutup(); - return(default_event_handler(key) == SYS_USB_CONNECTED); - } - } - error: - splash(HZ, ID2P(LANG_PLAYTIME_ERROR)); - exit: - return false; -} /* CONTEXT_WPS playlist options */ @@ -451,40 +209,83 @@ static bool shuffle_playlist(void) return false; playlist_sort(NULL, true); playlist_randomise(NULL, current_tick, true); + playlist_set_modified(NULL, true); return false; } + static bool save_playlist(void) { + /* save_playlist_screen should load the newly saved playlist and resume */ save_playlist_screen(NULL); return false; } -extern struct menu_item_ex view_cur_playlist; /* from playlist_menu.c */ +static int wps_view_cur_playlist(void) +{ + if (get_current_activity() == ACTIVITY_CONTEXTMENU) /* get rid of parent activity */ + pop_current_activity_without_refresh(); /* when called from ctxt menu */ + + playlist_viewer_ex(NULL, NULL); + + return 0; +} + +static void playing_time(void) +{ + plugin_load(PLUGIN_APPS_DIR"/playing_time.rock", NULL); +} + +MENUITEM_FUNCTION(wps_view_cur_playlist_item, 0, ID2P(LANG_VIEW_DYNAMIC_PLAYLIST), + wps_view_cur_playlist, NULL, Icon_NOICON); MENUITEM_FUNCTION(search_playlist_item, 0, ID2P(LANG_SEARCH_IN_PLAYLIST), - search_playlist, NULL, NULL, Icon_Playlist); + search_playlist, NULL, Icon_Playlist); MENUITEM_FUNCTION(playlist_save_item, 0, ID2P(LANG_SAVE_DYNAMIC_PLAYLIST), - save_playlist, NULL, NULL, Icon_Playlist); + save_playlist, NULL, Icon_Playlist); MENUITEM_FUNCTION(reshuffle_item, 0, ID2P(LANG_SHUFFLE_PLAYLIST), - shuffle_playlist, NULL, NULL, Icon_Playlist); + shuffle_playlist, NULL, Icon_Playlist); MENUITEM_FUNCTION(playing_time_item, 0, ID2P(LANG_PLAYING_TIME), - playing_time, NULL, NULL, Icon_Playlist); -MAKE_ONPLAYMENU( wps_playlist_menu, ID2P(LANG_PLAYLIST), + playing_time, NULL, Icon_Playlist); +MAKE_ONPLAYMENU( wps_playlist_menu, ID2P(LANG_CURRENT_PLAYLIST), NULL, Icon_Playlist, - &view_cur_playlist, &search_playlist_item, + &wps_view_cur_playlist_item, &search_playlist_item, &playlist_save_item, &reshuffle_item, &playing_time_item ); -/* CONTEXT_[TREE|ID3DB] playlist options */ -static bool add_to_playlist(int position, bool queue) +/* argument for add_to_playlist (for use by menu callbacks) */ +struct add_to_pl_param { - bool new_playlist = false; - if (!(audio_status() & AUDIO_STATUS_PLAY)) - { - new_playlist = true; - if (position == PLAYLIST_REPLACE) - position = PLAYLIST_INSERT; - } + int8_t position; + unsigned int queue: 1; + unsigned int replace: 1; +}; + +static struct add_to_pl_param addtopl_insert = {PLAYLIST_INSERT, 0, 0}; +static struct add_to_pl_param addtopl_insert_first = {PLAYLIST_INSERT_FIRST, 0, 0}; +static struct add_to_pl_param addtopl_insert_last = {PLAYLIST_INSERT_LAST, 0, 0}; +static struct add_to_pl_param addtopl_insert_shuf = {PLAYLIST_INSERT_SHUFFLED, 0, 0}; +static struct add_to_pl_param addtopl_insert_last_shuf = {PLAYLIST_INSERT_LAST_SHUFFLED, 0, 0}; + +static struct add_to_pl_param addtopl_queue = {PLAYLIST_INSERT, 1, 0}; +static struct add_to_pl_param addtopl_queue_first = {PLAYLIST_INSERT_FIRST, 1, 0}; +static struct add_to_pl_param addtopl_queue_last = {PLAYLIST_INSERT_LAST, 1, 0}; +static struct add_to_pl_param addtopl_queue_shuf = {PLAYLIST_INSERT_SHUFFLED, 1, 0}; +static struct add_to_pl_param addtopl_queue_last_shuf = {PLAYLIST_INSERT_LAST_SHUFFLED, 1, 0}; + +static struct add_to_pl_param addtopl_replace = {PLAYLIST_INSERT, 0, 1}; +static struct add_to_pl_param addtopl_replace_shuffled = {PLAYLIST_INSERT_LAST_SHUFFLED, 0, 1}; + +/* CONTEXT_[TREE|ID3DB|STD] playlist options */ +static int add_to_playlist(void* arg) +{ + struct add_to_pl_param* param = arg; + int position = param->position; + bool new_playlist = !!param->replace; + bool queue = !!param->queue; + + /* warn if replacing the playlist */ + if (new_playlist && !warn_on_pl_erase()) + return 0; const char *lines[] = { ID2P(LANG_RECURSE_DIRECTORY_QUESTION), @@ -494,6 +295,15 @@ static bool add_to_playlist(int position, bool queue) splash(0, ID2P(LANG_WAIT)); + if (new_playlist && global_settings.keep_current_track_on_replace_playlist) + { + if (audio_status() & AUDIO_STATUS_PLAY) + { + playlist_remove_all_tracks(NULL); + new_playlist = false; + } + } + if (new_playlist) playlist_create(NULL, NULL); @@ -507,9 +317,13 @@ static bool add_to_playlist(int position, bool queue) } #ifdef HAVE_TAGCACHE - if (context == CONTEXT_ID3DB) + if ((context == CONTEXT_ID3DB) && (selected_file_attr & ATTR_DIRECTORY)) + { + tagtree_current_playlist_insert(position, queue); + } + else if (context == CONTEXT_STD && ctx_current_playlist_insert != NULL) { - tagtree_insert_selection_playlist(position, queue); + ctx_current_playlist_insert(position, queue, false); } else #endif @@ -545,17 +359,17 @@ static bool add_to_playlist(int position, bool queue) onplay_result = ONPLAY_START_PLAY; } + playlist_set_modified(NULL, true); return false; } static bool view_playlist(void) { - bool was_playing = audio_status() & AUDIO_STATUS_PLAY; bool result; - result = playlist_viewer_ex(selected_file); + result = playlist_viewer_ex(selected_file, NULL); - if (!was_playing && (audio_status() & AUDIO_STATUS_PLAY) && + if (result == PLAYLIST_VIEWER_OK && onplay_result == ONPLAY_OK) /* playlist was started from viewer */ onplay_result = ONPLAY_START_PLAY; @@ -563,136 +377,74 @@ static bool view_playlist(void) return result; } -static int playlist_insert_func(void *param) -{ - if (((intptr_t)param == PLAYLIST_REPLACE || - ((intptr_t)param == PLAYLIST_INSERT_SHUFFLED && !(audio_status() & AUDIO_STATUS_PLAY))) && - !warn_on_pl_erase()) - return 0; - add_to_playlist((intptr_t)param, false); - return 0; -} - -static int playlist_queue_func(void *param) -{ - add_to_playlist((intptr_t)param, true); - return 0; -} - -static int treeplaylist_wplayback_callback(int action, - const struct menu_item_ex* this_item, - struct gui_synclist *this_list); - static int treeplaylist_callback(int action, const struct menu_item_ex *this_item, struct gui_synclist *this_list); /* insert items */ -MENUITEM_FUNCTION(i_pl_item, MENU_FUNC_USEPARAM, ID2P(LANG_INSERT), - playlist_insert_func, (intptr_t*)PLAYLIST_INSERT, - treeplaylist_wplayback_callback, Icon_Playlist); -MENUITEM_FUNCTION(i_first_pl_item, MENU_FUNC_USEPARAM, ID2P(LANG_INSERT_FIRST), - playlist_insert_func, (intptr_t*)PLAYLIST_INSERT_FIRST, - treeplaylist_wplayback_callback, Icon_Playlist); -MENUITEM_FUNCTION(i_last_pl_item, MENU_FUNC_USEPARAM, ID2P(LANG_INSERT_LAST), - playlist_insert_func, (intptr_t*)PLAYLIST_INSERT_LAST, - treeplaylist_wplayback_callback, Icon_Playlist); -MENUITEM_FUNCTION(i_shuf_pl_item, MENU_FUNC_USEPARAM, - ID2P(LANG_INSERT_SHUFFLED), playlist_insert_func, - (intptr_t*)PLAYLIST_INSERT_SHUFFLED, +MENUITEM_FUNCTION_W_PARAM(i_pl_item, 0, ID2P(LANG_ADD), + add_to_playlist, &addtopl_insert, treeplaylist_callback, Icon_Playlist); -MENUITEM_FUNCTION(i_last_shuf_pl_item, MENU_FUNC_USEPARAM, - ID2P(LANG_INSERT_LAST_SHUFFLED), playlist_insert_func, - (intptr_t*)PLAYLIST_INSERT_LAST_SHUFFLED, +MENUITEM_FUNCTION_W_PARAM(i_first_pl_item, 0, ID2P(LANG_PLAY_NEXT), + add_to_playlist, &addtopl_insert_first, treeplaylist_callback, Icon_Playlist); -/* queue items */ -MENUITEM_FUNCTION(q_pl_item, MENU_FUNC_USEPARAM, ID2P(LANG_QUEUE), - playlist_queue_func, (intptr_t*)PLAYLIST_INSERT, +MENUITEM_FUNCTION_W_PARAM(i_last_pl_item, 0, ID2P(LANG_PLAY_LAST), + add_to_playlist, &addtopl_insert_last, + treeplaylist_callback, Icon_Playlist); +MENUITEM_FUNCTION_W_PARAM(i_shuf_pl_item, 0, ID2P(LANG_ADD_SHUFFLED), + add_to_playlist, &addtopl_insert_shuf, treeplaylist_callback, Icon_Playlist); -MENUITEM_FUNCTION(q_first_pl_item, MENU_FUNC_USEPARAM, ID2P(LANG_QUEUE_FIRST), - playlist_queue_func, (intptr_t*)PLAYLIST_INSERT_FIRST, +MENUITEM_FUNCTION_W_PARAM(i_last_shuf_pl_item, 0, ID2P(LANG_PLAY_LAST_SHUFFLED), + add_to_playlist, &addtopl_insert_last_shuf, treeplaylist_callback, Icon_Playlist); -MENUITEM_FUNCTION(q_last_pl_item, MENU_FUNC_USEPARAM, ID2P(LANG_QUEUE_LAST), - playlist_queue_func, (intptr_t*)PLAYLIST_INSERT_LAST, +/* queue items */ +MENUITEM_FUNCTION_W_PARAM(q_pl_item, 0, ID2P(LANG_QUEUE), + add_to_playlist, &addtopl_queue, treeplaylist_callback, Icon_Playlist); -MENUITEM_FUNCTION(q_shuf_pl_item, MENU_FUNC_USEPARAM, - ID2P(LANG_QUEUE_SHUFFLED), playlist_queue_func, - (intptr_t*)PLAYLIST_INSERT_SHUFFLED, +MENUITEM_FUNCTION_W_PARAM(q_first_pl_item, 0, ID2P(LANG_QUEUE_FIRST), + add_to_playlist, &addtopl_queue_first, treeplaylist_callback, Icon_Playlist); -MENUITEM_FUNCTION(q_last_shuf_pl_item, MENU_FUNC_USEPARAM, - ID2P(LANG_QUEUE_LAST_SHUFFLED), playlist_queue_func, - (intptr_t*)PLAYLIST_INSERT_LAST_SHUFFLED, +MENUITEM_FUNCTION_W_PARAM(q_last_pl_item, 0, ID2P(LANG_QUEUE_LAST), + add_to_playlist, &addtopl_queue_last, treeplaylist_callback, Icon_Playlist); - -/* queue items in submenu */ -MENUITEM_FUNCTION(q_pl_submenu_item, MENU_FUNC_USEPARAM, ID2P(LANG_QUEUE), - playlist_queue_func, (intptr_t*)PLAYLIST_INSERT, - NULL, Icon_Playlist); -MENUITEM_FUNCTION(q_first_pl_submenu_item, MENU_FUNC_USEPARAM, ID2P(LANG_QUEUE_FIRST), - playlist_queue_func, (intptr_t*)PLAYLIST_INSERT_FIRST, - NULL, Icon_Playlist); -MENUITEM_FUNCTION(q_last_pl_submenu_item, MENU_FUNC_USEPARAM, ID2P(LANG_QUEUE_LAST), - playlist_queue_func, (intptr_t*)PLAYLIST_INSERT_LAST, - NULL, Icon_Playlist); -MENUITEM_FUNCTION(q_shuf_pl_submenu_item, MENU_FUNC_USEPARAM, - ID2P(LANG_QUEUE_SHUFFLED), playlist_queue_func, - (intptr_t*)PLAYLIST_INSERT_SHUFFLED, +MENUITEM_FUNCTION_W_PARAM(q_shuf_pl_item, 0, ID2P(LANG_QUEUE_SHUFFLED), + add_to_playlist, &addtopl_queue_shuf, treeplaylist_callback, Icon_Playlist); -MENUITEM_FUNCTION(q_last_shuf_pl_submenu_item, MENU_FUNC_USEPARAM, - ID2P(LANG_QUEUE_LAST_SHUFFLED), playlist_queue_func, - (intptr_t*)PLAYLIST_INSERT_LAST_SHUFFLED, +MENUITEM_FUNCTION_W_PARAM(q_last_shuf_pl_item, 0, ID2P(LANG_QUEUE_LAST_SHUFFLED), + add_to_playlist, &addtopl_queue_last_shuf, treeplaylist_callback, Icon_Playlist); +/* queue submenu */ MAKE_ONPLAYMENU(queue_menu, ID2P(LANG_QUEUE_MENU), - treeplaylist_wplayback_callback, Icon_Playlist, - &q_pl_submenu_item, - &q_first_pl_submenu_item, - &q_last_pl_submenu_item, - &q_shuf_pl_submenu_item, - &q_last_shuf_pl_submenu_item); - -static int treeplaylist_wplayback_callback(int action, - const struct menu_item_ex* this_item, - struct gui_synclist *this_list) -{ - (void)this_list; - switch (action) - { - case ACTION_REQUEST_MENUITEM: - if ((audio_status() & AUDIO_STATUS_PLAY) && - (this_item != &queue_menu || - global_settings.show_queue_options == QUEUE_SHOW_IN_SUBMENU)) - return action; - else - return ACTION_EXIT_MENUITEM; - break; - } - return action; -} + treeplaylist_callback, Icon_Playlist, + &q_first_pl_item, + &q_pl_item, + &q_shuf_pl_item, + &q_last_pl_item, + &q_last_shuf_pl_item); /* replace playlist */ -MENUITEM_FUNCTION(replace_pl_item, MENU_FUNC_USEPARAM, ID2P(LANG_CLEAR_LIST_AND_PLAY_NEXT), - playlist_insert_func, (intptr_t*)PLAYLIST_REPLACE, - NULL, Icon_Playlist); +MENUITEM_FUNCTION_W_PARAM(replace_pl_item, 0, ID2P(LANG_PLAY), + add_to_playlist, &addtopl_replace, + treeplaylist_callback, Icon_Playlist); -MENUITEM_FUNCTION(replace_shuf_pl_item, MENU_FUNC_USEPARAM, - ID2P(LANG_CLEAR_LIST_AND_PLAY_SHUFFLED), playlist_insert_func, - (intptr_t*)PLAYLIST_INSERT_SHUFFLED, +MENUITEM_FUNCTION_W_PARAM(replace_shuf_pl_item, 0, ID2P(LANG_PLAY_SHUFFLED), + add_to_playlist, &addtopl_replace_shuffled, treeplaylist_callback, Icon_Playlist); -MAKE_ONPLAYMENU(tree_playlist_menu, ID2P(LANG_CURRENT_PLAYLIST), +MAKE_ONPLAYMENU(tree_playlist_menu, ID2P(LANG_PLAYING_NEXT), treeplaylist_callback, Icon_Playlist, /* insert */ - &i_pl_item, &i_first_pl_item, + &i_pl_item, &i_last_pl_item, &i_shuf_pl_item, &i_last_shuf_pl_item, /* queue */ - &q_pl_item, &q_first_pl_item, + &q_pl_item, &q_last_pl_item, &q_shuf_pl_item, &q_last_shuf_pl_item, @@ -711,77 +463,70 @@ static int treeplaylist_callback(int action, (void)this_list; switch (action) { - case ACTION_REQUEST_MENUITEM: - if (this_item == &tree_playlist_menu) - { - if ((selected_file_attr & FILE_ATTR_MASK) == FILE_ATTR_AUDIO || - (selected_file_attr & FILE_ATTR_MASK) == FILE_ATTR_M3U || - (selected_file_attr & ATTR_DIRECTORY)) - return action; - } - else if ((this_item == &q_pl_item || - this_item == &q_first_pl_item || - this_item == &q_last_pl_item) && - global_settings.show_queue_options == QUEUE_SHOW_AT_TOPLEVEL && - (audio_status() & AUDIO_STATUS_PLAY)) - { - return action; - } - else if (this_item == &i_shuf_pl_item) - { - if (global_settings.show_shuffled_adding_options && - (audio_status() & AUDIO_STATUS_PLAY)) - { - return action; - } - } - else if (this_item == &replace_shuf_pl_item) + case ACTION_REQUEST_MENUITEM: + if (this_item == &tree_playlist_menu) + { + if ((selected_file_attr & FILE_ATTR_MASK) != FILE_ATTR_AUDIO && + (selected_file_attr & FILE_ATTR_MASK) != FILE_ATTR_M3U && + (selected_file_attr & ATTR_DIRECTORY) == 0) + return ACTION_EXIT_MENUITEM; + } + else if (this_item == &queue_menu) + { + if (global_settings.show_queue_options != QUEUE_SHOW_IN_SUBMENU) + return ACTION_EXIT_MENUITEM; + + /* queueing options only work during playback */ + if (!(audio_status() & AUDIO_STATUS_PLAY)) + return ACTION_EXIT_MENUITEM; + } + else if ((this_item->flags & MENU_TYPE_MASK) == MT_FUNCTION_CALL_W_PARAM && + this_item->function_param->function_w_param == add_to_playlist) + { + struct add_to_pl_param *param = this_item->function_param->param; + + if (param->queue) { - if (global_settings.show_shuffled_adding_options && - !(audio_status() & AUDIO_STATUS_PLAY) && - ((selected_file_attr & ATTR_DIRECTORY) || - ((selected_file_attr & FILE_ATTR_MASK) == FILE_ATTR_M3U))) - { - return action; - } + if (global_settings.show_queue_options != QUEUE_SHOW_AT_TOPLEVEL && + !in_queue_submenu) + return ACTION_EXIT_MENUITEM; } - else if (this_item == &q_shuf_pl_submenu_item || - (this_item == &q_shuf_pl_item && - global_settings.show_queue_options == QUEUE_SHOW_AT_TOPLEVEL)) + + if (param->position == PLAYLIST_INSERT_SHUFFLED || + param->position == PLAYLIST_INSERT_LAST_SHUFFLED) { - if (global_settings.show_shuffled_adding_options && - (audio_status() & AUDIO_STATUS_PLAY)) - { - return action; - } + if (!global_settings.show_shuffled_adding_options) + return ACTION_EXIT_MENUITEM; + + if ((selected_file_attr & FILE_ATTR_MASK) != FILE_ATTR_M3U && + (selected_file_attr & ATTR_DIRECTORY) == 0) + return ACTION_EXIT_MENUITEM; } - else if (this_item == &i_last_shuf_pl_item || - this_item == &q_last_shuf_pl_submenu_item || - (this_item == &q_last_shuf_pl_item && - global_settings.show_queue_options == QUEUE_SHOW_AT_TOPLEVEL)) + + if (!param->replace) { - if (global_settings.show_shuffled_adding_options && - (playlist_amount() > 0) && - (audio_status() & AUDIO_STATUS_PLAY) && - ((selected_file_attr & ATTR_DIRECTORY) || - ((selected_file_attr & FILE_ATTR_MASK) == FILE_ATTR_M3U))) - { - return action; - } + if (!(audio_status() & AUDIO_STATUS_PLAY)) + return ACTION_EXIT_MENUITEM; } - return ACTION_EXIT_MENUITEM; - break; + } + + break; + + case ACTION_ENTER_MENUITEM: + in_queue_submenu = this_item == &queue_menu; + break; } + return action; } -void onplay_show_playlist_menu(char* path) +void onplay_show_playlist_menu(const char* path, int attr, void (*playlist_insert_cb)) { + context = CONTEXT_STD; + ctx_current_playlist_insert = playlist_insert_cb; selected_file = path; - if (dir_exists(path)) - selected_file_attr = ATTR_DIRECTORY; - else - selected_file_attr = filetype_get_attr(path); + selected_file_attr = attr; + in_queue_submenu = false; do_menu(&tree_playlist_menu, NULL, NULL, false); } @@ -789,43 +534,33 @@ void onplay_show_playlist_menu(char* path) static bool cat_add_to_a_playlist(void) { return catalog_add_to_a_playlist(selected_file, selected_file_attr, - false, NULL); + false, NULL, ctx_add_to_playlist); } static bool cat_add_to_a_new_playlist(void) { return catalog_add_to_a_playlist(selected_file, selected_file_attr, - true, NULL); + true, NULL, ctx_add_to_playlist); } -static int clipboard_callback(int action, - const struct menu_item_ex *this_item, - struct gui_synclist *this_list); - -static bool set_catalogdir(void) -{ - catalog_set_directory(selected_file); - settings_save(); - return false; -} -MENUITEM_FUNCTION(set_catalogdir_item, 0, ID2P(LANG_SET_AS_PLAYLISTCAT_DIR), - set_catalogdir, NULL, clipboard_callback, Icon_Playlist); static int cat_playlist_callback(int action, const struct menu_item_ex *this_item, struct gui_synclist *this_list); -MENUITEM_FUNCTION(cat_add_to_list, 0, ID2P(LANG_CATALOG_ADD_TO), - cat_add_to_a_playlist, 0, NULL, Icon_Playlist); +MENUITEM_FUNCTION(cat_add_to_list, 0, ID2P(LANG_ADD_TO_EXISTING_PL), + cat_add_to_a_playlist, NULL, Icon_Playlist); MENUITEM_FUNCTION(cat_add_to_new, 0, ID2P(LANG_CATALOG_ADD_TO_NEW), - cat_add_to_a_new_playlist, 0, NULL, Icon_Playlist); -MAKE_ONPLAYMENU(cat_playlist_menu, ID2P(LANG_CATALOG), + cat_add_to_a_new_playlist, NULL, Icon_Playlist); +MAKE_ONPLAYMENU(cat_playlist_menu, ID2P(LANG_ADD_TO_PL), cat_playlist_callback, Icon_Playlist, - &cat_add_to_list, &cat_add_to_new, &set_catalogdir_item); + &cat_add_to_list, &cat_add_to_new); -void onplay_show_playlist_cat_menu(char* track_name) +void onplay_show_playlist_cat_menu(const char* track_name, int attr, void (*add_to_pl_cb)) { + context = CONTEXT_STD; + ctx_add_to_playlist = add_to_pl_cb; selected_file = track_name; - selected_file_attr = FILE_ATTR_AUDIO; + selected_file_attr = attr; do_menu(&cat_playlist_menu, NULL, NULL, false); } @@ -842,13 +577,6 @@ static int cat_playlist_callback(int action, { return ACTION_EXIT_MENUITEM; } -#ifdef HAVE_TAGCACHE - if (context == CONTEXT_ID3DB && - ((selected_file_attr & FILE_ATTR_MASK) != FILE_ATTR_AUDIO)) - { - return ACTION_EXIT_MENUITEM; - } -#endif switch (action) { @@ -912,22 +640,6 @@ static bool poll_cancel_action(const char *path) return ACTION_STD_CANCEL == get_action(CONTEXT_STD, TIMEOUT_NOBLOCK); } -static int confirm_overwrite(void) -{ - static const char *lines[] = { ID2P(LANG_REALLY_OVERWRITE) }; - static const struct text_message message = { lines, 1 }; - return gui_syncyesno_run(&message, NULL, NULL); -} - -static int confirm_delete(const char *file) -{ - const char *lines[] = { ID2P(LANG_REALLY_DELETE), file }; - const char *yes_lines[] = { ID2P(LANG_DELETING), file }; - const struct text_message message = { lines, 2 }; - const struct text_message yes_message = { yes_lines, 2 }; - return gui_syncyesno_run(&message, &yes_message, NULL); -} - static bool check_new_name(const char *basename) { /* at least prevent escapes out of the base directory from keyboard- @@ -1022,7 +734,7 @@ static int delete_file_dir(void) { const char *to_delete=selected_file; const int to_delete_attr=selected_file_attr; - if (confirm_delete(to_delete) != YESNO_YES) { + if (confirm_delete_yesno(to_delete) != YESNO_YES) { return 1; } @@ -1068,7 +780,7 @@ static int rename_file(void) size_t pathlen = oldbase - selection; char *newbase = newname + pathlen; - if (strlcpy(newname, selection, sizeof (newname)) >= sizeof (newname)) { + if (strmemccpy(newname, selection, sizeof (newname)) == NULL) { /* Too long */ } else if (kbd_input(newbase, sizeof (newname) - pathlen, NULL) < 0) { rc = OPRC_CANCELLED; @@ -1399,7 +1111,7 @@ static int clipboard_paste(void) case RELATE_DIFFERENT: if (file_exists(target.path)) { /* If user chooses not to overwrite, cancel */ - if (confirm_overwrite() == YESNO_NO) { + if (confirm_overwrite_yesno() == YESNO_NO) { rc = OPRC_NOOVERWRT; break; } @@ -1440,10 +1152,13 @@ static int clipboard_paste(void) { case OPRC_CANCELLED: splash_cancelled(); + /* Fallthrough */ case OPRC_SUCCESS: onplay_result = ONPLAY_RELOAD_DIR; + /* Fallthrough */ case OPRC_NOOP: clipboard_clear_selection(&clipboard); + /* Fallthrough */ case OPRC_NOOVERWRT: break; default: @@ -1487,7 +1202,7 @@ static int ratingitem_callback(int action, return action; } MENUITEM_FUNCTION(rating_item, 0, ID2P(LANG_MENU_SET_RATING), - set_rating_inline, NULL, + set_rating_inline, ratingitem_callback, Icon_Questionmark); #endif MENUITEM_RETURNVALUE(plugin_item, ID2P(LANG_OPEN_PLUGIN), @@ -1520,22 +1235,27 @@ static int view_cue_item_callback(int action, return action; } MENUITEM_FUNCTION(view_cue_item, 0, ID2P(LANG_BROWSE_CUESHEET), - view_cue, NULL, view_cue_item_callback, Icon_NOICON); + view_cue, view_cue_item_callback, Icon_NOICON); static int browse_id3_wrapper(void) { - if (browse_id3()) + if (get_current_activity() == ACTIVITY_CONTEXTMENU) /* get rid of parent activity */ + pop_current_activity_without_refresh(); /* when called from ctxt menu */ + + if (browse_id3(audio_current_track(), + playlist_get_display_index(), + playlist_amount(), NULL, 1)) return GO_TO_ROOT; return GO_TO_PREVIOUS; } /* CONTEXT_WPS items */ MENUITEM_FUNCTION(browse_id3_item, MENU_FUNC_CHECK_RETVAL, ID2P(LANG_MENU_SHOW_ID3_INFO), - browse_id3_wrapper, NULL, NULL, Icon_NOICON); + browse_id3_wrapper, NULL, Icon_NOICON); #ifdef HAVE_PITCHCONTROL MENUITEM_FUNCTION(pitch_screen_item, 0, ID2P(LANG_PITCH), - gui_syncpitchscreen_run, NULL, NULL, Icon_Audio); + gui_syncpitchscreen_run, NULL, Icon_Audio); #endif /* CONTEXT_[TREE|ID3DB] items */ @@ -1544,19 +1264,19 @@ static int clipboard_callback(int action, struct gui_synclist *this_list); MENUITEM_FUNCTION(rename_file_item, 0, ID2P(LANG_RENAME), - rename_file, NULL, clipboard_callback, Icon_NOICON); + rename_file, clipboard_callback, Icon_NOICON); MENUITEM_FUNCTION(clipboard_cut_item, 0, ID2P(LANG_CUT), - clipboard_cut, NULL, clipboard_callback, Icon_NOICON); + clipboard_cut, clipboard_callback, Icon_NOICON); MENUITEM_FUNCTION(clipboard_copy_item, 0, ID2P(LANG_COPY), - clipboard_copy, NULL, clipboard_callback, Icon_NOICON); + clipboard_copy, clipboard_callback, Icon_NOICON); MENUITEM_FUNCTION(clipboard_paste_item, 0, ID2P(LANG_PASTE), - clipboard_paste, NULL, clipboard_callback, Icon_NOICON); + clipboard_paste, clipboard_callback, Icon_NOICON); MENUITEM_FUNCTION(delete_file_item, 0, ID2P(LANG_DELETE), - delete_file_dir, NULL, clipboard_callback, Icon_NOICON); + delete_file_dir, clipboard_callback, Icon_NOICON); MENUITEM_FUNCTION(delete_dir_item, 0, ID2P(LANG_DELETE_DIR), - delete_file_dir, NULL, clipboard_callback, Icon_NOICON); + delete_file_dir, clipboard_callback, Icon_NOICON); MENUITEM_FUNCTION(create_dir_item, 0, ID2P(LANG_CREATE_DIR), - create_dir, NULL, clipboard_callback, Icon_NOICON); + create_dir, clipboard_callback, Icon_NOICON); /* other items */ static bool list_viewers(void) @@ -1567,32 +1287,69 @@ static bool list_viewers(void) return false; } +#ifdef HAVE_TAGCACHE +static bool prepare_database_sel(void *param) +{ + if (context == CONTEXT_ID3DB && + (selected_file_attr & FILE_ATTR_MASK) != FILE_ATTR_AUDIO) + { + if (!strcmp(param, "properties")) + strmemccpy(selected_file_path, MAKE_ACT_STR(ACTIVITY_DATABASEBROWSER), + sizeof(selected_file_path)); + else if (!tagtree_get_subentry_filename(selected_file_path, MAX_PATH)) + { + onplay_result = ONPLAY_RELOAD_DIR; + return false; + } + + selected_file = selected_file_path; + } + return true; +} +#endif + static bool onplay_load_plugin(void *param) { +#ifdef HAVE_TAGCACHE + if (!prepare_database_sel(param)) + return false; +#endif int ret = filetype_load_plugin((const char*)param, selected_file); if (ret == PLUGIN_USB_CONNECTED) onplay_result = ONPLAY_RELOAD_DIR; + else if (ret == PLUGIN_GOTO_PLUGIN) + onplay_result = ONPLAY_PLUGIN; + else if (ret == PLUGIN_GOTO_WPS) + onplay_result = ONPLAY_START_PLAY; return false; } MENUITEM_FUNCTION(list_viewers_item, 0, ID2P(LANG_ONPLAY_OPEN_WITH), - list_viewers, NULL, clipboard_callback, Icon_NOICON); -MENUITEM_FUNCTION(properties_item, MENU_FUNC_USEPARAM, ID2P(LANG_PROPERTIES), + list_viewers, clipboard_callback, Icon_NOICON); +MENUITEM_FUNCTION_W_PARAM(properties_item, 0, ID2P(LANG_PROPERTIES), onplay_load_plugin, (void *)"properties", clipboard_callback, Icon_NOICON); +MENUITEM_FUNCTION_W_PARAM(track_info_item, 0, ID2P(LANG_MENU_SHOW_ID3_INFO), + onplay_load_plugin, (void *)"properties", + clipboard_callback, Icon_NOICON); +#ifdef HAVE_TAGCACHE +MENUITEM_FUNCTION_W_PARAM(pictureflow_item, 0, ID2P(LANG_ONPLAY_PICTUREFLOW), + onplay_load_plugin, (void *)"pictureflow", + clipboard_callback, Icon_NOICON); +#endif static bool onplay_add_to_shortcuts(void) { shortcuts_add(SHORTCUT_BROWSER, selected_file); return false; } MENUITEM_FUNCTION(add_to_faves_item, 0, ID2P(LANG_ADD_TO_FAVES), - onplay_add_to_shortcuts, NULL, + onplay_add_to_shortcuts, clipboard_callback, Icon_NOICON); #if LCD_DEPTH > 1 static bool set_backdrop(void) { - strlcpy(global_settings.backdrop_file, selected_file, + strmemccpy(global_settings.backdrop_file, selected_file, sizeof(global_settings.backdrop_file)); settings_save(); skin_backdrop_load_setting(); @@ -1600,18 +1357,18 @@ static bool set_backdrop(void) return true; } MENUITEM_FUNCTION(set_backdrop_item, 0, ID2P(LANG_SET_AS_BACKDROP), - set_backdrop, NULL, clipboard_callback, Icon_NOICON); + set_backdrop, clipboard_callback, Icon_NOICON); #endif #ifdef HAVE_RECORDING static bool set_recdir(void) { - strlcpy(global_settings.rec_directory, selected_file, + strmemccpy(global_settings.rec_directory, selected_file, sizeof(global_settings.rec_directory)); settings_save(); return false; } -MENUITEM_FUNCTION(set_recdir_item, 0, ID2P(LANG_SET_AS_REC_DIR), - set_recdir, NULL, clipboard_callback, Icon_Recording); +MENUITEM_FUNCTION(set_recdir_item, 0, ID2P(LANG_RECORDING_DIR), + set_recdir, clipboard_callback, Icon_Recording); #endif static bool set_startdir(void) { @@ -1621,8 +1378,25 @@ static bool set_startdir(void) settings_save(); return false; } -MENUITEM_FUNCTION(set_startdir_item, 0, ID2P(LANG_SET_AS_START_DIR), - set_startdir, NULL, clipboard_callback, Icon_file_view_menu); +MENUITEM_FUNCTION(set_startdir_item, 0, ID2P(LANG_START_DIR), + set_startdir, clipboard_callback, Icon_file_view_menu); + +static bool set_catalogdir(void) +{ + catalog_set_directory(selected_file); + settings_save(); + return false; +} +MENUITEM_FUNCTION(set_catalogdir_item, 0, ID2P(LANG_PLAYLIST_DIR), + set_catalogdir, clipboard_callback, Icon_Playlist); + +MAKE_ONPLAYMENU(set_as_dir_menu, ID2P(LANG_SET_AS), + clipboard_callback, Icon_NOICON, + &set_catalogdir_item, +#ifdef HAVE_RECORDING + &set_recdir_item, +#endif + &set_startdir_item); static int clipboard_callback(int action, const struct menu_item_ex *this_item, @@ -1644,9 +1418,8 @@ static int clipboard_callback(int action, #ifdef HAVE_TAGCACHE if (context == CONTEXT_ID3DB) { - if (((selected_file_attr & FILE_ATTR_MASK) == - FILE_ATTR_AUDIO) && - this_item == &properties_item) + if (this_item == &track_info_item || + this_item == &pictureflow_item) return action; return ACTION_EXIT_MENUITEM; } @@ -1667,7 +1440,10 @@ static int clipboard_callback(int action, if (this_item == &rename_file_item || this_item == &clipboard_cut_item || this_item == &clipboard_copy_item || - this_item == &properties_item || + (this_item == &track_info_item && + (selected_file_attr & FILE_ATTR_MASK) == FILE_ATTR_AUDIO) || + (this_item == &properties_item && + (selected_file_attr & FILE_ATTR_MASK) != FILE_ATTR_AUDIO) || this_item == &add_to_faves_item) { return action; @@ -1677,7 +1453,8 @@ static int clipboard_callback(int action, /* only for directories */ if (this_item == &delete_dir_item || this_item == &set_startdir_item || - this_item == &set_catalogdir_item + this_item == &set_catalogdir_item || + this_item == &set_as_dir_menu #ifdef HAVE_RECORDING || this_item == &set_recdir_item #endif @@ -1732,7 +1509,7 @@ MAKE_ONPLAYMENU( wps_onplay_menu, ID2P(LANG_ONPLAY_MENU_TITLE), ); MENUITEM_FUNCTION(view_playlist_item, 0, ID2P(LANG_VIEW), - view_playlist, NULL, + view_playlist, onplaymenu_callback, Icon_Playlist); /* used when onplay() is not called in the CONTEXT_WPS context */ @@ -1741,14 +1518,14 @@ MAKE_ONPLAYMENU( tree_onplay_menu, ID2P(LANG_ONPLAY_MENU_TITLE), &view_playlist_item, &tree_playlist_menu, &cat_playlist_menu, &rename_file_item, &clipboard_cut_item, &clipboard_copy_item, &clipboard_paste_item, &delete_file_item, &delete_dir_item, + &list_viewers_item, &create_dir_item, &properties_item, &track_info_item, +#ifdef HAVE_TAGCACHE + &pictureflow_item, +#endif #if LCD_DEPTH > 1 &set_backdrop_item, #endif - &list_viewers_item, &create_dir_item, &properties_item, -#ifdef HAVE_RECORDING - &set_recdir_item, -#endif - &set_startdir_item, &add_to_faves_item, &file_menu, + &add_to_faves_item, &set_as_dir_menu, &file_menu, ); static int onplaymenu_callback(int action, const struct menu_item_ex *this_item, @@ -1782,17 +1559,24 @@ static int onplaymenu_callback(int action, #ifdef HAVE_HOTKEY /* direct function calls, no need for menu callbacks */ -static bool delete_item(void) +static bool hotkey_delete_item(void) { #ifdef HAVE_MULTIVOLUME /* no delete for volumes */ if (selected_file_attr & ATTR_VOLUME) return false; #endif + +#ifdef HAVE_TAGCACHE + if (context == CONTEXT_ID3DB && + (selected_file_attr & FILE_ATTR_MASK) != FILE_ATTR_AUDIO) + return false; +#endif + return delete_file_dir(); } -static bool open_with(void) +static bool hotkey_open_with(void) { /* only open files */ if (selected_file_attr & ATTR_DIRECTORY) @@ -1804,116 +1588,146 @@ static bool open_with(void) return list_viewers(); } -static int playlist_insert_shuffled(void) +static int hotkey_tree_pl_insert_shuffled(void) { if ((audio_status() & AUDIO_STATUS_PLAY) || (selected_file_attr & ATTR_DIRECTORY) || ((selected_file_attr & FILE_ATTR_MASK) == FILE_ATTR_M3U)) { - playlist_insert_func((intptr_t*)PLAYLIST_INSERT_SHUFFLED); - return ONPLAY_START_PLAY; + add_to_playlist(&addtopl_insert_shuf); } + return ONPLAY_RELOAD_DIR; +} + +static int hotkey_tree_run_plugin(void *param) +{ +#ifdef HAVE_TAGCACHE + if (!prepare_database_sel(param)) + return ONPLAY_RELOAD_DIR; +#endif + if (filetype_load_plugin((const char*)param, selected_file) == PLUGIN_GOTO_WPS) + return ONPLAY_START_PLAY; return ONPLAY_RELOAD_DIR; } -static void hotkey_run_plugin(void) +static int hotkey_wps_run_plugin(void) { open_plugin_run(ID2P(LANG_HOTKEY_WPS)); + return ONPLAY_OK; } - -struct hotkey_assignment { - int action; /* hotkey_action */ - int lang_id; /* Language ID */ - struct menu_func func; /* Function to run if this entry is selected */ - int return_code; /* What to return after the function is run */ -}; - #define HOTKEY_FUNC(func, param) {{(void *)func}, param} /* Any desired hotkey functions go here, in the enum in onplay.h, and in the settings menu in settings_list.c. The order here is not important. */ -static struct hotkey_assignment hotkey_items[] = { - { HOTKEY_VIEW_PLAYLIST, LANG_VIEW_DYNAMIC_PLAYLIST, - HOTKEY_FUNC(NULL, NULL), - ONPLAY_PLAYLIST }, - { HOTKEY_SHOW_TRACK_INFO, LANG_MENU_SHOW_ID3_INFO, - HOTKEY_FUNC(browse_id3, NULL), - ONPLAY_RELOAD_DIR }, +static const struct hotkey_assignment hotkey_items[] = { + [0]{ .action = HOTKEY_OFF, + .lang_id = LANG_OFF, + .func = HOTKEY_FUNC(NULL,NULL), + .return_code = ONPLAY_RELOAD_DIR, + .flags = HOTKEY_FLAG_WPS | HOTKEY_FLAG_TREE }, + { .action = HOTKEY_VIEW_PLAYLIST, + .lang_id = LANG_VIEW_DYNAMIC_PLAYLIST, + .func = HOTKEY_FUNC(NULL, NULL), + .return_code = ONPLAY_PLAYLIST, + .flags = HOTKEY_FLAG_WPS }, + { .action = HOTKEY_SHOW_TRACK_INFO, + .lang_id = LANG_MENU_SHOW_ID3_INFO, + .func = HOTKEY_FUNC(browse_id3_wrapper, NULL), + .return_code = ONPLAY_RELOAD_DIR, + .flags = HOTKEY_FLAG_WPS }, #ifdef HAVE_PITCHCONTROL - { HOTKEY_PITCHSCREEN, LANG_PITCH, - HOTKEY_FUNC(gui_syncpitchscreen_run, NULL), - ONPLAY_RELOAD_DIR }, + { .action = HOTKEY_PITCHSCREEN, + .lang_id = LANG_PITCH, + .func = HOTKEY_FUNC(gui_syncpitchscreen_run, NULL), + .return_code = ONPLAY_RELOAD_DIR, + .flags = HOTKEY_FLAG_WPS | HOTKEY_FLAG_NOSBS }, +#endif + { .action = HOTKEY_OPEN_WITH, + .lang_id = LANG_ONPLAY_OPEN_WITH, + .func = HOTKEY_FUNC(hotkey_open_with, NULL), + .return_code = ONPLAY_RELOAD_DIR, + .flags = HOTKEY_FLAG_WPS | HOTKEY_FLAG_TREE }, + { .action = HOTKEY_DELETE, + .lang_id = LANG_DELETE, + .func = HOTKEY_FUNC(hotkey_delete_item, NULL), + .return_code = ONPLAY_RELOAD_DIR, + .flags = HOTKEY_FLAG_WPS | HOTKEY_FLAG_TREE }, + { .action = HOTKEY_INSERT, + .lang_id = LANG_ADD, + .func = HOTKEY_FUNC(add_to_playlist, (intptr_t*)&addtopl_insert), + .return_code = ONPLAY_RELOAD_DIR, + .flags = HOTKEY_FLAG_TREE }, + { .action = HOTKEY_INSERT_SHUFFLED, + .lang_id = LANG_ADD_SHUFFLED, + .func = HOTKEY_FUNC(hotkey_tree_pl_insert_shuffled, NULL), + .return_code = ONPLAY_FUNC_RETURN, + .flags = HOTKEY_FLAG_TREE }, + { .action = HOTKEY_PLUGIN, + .lang_id = LANG_OPEN_PLUGIN, + .func = HOTKEY_FUNC(hotkey_wps_run_plugin, NULL), + .return_code = ONPLAY_FUNC_RETURN, + .flags = HOTKEY_FLAG_WPS | HOTKEY_FLAG_NOSBS }, + { .action = HOTKEY_BOOKMARK, + .lang_id = LANG_BOOKMARK_MENU_CREATE, + .func = HOTKEY_FUNC(bookmark_create_menu, NULL), + .return_code = ONPLAY_OK, + .flags = HOTKEY_FLAG_WPS | HOTKEY_FLAG_NOSBS }, + { .action = HOTKEY_BOOKMARK_LIST, + .lang_id = LANG_BOOKMARK_MENU_LIST, + .func = HOTKEY_FUNC(bookmark_load_menu, NULL), + .return_code = ONPLAY_START_PLAY, + .flags = HOTKEY_FLAG_WPS }, + { .action = HOTKEY_PROPERTIES, + .lang_id = LANG_PROPERTIES, + .func = HOTKEY_FUNC(hotkey_tree_run_plugin, (void *)"properties"), + .return_code = ONPLAY_FUNC_RETURN, + .flags = HOTKEY_FLAG_TREE }, +#ifdef HAVE_TAGCACHE + { .action = HOTKEY_PICTUREFLOW, + .lang_id = LANG_ONPLAY_PICTUREFLOW, + .func = HOTKEY_FUNC(hotkey_tree_run_plugin, (void *)"pictureflow"), + .return_code = ONPLAY_FUNC_RETURN, + .flags = HOTKEY_FLAG_TREE }, #endif - { HOTKEY_OPEN_WITH, LANG_ONPLAY_OPEN_WITH, - HOTKEY_FUNC(open_with, NULL), - ONPLAY_RELOAD_DIR }, - { HOTKEY_DELETE, LANG_DELETE, - HOTKEY_FUNC(delete_item, NULL), - ONPLAY_RELOAD_DIR }, - { HOTKEY_INSERT, LANG_INSERT, - HOTKEY_FUNC(playlist_insert_func, (intptr_t*)PLAYLIST_INSERT), - ONPLAY_RELOAD_DIR }, - { HOTKEY_INSERT_SHUFFLED, LANG_INSERT_SHUFFLED, - HOTKEY_FUNC(playlist_insert_shuffled, NULL), - ONPLAY_RELOAD_DIR }, - { HOTKEY_PLUGIN, LANG_OPEN_PLUGIN, - HOTKEY_FUNC(hotkey_run_plugin, NULL), - ONPLAY_OK }, - { HOTKEY_BOOKMARK, LANG_BOOKMARK_MENU_CREATE, - HOTKEY_FUNC(bookmark_create_menu, NULL), - ONPLAY_OK }, }; -/* Return the language ID for this action */ -int get_hotkey_lang_id(int action) +const struct hotkey_assignment *get_hotkey(int action) { - int i = ARRAYLEN(hotkey_items); - while (i--) + for (size_t i = ARRAYLEN(hotkey_items) - 1; i < ARRAYLEN(hotkey_items); i--) { if (hotkey_items[i].action == action) - return hotkey_items[i].lang_id; + return &hotkey_items[i]; } - - return LANG_OFF; + return &hotkey_items[0]; /* no valid hotkey set, return HOTKEY_OFF*/ } /* Execute the hotkey function, if listed */ static int execute_hotkey(bool is_wps) { - int i = ARRAYLEN(hotkey_items); - struct hotkey_assignment *this_item; const int action = (is_wps ? global_settings.hotkey_wps : - global_settings.hotkey_tree); + global_settings.hotkey_tree); /* search assignment struct for a match for the hotkey setting */ - while (i--) + const struct hotkey_assignment *this_item = get_hotkey(action); + + /* run the associated function (with optional param), if any */ + const struct menu_func_param func = this_item->func; + + int func_return = ONPLAY_RELOAD_DIR; + if (func.function != NULL) { - this_item = &hotkey_items[i]; - if (this_item->action == action) - { - /* run the associated function (with optional param), if any */ - const struct menu_func func = this_item->func; - int func_return = ONPLAY_RELOAD_DIR; - if (func.function != NULL) - { - if (func.param != NULL) - func_return = (*func.function_w_param)(func.param); - else - func_return = (*func.function)(); - } - /* return with the associated code */ - const int return_code = this_item->return_code; - /* ONPLAY_OK here means to use the function return code */ - if (return_code == ONPLAY_OK) - return func_return; - return return_code; - } + if (func.param != NULL) + func_return = (*func.function_w_param)(func.param); + else + func_return = (*func.function)(); } + const int return_code = this_item->return_code; - /* no valid hotkey set, ignore hotkey */ - return ONPLAY_RELOAD_DIR; + if (return_code == ONPLAY_FUNC_RETURN) + return func_return; /* Use value returned by function */ + return return_code; /* or return the associated value */ } #endif /* HOTKEY */ @@ -1922,12 +1736,31 @@ int onplay(char* file, int attr, int from, bool hotkey) const struct menu_item_ex *menu; onplay_result = ONPLAY_OK; context = from; - if (file == NULL) - selected_file = NULL; - else + ctx_current_playlist_insert = NULL; + selected_file = NULL; +#ifdef HAVE_TAGCACHE + if (context == CONTEXT_ID3DB && + (attr & FILE_ATTR_MASK) != FILE_ATTR_AUDIO) { - strlcpy(selected_file_path, file, MAX_PATH); - selected_file = selected_file_path; + ctx_add_to_playlist = tagtree_add_to_playlist; + if (file != NULL) + { + /* add a leading slash so that catalog_add_to_a_playlist + later prefills the name when creating a new playlist */ + snprintf(selected_file_path, MAX_PATH, "/%s", file); + selected_file = selected_file_path; + } + } + else +#endif + { + ctx_add_to_playlist = NULL; + if (file != NULL) + { + strmemccpy(selected_file_path, file, MAX_PATH); + selected_file = selected_file_path; + } + } selected_file_attr = attr; int menu_selection; @@ -1944,7 +1777,9 @@ int onplay(char* file, int attr, int from, bool hotkey) else menu = &tree_onplay_menu; menu_selection = do_menu(menu, NULL, NULL, false); - pop_current_activity(); + + if (get_current_activity() == ACTIVITY_CONTEXTMENU) /* Activity may have been */ + pop_current_activity(); /* popped already by menu item */ switch (menu_selection) { @@ -1961,3 +1796,9 @@ int onplay(char* file, int attr, int from, bool hotkey) return onplay_result; } } + +int get_onplay_context(void) +{ + return context; +} + |