Björn Stenberg | d7a55e1 | 2003-03-12 20:21:30 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * $Id$ |
| 9 | * |
Nicolas Pennequin | 357ffb3 | 2008-05-05 10:32:46 +0000 | [diff] [blame] | 10 | * Copyright (C) 2002 Björn Stenberg |
Björn Stenberg | d7a55e1 | 2003-03-12 20:21:30 +0000 | [diff] [blame] | 11 | * |
Daniel Stenberg | 2acc0ac | 2008-06-28 18:10:04 +0000 | [diff] [blame] | 12 | * This program is free software; you can redistribute it and/or |
| 13 | * modify it under the terms of the GNU General Public License |
| 14 | * as published by the Free Software Foundation; either version 2 |
| 15 | * of the License, or (at your option) any later version. |
Björn Stenberg | d7a55e1 | 2003-03-12 20:21:30 +0000 | [diff] [blame] | 16 | * |
| 17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 18 | * KIND, either express or implied. |
| 19 | * |
| 20 | ****************************************************************************/ |
Dan Everton | 1429c9b | 2006-03-20 11:46:06 +0000 | [diff] [blame] | 21 | #include <errno.h> |
Björn Stenberg | d7a55e1 | 2003-03-12 20:21:30 +0000 | [diff] [blame] | 22 | #include <stdio.h> |
| 23 | #include <string.h> |
| 24 | #include <stdlib.h> |
| 25 | #include <stdbool.h> |
| 26 | |
Linus Nielsen Feltzing | 2bf4a05 | 2003-04-01 20:58:31 +0000 | [diff] [blame] | 27 | #include "debug.h" |
Björn Stenberg | d7a55e1 | 2003-03-12 20:21:30 +0000 | [diff] [blame] | 28 | #include "lcd.h" |
Björn Stenberg | d7a55e1 | 2003-03-12 20:21:30 +0000 | [diff] [blame] | 29 | #include "file.h" |
Linus Nielsen Feltzing | 8a237a8 | 2005-04-04 12:06:29 +0000 | [diff] [blame] | 30 | #include "audio.h" |
Björn Stenberg | d7a55e1 | 2003-03-12 20:21:30 +0000 | [diff] [blame] | 31 | #include "menu.h" |
| 32 | #include "lang.h" |
| 33 | #include "playlist.h" |
| 34 | #include "button.h" |
| 35 | #include "kernel.h" |
| 36 | #include "keyboard.h" |
Linus Nielsen Feltzing | 2bf4a05 | 2003-04-01 20:58:31 +0000 | [diff] [blame] | 37 | #include "mp3data.h" |
Björn Stenberg | 51b45d5 | 2008-10-15 06:38:51 +0000 | [diff] [blame] | 38 | #include "metadata.h" |
Linus Nielsen Feltzing | 2bf4a05 | 2003-04-01 20:58:31 +0000 | [diff] [blame] | 39 | #include "screens.h" |
Björn Stenberg | 276b9e3 | 2003-03-24 13:17:43 +0000 | [diff] [blame] | 40 | #include "tree.h" |
Hardeep Sidhu | 9e42620 | 2003-07-01 21:05:43 +0000 | [diff] [blame] | 41 | #include "settings.h" |
Hardeep Sidhu | 107ebc5 | 2004-01-26 17:05:21 +0000 | [diff] [blame] | 42 | #include "playlist_viewer.h" |
Jörg Hohensohn | 4f36ea8 | 2004-03-14 21:33:53 +0000 | [diff] [blame] | 43 | #include "talk.h" |
Hardeep Sidhu | 9e42620 | 2003-07-01 21:05:43 +0000 | [diff] [blame] | 44 | #include "onplay.h" |
Björn Stenberg | fb00c21 | 2004-05-21 20:08:24 +0000 | [diff] [blame] | 45 | #include "filetypes.h" |
Linus Nielsen Feltzing | ae9b319 | 2004-07-13 13:57:14 +0000 | [diff] [blame] | 46 | #include "plugin.h" |
Linus Nielsen Feltzing | 6e0436f | 2005-06-23 01:31:26 +0000 | [diff] [blame] | 47 | #include "bookmark.h" |
Linus Nielsen Feltzing | 6e0436f | 2005-06-23 01:31:26 +0000 | [diff] [blame] | 48 | #include "action.h" |
Kevin Ferrare | e991bee | 2005-11-16 15:12:15 +0000 | [diff] [blame] | 49 | #include "splash.h" |
Kevin Ferrare | 40cc43a | 2005-11-22 22:19:08 +0000 | [diff] [blame] | 50 | #include "yesno.h" |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 51 | #include "menus/exported_menus.h" |
Linus Nielsen Feltzing | 6e0436f | 2005-06-23 01:31:26 +0000 | [diff] [blame] | 52 | #ifdef HAVE_LCD_BITMAP |
| 53 | #include "icons.h" |
| 54 | #endif |
Linus Nielsen Feltzing | 22c1a8e | 2005-06-24 22:33:42 +0000 | [diff] [blame] | 55 | #include "sound_menu.h" |
Hardeep Sidhu | 0cca6ca | 2006-02-09 09:09:32 +0000 | [diff] [blame] | 56 | #include "playlist_menu.h" |
Linus Nielsen Feltzing | da0525f | 2006-07-18 13:54:12 +0000 | [diff] [blame] | 57 | #include "playlist_catalog.h" |
Jonathan Gordon | 710ccb7 | 2006-10-25 10:17:57 +0000 | [diff] [blame] | 58 | #ifdef HAVE_TAGCACHE |
Miika Pekkarinen | 4e6c79b | 2006-07-25 07:41:00 +0000 | [diff] [blame] | 59 | #include "tagtree.h" |
Jonathan Gordon | 710ccb7 | 2006-10-25 10:17:57 +0000 | [diff] [blame] | 60 | #endif |
Nicolas Pennequin | 6190a0d | 2007-05-14 17:34:52 +0000 | [diff] [blame] | 61 | #include "cuesheet.h" |
Jonathan Gordon | eee5423 | 2010-01-29 07:52:13 +0000 | [diff] [blame] | 62 | #include "statusbar-skinned.h" |
Jonathan Gordon | 1da2f01 | 2008-10-05 13:01:54 +0000 | [diff] [blame] | 63 | #include "pitchscreen.h" |
Thomas Martitz | 595a828 | 2009-08-23 15:06:11 +0000 | [diff] [blame] | 64 | #include "viewport.h" |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 65 | #include "pathfuncs.h" |
Jonathan Gordon | 101693f | 2011-11-15 13:22:02 +0000 | [diff] [blame] | 66 | #include "shortcuts.h" |
Nicolas Pennequin | 1cf2ec3 | 2007-04-25 22:08:00 +0000 | [diff] [blame] | 67 | |
Linus Nielsen Feltzing | 6e0436f | 2005-06-23 01:31:26 +0000 | [diff] [blame] | 68 | static int context; |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 69 | static const char *selected_file = NULL; |
Hardeep Sidhu | 9e42620 | 2003-07-01 21:05:43 +0000 | [diff] [blame] | 70 | static int selected_file_attr = 0; |
| 71 | static int onplay_result = ONPLAY_OK; |
William Wilgus | 0c06e5f | 2017-09-07 12:27:54 +0200 | [diff] [blame] | 72 | extern struct menu_item_ex file_menu; /* settings_menu.c */ |
Björn Stenberg | d7a55e1 | 2003-03-12 20:21:30 +0000 | [diff] [blame] | 73 | |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 74 | /* redefine MAKE_MENU so the MENU_EXITAFTERTHISMENU flag can be added easily */ |
| 75 | #define MAKE_ONPLAYMENU( name, str, callback, icon, ... ) \ |
| 76 | static const struct menu_item_ex *name##_[] = {__VA_ARGS__}; \ |
| 77 | static const struct menu_callback_with_desc name##__ = {callback,str,icon};\ |
Jonathan Gordon | a6f2b82 | 2007-11-04 12:40:18 +0000 | [diff] [blame] | 78 | static const struct menu_item_ex name = \ |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 79 | {MT_MENU|MENU_HAS_DESC|MENU_EXITAFTERTHISMENU| \ |
| 80 | MENU_ITEM_COUNT(sizeof( name##_)/sizeof(*name##_)), \ |
| 81 | { (void*)name##_},{.callback_and_desc = & name##__}}; |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 82 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 83 | /* Used for directory move, copy and delete */ |
| 84 | struct dirrecurse_params |
| 85 | { |
| 86 | char path[MAX_PATH]; /* Buffer for full path */ |
| 87 | size_t append; /* Append position in 'path' for stack push */ |
| 88 | }; |
| 89 | |
| 90 | enum clipboard_op_flags |
| 91 | { |
| 92 | PASTE_CUT = 0x00, /* Is a move (cut) operation (default) */ |
| 93 | PASTE_COPY = 0x01, /* Is a copy operation */ |
| 94 | PASTE_OVERWRITE = 0x02, /* Overwrite destination */ |
| 95 | PASTE_EXDEV = 0x04, /* Actually copy/move across volumes */ |
| 96 | }; |
| 97 | |
| 98 | /* result codec of various onplay operations */ |
| 99 | enum onplay_result_code |
| 100 | { |
| 101 | /* Anything < 0 is failure */ |
| 102 | OPRC_SUCCESS = 0, /* All operations completed successfully */ |
| 103 | OPRC_NOOP = 1, /* Operation didn't need to do anything */ |
| 104 | OPRC_CANCELLED = 2, /* Operation was cancelled by user */ |
| 105 | OPRC_NOOVERWRT = 3, |
| 106 | }; |
| 107 | |
| 108 | static struct clipboard |
| 109 | { |
| 110 | char path[MAX_PATH]; /* Clipped file's path */ |
| 111 | unsigned int attr; /* Clipped file's attributes */ |
| 112 | unsigned int flags; /* Operation type flags */ |
| 113 | } clipboard; |
| 114 | |
| 115 | /* Empty the clipboard */ |
| 116 | static void clipboard_clear_selection(struct clipboard *clip) |
| 117 | { |
| 118 | clip->path[0] = '\0'; |
| 119 | clip->attr = 0; |
| 120 | clip->flags = 0; |
| 121 | } |
| 122 | |
| 123 | /* Store the selection in the clipboard */ |
| 124 | static bool clipboard_clip(struct clipboard *clip, const char *path, |
| 125 | unsigned int attr, unsigned int flags) |
| 126 | { |
| 127 | /* if it fits it clips */ |
| 128 | if (strlcpy(clip->path, path, sizeof (clip->path)) |
| 129 | < sizeof (clip->path)) { |
| 130 | clip->attr = attr; |
| 131 | clip->flags = flags; |
| 132 | return true; |
| 133 | } |
| 134 | else { |
| 135 | clipboard_clear_selection(clip); |
| 136 | return false; |
| 137 | } |
| 138 | } |
| 139 | |
Linus Nielsen Feltzing | 6e0436f | 2005-06-23 01:31:26 +0000 | [diff] [blame] | 140 | /* ----------------------------------------------------------------------- */ |
| 141 | /* Displays the bookmark menu options for the user to decide. This is an */ |
| 142 | /* interface function. */ |
| 143 | /* ----------------------------------------------------------------------- */ |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 144 | |
Hardeep Sidhu | 8c2bcf1 | 2007-05-15 23:30:30 +0000 | [diff] [blame] | 145 | static int bookmark_menu_callback(int action, |
| 146 | const struct menu_item_ex *this_item); |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 147 | MENUITEM_FUNCTION(bookmark_create_menu_item, 0, |
| 148 | ID2P(LANG_BOOKMARK_MENU_CREATE), |
Osborne Jacobs | fb30d01 | 2012-03-11 00:47:28 -0500 | [diff] [blame] | 149 | bookmark_create_menu, NULL, |
| 150 | bookmark_menu_callback, Icon_Bookmark); |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 151 | MENUITEM_FUNCTION(bookmark_load_menu_item, 0, |
| 152 | ID2P(LANG_BOOKMARK_MENU_LIST), |
| 153 | bookmark_load_menu, NULL, |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 154 | bookmark_menu_callback, Icon_Bookmark); |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 155 | MAKE_ONPLAYMENU(bookmark_menu, ID2P(LANG_BOOKMARK_MENU), |
| 156 | bookmark_menu_callback, Icon_Bookmark, |
| 157 | &bookmark_create_menu_item, &bookmark_load_menu_item); |
Hardeep Sidhu | 8c2bcf1 | 2007-05-15 23:30:30 +0000 | [diff] [blame] | 158 | static int bookmark_menu_callback(int action, |
| 159 | const struct menu_item_ex *this_item) |
Linus Nielsen Feltzing | 6e0436f | 2005-06-23 01:31:26 +0000 | [diff] [blame] | 160 | { |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 161 | switch (action) |
Linus Nielsen Feltzing | 6e0436f | 2005-06-23 01:31:26 +0000 | [diff] [blame] | 162 | { |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 163 | case ACTION_REQUEST_MENUITEM: |
Osborne Jacobs | fb30d01 | 2012-03-11 00:47:28 -0500 | [diff] [blame] | 164 | /* hide create bookmark option if bookmarking isn't currently possible (no track playing, queued tracks...) */ |
| 165 | if (this_item == &bookmark_create_menu_item) |
| 166 | { |
| 167 | if (!bookmark_is_bookmarkable_state()) |
| 168 | return ACTION_EXIT_MENUITEM; |
| 169 | } |
| 170 | /* hide loading bookmarks menu if no bookmarks exist */ |
| 171 | else if (this_item == &bookmark_load_menu_item) |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 172 | { |
Alexander Levin | 7d4c0c5 | 2010-07-06 16:53:52 +0000 | [diff] [blame] | 173 | if (!bookmark_exists()) |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 174 | return ACTION_EXIT_MENUITEM; |
| 175 | } |
Osborne Jacobs | fb30d01 | 2012-03-11 00:47:28 -0500 | [diff] [blame] | 176 | /* hide the bookmark menu if bookmarks can't be loaded or created */ |
| 177 | else if (!bookmark_is_bookmarkable_state() && !bookmark_exists()) |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 178 | return ACTION_EXIT_MENUITEM; |
| 179 | break; |
| 180 | #ifdef HAVE_LCD_CHARCELLS |
| 181 | case ACTION_ENTER_MENUITEM: |
| 182 | status_set_param(true); |
| 183 | break; |
| 184 | #endif |
| 185 | case ACTION_EXIT_MENUITEM: |
| 186 | #ifdef HAVE_LCD_CHARCELLS |
| 187 | status_set_param(false); |
| 188 | #endif |
| 189 | settings_save(); |
| 190 | break; |
Linus Nielsen Feltzing | 6e0436f | 2005-06-23 01:31:26 +0000 | [diff] [blame] | 191 | } |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 192 | return action; |
Linus Nielsen Feltzing | 6e0436f | 2005-06-23 01:31:26 +0000 | [diff] [blame] | 193 | } |
| 194 | |
Solomon Peachy | fe95127 | 2018-12-14 08:20:25 -0500 | [diff] [blame^] | 195 | /* playing_time screen context */ |
| 196 | struct playing_time_info { |
| 197 | int curr_playing; /* index of currently playing track in playlist */ |
| 198 | int nb_tracks; /* how many tracks in playlist */ |
| 199 | /* seconds before and after current position, and total. Datatype |
| 200 | allows for values up to 68years. If I had kept it in ms |
| 201 | though, it would have overflowed at 24days, which takes |
| 202 | something like 8.5GB at 32kbps, and so we could conceivably |
| 203 | have playlists lasting longer than that. */ |
| 204 | long secs_bef, secs_aft, secs_ttl; |
| 205 | long trk_secs_bef, trk_secs_aft, trk_secs_ttl; |
| 206 | /* kilobytes played before and after current pos, and total. |
| 207 | Kilobytes because bytes would overflow. Data type range is up |
| 208 | to 2TB. */ |
| 209 | long kbs_bef, kbs_aft, kbs_ttl; |
| 210 | }; |
| 211 | |
| 212 | /* list callback for playing_time screen */ |
| 213 | static const char * playing_time_get_or_speak_info(int selected_item, void * data, |
| 214 | char *buf, size_t buffer_len, |
| 215 | bool say_it) |
| 216 | { |
| 217 | struct playing_time_info *pti = (struct playing_time_info *)data; |
| 218 | switch(selected_item) { |
| 219 | case 0: { /* elapsed and total time */ |
| 220 | char timestr1[25], timestr2[25]; |
| 221 | format_time_auto(timestr1, sizeof(timestr1), pti->secs_bef, |
| 222 | UNIT_SEC, false); |
| 223 | format_time_auto(timestr2, sizeof(timestr2), pti->secs_ttl, |
| 224 | UNIT_SEC, false); |
| 225 | long elapsed_perc; /* percentage of duration elapsed */ |
| 226 | if (pti->secs_ttl == 0) |
| 227 | elapsed_perc = 0; |
| 228 | else if (pti->secs_ttl <= 0xFFFFFF) |
| 229 | elapsed_perc = pti->secs_bef *100 / pti->secs_ttl; |
| 230 | else /* sacrifice some precision to avoid overflow */ |
| 231 | elapsed_perc = (pti->secs_bef>>7) *100 /(pti->secs_ttl>>7); |
| 232 | snprintf(buf, buffer_len, str(LANG_PLAYTIME_ELAPSED), |
| 233 | timestr1, timestr2, elapsed_perc); |
| 234 | if (say_it) |
| 235 | talk_ids(false, LANG_PLAYTIME_ELAPSED, |
| 236 | TALK_ID(pti->secs_bef, UNIT_TIME), |
| 237 | VOICE_OF, |
| 238 | TALK_ID(pti->secs_ttl, UNIT_TIME), |
| 239 | VOICE_PAUSE, |
| 240 | TALK_ID(elapsed_perc, UNIT_PERCENT)); |
| 241 | break; |
| 242 | } |
| 243 | case 1: { /* playlist remaining time */ |
| 244 | char timestr[25]; |
| 245 | format_time_auto(timestr, sizeof(timestr), pti->secs_aft, |
| 246 | UNIT_SEC, false); |
| 247 | snprintf(buf, buffer_len, str(LANG_PLAYTIME_REMAINING), |
| 248 | timestr); |
| 249 | if (say_it) |
| 250 | talk_ids(false, LANG_PLAYTIME_REMAINING, |
| 251 | TALK_ID(pti->secs_aft, UNIT_TIME)); |
| 252 | break; |
| 253 | } |
| 254 | case 2: { /* track elapsed and duration */ |
| 255 | char timestr1[25], timestr2[25]; |
| 256 | format_time_auto(timestr1, sizeof(timestr1), pti->trk_secs_bef, |
| 257 | UNIT_SEC, false); |
| 258 | format_time_auto(timestr2, sizeof(timestr2), pti->trk_secs_ttl, |
| 259 | UNIT_SEC, false); |
| 260 | long elapsed_perc; /* percentage of duration elapsed */ |
| 261 | if (pti->trk_secs_ttl == 0) |
| 262 | elapsed_perc = 0; |
| 263 | else if (pti->trk_secs_ttl <= 0xFFFFFF) |
| 264 | elapsed_perc = pti->trk_secs_bef *100 / pti->trk_secs_ttl; |
| 265 | else /* sacrifice some precision to avoid overflow */ |
| 266 | elapsed_perc = (pti->trk_secs_bef>>7) *100 /(pti->trk_secs_ttl>>7); |
| 267 | snprintf(buf, buffer_len, str(LANG_PLAYTIME_TRK_ELAPSED), |
| 268 | timestr1, timestr2, elapsed_perc); |
| 269 | if (say_it) |
| 270 | talk_ids(false, LANG_PLAYTIME_TRK_ELAPSED, |
| 271 | TALK_ID(pti->trk_secs_bef, UNIT_TIME), |
| 272 | VOICE_OF, |
| 273 | TALK_ID(pti->trk_secs_ttl, UNIT_TIME), |
| 274 | VOICE_PAUSE, |
| 275 | TALK_ID(elapsed_perc, UNIT_PERCENT)); |
| 276 | break; |
| 277 | } |
| 278 | case 3: { /* track remaining time */ |
| 279 | char timestr[25]; |
| 280 | format_time_auto(timestr, sizeof(timestr), pti->trk_secs_aft, |
| 281 | UNIT_SEC, false); |
| 282 | snprintf(buf, buffer_len, str(LANG_PLAYTIME_TRK_REMAINING), |
| 283 | timestr); |
| 284 | if (say_it) |
| 285 | talk_ids(false, LANG_PLAYTIME_TRK_REMAINING, |
| 286 | TALK_ID(pti->trk_secs_aft, UNIT_TIME)); |
| 287 | break; |
| 288 | } |
| 289 | case 4: { /* track index */ |
| 290 | int track_perc = (pti->curr_playing+1) *100 / pti->nb_tracks; |
| 291 | snprintf(buf, buffer_len, str(LANG_PLAYTIME_TRACK), |
| 292 | pti->curr_playing, pti->nb_tracks, track_perc); |
| 293 | if (say_it) |
| 294 | talk_ids(false, LANG_PLAYTIME_TRACK, |
| 295 | TALK_ID(pti->curr_playing+1, UNIT_INT), |
| 296 | VOICE_OF, |
| 297 | TALK_ID(pti->nb_tracks, UNIT_INT), |
| 298 | VOICE_PAUSE, |
| 299 | TALK_ID(track_perc, UNIT_PERCENT)); |
| 300 | break; |
| 301 | } |
| 302 | case 5: { /* storage size */ |
| 303 | char str1[10], str2[10], str3[10]; |
| 304 | output_dyn_value(str1, sizeof(str1), pti->kbs_ttl, kibyte_units, 3, true); |
| 305 | output_dyn_value(str2, sizeof(str2), pti->kbs_bef, kibyte_units, 3, true); |
| 306 | output_dyn_value(str3, sizeof(str3), pti->kbs_aft, kibyte_units, 3, true); |
| 307 | snprintf(buf, buffer_len, str(LANG_PLAYTIME_STORAGE), |
| 308 | str1,str2,str3); |
| 309 | if (say_it) { |
| 310 | talk_id(LANG_PLAYTIME_STORAGE, false); |
| 311 | output_dyn_value(NULL, 0, pti->kbs_ttl, kibyte_units, 3, true); |
| 312 | talk_ids(true, VOICE_PAUSE, VOICE_PLAYTIME_DONE); |
| 313 | output_dyn_value(NULL, 0, pti->kbs_bef, kibyte_units, 3, true); |
| 314 | talk_id(LANG_PLAYTIME_REMAINING, true); |
| 315 | output_dyn_value(NULL, 0, pti->kbs_aft, kibyte_units, 3, true); |
| 316 | } |
| 317 | break; |
| 318 | } |
| 319 | case 6: { /* Average track file size */ |
| 320 | char str[10]; |
| 321 | long avg_track_size = pti->kbs_ttl /pti->nb_tracks; |
| 322 | output_dyn_value(str, sizeof(str), avg_track_size, kibyte_units, 3, true); |
| 323 | snprintf(buf, buffer_len, str(LANG_PLAYTIME_AVG_TRACK_SIZE), |
| 324 | str); |
| 325 | if (say_it) { |
| 326 | talk_id(LANG_PLAYTIME_AVG_TRACK_SIZE, false); |
| 327 | output_dyn_value(NULL, 0, avg_track_size, kibyte_units, 3, true); |
| 328 | } |
| 329 | break; |
| 330 | } |
| 331 | case 7: { /* Average bitrate */ |
| 332 | /* Convert power of 2 kilobytes to power of 10 kilobits */ |
| 333 | long avg_bitrate = pti->kbs_ttl / pti->secs_ttl *1024 *8 /1000; |
| 334 | snprintf(buf, buffer_len, str(LANG_PLAYTIME_AVG_BITRATE), |
| 335 | avg_bitrate); |
| 336 | if (say_it) |
| 337 | talk_ids(false, LANG_PLAYTIME_AVG_BITRATE, |
| 338 | TALK_ID(avg_bitrate, UNIT_KBIT)); |
| 339 | break; |
| 340 | } |
| 341 | } |
| 342 | return buf; |
| 343 | } |
| 344 | |
| 345 | static const char * playing_time_get_info(int selected_item, void * data, |
| 346 | char *buffer, size_t buffer_len) |
| 347 | { |
| 348 | return playing_time_get_or_speak_info(selected_item, data, |
| 349 | buffer, buffer_len, false); |
| 350 | } |
| 351 | |
| 352 | static int playing_time_speak_info(int selected_item, void * data) |
| 353 | { |
| 354 | static char buffer[MAX_PATH]; |
| 355 | playing_time_get_or_speak_info(selected_item, data, |
| 356 | buffer, MAX_PATH, true); |
| 357 | return 0; |
| 358 | } |
| 359 | |
| 360 | /* playing time screen: shows total and elapsed playlist duration and |
| 361 | other stats */ |
| 362 | static bool playing_time(void) |
| 363 | { |
| 364 | unsigned long talked_tick = current_tick; |
| 365 | struct playing_time_info pti; |
| 366 | struct playlist_track_info pltrack; |
| 367 | struct mp3entry id3; |
| 368 | int i, fd, ret; |
| 369 | |
| 370 | pti.nb_tracks = playlist_amount(); |
| 371 | playlist_get_resume_info(&pti.curr_playing); |
| 372 | struct mp3entry *curr_id3 = audio_current_track(); |
| 373 | if (pti.curr_playing == -1 || !curr_id3) |
| 374 | return false; |
| 375 | pti.secs_bef = pti.trk_secs_bef = curr_id3->elapsed/1000; |
| 376 | pti.secs_aft = pti.trk_secs_aft |
| 377 | = (curr_id3->length -curr_id3->elapsed)/1000; |
| 378 | pti.kbs_bef = curr_id3->offset/1024; |
| 379 | pti.kbs_aft = (curr_id3->filesize -curr_id3->offset)/1024; |
| 380 | |
| 381 | splash(0, ID2P(LANG_WAIT)); |
| 382 | |
| 383 | /* Go through each file in the playlist and get its stats. For |
| 384 | huge playlists this can take a while... The reference position |
| 385 | is the position at the moment this function was invoked, |
| 386 | although playback continues forward. */ |
| 387 | for (i = 0; i < pti.nb_tracks; i++) { |
| 388 | /* Show a splash while we are loading. */ |
| 389 | splashf(0, str(LANG_LOADING_PERCENT), |
| 390 | i*100/pti.nb_tracks, str(LANG_OFF_ABORT)); |
| 391 | /* Voice equivalent */ |
| 392 | if (TIME_AFTER(current_tick, talked_tick+5*HZ)) { |
| 393 | talked_tick = current_tick; |
| 394 | talk_ids(false, LANG_LOADING_PERCENT, |
| 395 | TALK_ID(i*100/pti.nb_tracks, UNIT_PERCENT)); |
| 396 | } |
| 397 | if (action_userabort(TIMEOUT_NOBLOCK)) |
| 398 | goto exit; |
| 399 | |
| 400 | if (i == pti.curr_playing) |
| 401 | continue; |
| 402 | |
| 403 | if (playlist_get_track_info(NULL, i, &pltrack) < 0) |
| 404 | goto error; |
| 405 | if ((fd = open(pltrack.filename, O_RDONLY)) < 0) |
| 406 | goto error; |
| 407 | ret = get_metadata(&id3, fd, pltrack.filename); |
| 408 | close(fd); |
| 409 | if (!ret) |
| 410 | goto error; |
| 411 | |
| 412 | if (i < pti.curr_playing) { |
| 413 | pti.secs_bef += id3.length/1000; |
| 414 | pti.kbs_bef += id3.filesize/1024; |
| 415 | } else { |
| 416 | pti.secs_aft += id3.length/1000; |
| 417 | pti.kbs_aft += id3.filesize/1024; |
| 418 | } |
| 419 | } |
| 420 | |
| 421 | pti.secs_ttl = pti.secs_bef +pti.secs_aft; |
| 422 | pti.trk_secs_ttl = pti.trk_secs_bef +pti.trk_secs_aft; |
| 423 | pti.kbs_ttl = pti.kbs_bef +pti.kbs_aft; |
| 424 | |
| 425 | struct gui_synclist pt_lists; |
| 426 | int key; |
| 427 | |
| 428 | gui_synclist_init(&pt_lists, &playing_time_get_info, &pti, true, 1, NULL); |
| 429 | if (global_settings.talk_menu) |
| 430 | gui_synclist_set_voice_callback(&pt_lists, playing_time_speak_info); |
| 431 | gui_synclist_set_nb_items(&pt_lists, 8); |
| 432 | gui_synclist_draw(&pt_lists); |
| 433 | gui_syncstatusbar_draw(&statusbars, true); |
| 434 | gui_synclist_speak_item(&pt_lists); |
| 435 | while (true) { |
| 436 | gui_syncstatusbar_draw(&statusbars, false); |
| 437 | if (list_do_action(CONTEXT_LIST, HZ/2, |
| 438 | &pt_lists, &key, LIST_WRAP_UNLESS_HELD) == 0 |
| 439 | && key!=ACTION_NONE && key!=ACTION_UNKNOWN) |
| 440 | { |
| 441 | talk_force_shutup(); |
| 442 | return(default_event_handler(key) == SYS_USB_CONNECTED); |
| 443 | } |
| 444 | } |
| 445 | error: |
| 446 | splash(HZ, ID2P(LANG_PLAYTIME_ERROR)); |
| 447 | exit: |
| 448 | return false; |
| 449 | } |
| 450 | |
| 451 | |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 452 | /* CONTEXT_WPS playlist options */ |
Tomas Salfischberger | 8fd0378 | 2005-06-23 15:49:36 +0000 | [diff] [blame] | 453 | static bool shuffle_playlist(void) |
| 454 | { |
Tomas Salfischberger | bec1afa | 2005-06-23 16:27:15 +0000 | [diff] [blame] | 455 | playlist_sort(NULL, true); |
Zakk Roberts | 5b93eb6 | 2006-03-22 02:18:44 +0000 | [diff] [blame] | 456 | playlist_randomise(NULL, current_tick, true); |
| 457 | |
Tomas Salfischberger | 8fd0378 | 2005-06-23 15:49:36 +0000 | [diff] [blame] | 458 | return false; |
| 459 | } |
Linus Nielsen Feltzing | 6e0436f | 2005-06-23 01:31:26 +0000 | [diff] [blame] | 460 | static bool save_playlist(void) |
| 461 | { |
Hardeep Sidhu | 0cca6ca | 2006-02-09 09:09:32 +0000 | [diff] [blame] | 462 | save_playlist_screen(NULL); |
Linus Nielsen Feltzing | 6e0436f | 2005-06-23 01:31:26 +0000 | [diff] [blame] | 463 | return false; |
| 464 | } |
Hardeep Sidhu | 9e42620 | 2003-07-01 21:05:43 +0000 | [diff] [blame] | 465 | |
Thomas Martitz | c19e536 | 2010-02-20 19:06:39 +0000 | [diff] [blame] | 466 | extern struct menu_item_ex view_cur_playlist; /* from playlist_menu.c */ |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 467 | MENUITEM_FUNCTION(search_playlist_item, 0, ID2P(LANG_SEARCH_IN_PLAYLIST), |
| 468 | search_playlist, NULL, NULL, Icon_Playlist); |
| 469 | MENUITEM_FUNCTION(playlist_save_item, 0, ID2P(LANG_SAVE_DYNAMIC_PLAYLIST), |
| 470 | save_playlist, NULL, NULL, Icon_Playlist); |
| 471 | MENUITEM_FUNCTION(reshuffle_item, 0, ID2P(LANG_SHUFFLE_PLAYLIST), |
| 472 | shuffle_playlist, NULL, NULL, Icon_Playlist); |
Solomon Peachy | fe95127 | 2018-12-14 08:20:25 -0500 | [diff] [blame^] | 473 | MENUITEM_FUNCTION(playing_time_item, 0, ID2P(LANG_PLAYING_TIME), |
| 474 | playing_time, NULL, NULL, Icon_Playlist); |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 475 | MAKE_ONPLAYMENU( wps_playlist_menu, ID2P(LANG_PLAYLIST), |
| 476 | NULL, Icon_Playlist, |
Thomas Martitz | c19e536 | 2010-02-20 19:06:39 +0000 | [diff] [blame] | 477 | &view_cur_playlist, &search_playlist_item, |
Solomon Peachy | fe95127 | 2018-12-14 08:20:25 -0500 | [diff] [blame^] | 478 | &playlist_save_item, &reshuffle_item, &playing_time_item |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 479 | ); |
| 480 | |
| 481 | /* CONTEXT_[TREE|ID3DB] playlist options */ |
Hardeep Sidhu | 9e42620 | 2003-07-01 21:05:43 +0000 | [diff] [blame] | 482 | static bool add_to_playlist(int position, bool queue) |
Björn Stenberg | d7a55e1 | 2003-03-12 20:21:30 +0000 | [diff] [blame] | 483 | { |
Linus Nielsen Feltzing | 8a237a8 | 2005-04-04 12:06:29 +0000 | [diff] [blame] | 484 | bool new_playlist = !(audio_status() & AUDIO_STATUS_PLAY); |
Nils Wallménius | 33c4446 | 2008-04-26 09:30:24 +0000 | [diff] [blame] | 485 | const char *lines[] = { |
Nils Wallménius | 5b76936 | 2007-08-06 13:08:36 +0000 | [diff] [blame] | 486 | ID2P(LANG_RECURSE_DIRECTORY_QUESTION), |
Hristo Kovachev | d694a21 | 2006-03-21 11:11:31 +0000 | [diff] [blame] | 487 | selected_file |
| 488 | }; |
Nils Wallménius | 33c4446 | 2008-04-26 09:30:24 +0000 | [diff] [blame] | 489 | const struct text_message message={lines, 2}; |
Hardeep Sidhu | 9e42620 | 2003-07-01 21:05:43 +0000 | [diff] [blame] | 490 | |
Nils Wallménius | 01729e7 | 2008-08-15 08:27:39 +0000 | [diff] [blame] | 491 | splash(0, ID2P(LANG_WAIT)); |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 492 | |
Hardeep Sidhu | 9e42620 | 2003-07-01 21:05:43 +0000 | [diff] [blame] | 493 | if (new_playlist) |
| 494 | playlist_create(NULL, NULL); |
| 495 | |
Hardeep Sidhu | 8fe4507 | 2006-09-15 23:51:21 +0000 | [diff] [blame] | 496 | /* always set seed before inserting shuffled */ |
Teruaki Kawashima | 30faf03 | 2009-11-01 14:25:38 +0000 | [diff] [blame] | 497 | if (position == PLAYLIST_INSERT_SHUFFLED || |
| 498 | position == PLAYLIST_INSERT_LAST_SHUFFLED) |
Dave Hooper | 494fd96 | 2009-10-28 22:27:38 +0000 | [diff] [blame] | 499 | { |
Hardeep Sidhu | 8fe4507 | 2006-09-15 23:51:21 +0000 | [diff] [blame] | 500 | srand(current_tick); |
Teruaki Kawashima | 30faf03 | 2009-11-01 14:25:38 +0000 | [diff] [blame] | 501 | if (position == PLAYLIST_INSERT_LAST_SHUFFLED) |
| 502 | playlist_set_last_shuffled_start(); |
Dave Hooper | 494fd96 | 2009-10-28 22:27:38 +0000 | [diff] [blame] | 503 | } |
Hardeep Sidhu | 8fe4507 | 2006-09-15 23:51:21 +0000 | [diff] [blame] | 504 | |
Jonathan Gordon | 710ccb7 | 2006-10-25 10:17:57 +0000 | [diff] [blame] | 505 | #ifdef HAVE_TAGCACHE |
Miika Pekkarinen | 4e6c79b | 2006-07-25 07:41:00 +0000 | [diff] [blame] | 506 | if (context == CONTEXT_ID3DB) |
Hardeep Sidhu | 11e7ad5 | 2003-07-02 15:54:44 +0000 | [diff] [blame] | 507 | { |
Miika Pekkarinen | 4e6c79b | 2006-07-25 07:41:00 +0000 | [diff] [blame] | 508 | tagtree_insert_selection_playlist(position, queue); |
Hardeep Sidhu | 11e7ad5 | 2003-07-02 15:54:44 +0000 | [diff] [blame] | 509 | } |
Miika Pekkarinen | 4e6c79b | 2006-07-25 07:41:00 +0000 | [diff] [blame] | 510 | else |
Jonathan Gordon | 710ccb7 | 2006-10-25 10:17:57 +0000 | [diff] [blame] | 511 | #endif |
Miika Pekkarinen | 4e6c79b | 2006-07-25 07:41:00 +0000 | [diff] [blame] | 512 | { |
Jonathan Gordon | 36a2e30 | 2007-04-18 13:03:01 +0000 | [diff] [blame] | 513 | if ((selected_file_attr & FILE_ATTR_MASK) == FILE_ATTR_AUDIO) |
Miika Pekkarinen | 887cfeb | 2006-08-10 09:50:45 +0000 | [diff] [blame] | 514 | playlist_insert_track(NULL, selected_file, position, queue, true); |
Miika Pekkarinen | 4e6c79b | 2006-07-25 07:41:00 +0000 | [diff] [blame] | 515 | else if (selected_file_attr & ATTR_DIRECTORY) |
| 516 | { |
| 517 | bool recurse = false; |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 518 | |
Miika Pekkarinen | 4e6c79b | 2006-07-25 07:41:00 +0000 | [diff] [blame] | 519 | if (global_settings.recursive_dir_insert != RECURSE_ASK) |
| 520 | recurse = (bool)global_settings.recursive_dir_insert; |
| 521 | else |
| 522 | { |
| 523 | /* Ask if user wants to recurse directory */ |
| 524 | recurse = (gui_syncyesno_run(&message, NULL, NULL)==YESNO_YES); |
| 525 | } |
Thomas Martitz | 87d1744 | 2009-03-08 17:18:18 +0000 | [diff] [blame] | 526 | |
Miika Pekkarinen | 4e6c79b | 2006-07-25 07:41:00 +0000 | [diff] [blame] | 527 | playlist_insert_directory(NULL, selected_file, position, queue, |
| 528 | recurse); |
| 529 | } |
Jonathan Gordon | 36a2e30 | 2007-04-18 13:03:01 +0000 | [diff] [blame] | 530 | else if ((selected_file_attr & FILE_ATTR_MASK) == FILE_ATTR_M3U) |
Miika Pekkarinen | 4e6c79b | 2006-07-25 07:41:00 +0000 | [diff] [blame] | 531 | playlist_insert_playlist(NULL, selected_file, position, queue); |
| 532 | } |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 533 | |
Hardeep Sidhu | 9e42620 | 2003-07-01 21:05:43 +0000 | [diff] [blame] | 534 | if (new_playlist && (playlist_amount() > 0)) |
| 535 | { |
| 536 | /* nothing is currently playing so begin playing what we just |
| 537 | inserted */ |
| 538 | if (global_settings.playlist_shuffle) |
| 539 | playlist_shuffle(current_tick, -1); |
Michael Sevakis | 31b7122 | 2013-07-14 07:59:39 -0400 | [diff] [blame] | 540 | playlist_start(0, 0, 0); |
Hardeep Sidhu | 9e42620 | 2003-07-01 21:05:43 +0000 | [diff] [blame] | 541 | onplay_result = ONPLAY_START_PLAY; |
| 542 | } |
| 543 | |
| 544 | return false; |
| 545 | } |
| 546 | |
Hardeep Sidhu | 107ebc5 | 2004-01-26 17:05:21 +0000 | [diff] [blame] | 547 | static bool view_playlist(void) |
| 548 | { |
Linus Nielsen Feltzing | 8a237a8 | 2005-04-04 12:06:29 +0000 | [diff] [blame] | 549 | bool was_playing = audio_status() & AUDIO_STATUS_PLAY; |
Hardeep Sidhu | 107ebc5 | 2004-01-26 17:05:21 +0000 | [diff] [blame] | 550 | bool result; |
| 551 | |
| 552 | result = playlist_viewer_ex(selected_file); |
| 553 | |
Linus Nielsen Feltzing | 8a237a8 | 2005-04-04 12:06:29 +0000 | [diff] [blame] | 554 | if (!was_playing && (audio_status() & AUDIO_STATUS_PLAY) && |
Hardeep Sidhu | 107ebc5 | 2004-01-26 17:05:21 +0000 | [diff] [blame] | 555 | onplay_result == ONPLAY_OK) |
| 556 | /* playlist was started from viewer */ |
| 557 | onplay_result = ONPLAY_START_PLAY; |
| 558 | |
| 559 | return result; |
| 560 | } |
| 561 | |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 562 | static int playlist_insert_func(void *param) |
| 563 | { |
| 564 | if (((intptr_t)param == PLAYLIST_REPLACE) && !warn_on_pl_erase()) |
| 565 | return 0; |
| 566 | add_to_playlist((intptr_t)param, false); |
| 567 | return 0; |
| 568 | } |
| 569 | |
| 570 | static int playlist_queue_func(void *param) |
| 571 | { |
| 572 | add_to_playlist((intptr_t)param, true); |
| 573 | return 0; |
| 574 | } |
| 575 | |
| 576 | static int treeplaylist_wplayback_callback(int action, |
| 577 | const struct menu_item_ex* this_item) |
| 578 | { |
| 579 | (void)this_item; |
| 580 | switch (action) |
| 581 | { |
| 582 | case ACTION_REQUEST_MENUITEM: |
| 583 | if (audio_status() & AUDIO_STATUS_PLAY) |
| 584 | return action; |
| 585 | else |
| 586 | return ACTION_EXIT_MENUITEM; |
| 587 | break; |
| 588 | } |
| 589 | return action; |
| 590 | } |
| 591 | |
| 592 | static int treeplaylist_callback(int action, |
| 593 | const struct menu_item_ex *this_item); |
| 594 | |
| 595 | /* insert items */ |
Jeffrey Goode | 1ad76ff | 2010-05-09 02:02:51 +0000 | [diff] [blame] | 596 | MENUITEM_FUNCTION(i_pl_item, MENU_FUNC_USEPARAM, ID2P(LANG_INSERT), |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 597 | playlist_insert_func, (intptr_t*)PLAYLIST_INSERT, |
Teruaki Kawashima | 9bea349 | 2010-02-15 13:04:09 +0000 | [diff] [blame] | 598 | NULL, Icon_Playlist); |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 599 | MENUITEM_FUNCTION(i_first_pl_item, MENU_FUNC_USEPARAM, ID2P(LANG_INSERT_FIRST), |
| 600 | playlist_insert_func, (intptr_t*)PLAYLIST_INSERT_FIRST, |
| 601 | treeplaylist_wplayback_callback, Icon_Playlist); |
| 602 | MENUITEM_FUNCTION(i_last_pl_item, MENU_FUNC_USEPARAM, ID2P(LANG_INSERT_LAST), |
| 603 | playlist_insert_func, (intptr_t*)PLAYLIST_INSERT_LAST, |
| 604 | treeplaylist_wplayback_callback, Icon_Playlist); |
| 605 | MENUITEM_FUNCTION(i_shuf_pl_item, MENU_FUNC_USEPARAM, |
| 606 | ID2P(LANG_INSERT_SHUFFLED), playlist_insert_func, |
| 607 | (intptr_t*)PLAYLIST_INSERT_SHUFFLED, |
| 608 | treeplaylist_callback, Icon_Playlist); |
| 609 | MENUITEM_FUNCTION(i_last_shuf_pl_item, MENU_FUNC_USEPARAM, |
| 610 | ID2P(LANG_INSERT_LAST_SHUFFLED), playlist_insert_func, |
| 611 | (intptr_t*)PLAYLIST_INSERT_LAST_SHUFFLED, |
| 612 | treeplaylist_callback, Icon_Playlist); |
| 613 | /* queue items */ |
| 614 | MENUITEM_FUNCTION(q_pl_item, MENU_FUNC_USEPARAM, ID2P(LANG_QUEUE), |
| 615 | playlist_queue_func, (intptr_t*)PLAYLIST_INSERT, |
| 616 | treeplaylist_wplayback_callback, Icon_Playlist); |
| 617 | MENUITEM_FUNCTION(q_first_pl_item, MENU_FUNC_USEPARAM, ID2P(LANG_QUEUE_FIRST), |
| 618 | playlist_queue_func, (intptr_t*)PLAYLIST_INSERT_FIRST, |
| 619 | treeplaylist_wplayback_callback, Icon_Playlist); |
| 620 | MENUITEM_FUNCTION(q_last_pl_item, MENU_FUNC_USEPARAM, ID2P(LANG_QUEUE_LAST), |
| 621 | playlist_queue_func, (intptr_t*)PLAYLIST_INSERT_LAST, |
| 622 | treeplaylist_wplayback_callback, Icon_Playlist); |
| 623 | MENUITEM_FUNCTION(q_shuf_pl_item, MENU_FUNC_USEPARAM, |
| 624 | ID2P(LANG_QUEUE_SHUFFLED), playlist_queue_func, |
| 625 | (intptr_t*)PLAYLIST_INSERT_SHUFFLED, |
| 626 | treeplaylist_wplayback_callback, Icon_Playlist); |
| 627 | MENUITEM_FUNCTION(q_last_shuf_pl_item, MENU_FUNC_USEPARAM, |
| 628 | ID2P(LANG_QUEUE_LAST_SHUFFLED), playlist_queue_func, |
| 629 | (intptr_t*)PLAYLIST_INSERT_LAST_SHUFFLED, |
| 630 | treeplaylist_callback, Icon_Playlist); |
| 631 | /* replace playlist */ |
| 632 | MENUITEM_FUNCTION(replace_pl_item, MENU_FUNC_USEPARAM, ID2P(LANG_REPLACE), |
| 633 | playlist_insert_func, (intptr_t*)PLAYLIST_REPLACE, |
| 634 | treeplaylist_wplayback_callback, Icon_Playlist); |
| 635 | |
| 636 | /* others */ |
| 637 | MENUITEM_FUNCTION(view_playlist_item, 0, ID2P(LANG_VIEW), |
| 638 | view_playlist, NULL, |
| 639 | treeplaylist_callback, Icon_Playlist); |
| 640 | |
Jonathan Gordon | 97a4c1e | 2011-07-20 14:11:15 +0000 | [diff] [blame] | 641 | MAKE_ONPLAYMENU( tree_playlist_menu, ID2P(LANG_CURRENT_PLAYLIST), |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 642 | treeplaylist_callback, Icon_Playlist, |
Solomon Peachy | fe95127 | 2018-12-14 08:20:25 -0500 | [diff] [blame^] | 643 | |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 644 | /* view */ |
| 645 | &view_playlist_item, |
Solomon Peachy | fe95127 | 2018-12-14 08:20:25 -0500 | [diff] [blame^] | 646 | |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 647 | /* insert */ |
| 648 | &i_pl_item, &i_first_pl_item, &i_last_pl_item, |
| 649 | &i_shuf_pl_item, &i_last_shuf_pl_item, |
| 650 | /* queue */ |
Solomon Peachy | fe95127 | 2018-12-14 08:20:25 -0500 | [diff] [blame^] | 651 | |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 652 | &q_pl_item, &q_first_pl_item, &q_last_pl_item, |
| 653 | &q_shuf_pl_item, &q_last_shuf_pl_item, |
Solomon Peachy | fe95127 | 2018-12-14 08:20:25 -0500 | [diff] [blame^] | 654 | |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 655 | /* replace */ |
| 656 | &replace_pl_item |
| 657 | ); |
| 658 | static int treeplaylist_callback(int action, |
| 659 | const struct menu_item_ex *this_item) |
| 660 | { |
| 661 | switch (action) |
| 662 | { |
| 663 | case ACTION_REQUEST_MENUITEM: |
| 664 | if (this_item == &tree_playlist_menu) |
| 665 | { |
| 666 | if (((selected_file_attr & FILE_ATTR_MASK) == |
| 667 | FILE_ATTR_AUDIO) || |
| 668 | ((selected_file_attr & FILE_ATTR_MASK) == FILE_ATTR_M3U)|| |
| 669 | (selected_file_attr & ATTR_DIRECTORY)) |
| 670 | { |
| 671 | return action; |
| 672 | } |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 673 | } |
| 674 | else if (this_item == &view_playlist_item) |
| 675 | { |
| 676 | if ((selected_file_attr & FILE_ATTR_MASK) == FILE_ATTR_M3U && |
| 677 | context == CONTEXT_TREE) |
| 678 | { |
| 679 | return action; |
| 680 | } |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 681 | } |
| 682 | else if (this_item == &i_shuf_pl_item) |
| 683 | { |
| 684 | if ((audio_status() & AUDIO_STATUS_PLAY) || |
| 685 | (selected_file_attr & ATTR_DIRECTORY) || |
| 686 | ((selected_file_attr & FILE_ATTR_MASK) == FILE_ATTR_M3U)) |
| 687 | { |
| 688 | return action; |
| 689 | } |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 690 | } |
| 691 | else if (this_item == &i_last_shuf_pl_item || |
| 692 | this_item == &q_last_shuf_pl_item) |
| 693 | { |
| 694 | if ((playlist_amount() > 0) && |
| 695 | (audio_status() & AUDIO_STATUS_PLAY) && |
| 696 | ((selected_file_attr & ATTR_DIRECTORY) || |
| 697 | ((selected_file_attr & FILE_ATTR_MASK) == FILE_ATTR_M3U))) |
| 698 | { |
| 699 | return action; |
| 700 | } |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 701 | } |
Teruaki Kawashima | 9bea349 | 2010-02-15 13:04:09 +0000 | [diff] [blame] | 702 | return ACTION_EXIT_MENUITEM; |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 703 | break; |
| 704 | } |
| 705 | return action; |
| 706 | } |
| 707 | |
Jonathan Gordon | 101693f | 2011-11-15 13:22:02 +0000 | [diff] [blame] | 708 | void onplay_show_playlist_menu(char* path) |
Jonathan Gordon | 97a4c1e | 2011-07-20 14:11:15 +0000 | [diff] [blame] | 709 | { |
Jonathan Gordon | 101693f | 2011-11-15 13:22:02 +0000 | [diff] [blame] | 710 | selected_file = path; |
| 711 | if (dir_exists(path)) |
| 712 | selected_file_attr = ATTR_DIRECTORY; |
| 713 | else |
| 714 | selected_file_attr = filetype_get_attr(path); |
Jonathan Gordon | 97a4c1e | 2011-07-20 14:11:15 +0000 | [diff] [blame] | 715 | do_menu(&tree_playlist_menu, NULL, NULL, false); |
| 716 | } |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 717 | |
| 718 | /* playlist catalog options */ |
Jens Arnold | 2597a13 | 2006-12-25 14:01:47 +0000 | [diff] [blame] | 719 | static bool cat_add_to_a_playlist(void) |
Linus Nielsen Feltzing | da0525f | 2006-07-18 13:54:12 +0000 | [diff] [blame] | 720 | { |
| 721 | return catalog_add_to_a_playlist(selected_file, selected_file_attr, |
Jonathan Gordon | 517aca8 | 2008-05-04 13:01:16 +0000 | [diff] [blame] | 722 | false, NULL); |
Linus Nielsen Feltzing | da0525f | 2006-07-18 13:54:12 +0000 | [diff] [blame] | 723 | } |
| 724 | |
Jens Arnold | 2597a13 | 2006-12-25 14:01:47 +0000 | [diff] [blame] | 725 | static bool cat_add_to_a_new_playlist(void) |
Linus Nielsen Feltzing | da0525f | 2006-07-18 13:54:12 +0000 | [diff] [blame] | 726 | { |
Jonathan Gordon | 517aca8 | 2008-05-04 13:01:16 +0000 | [diff] [blame] | 727 | return catalog_add_to_a_playlist(selected_file, selected_file_attr, |
| 728 | true, NULL); |
Linus Nielsen Feltzing | da0525f | 2006-07-18 13:54:12 +0000 | [diff] [blame] | 729 | } |
Jonathan Gordon | 97a4c1e | 2011-07-20 14:11:15 +0000 | [diff] [blame] | 730 | static int clipboard_callback(int action,const struct menu_item_ex *this_item); |
| 731 | static bool set_catalogdir(void) |
| 732 | { |
| 733 | catalog_set_directory(selected_file); |
| 734 | settings_save(); |
| 735 | return false; |
| 736 | } |
| 737 | MENUITEM_FUNCTION(set_catalogdir_item, 0, ID2P(LANG_SET_AS_PLAYLISTCAT_DIR), |
| 738 | set_catalogdir, NULL, clipboard_callback, Icon_Playlist); |
Linus Nielsen Feltzing | da0525f | 2006-07-18 13:54:12 +0000 | [diff] [blame] | 739 | |
Hardeep Sidhu | 8c2bcf1 | 2007-05-15 23:30:30 +0000 | [diff] [blame] | 740 | static int cat_playlist_callback(int action, |
| 741 | const struct menu_item_ex *this_item); |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 742 | MENUITEM_FUNCTION(cat_add_to_list, 0, ID2P(LANG_CATALOG_ADD_TO), |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 743 | cat_add_to_a_playlist, 0, NULL, Icon_Playlist); |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 744 | MENUITEM_FUNCTION(cat_add_to_new, 0, ID2P(LANG_CATALOG_ADD_TO_NEW), |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 745 | cat_add_to_a_new_playlist, 0, NULL, Icon_Playlist); |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 746 | MAKE_ONPLAYMENU(cat_playlist_menu, ID2P(LANG_CATALOG), |
| 747 | cat_playlist_callback, Icon_Playlist, |
Jonathan Gordon | 97a4c1e | 2011-07-20 14:11:15 +0000 | [diff] [blame] | 748 | &cat_add_to_list, &cat_add_to_new, &set_catalogdir_item); |
| 749 | |
| 750 | void onplay_show_playlist_cat_menu(char* track_name) |
| 751 | { |
| 752 | selected_file = track_name; |
| 753 | selected_file_attr = FILE_ATTR_AUDIO; |
| 754 | do_menu(&cat_playlist_menu, NULL, NULL, false); |
| 755 | } |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 756 | |
Hardeep Sidhu | 8c2bcf1 | 2007-05-15 23:30:30 +0000 | [diff] [blame] | 757 | static int cat_playlist_callback(int action, |
| 758 | const struct menu_item_ex *this_item) |
Linus Nielsen Feltzing | da0525f | 2006-07-18 13:54:12 +0000 | [diff] [blame] | 759 | { |
Jonathan Gordon | 97a4c1e | 2011-07-20 14:11:15 +0000 | [diff] [blame] | 760 | (void)this_item; |
Teruaki Kawashima | 9bea349 | 2010-02-15 13:04:09 +0000 | [diff] [blame] | 761 | if (!selected_file || |
| 762 | (((selected_file_attr & FILE_ATTR_MASK) != FILE_ATTR_AUDIO) && |
| 763 | ((selected_file_attr & FILE_ATTR_MASK) != FILE_ATTR_M3U) && |
| 764 | ((selected_file_attr & ATTR_DIRECTORY) == 0))) |
Jonathan Gordon | dada324 | 2008-04-14 10:03:46 +0000 | [diff] [blame] | 765 | { |
| 766 | return ACTION_EXIT_MENUITEM; |
| 767 | } |
Teruaki Kawashima | 993376c | 2010-02-21 12:01:14 +0000 | [diff] [blame] | 768 | #ifdef HAVE_TAGCACHE |
| 769 | if (context == CONTEXT_ID3DB && |
| 770 | ((selected_file_attr & FILE_ATTR_MASK) != FILE_ATTR_AUDIO)) |
| 771 | { |
| 772 | return ACTION_EXIT_MENUITEM; |
| 773 | } |
| 774 | #endif |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 775 | |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 776 | switch (action) |
Linus Nielsen Feltzing | da0525f | 2006-07-18 13:54:12 +0000 | [diff] [blame] | 777 | { |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 778 | case ACTION_REQUEST_MENUITEM: |
Jonathan Gordon | 97a4c1e | 2011-07-20 14:11:15 +0000 | [diff] [blame] | 779 | if ((audio_status() & AUDIO_STATUS_PLAY) || context != CONTEXT_WPS) |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 780 | { |
| 781 | return action; |
| 782 | } |
| 783 | else |
| 784 | return ACTION_EXIT_MENUITEM; |
| 785 | break; |
Hardeep Sidhu | 9e42620 | 2003-07-01 21:05:43 +0000 | [diff] [blame] | 786 | } |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 787 | return action; |
Björn Stenberg | d7a55e1 | 2003-03-12 20:21:30 +0000 | [diff] [blame] | 788 | } |
| 789 | |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 790 | #ifdef HAVE_LCD_BITMAP |
| 791 | static void draw_slider(void) |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 792 | { |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 793 | FOR_NB_SCREENS(i) |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 794 | { |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 795 | struct viewport vp; |
| 796 | int slider_height = 2*screens[i].getcharheight(); |
| 797 | viewport_set_defaults(&vp, i); |
| 798 | screens[i].set_viewport(&vp); |
| 799 | show_busy_slider(&screens[i], 1, vp.height - slider_height, |
| 800 | vp.width-2, slider_height-1); |
| 801 | screens[i].update_viewport(); |
| 802 | screens[i].set_viewport(NULL); |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 803 | } |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 804 | } |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 805 | #else |
| 806 | #define draw_slider() |
| 807 | #endif |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 808 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 809 | static void clear_display(bool update) |
Jörg Hohensohn | bd1ff3e | 2004-04-08 06:38:56 +0000 | [diff] [blame] | 810 | { |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 811 | struct viewport vp; |
Zakk Roberts | 5b93eb6 | 2006-03-22 02:18:44 +0000 | [diff] [blame] | 812 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 813 | FOR_NB_SCREENS(i) |
Jörg Hohensohn | bd1ff3e | 2004-04-08 06:38:56 +0000 | [diff] [blame] | 814 | { |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 815 | struct screen * screen = &screens[i]; |
| 816 | viewport_set_defaults(&vp, screen->screen_type); |
| 817 | screen->set_viewport(&vp); |
| 818 | screen->clear_viewport(); |
| 819 | if (update) { |
| 820 | screen->update_viewport(); |
| 821 | } |
| 822 | screen->set_viewport(NULL); |
| 823 | } |
| 824 | } |
| 825 | |
| 826 | static void splash_path(const char *path) |
| 827 | { |
| 828 | clear_display(false); |
| 829 | path_basename(path, &path); |
| 830 | splash(0, path); |
| 831 | draw_slider(); |
| 832 | } |
| 833 | |
| 834 | /* Splashes the path and checks the keys */ |
| 835 | static bool poll_cancel_action(const char *path) |
| 836 | { |
| 837 | splash_path(path); |
| 838 | return ACTION_STD_CANCEL == get_action(CONTEXT_STD, TIMEOUT_NOBLOCK); |
| 839 | } |
| 840 | |
| 841 | static int confirm_overwrite(void) |
| 842 | { |
| 843 | static const char *lines[] = { ID2P(LANG_REALLY_OVERWRITE) }; |
| 844 | static const struct text_message message = { lines, 1 }; |
| 845 | return gui_syncyesno_run(&message, NULL, NULL); |
| 846 | } |
| 847 | |
| 848 | static int confirm_delete(const char *file) |
| 849 | { |
| 850 | const char *lines[] = { ID2P(LANG_REALLY_DELETE), file }; |
| 851 | const char *yes_lines[] = { ID2P(LANG_DELETING), file }; |
| 852 | const struct text_message message = { lines, 2 }; |
| 853 | const struct text_message yes_message = { yes_lines, 2 }; |
| 854 | return gui_syncyesno_run(&message, &yes_message, NULL); |
| 855 | } |
| 856 | |
| 857 | static bool check_new_name(const char *basename) |
| 858 | { |
| 859 | /* at least prevent escapes out of the base directory from keyboard- |
| 860 | entered filenames; the file code should reject other invalidities */ |
| 861 | return *basename != '\0' && !strchr(basename, PATH_SEPCH) && |
| 862 | !is_dotdir_name(basename); |
| 863 | } |
| 864 | |
| 865 | static void splash_cancelled(void) |
| 866 | { |
| 867 | clear_display(true); |
| 868 | splash(HZ, ID2P(LANG_CANCEL)); |
| 869 | } |
| 870 | |
| 871 | static void splash_failed(int lang_what) |
| 872 | { |
| 873 | cond_talk_ids_fq(lang_what, LANG_FAILED); |
| 874 | clear_display(true); |
| 875 | splashf(HZ*2, "%s %s", str(lang_what), str(LANG_FAILED)); |
| 876 | } |
| 877 | |
| 878 | /* helper function to remove a non-empty directory */ |
| 879 | static int remove_dir(struct dirrecurse_params *parm) |
| 880 | { |
| 881 | DIR *dir = opendir(parm->path); |
| 882 | if (!dir) { |
| 883 | return -1; /* open error */ |
| 884 | } |
| 885 | |
| 886 | size_t append = parm->append; |
| 887 | int rc = OPRC_SUCCESS; |
| 888 | |
| 889 | /* walk through the directory content */ |
| 890 | while (rc == OPRC_SUCCESS) { |
| 891 | errno = 0; /* distinguish failure from eod */ |
| 892 | struct dirent *entry = readdir(dir); |
| 893 | if (!entry) { |
| 894 | if (errno) { |
| 895 | rc = -1; |
| 896 | } |
Jörg Hohensohn | bd1ff3e | 2004-04-08 06:38:56 +0000 | [diff] [blame] | 897 | break; |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 898 | } |
| 899 | |
Thomas Martitz | 6eaab4d | 2010-09-01 21:29:34 +0000 | [diff] [blame] | 900 | struct dirinfo info = dir_get_info(dir, entry); |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 901 | if ((info.attribute & ATTR_DIRECTORY) && |
| 902 | is_dotdir_name(entry->d_name)) { |
| 903 | continue; /* skip these */ |
| 904 | } |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 905 | |
Jörg Hohensohn | bd1ff3e | 2004-04-08 06:38:56 +0000 | [diff] [blame] | 906 | /* append name to current directory */ |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 907 | parm->append = append + path_append(&parm->path[append], |
| 908 | PA_SEP_HARD, entry->d_name, |
| 909 | sizeof (parm->path) - append); |
| 910 | if (parm->append >= sizeof (parm->path)) { |
| 911 | rc = -1; |
| 912 | break; /* no space left in buffer */ |
| 913 | } |
Jörg Hohensohn | bd1ff3e | 2004-04-08 06:38:56 +0000 | [diff] [blame] | 914 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 915 | if (info.attribute & ATTR_DIRECTORY) { |
| 916 | /* remove a subdirectory */ |
| 917 | rc = remove_dir(parm); |
| 918 | } else { |
| 919 | /* remove a file */ |
| 920 | if (poll_cancel_action(parm->path)) { |
| 921 | rc = OPRC_CANCELLED; |
| 922 | break; |
| 923 | } |
| 924 | |
| 925 | rc = remove(parm->path); |
Jörg Hohensohn | bd1ff3e | 2004-04-08 06:38:56 +0000 | [diff] [blame] | 926 | } |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 927 | |
| 928 | /* Remove basename we added above */ |
| 929 | parm->path[append] = '\0'; |
| 930 | } |
| 931 | |
| 932 | closedir(dir); |
| 933 | |
| 934 | if (rc == 0) { |
| 935 | /* remove the now empty directory */ |
| 936 | if (poll_cancel_action(parm->path)) { |
| 937 | rc = OPRC_CANCELLED; |
| 938 | } else { |
| 939 | rc = rmdir(parm->path); |
Jörg Hohensohn | bd1ff3e | 2004-04-08 06:38:56 +0000 | [diff] [blame] | 940 | } |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 941 | } |
| 942 | |
| 943 | return rc; |
| 944 | } |
| 945 | |
| 946 | /* share code for file and directory deletion, saves space */ |
| 947 | static int delete_file_dir(void) |
| 948 | { |
| 949 | if (confirm_delete(selected_file) != YESNO_YES) { |
| 950 | return 1; |
| 951 | } |
| 952 | |
| 953 | clear_display(true); |
| 954 | splash(HZ/2, str(LANG_DELETING)); |
| 955 | |
| 956 | int rc = -1; |
| 957 | |
| 958 | if (selected_file_attr & ATTR_DIRECTORY) { /* true if directory */ |
| 959 | struct dirrecurse_params parm; |
| 960 | parm.append = strlcpy(parm.path, selected_file, sizeof (parm.path)); |
| 961 | |
| 962 | if (parm.append < sizeof (parm.path)) { |
| 963 | cpu_boost(true); |
| 964 | rc = remove_dir(&parm); |
| 965 | cpu_boost(false); |
| 966 | } |
| 967 | } else { |
| 968 | rc = remove(selected_file); |
| 969 | } |
| 970 | |
| 971 | if (rc < OPRC_SUCCESS) { |
| 972 | splash_failed(LANG_DELETE); |
| 973 | } else if (rc == OPRC_CANCELLED) { |
| 974 | splash_cancelled(); |
| 975 | } |
| 976 | |
| 977 | if (rc != OPRC_NOOP) { |
| 978 | /* Could have failed after some but not all needed changes; reload */ |
| 979 | onplay_result = ONPLAY_RELOAD_DIR; |
| 980 | } |
| 981 | |
| 982 | return 1; |
| 983 | } |
| 984 | |
| 985 | static int rename_file(void) |
| 986 | { |
| 987 | int rc = -1; |
| 988 | char newname[MAX_PATH]; |
| 989 | const char *oldbase, *selection = selected_file; |
| 990 | |
| 991 | path_basename(selection, &oldbase); |
| 992 | size_t pathlen = oldbase - selection; |
| 993 | char *newbase = newname + pathlen; |
| 994 | |
| 995 | if (strlcpy(newname, selection, sizeof (newname)) >= sizeof (newname)) { |
| 996 | /* Too long */ |
| 997 | } else if (kbd_input(newbase, sizeof (newname) - pathlen) < 0) { |
| 998 | rc = OPRC_CANCELLED; |
| 999 | } else if (!strcmp(oldbase, newbase)) { |
| 1000 | rc = OPRC_NOOP; /* No change at all */ |
| 1001 | } else if (check_new_name(newbase)) { |
| 1002 | switch (relate(selection, newname)) |
Peter D'Hoye | e21e87a | 2006-12-14 22:43:16 +0000 | [diff] [blame] | 1003 | { |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1004 | case RELATE_DIFFERENT: |
| 1005 | if (file_exists(newname)) { |
| 1006 | break; /* don't overwrite */ |
| 1007 | } |
| 1008 | /* Fall-through */ |
| 1009 | case RELATE_SAME: |
| 1010 | rc = rename(selection, newname); |
| 1011 | break; |
| 1012 | case RELATE_PREFIX: |
| 1013 | default: |
Peter D'Hoye | e21e87a | 2006-12-14 22:43:16 +0000 | [diff] [blame] | 1014 | break; |
| 1015 | } |
Jörg Hohensohn | bd1ff3e | 2004-04-08 06:38:56 +0000 | [diff] [blame] | 1016 | } |
Jörg Hohensohn | bd1ff3e | 2004-04-08 06:38:56 +0000 | [diff] [blame] | 1017 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1018 | if (rc < OPRC_SUCCESS) { |
| 1019 | splash_failed(LANG_RENAME); |
| 1020 | } else if (rc == OPRC_CANCELLED) { |
| 1021 | /* splash_cancelled(); kbd_input() splashes it */ |
| 1022 | } else if (rc == OPRC_SUCCESS) { |
Kevin Ferrare | 40cc43a | 2005-11-22 22:19:08 +0000 | [diff] [blame] | 1023 | onplay_result = ONPLAY_RELOAD_DIR; |
Björn Stenberg | d7a55e1 | 2003-03-12 20:21:30 +0000 | [diff] [blame] | 1024 | } |
| 1025 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1026 | return 1; |
Björn Stenberg | d7a55e1 | 2003-03-12 20:21:30 +0000 | [diff] [blame] | 1027 | } |
| 1028 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1029 | static int create_dir(void) |
Linus Nielsen Feltzing | 642cce2 | 2004-03-11 10:43:53 +0000 | [diff] [blame] | 1030 | { |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1031 | int rc = -1; |
Linus Nielsen Feltzing | 642cce2 | 2004-03-11 10:43:53 +0000 | [diff] [blame] | 1032 | char dirname[MAX_PATH]; |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1033 | size_t pathlen = path_append(dirname, getcwd(NULL, 0), PA_SEP_HARD, |
| 1034 | sizeof (dirname)); |
| 1035 | char *basename = dirname + pathlen; |
Linus Nielsen Feltzing | 642cce2 | 2004-03-11 10:43:53 +0000 | [diff] [blame] | 1036 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1037 | if (pathlen >= sizeof (dirname)) { |
| 1038 | /* Too long */ |
| 1039 | } else if (kbd_input(basename, sizeof (dirname) - pathlen) < 0) { |
| 1040 | rc = OPRC_CANCELLED; |
| 1041 | } else if (check_new_name(basename)) { |
| 1042 | rc = mkdir(dirname); |
| 1043 | } |
Zakk Roberts | 5b93eb6 | 2006-03-22 02:18:44 +0000 | [diff] [blame] | 1044 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1045 | if (rc < OPRC_SUCCESS) { |
| 1046 | splash_failed(LANG_CREATE_DIR); |
| 1047 | } else if (rc == OPRC_CANCELLED) { |
| 1048 | /* splash_cancelled(); kbd_input() splashes it */ |
| 1049 | } else if (rc == OPRC_SUCCESS) { |
Linus Nielsen Feltzing | 642cce2 | 2004-03-11 10:43:53 +0000 | [diff] [blame] | 1050 | onplay_result = ONPLAY_RELOAD_DIR; |
| 1051 | } |
| 1052 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1053 | return 1; |
Linus Nielsen Feltzing | 642cce2 | 2004-03-11 10:43:53 +0000 | [diff] [blame] | 1054 | } |
| 1055 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1056 | /* Paste a file */ |
| 1057 | static int clipboard_pastefile(const char *src, const char *target, |
| 1058 | unsigned int flags) |
Dan Everton | 1429c9b | 2006-03-20 11:46:06 +0000 | [diff] [blame] | 1059 | { |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1060 | int rc = -1; |
Dan Everton | 1429c9b | 2006-03-20 11:46:06 +0000 | [diff] [blame] | 1061 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1062 | while (!(flags & (PASTE_COPY | PASTE_EXDEV))) { |
| 1063 | if ((flags & PASTE_OVERWRITE) || !file_exists(target)) { |
| 1064 | /* Rename and possibly overwrite the file */ |
| 1065 | if (poll_cancel_action(src)) { |
| 1066 | rc = OPRC_CANCELLED; |
| 1067 | } else { |
| 1068 | rc = rename(src, target); |
| 1069 | } |
| 1070 | |
| 1071 | #ifdef HAVE_MULTIVOLUME |
| 1072 | if (rc < 0 && errno == EXDEV) { |
| 1073 | /* Failed because cross volume rename doesn't work; force |
| 1074 | a move instead */ |
| 1075 | flags |= PASTE_EXDEV; |
| 1076 | break; |
| 1077 | } |
| 1078 | #endif /* HAVE_MULTIVOLUME */ |
| 1079 | } |
| 1080 | |
| 1081 | return rc; |
| 1082 | } |
| 1083 | |
| 1084 | /* See if we can get the plugin buffer for the file copy buffer */ |
| 1085 | size_t buffersize; |
| 1086 | char *buffer = (char *) plugin_get_buffer(&buffersize); |
| 1087 | if (buffer == NULL || buffersize < 512) { |
| 1088 | /* Not large enough, try for a disk sector worth of stack |
| 1089 | instead */ |
| 1090 | buffersize = 512; |
| 1091 | buffer = (char *)alloca(buffersize); |
| 1092 | } |
| 1093 | |
| 1094 | if (buffer == NULL) { |
| 1095 | return -1; |
| 1096 | } |
| 1097 | |
| 1098 | buffersize &= ~0x1ff; /* Round buffer size to multiple of sector |
| 1099 | size */ |
| 1100 | |
| 1101 | int src_fd = open(src, O_RDONLY); |
| 1102 | if (src_fd >= 0) { |
| 1103 | int oflag = O_WRONLY|O_CREAT; |
| 1104 | |
| 1105 | if (!(flags & PASTE_OVERWRITE)) { |
| 1106 | oflag |= O_EXCL; |
| 1107 | } |
| 1108 | |
| 1109 | int target_fd = open(target, oflag, 0666); |
| 1110 | if (target_fd >= 0) { |
| 1111 | off_t total_size = 0; |
| 1112 | off_t next_cancel_test = 0; /* No excessive button polling */ |
| 1113 | |
| 1114 | rc = OPRC_SUCCESS; |
| 1115 | |
| 1116 | while (rc == OPRC_SUCCESS) { |
| 1117 | if (total_size >= next_cancel_test) { |
| 1118 | next_cancel_test = total_size + 0x10000; |
| 1119 | if (poll_cancel_action(src)) { |
| 1120 | rc = OPRC_CANCELLED; |
| 1121 | break; |
| 1122 | } |
| 1123 | } |
| 1124 | |
| 1125 | ssize_t bytesread = read(src_fd, buffer, buffersize); |
| 1126 | if (bytesread <= 0) { |
| 1127 | if (bytesread < 0) { |
| 1128 | rc = -1; |
| 1129 | } |
| 1130 | /* else eof on buffer boundary; nothing to write */ |
| 1131 | break; |
| 1132 | } |
| 1133 | |
| 1134 | ssize_t byteswritten = write(target_fd, buffer, bytesread); |
| 1135 | if (byteswritten < bytesread) { |
| 1136 | /* Some I/O error */ |
| 1137 | rc = -1; |
| 1138 | break; |
| 1139 | } |
| 1140 | |
| 1141 | total_size += byteswritten; |
| 1142 | |
| 1143 | if (bytesread < (ssize_t)buffersize) { |
| 1144 | /* EOF with trailing bytes */ |
| 1145 | break; |
| 1146 | } |
| 1147 | } |
| 1148 | |
| 1149 | if (rc == OPRC_SUCCESS) { |
| 1150 | /* If overwriting, set the correct length if original was |
| 1151 | longer */ |
| 1152 | rc = ftruncate(target_fd, total_size); |
| 1153 | } |
| 1154 | |
| 1155 | close(target_fd); |
| 1156 | |
| 1157 | if (rc != OPRC_SUCCESS) { |
| 1158 | /* Copy failed. Cleanup. */ |
| 1159 | remove(target); |
| 1160 | } |
| 1161 | } |
| 1162 | |
| 1163 | close(src_fd); |
| 1164 | } |
| 1165 | |
| 1166 | if (rc == OPRC_SUCCESS && !(flags & PASTE_COPY)) { |
| 1167 | /* Remove the source file */ |
| 1168 | rc = remove(src); |
| 1169 | } |
| 1170 | |
| 1171 | return rc; |
| 1172 | } |
| 1173 | |
| 1174 | /* Paste a directory */ |
| 1175 | static int clipboard_pastedirectory(struct dirrecurse_params *src, |
| 1176 | struct dirrecurse_params *target, |
| 1177 | unsigned int flags) |
| 1178 | { |
| 1179 | int rc = -1; |
| 1180 | |
| 1181 | while (!(flags & (PASTE_COPY | PASTE_EXDEV))) { |
| 1182 | if ((flags & PASTE_OVERWRITE) || !file_exists(target->path)) { |
| 1183 | /* Just try to move the directory */ |
| 1184 | if (poll_cancel_action(src->path)) { |
| 1185 | rc = OPRC_CANCELLED; |
| 1186 | } else { |
| 1187 | rc = rename(src->path, target->path); |
| 1188 | } |
| 1189 | |
| 1190 | if (rc < 0) { |
| 1191 | int errnum = errno; |
| 1192 | if (errnum == ENOTEMPTY && (flags & PASTE_OVERWRITE)) { |
| 1193 | /* Directory is not empty thus rename() will not do a quick |
| 1194 | overwrite */ |
| 1195 | break; |
| 1196 | } |
| 1197 | #ifdef HAVE_MULTIVOLUME |
| 1198 | else if (errnum == EXDEV) { |
| 1199 | /* Failed because cross volume rename doesn't work; force |
| 1200 | a move instead */ |
| 1201 | flags |= PASTE_EXDEV; |
| 1202 | break; |
Solomon Peachy | fe95127 | 2018-12-14 08:20:25 -0500 | [diff] [blame^] | 1203 | } |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1204 | #endif /* HAVE_MULTIVOLUME */ |
| 1205 | } |
| 1206 | } |
| 1207 | |
| 1208 | return rc; |
| 1209 | } |
| 1210 | |
| 1211 | DIR *srcdir = opendir(src->path); |
| 1212 | |
| 1213 | if (srcdir) { |
| 1214 | /* Make a directory to copy things to */ |
| 1215 | rc = mkdir(target->path); |
| 1216 | if (rc < 0 && errno == EEXIST && (flags & PASTE_OVERWRITE)) { |
| 1217 | /* Exists and overwrite was approved */ |
| 1218 | rc = OPRC_SUCCESS; |
| 1219 | } |
| 1220 | } |
| 1221 | |
| 1222 | size_t srcap = src->append, targetap = target->append; |
| 1223 | |
| 1224 | /* Walk through the directory content; this loop will exit as soon as |
| 1225 | there's a problem */ |
| 1226 | while (rc == OPRC_SUCCESS) { |
| 1227 | errno = 0; /* Distinguish failure from eod */ |
| 1228 | struct dirent *entry = readdir(srcdir); |
| 1229 | if (!entry) { |
| 1230 | if (errno) { |
| 1231 | rc = -1; |
| 1232 | } |
| 1233 | break; |
| 1234 | } |
| 1235 | |
| 1236 | struct dirinfo info = dir_get_info(srcdir, entry); |
| 1237 | if ((info.attribute & ATTR_DIRECTORY) && |
| 1238 | is_dotdir_name(entry->d_name)) { |
| 1239 | continue; /* Skip these */ |
| 1240 | } |
| 1241 | |
| 1242 | /* Append names to current directories */ |
| 1243 | src->append = srcap + |
| 1244 | path_append(&src->path[srcap], PA_SEP_HARD, entry->d_name, |
| 1245 | sizeof(src->path) - srcap); |
| 1246 | |
| 1247 | target->append = targetap + |
| 1248 | path_append(&target->path[targetap], PA_SEP_HARD, entry->d_name, |
| 1249 | sizeof (target->path) - targetap); |
| 1250 | |
| 1251 | if (src->append >= sizeof (src->path) || |
| 1252 | target->append >= sizeof (target->path)) { |
| 1253 | rc = -1; /* No space left in buffer */ |
| 1254 | break; |
| 1255 | } |
| 1256 | |
| 1257 | if (poll_cancel_action(src->path)) { |
| 1258 | rc = OPRC_CANCELLED; |
| 1259 | break; |
| 1260 | } |
Solomon Peachy | fe95127 | 2018-12-14 08:20:25 -0500 | [diff] [blame^] | 1261 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1262 | DEBUGF("Copy %s to %s\n", src->path, target->path); |
| 1263 | |
| 1264 | if (info.attribute & ATTR_DIRECTORY) { |
| 1265 | /* Copy/move a subdirectory */ |
| 1266 | rc = clipboard_pastedirectory(src, target, flags); /* recursion */ |
| 1267 | } else { |
| 1268 | /* Copy/move a file */ |
| 1269 | rc = clipboard_pastefile(src->path, target->path, flags); |
| 1270 | } |
| 1271 | |
| 1272 | /* Remove basenames we added above */ |
| 1273 | src->path[srcap] = target->path[targetap] = '\0'; |
| 1274 | } |
| 1275 | |
| 1276 | if (rc == OPRC_SUCCESS && !(flags & PASTE_COPY)) { |
| 1277 | /* Remove the now empty directory */ |
| 1278 | rc = rmdir(src->path); |
| 1279 | } |
| 1280 | |
| 1281 | closedir(srcdir); |
| 1282 | return rc; |
Dan Everton | 1429c9b | 2006-03-20 11:46:06 +0000 | [diff] [blame] | 1283 | } |
| 1284 | |
| 1285 | static bool clipboard_cut(void) |
| 1286 | { |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1287 | return clipboard_clip(&clipboard, selected_file, selected_file_attr, |
| 1288 | PASTE_CUT); |
Dan Everton | 1429c9b | 2006-03-20 11:46:06 +0000 | [diff] [blame] | 1289 | } |
| 1290 | |
| 1291 | static bool clipboard_copy(void) |
| 1292 | { |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1293 | return clipboard_clip(&clipboard, selected_file, selected_file_attr, |
| 1294 | PASTE_COPY); |
Dan Everton | 1429c9b | 2006-03-20 11:46:06 +0000 | [diff] [blame] | 1295 | } |
| 1296 | |
| 1297 | /* Paste the clipboard to the current directory */ |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1298 | static int clipboard_paste(void) |
Dan Everton | 1429c9b | 2006-03-20 11:46:06 +0000 | [diff] [blame] | 1299 | { |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1300 | if (!clipboard.path[0]) |
| 1301 | return 1; |
Dan Everton | 1429c9b | 2006-03-20 11:46:06 +0000 | [diff] [blame] | 1302 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1303 | int rc = -1; |
Dan Everton | 1429c9b | 2006-03-20 11:46:06 +0000 | [diff] [blame] | 1304 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1305 | struct dirrecurse_params src, target; |
| 1306 | unsigned int flags = clipboard.flags; |
Dan Everton | 1429c9b | 2006-03-20 11:46:06 +0000 | [diff] [blame] | 1307 | |
| 1308 | /* Figure out the name of the selection */ |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1309 | const char *nameptr; |
| 1310 | path_basename(clipboard.path, &nameptr); |
Dan Everton | 1429c9b | 2006-03-20 11:46:06 +0000 | [diff] [blame] | 1311 | |
Peter D'Hoye | 6be6156 | 2007-04-12 22:38:54 +0000 | [diff] [blame] | 1312 | /* Final target is current directory plus name of selection */ |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1313 | target.append = path_append(target.path, getcwd(NULL, 0), |
| 1314 | nameptr, sizeof (target.path)); |
Dan Everton | 1429c9b | 2006-03-20 11:46:06 +0000 | [diff] [blame] | 1315 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1316 | switch (target.append < sizeof (target.path) ? |
| 1317 | relate(clipboard.path, target.path) : -1) |
Dan Everton | 4c486ce | 2007-05-20 10:04:39 +0000 | [diff] [blame] | 1318 | { |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1319 | case RELATE_SAME: |
| 1320 | rc = OPRC_NOOP; |
| 1321 | break; |
Dan Everton | 4c486ce | 2007-05-20 10:04:39 +0000 | [diff] [blame] | 1322 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1323 | case RELATE_DIFFERENT: |
| 1324 | if (file_exists(target.path)) { |
| 1325 | /* If user chooses not to overwrite, cancel */ |
| 1326 | if (confirm_overwrite() == YESNO_NO) { |
| 1327 | rc = OPRC_NOOVERWRT; |
| 1328 | break; |
Nils Wallménius | d7fb430 | 2008-12-01 11:31:22 +0000 | [diff] [blame] | 1329 | } |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1330 | |
| 1331 | flags |= PASTE_OVERWRITE; |
Jonathan Gordon | 96016e4 | 2007-02-27 10:06:55 +0000 | [diff] [blame] | 1332 | } |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1333 | |
| 1334 | clear_display(true); |
| 1335 | splash(HZ/2, (flags & PASTE_COPY) ? ID2P(LANG_COPYING) : |
| 1336 | ID2P(LANG_MOVING)); |
| 1337 | |
| 1338 | /* Now figure out what we're doing */ |
| 1339 | cpu_boost(true); |
| 1340 | |
| 1341 | if (clipboard.attr & ATTR_DIRECTORY) { |
| 1342 | /* Copy or move a subdirectory */ |
| 1343 | src.append = strlcpy(src.path, clipboard.path, |
| 1344 | sizeof (src.path)); |
| 1345 | if (src.append < sizeof (src.path)) { |
| 1346 | rc = clipboard_pastedirectory(&src, &target, flags); |
| 1347 | } |
| 1348 | } else { |
| 1349 | /* Copy or move a file */ |
| 1350 | rc = clipboard_pastefile(clipboard.path, target.path, flags); |
| 1351 | } |
| 1352 | |
| 1353 | cpu_boost(false); |
| 1354 | break; |
| 1355 | |
| 1356 | case RELATE_PREFIX: |
| 1357 | default: /* Some other relation / failure */ |
| 1358 | break; |
Dan Everton | 1429c9b | 2006-03-20 11:46:06 +0000 | [diff] [blame] | 1359 | } |
| 1360 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1361 | clear_display(true); |
Dan Everton | 1429c9b | 2006-03-20 11:46:06 +0000 | [diff] [blame] | 1362 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1363 | switch (rc) |
| 1364 | { |
| 1365 | case OPRC_CANCELLED: |
| 1366 | splash_cancelled(); |
| 1367 | case OPRC_SUCCESS: |
Dan Everton | 1429c9b | 2006-03-20 11:46:06 +0000 | [diff] [blame] | 1368 | onplay_result = ONPLAY_RELOAD_DIR; |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1369 | case OPRC_NOOP: |
| 1370 | clipboard_clear_selection(&clipboard); |
| 1371 | case OPRC_NOOVERWRT: |
| 1372 | break; |
| 1373 | default: |
| 1374 | if (rc < OPRC_SUCCESS) { |
| 1375 | splash_failed(LANG_PASTE); |
| 1376 | onplay_result = ONPLAY_RELOAD_DIR; |
| 1377 | } |
Dan Everton | 1429c9b | 2006-03-20 11:46:06 +0000 | [diff] [blame] | 1378 | } |
| 1379 | |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1380 | return 1; |
Dan Everton | 1429c9b | 2006-03-20 11:46:06 +0000 | [diff] [blame] | 1381 | } |
| 1382 | |
Robert Kukla | 40595bd | 2007-03-26 23:10:40 +0000 | [diff] [blame] | 1383 | #ifdef HAVE_TAGCACHE |
Jonathan Gordon | 49ca667 | 2007-11-08 14:00:36 +0000 | [diff] [blame] | 1384 | static int set_rating_inline(void) |
Robert Kukla | 226cb7b | 2007-03-26 15:08:59 +0000 | [diff] [blame] | 1385 | { |
| 1386 | struct mp3entry* id3 = audio_current_track(); |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 1387 | if (id3 && id3->tagcache_idx && global_settings.runtimedb) |
Miika Pekkarinen | 9d756e2 | 2007-07-21 17:35:19 +0000 | [diff] [blame] | 1388 | { |
Jonathan Gordon | 49ca667 | 2007-11-08 14:00:36 +0000 | [diff] [blame] | 1389 | set_int_ex(str(LANG_MENU_SET_RATING), "", UNIT_INT, (void*)(&id3->rating), |
| 1390 | NULL, 1, 0, 10, NULL, NULL); |
Robert Kukla | ad5610d | 2008-02-12 18:51:10 +0000 | [diff] [blame] | 1391 | tagcache_update_numeric(id3->tagcache_idx-1, tag_rating, id3->rating); |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1392 | } |
Jonathan Gordon | 49ca667 | 2007-11-08 14:00:36 +0000 | [diff] [blame] | 1393 | else |
Nils Wallménius | 01729e7 | 2008-08-15 08:27:39 +0000 | [diff] [blame] | 1394 | splash(HZ*2, ID2P(LANG_ID3_NO_INFO)); |
Jonathan Gordon | 49ca667 | 2007-11-08 14:00:36 +0000 | [diff] [blame] | 1395 | return 0; |
Robert Kukla | 226cb7b | 2007-03-26 15:08:59 +0000 | [diff] [blame] | 1396 | } |
Robert Kukla | 987faea | 2007-11-08 16:31:44 +0000 | [diff] [blame] | 1397 | static int ratingitem_callback(int action,const struct menu_item_ex *this_item) |
| 1398 | { |
| 1399 | (void)this_item; |
| 1400 | switch (action) |
| 1401 | { |
| 1402 | case ACTION_REQUEST_MENUITEM: |
Jonathan Gordon | ff2e9bd | 2008-12-21 09:58:11 +0000 | [diff] [blame] | 1403 | if (!selected_file || !global_settings.runtimedb || |
| 1404 | !tagcache_is_usable()) |
Robert Kukla | 987faea | 2007-11-08 16:31:44 +0000 | [diff] [blame] | 1405 | return ACTION_EXIT_MENUITEM; |
| 1406 | break; |
| 1407 | } |
| 1408 | return action; |
| 1409 | } |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 1410 | MENUITEM_FUNCTION(rating_item, 0, ID2P(LANG_MENU_SET_RATING), |
| 1411 | set_rating_inline, NULL, |
Robert Kukla | 987faea | 2007-11-08 16:31:44 +0000 | [diff] [blame] | 1412 | ratingitem_callback, Icon_Questionmark); |
Solomon Peachy | fe95127 | 2018-12-14 08:20:25 -0500 | [diff] [blame^] | 1413 | #endif |
| 1414 | #ifdef HAVE_PICTUREFLOW_INTEGRATION |
| 1415 | MENUITEM_RETURNVALUE(pictureflow_item, ID2P(LANG_ONPLAY_PICTUREFLOW), |
| 1416 | GO_TO_PICTUREFLOW, NULL, Icon_NOICON); |
Robert Kukla | 40595bd | 2007-03-26 23:10:40 +0000 | [diff] [blame] | 1417 | #endif |
Robert Kukla | 226cb7b | 2007-03-26 15:08:59 +0000 | [diff] [blame] | 1418 | |
Nicolas Pennequin | 6190a0d | 2007-05-14 17:34:52 +0000 | [diff] [blame] | 1419 | static bool view_cue(void) |
| 1420 | { |
| 1421 | struct mp3entry* id3 = audio_current_track(); |
Solomon Peachy | fe95127 | 2018-12-14 08:20:25 -0500 | [diff] [blame^] | 1422 | if (id3 && id3->cuesheet) |
Nicolas Pennequin | 6190a0d | 2007-05-14 17:34:52 +0000 | [diff] [blame] | 1423 | { |
Jonathan Gordon | 24b136f | 2009-07-20 05:18:18 +0000 | [diff] [blame] | 1424 | browse_cuesheet(id3->cuesheet); |
Nicolas Pennequin | 6190a0d | 2007-05-14 17:34:52 +0000 | [diff] [blame] | 1425 | } |
| 1426 | return false; |
| 1427 | } |
Hardeep Sidhu | 8c2bcf1 | 2007-05-15 23:30:30 +0000 | [diff] [blame] | 1428 | static int view_cue_item_callback(int action, |
| 1429 | const struct menu_item_ex *this_item) |
Nicolas Pennequin | 6190a0d | 2007-05-14 17:34:52 +0000 | [diff] [blame] | 1430 | { |
| 1431 | (void)this_item; |
| 1432 | struct mp3entry* id3 = audio_current_track(); |
| 1433 | switch (action) |
| 1434 | { |
| 1435 | case ACTION_REQUEST_MENUITEM: |
Jonathan Gordon | 24b136f | 2009-07-20 05:18:18 +0000 | [diff] [blame] | 1436 | if (!selected_file |
| 1437 | || !id3 || !id3->cuesheet) |
Nicolas Pennequin | 6190a0d | 2007-05-14 17:34:52 +0000 | [diff] [blame] | 1438 | return ACTION_EXIT_MENUITEM; |
| 1439 | break; |
| 1440 | } |
| 1441 | return action; |
| 1442 | } |
| 1443 | MENUITEM_FUNCTION(view_cue_item, 0, ID2P(LANG_BROWSE_CUESHEET), |
| 1444 | view_cue, NULL, view_cue_item_callback, Icon_NOICON); |
| 1445 | |
Thomas Martitz | b779fcc | 2011-10-07 22:59:06 +0000 | [diff] [blame] | 1446 | |
| 1447 | static int browse_id3_wrapper(void) |
| 1448 | { |
| 1449 | if (browse_id3()) |
| 1450 | return GO_TO_ROOT; |
| 1451 | return GO_TO_PREVIOUS; |
| 1452 | } |
| 1453 | |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1454 | /* CONTEXT_WPS items */ |
Thomas Martitz | b779fcc | 2011-10-07 22:59:06 +0000 | [diff] [blame] | 1455 | MENUITEM_FUNCTION(browse_id3_item, MENU_FUNC_CHECK_RETVAL, ID2P(LANG_MENU_SHOW_ID3_INFO), |
| 1456 | browse_id3_wrapper, NULL, NULL, Icon_NOICON); |
Nils Wallménius | d29a11b | 2012-05-08 16:34:26 +0200 | [diff] [blame] | 1457 | #ifdef HAVE_PITCHCONTROL |
Jeffrey Goode | 1ad76ff | 2010-05-09 02:02:51 +0000 | [diff] [blame] | 1458 | MENUITEM_FUNCTION(pitch_screen_item, 0, ID2P(LANG_PITCH), |
Jonathan Gordon | 1da2f01 | 2008-10-05 13:01:54 +0000 | [diff] [blame] | 1459 | gui_syncpitchscreen_run, NULL, NULL, Icon_Audio); |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1460 | #endif |
Stéphane Doyon | ab0f7e1 | 2008-05-04 13:47:58 +0000 | [diff] [blame] | 1461 | |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1462 | /* CONTEXT_[TREE|ID3DB] items */ |
| 1463 | static int clipboard_callback(int action,const struct menu_item_ex *this_item); |
| 1464 | MENUITEM_FUNCTION(rename_file_item, 0, ID2P(LANG_RENAME), |
| 1465 | rename_file, NULL, clipboard_callback, Icon_NOICON); |
| 1466 | MENUITEM_FUNCTION(clipboard_cut_item, 0, ID2P(LANG_CUT), |
| 1467 | clipboard_cut, NULL, clipboard_callback, Icon_NOICON); |
| 1468 | MENUITEM_FUNCTION(clipboard_copy_item, 0, ID2P(LANG_COPY), |
| 1469 | clipboard_copy, NULL, clipboard_callback, Icon_NOICON); |
| 1470 | MENUITEM_FUNCTION(clipboard_paste_item, 0, ID2P(LANG_PASTE), |
| 1471 | clipboard_paste, NULL, clipboard_callback, Icon_NOICON); |
Jeffrey Goode | 1ad76ff | 2010-05-09 02:02:51 +0000 | [diff] [blame] | 1472 | MENUITEM_FUNCTION(delete_file_item, 0, ID2P(LANG_DELETE), |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1473 | delete_file_dir, NULL, clipboard_callback, Icon_NOICON); |
Jeffrey Goode | 1ad76ff | 2010-05-09 02:02:51 +0000 | [diff] [blame] | 1474 | MENUITEM_FUNCTION(delete_dir_item, 0, ID2P(LANG_DELETE_DIR), |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1475 | delete_file_dir, NULL, clipboard_callback, Icon_NOICON); |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1476 | MENUITEM_FUNCTION(create_dir_item, 0, ID2P(LANG_CREATE_DIR), |
| 1477 | create_dir, NULL, clipboard_callback, Icon_NOICON); |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 1478 | |
| 1479 | /* other items */ |
| 1480 | static bool list_viewers(void) |
| 1481 | { |
| 1482 | int ret = filetype_list_viewers(selected_file); |
| 1483 | if (ret == PLUGIN_USB_CONNECTED) |
| 1484 | onplay_result = ONPLAY_RELOAD_DIR; |
| 1485 | return false; |
| 1486 | } |
| 1487 | |
| 1488 | static bool onplay_load_plugin(void *param) |
| 1489 | { |
| 1490 | int ret = filetype_load_plugin((const char*)param, selected_file); |
| 1491 | if (ret == PLUGIN_USB_CONNECTED) |
| 1492 | onplay_result = ONPLAY_RELOAD_DIR; |
| 1493 | return false; |
| 1494 | } |
| 1495 | |
Jeffrey Goode | 1ad76ff | 2010-05-09 02:02:51 +0000 | [diff] [blame] | 1496 | MENUITEM_FUNCTION(list_viewers_item, 0, ID2P(LANG_ONPLAY_OPEN_WITH), |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1497 | list_viewers, NULL, clipboard_callback, Icon_NOICON); |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 1498 | MENUITEM_FUNCTION(properties_item, MENU_FUNC_USEPARAM, ID2P(LANG_PROPERTIES), |
| 1499 | onplay_load_plugin, (void *)"properties", |
| 1500 | clipboard_callback, Icon_NOICON); |
Jonathan Gordon | 101693f | 2011-11-15 13:22:02 +0000 | [diff] [blame] | 1501 | static bool onplay_add_to_shortcuts(void) |
| 1502 | { |
| 1503 | shortcuts_add(SHORTCUT_BROWSER, selected_file); |
| 1504 | return false; |
| 1505 | } |
| 1506 | MENUITEM_FUNCTION(add_to_faves_item, 0, ID2P(LANG_ADD_TO_FAVES), |
| 1507 | onplay_add_to_shortcuts, NULL, |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 1508 | clipboard_callback, Icon_NOICON); |
| 1509 | |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1510 | #if LCD_DEPTH > 1 |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 1511 | static bool set_backdrop(void) |
| 1512 | { |
Frank Gevaerts | d09f978 | 2011-04-10 13:25:47 +0000 | [diff] [blame] | 1513 | strlcpy(global_settings.backdrop_file, selected_file, |
| 1514 | sizeof(global_settings.backdrop_file)); |
| 1515 | settings_save(); |
Jonathan Gordon | 9928e34 | 2010-09-14 11:56:50 +0000 | [diff] [blame] | 1516 | skin_backdrop_load_setting(); |
Thomas Martitz | e126153 | 2011-10-28 17:09:38 +0000 | [diff] [blame] | 1517 | skin_backdrop_show(sb_get_backdrop(SCREEN_MAIN)); |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 1518 | return true; |
| 1519 | } |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1520 | MENUITEM_FUNCTION(set_backdrop_item, 0, ID2P(LANG_SET_AS_BACKDROP), |
| 1521 | set_backdrop, NULL, clipboard_callback, Icon_NOICON); |
| 1522 | #endif |
Jonathan Gordon | 415e9d7 | 2007-07-10 07:41:37 +0000 | [diff] [blame] | 1523 | #ifdef HAVE_RECORDING |
| 1524 | static bool set_recdir(void) |
| 1525 | { |
Teruaki Kawashima | 2142628 | 2010-11-15 12:33:47 +0000 | [diff] [blame] | 1526 | strlcpy(global_settings.rec_directory, selected_file, |
| 1527 | sizeof(global_settings.rec_directory)); |
Peter D'Hoye | 80ad459 | 2008-02-10 18:28:59 +0000 | [diff] [blame] | 1528 | settings_save(); |
Jonathan Gordon | 415e9d7 | 2007-07-10 07:41:37 +0000 | [diff] [blame] | 1529 | return false; |
| 1530 | } |
| 1531 | MENUITEM_FUNCTION(set_recdir_item, 0, ID2P(LANG_SET_AS_REC_DIR), |
| 1532 | set_recdir, NULL, clipboard_callback, Icon_Recording); |
| 1533 | #endif |
Jonathan Gordon | efbcece | 2010-10-04 10:34:38 +0000 | [diff] [blame] | 1534 | static bool set_startdir(void) |
| 1535 | { |
Solomon Peachy | fe95127 | 2018-12-14 08:20:25 -0500 | [diff] [blame^] | 1536 | snprintf(global_settings.start_directory, |
Jonathan Gordon | efbcece | 2010-10-04 10:34:38 +0000 | [diff] [blame] | 1537 | sizeof(global_settings.start_directory), |
| 1538 | "%s/", selected_file); |
| 1539 | settings_save(); |
| 1540 | return false; |
| 1541 | } |
| 1542 | MENUITEM_FUNCTION(set_startdir_item, 0, ID2P(LANG_SET_AS_START_DIR), |
| 1543 | set_startdir, NULL, clipboard_callback, Icon_file_view_menu); |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1544 | |
| 1545 | static int clipboard_callback(int action,const struct menu_item_ex *this_item) |
| 1546 | { |
| 1547 | switch (action) |
| 1548 | { |
| 1549 | case ACTION_REQUEST_MENUITEM: |
Jonathan Gordon | e8dbe2e | 2008-04-21 14:52:42 +0000 | [diff] [blame] | 1550 | #ifdef HAVE_MULTIVOLUME |
Teruaki Kawashima | 9bea349 | 2010-02-15 13:04:09 +0000 | [diff] [blame] | 1551 | /* no rename+delete for volumes */ |
| 1552 | if ((selected_file_attr & ATTR_VOLUME) && |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1553 | (this_item == &rename_file_item || |
| 1554 | this_item == &delete_dir_item || |
| 1555 | this_item == &clipboard_cut_item || |
| 1556 | this_item == &list_viewers_item)) |
Teruaki Kawashima | 9bea349 | 2010-02-15 13:04:09 +0000 | [diff] [blame] | 1557 | return ACTION_EXIT_MENUITEM; |
Jonathan Gordon | e8dbe2e | 2008-04-21 14:52:42 +0000 | [diff] [blame] | 1558 | #endif |
Teruaki Kawashima | 9bea349 | 2010-02-15 13:04:09 +0000 | [diff] [blame] | 1559 | #ifdef HAVE_TAGCACHE |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1560 | if (context == CONTEXT_ID3DB) |
Teruaki Kawashima | 993376c | 2010-02-21 12:01:14 +0000 | [diff] [blame] | 1561 | { |
| 1562 | if (((selected_file_attr & FILE_ATTR_MASK) == |
| 1563 | FILE_ATTR_AUDIO) && |
| 1564 | this_item == &properties_item) |
| 1565 | return action; |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1566 | return ACTION_EXIT_MENUITEM; |
Teruaki Kawashima | 993376c | 2010-02-21 12:01:14 +0000 | [diff] [blame] | 1567 | } |
Teruaki Kawashima | 9bea349 | 2010-02-15 13:04:09 +0000 | [diff] [blame] | 1568 | #endif |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1569 | if (this_item == &clipboard_paste_item) |
| 1570 | { /* visible if there is something to paste */ |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1571 | return (clipboard.path[0] != 0) ? |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1572 | action : ACTION_EXIT_MENUITEM; |
| 1573 | } |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 1574 | else if (this_item == &create_dir_item) |
Robert Kukla | f617ba4 | 2008-04-09 13:50:33 +0000 | [diff] [blame] | 1575 | { |
| 1576 | /* always visible */ |
| 1577 | return action; |
| 1578 | } |
Teruaki Kawashima | 9bea349 | 2010-02-15 13:04:09 +0000 | [diff] [blame] | 1579 | else if (selected_file) |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1580 | { |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 1581 | /* requires an actual file */ |
Teruaki Kawashima | 9bea349 | 2010-02-15 13:04:09 +0000 | [diff] [blame] | 1582 | if (this_item == &rename_file_item || |
| 1583 | this_item == &clipboard_cut_item || |
| 1584 | this_item == &clipboard_copy_item || |
| 1585 | this_item == &properties_item || |
| 1586 | this_item == &add_to_faves_item) |
| 1587 | { |
| 1588 | return action; |
| 1589 | } |
| 1590 | else if ((selected_file_attr & ATTR_DIRECTORY)) |
| 1591 | { |
| 1592 | /* only for directories */ |
Jonathan Gordon | efbcece | 2010-10-04 10:34:38 +0000 | [diff] [blame] | 1593 | if (this_item == &delete_dir_item || |
Jonathan Gordon | 97a4c1e | 2011-07-20 14:11:15 +0000 | [diff] [blame] | 1594 | this_item == &set_startdir_item || |
| 1595 | this_item == &set_catalogdir_item |
Teruaki Kawashima | 9bea349 | 2010-02-15 13:04:09 +0000 | [diff] [blame] | 1596 | #ifdef HAVE_RECORDING |
| 1597 | || this_item == &set_recdir_item |
| 1598 | #endif |
| 1599 | ) |
| 1600 | return action; |
| 1601 | } |
| 1602 | else if (this_item == &delete_file_item || |
| 1603 | this_item == &list_viewers_item) |
| 1604 | { |
| 1605 | /* only for files */ |
| 1606 | return action; |
| 1607 | } |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1608 | #if LCD_DEPTH > 1 |
Teruaki Kawashima | 9bea349 | 2010-02-15 13:04:09 +0000 | [diff] [blame] | 1609 | else if (this_item == &set_backdrop_item) |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1610 | { |
| 1611 | char *suffix = strrchr(selected_file, '.'); |
| 1612 | if (suffix) |
| 1613 | { |
| 1614 | if (strcasecmp(suffix, ".bmp") == 0) |
| 1615 | { |
| 1616 | return action; |
| 1617 | } |
| 1618 | } |
| 1619 | } |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1620 | #endif |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1621 | } |
| 1622 | return ACTION_EXIT_MENUITEM; |
| 1623 | break; |
| 1624 | } |
| 1625 | return action; |
| 1626 | } |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1627 | |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 1628 | static int onplaymenu_callback(int action,const struct menu_item_ex *this_item); |
| 1629 | /* used when onplay() is called in the CONTEXT_WPS context */ |
| 1630 | MAKE_ONPLAYMENU( wps_onplay_menu, ID2P(LANG_ONPLAY_MENU_TITLE), |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1631 | onplaymenu_callback, Icon_Audio, |
Nils Wallménius | b2ee5bc | 2008-05-22 16:28:20 +0000 | [diff] [blame] | 1632 | &wps_playlist_menu, &cat_playlist_menu, |
| 1633 | &sound_settings, &playback_settings, |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1634 | #ifdef HAVE_TAGCACHE |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 1635 | &rating_item, |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1636 | #endif |
Solomon Peachy | fe95127 | 2018-12-14 08:20:25 -0500 | [diff] [blame^] | 1637 | &bookmark_menu, |
Jonathan Gordon | edf06dc | 2010-06-09 09:00:42 +0000 | [diff] [blame] | 1638 | #ifdef HAVE_PICTUREFLOW_INTEGRATION |
Jonathan Gordon | d871ff8 | 2010-06-09 04:25:41 +0000 | [diff] [blame] | 1639 | &pictureflow_item, |
Solomon Peachy | fe95127 | 2018-12-14 08:20:25 -0500 | [diff] [blame^] | 1640 | #endif |
Jonathan Gordon | d871ff8 | 2010-06-09 04:25:41 +0000 | [diff] [blame] | 1641 | &browse_id3_item, &list_viewers_item, |
Nils Wallménius | b2ee5bc | 2008-05-22 16:28:20 +0000 | [diff] [blame] | 1642 | &delete_file_item, &view_cue_item, |
Nils Wallménius | d29a11b | 2012-05-08 16:34:26 +0200 | [diff] [blame] | 1643 | #ifdef HAVE_PITCHCONTROL |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1644 | &pitch_screen_item, |
| 1645 | #endif |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1646 | ); |
| 1647 | /* used when onplay() is not called in the CONTEXT_WPS context */ |
Teruaki Kawashima | f884068 | 2010-02-14 12:42:32 +0000 | [diff] [blame] | 1648 | MAKE_ONPLAYMENU( tree_onplay_menu, ID2P(LANG_ONPLAY_MENU_TITLE), |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1649 | onplaymenu_callback, Icon_file_view_menu, |
| 1650 | &tree_playlist_menu, &cat_playlist_menu, |
| 1651 | &rename_file_item, &clipboard_cut_item, &clipboard_copy_item, |
| 1652 | &clipboard_paste_item, &delete_file_item, &delete_dir_item, |
| 1653 | #if LCD_DEPTH > 1 |
| 1654 | &set_backdrop_item, |
| 1655 | #endif |
Jonathan Gordon | 415e9d7 | 2007-07-10 07:41:37 +0000 | [diff] [blame] | 1656 | &list_viewers_item, &create_dir_item, &properties_item, |
| 1657 | #ifdef HAVE_RECORDING |
| 1658 | &set_recdir_item, |
| 1659 | #endif |
William Wilgus | 0c06e5f | 2017-09-07 12:27:54 +0200 | [diff] [blame] | 1660 | &set_startdir_item, &add_to_faves_item, &file_menu, |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1661 | ); |
Jonathan Gordon | a6f2b82 | 2007-11-04 12:40:18 +0000 | [diff] [blame] | 1662 | static int onplaymenu_callback(int action,const struct menu_item_ex *this_item) |
| 1663 | { |
Jonathan Gordon | a6f2b82 | 2007-11-04 12:40:18 +0000 | [diff] [blame] | 1664 | switch (action) |
| 1665 | { |
| 1666 | case ACTION_TREE_STOP: |
| 1667 | if (this_item == &wps_onplay_menu) |
| 1668 | { |
| 1669 | list_stop_handler(); |
| 1670 | return ACTION_STD_CANCEL; |
| 1671 | } |
| 1672 | break; |
| 1673 | case ACTION_EXIT_MENUITEM: |
| 1674 | return ACTION_EXIT_AFTER_THIS_MENUITEM; |
| 1675 | break; |
| 1676 | } |
| 1677 | return action; |
| 1678 | } |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1679 | |
| 1680 | #ifdef HAVE_HOTKEY |
| 1681 | /* direct function calls, no need for menu callbacks */ |
| 1682 | static bool delete_item(void) |
| 1683 | { |
| 1684 | #ifdef HAVE_MULTIVOLUME |
| 1685 | /* no delete for volumes */ |
Michael Sevakis | 7d1a47c | 2013-08-05 22:02:45 -0400 | [diff] [blame] | 1686 | if (selected_file_attr & ATTR_VOLUME) |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1687 | return false; |
| 1688 | #endif |
| 1689 | return delete_file_dir(); |
| 1690 | } |
| 1691 | |
| 1692 | static bool open_with(void) |
| 1693 | { |
| 1694 | /* only open files */ |
| 1695 | if (selected_file_attr & ATTR_DIRECTORY) |
| 1696 | return false; |
| 1697 | #ifdef HAVE_MULTIVOLUME |
| 1698 | if (selected_file_attr & ATTR_VOLUME) |
| 1699 | return false; |
| 1700 | #endif |
| 1701 | return list_viewers(); |
| 1702 | } |
| 1703 | |
Jeffrey Goode | e141f80 | 2010-05-11 13:40:25 +0000 | [diff] [blame] | 1704 | static int playlist_insert_shuffled(void) |
| 1705 | { |
| 1706 | if ((audio_status() & AUDIO_STATUS_PLAY) || |
| 1707 | (selected_file_attr & ATTR_DIRECTORY) || |
| 1708 | ((selected_file_attr & FILE_ATTR_MASK) == FILE_ATTR_M3U)) |
| 1709 | { |
| 1710 | playlist_insert_func((intptr_t*)PLAYLIST_INSERT_SHUFFLED); |
| 1711 | return ONPLAY_START_PLAY; |
| 1712 | } |
Solomon Peachy | fe95127 | 2018-12-14 08:20:25 -0500 | [diff] [blame^] | 1713 | |
Jeffrey Goode | e141f80 | 2010-05-11 13:40:25 +0000 | [diff] [blame] | 1714 | return ONPLAY_RELOAD_DIR; |
| 1715 | } |
| 1716 | |
Alexander Levin | 31959e7 | 2010-04-10 19:43:47 +0000 | [diff] [blame] | 1717 | struct hotkey_assignment { |
Jeffrey Goode | 156272f | 2010-05-11 04:41:15 +0000 | [diff] [blame] | 1718 | int action; /* hotkey_action */ |
| 1719 | int lang_id; /* Language ID */ |
Alexander Levin | 4779456 | 2010-04-10 20:31:01 +0000 | [diff] [blame] | 1720 | struct menu_func func; /* Function to run if this entry is selected */ |
| 1721 | int return_code; /* What to return after the function is run */ |
Alexander Levin | 31959e7 | 2010-04-10 19:43:47 +0000 | [diff] [blame] | 1722 | }; |
| 1723 | |
| 1724 | #define HOTKEY_FUNC(func, param) {{(void *)func}, param} |
| 1725 | |
Jeffrey Goode | 1ad76ff | 2010-05-09 02:02:51 +0000 | [diff] [blame] | 1726 | /* Any desired hotkey functions go here, in the enum in onplay.h, |
Solomon Peachy | fe95127 | 2018-12-14 08:20:25 -0500 | [diff] [blame^] | 1727 | and in the settings menu in settings_list.c. The order here |
Jeffrey Goode | 1ad76ff | 2010-05-09 02:02:51 +0000 | [diff] [blame] | 1728 | is not important. */ |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1729 | static struct hotkey_assignment hotkey_items[] = { |
Jeffrey Goode | 156272f | 2010-05-11 04:41:15 +0000 | [diff] [blame] | 1730 | { HOTKEY_VIEW_PLAYLIST, LANG_VIEW_DYNAMIC_PLAYLIST, |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1731 | HOTKEY_FUNC(NULL, NULL), |
Jeffrey Goode | 156272f | 2010-05-11 04:41:15 +0000 | [diff] [blame] | 1732 | ONPLAY_PLAYLIST }, |
| 1733 | { HOTKEY_SHOW_TRACK_INFO, LANG_MENU_SHOW_ID3_INFO, |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1734 | HOTKEY_FUNC(browse_id3, NULL), |
Jeffrey Goode | 156272f | 2010-05-11 04:41:15 +0000 | [diff] [blame] | 1735 | ONPLAY_RELOAD_DIR }, |
Nils Wallménius | d29a11b | 2012-05-08 16:34:26 +0200 | [diff] [blame] | 1736 | #ifdef HAVE_PITCHCONTROL |
Jeffrey Goode | 156272f | 2010-05-11 04:41:15 +0000 | [diff] [blame] | 1737 | { HOTKEY_PITCHSCREEN, LANG_PITCH, |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1738 | HOTKEY_FUNC(gui_syncpitchscreen_run, NULL), |
Jeffrey Goode | 156272f | 2010-05-11 04:41:15 +0000 | [diff] [blame] | 1739 | ONPLAY_RELOAD_DIR }, |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1740 | #endif |
Jeffrey Goode | 156272f | 2010-05-11 04:41:15 +0000 | [diff] [blame] | 1741 | { HOTKEY_OPEN_WITH, LANG_ONPLAY_OPEN_WITH, |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1742 | HOTKEY_FUNC(open_with, NULL), |
Jeffrey Goode | 156272f | 2010-05-11 04:41:15 +0000 | [diff] [blame] | 1743 | ONPLAY_RELOAD_DIR }, |
| 1744 | { HOTKEY_DELETE, LANG_DELETE, |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1745 | HOTKEY_FUNC(delete_item, NULL), |
Jeffrey Goode | 156272f | 2010-05-11 04:41:15 +0000 | [diff] [blame] | 1746 | ONPLAY_RELOAD_DIR }, |
| 1747 | { HOTKEY_INSERT, LANG_INSERT, |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1748 | HOTKEY_FUNC(playlist_insert_func, (intptr_t*)PLAYLIST_INSERT), |
Alexander Levin | 482b45b | 2010-12-17 09:54:18 +0000 | [diff] [blame] | 1749 | ONPLAY_RELOAD_DIR }, |
Jeffrey Goode | e141f80 | 2010-05-11 13:40:25 +0000 | [diff] [blame] | 1750 | { HOTKEY_INSERT_SHUFFLED, LANG_INSERT_SHUFFLED, |
| 1751 | HOTKEY_FUNC(playlist_insert_shuffled, NULL), |
Alexander Levin | 482b45b | 2010-12-17 09:54:18 +0000 | [diff] [blame] | 1752 | ONPLAY_RELOAD_DIR }, |
Jonathan Gordon | 10e24d2 | 2010-06-09 08:51:29 +0000 | [diff] [blame] | 1753 | #ifdef HAVE_PICTUREFLOW_INTEGRATION |
Jonathan Gordon | d871ff8 | 2010-06-09 04:25:41 +0000 | [diff] [blame] | 1754 | { HOTKEY_PICTUREFLOW, LANG_ONPLAY_PICTUREFLOW, |
| 1755 | HOTKEY_FUNC(NULL, NULL), |
| 1756 | ONPLAY_PICTUREFLOW }, |
| 1757 | #endif |
Solomon Peachy | 5e8db16 | 2019-01-01 19:37:13 -0500 | [diff] [blame] | 1758 | { HOTKEY_BOOKMARK, LANG_BOOKMARK_MENU_CREATE, |
| 1759 | HOTKEY_FUNC(bookmark_create_menu, NULL), |
| 1760 | ONPLAY_OK }, |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1761 | }; |
| 1762 | |
Jeffrey Goode | 156272f | 2010-05-11 04:41:15 +0000 | [diff] [blame] | 1763 | /* Return the language ID for this action */ |
| 1764 | int get_hotkey_lang_id(int action) |
Jeffrey Goode | accc046 | 2010-04-08 01:43:50 +0000 | [diff] [blame] | 1765 | { |
Alexander Levin | c79bc80 | 2010-05-11 17:10:07 +0000 | [diff] [blame] | 1766 | int i = ARRAYLEN(hotkey_items); |
Jeffrey Goode | 156272f | 2010-05-11 04:41:15 +0000 | [diff] [blame] | 1767 | while (i--) |
Jeffrey Goode | accc046 | 2010-04-08 01:43:50 +0000 | [diff] [blame] | 1768 | { |
Jeffrey Goode | 156272f | 2010-05-11 04:41:15 +0000 | [diff] [blame] | 1769 | if (hotkey_items[i].action == action) |
Jeffrey Goode | 1ad76ff | 2010-05-09 02:02:51 +0000 | [diff] [blame] | 1770 | return hotkey_items[i].lang_id; |
Jeffrey Goode | accc046 | 2010-04-08 01:43:50 +0000 | [diff] [blame] | 1771 | } |
Solomon Peachy | fe95127 | 2018-12-14 08:20:25 -0500 | [diff] [blame^] | 1772 | |
Jeffrey Goode | 1ad76ff | 2010-05-09 02:02:51 +0000 | [diff] [blame] | 1773 | return LANG_OFF; |
Jeffrey Goode | accc046 | 2010-04-08 01:43:50 +0000 | [diff] [blame] | 1774 | } |
| 1775 | |
Jeffrey Goode | 156272f | 2010-05-11 04:41:15 +0000 | [diff] [blame] | 1776 | /* Execute the hotkey function, if listed */ |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1777 | static int execute_hotkey(bool is_wps) |
| 1778 | { |
Alexander Levin | c79bc80 | 2010-05-11 17:10:07 +0000 | [diff] [blame] | 1779 | int i = ARRAYLEN(hotkey_items); |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1780 | struct hotkey_assignment *this_item; |
Jeffrey Goode | 156272f | 2010-05-11 04:41:15 +0000 | [diff] [blame] | 1781 | const int action = (is_wps ? global_settings.hotkey_wps : |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1782 | global_settings.hotkey_tree); |
Solomon Peachy | fe95127 | 2018-12-14 08:20:25 -0500 | [diff] [blame^] | 1783 | |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1784 | /* search assignment struct for a match for the hotkey setting */ |
Jeffrey Goode | 156272f | 2010-05-11 04:41:15 +0000 | [diff] [blame] | 1785 | while (i--) |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1786 | { |
| 1787 | this_item = &hotkey_items[i]; |
Jeffrey Goode | 156272f | 2010-05-11 04:41:15 +0000 | [diff] [blame] | 1788 | if (this_item->action == action) |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1789 | { |
| 1790 | /* run the associated function (with optional param), if any */ |
| 1791 | const struct menu_func func = this_item->func; |
Jeffrey Goode | aaa0797 | 2010-05-11 13:50:39 +0000 | [diff] [blame] | 1792 | int func_return = ONPLAY_RELOAD_DIR; |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1793 | if (func.function != NULL) |
| 1794 | { |
| 1795 | if (func.param != NULL) |
Jeffrey Goode | e141f80 | 2010-05-11 13:40:25 +0000 | [diff] [blame] | 1796 | func_return = (*func.function_w_param)(func.param); |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1797 | else |
Jeffrey Goode | e141f80 | 2010-05-11 13:40:25 +0000 | [diff] [blame] | 1798 | func_return = (*func.function)(); |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1799 | } |
| 1800 | /* return with the associated code */ |
Jeffrey Goode | e141f80 | 2010-05-11 13:40:25 +0000 | [diff] [blame] | 1801 | const int return_code = this_item->return_code; |
| 1802 | /* ONPLAY_OK here means to use the function return code */ |
| 1803 | if (return_code == ONPLAY_OK) |
| 1804 | return func_return; |
| 1805 | return return_code; |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1806 | } |
| 1807 | } |
Solomon Peachy | fe95127 | 2018-12-14 08:20:25 -0500 | [diff] [blame^] | 1808 | |
Jeffrey Goode | 1ad76ff | 2010-05-09 02:02:51 +0000 | [diff] [blame] | 1809 | /* no valid hotkey set, ignore hotkey */ |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1810 | return ONPLAY_RELOAD_DIR; |
| 1811 | } |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1812 | #endif /* HOTKEY */ |
| 1813 | |
| 1814 | int onplay(char* file, int attr, int from, bool hotkey) |
Björn Stenberg | d7a55e1 | 2003-03-12 20:21:30 +0000 | [diff] [blame] | 1815 | { |
Jonathan Gordon | 49ca667 | 2007-11-08 14:00:36 +0000 | [diff] [blame] | 1816 | const struct menu_item_ex *menu; |
Hardeep Sidhu | 9e42620 | 2003-07-01 21:05:43 +0000 | [diff] [blame] | 1817 | onplay_result = ONPLAY_OK; |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1818 | context = from; |
Linus Nielsen Feltzing | 6e0436f | 2005-06-23 01:31:26 +0000 | [diff] [blame] | 1819 | selected_file = file; |
| 1820 | selected_file_attr = attr; |
Jeffrey Goode | 7be582b | 2010-04-08 14:34:14 +0000 | [diff] [blame] | 1821 | int menu_selection; |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1822 | #ifdef HAVE_HOTKEY |
| 1823 | if (hotkey) |
| 1824 | return execute_hotkey(context == CONTEXT_WPS); |
Jeffrey Goode | d5e6bc7 | 2010-04-01 03:14:44 +0000 | [diff] [blame] | 1825 | #else |
| 1826 | (void)hotkey; |
| 1827 | #endif |
Jonathan Gordon | e918b7b | 2011-08-05 00:47:11 +0000 | [diff] [blame] | 1828 | |
| 1829 | push_current_activity(ACTIVITY_CONTEXTMENU); |
Linus Nielsen Feltzing | 22c1a8e | 2005-06-24 22:33:42 +0000 | [diff] [blame] | 1830 | if (context == CONTEXT_WPS) |
Jonathan Gordon | 49ca667 | 2007-11-08 14:00:36 +0000 | [diff] [blame] | 1831 | menu = &wps_onplay_menu; |
Dan Everton | 1429c9b | 2006-03-20 11:46:06 +0000 | [diff] [blame] | 1832 | else |
Jonathan Gordon | 49ca667 | 2007-11-08 14:00:36 +0000 | [diff] [blame] | 1833 | menu = &tree_onplay_menu; |
Jeffrey Goode | 7be582b | 2010-04-08 14:34:14 +0000 | [diff] [blame] | 1834 | menu_selection = do_menu(menu, NULL, NULL, false); |
Jonathan Gordon | e918b7b | 2011-08-05 00:47:11 +0000 | [diff] [blame] | 1835 | pop_current_activity(); |
| 1836 | |
Jeffrey Goode | 7be582b | 2010-04-08 14:34:14 +0000 | [diff] [blame] | 1837 | switch (menu_selection) |
| 1838 | { |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1839 | case GO_TO_WPS: |
| 1840 | return ONPLAY_START_PLAY; |
| 1841 | case GO_TO_ROOT: |
| 1842 | case GO_TO_MAINMENU: |
| 1843 | return ONPLAY_MAINMENU; |
Thomas Martitz | c19e536 | 2010-02-20 19:06:39 +0000 | [diff] [blame] | 1844 | case GO_TO_PLAYLIST_VIEWER: |
| 1845 | return ONPLAY_PLAYLIST; |
Jonathan Gordon | 10e24d2 | 2010-06-09 08:51:29 +0000 | [diff] [blame] | 1846 | #ifdef HAVE_PICTUREFLOW_INTEGRATION |
Jonathan Gordon | d871ff8 | 2010-06-09 04:25:41 +0000 | [diff] [blame] | 1847 | case GO_TO_PICTUREFLOW: |
| 1848 | return ONPLAY_PICTUREFLOW; |
| 1849 | #endif |
Jonathan Gordon | 3a7760c | 2007-04-30 13:41:33 +0000 | [diff] [blame] | 1850 | default: |
Teruaki Kawashima | 9bea349 | 2010-02-15 13:04:09 +0000 | [diff] [blame] | 1851 | return onplay_result; |
Dan Everton | 1429c9b | 2006-03-20 11:46:06 +0000 | [diff] [blame] | 1852 | } |
Björn Stenberg | d7a55e1 | 2003-03-12 20:21:30 +0000 | [diff] [blame] | 1853 | } |