diff options
Diffstat (limited to 'apps/plugins/properties.c')
-rw-r--r-- | apps/plugins/properties.c | 236 |
1 files changed, 72 insertions, 164 deletions
diff --git a/apps/plugins/properties.c b/apps/plugins/properties.c index fa3517726a..e5f00e307b 100644 --- a/apps/plugins/properties.c +++ b/apps/plugins/properties.c | |||
@@ -20,9 +20,19 @@ | |||
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | #include "plugin.h" | 21 | #include "plugin.h" |
22 | 22 | ||
23 | #if !defined(ARRAY_SIZE) | ||
24 | #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0])) | ||
25 | #endif | ||
26 | |||
27 | enum props_types { | ||
28 | PROPS_FILE = 0, | ||
29 | PROPS_ID3, | ||
30 | PROPS_DIR | ||
31 | }; | ||
23 | 32 | ||
33 | static int props_type = PROPS_FILE; | ||
24 | 34 | ||
25 | bool its_a_dir = false; | 35 | static struct mp3entry id3; |
26 | 36 | ||
27 | char str_filename[MAX_PATH]; | 37 | char str_filename[MAX_PATH]; |
28 | char str_dirname[MAX_PATH]; | 38 | char str_dirname[MAX_PATH]; |
@@ -32,27 +42,12 @@ char str_filecount[64]; | |||
32 | char str_date[64]; | 42 | char str_date[64]; |
33 | char str_time[64]; | 43 | char str_time[64]; |
34 | 44 | ||
35 | char str_title[MAX_PATH]; | ||
36 | char str_composer[MAX_PATH]; | ||
37 | char str_artist[MAX_PATH]; | ||
38 | char str_albumartist[MAX_PATH]; | ||
39 | char str_album[MAX_PATH]; | ||
40 | char str_genre[MAX_PATH]; | ||
41 | char str_comment[MAX_PATH]; | ||
42 | char str_year[MAX_PATH]; | ||
43 | char str_discnum[MAX_PATH]; | ||
44 | char str_tracknum[MAX_PATH]; | ||
45 | char str_duration[32]; | ||
46 | char str_bitrate[32]; | ||
47 | char str_frequency[32]; | ||
48 | |||
49 | unsigned nseconds; | 45 | unsigned nseconds; |
50 | unsigned long nsize; | 46 | unsigned long nsize; |
51 | int32_t size_unit; | 47 | int32_t size_unit; |
52 | struct tm tm; | 48 | struct tm tm; |
53 | 49 | ||
54 | int num_properties; | 50 | #define NUM_FILE_PROPERTIES 5 |
55 | |||
56 | static const unsigned char* const props_file[] = | 51 | static const unsigned char* const props_file[] = |
57 | { | 52 | { |
58 | ID2P(LANG_PROPERTIES_PATH), str_dirname, | 53 | ID2P(LANG_PROPERTIES_PATH), str_dirname, |
@@ -60,20 +55,9 @@ static const unsigned char* const props_file[] = | |||
60 | ID2P(LANG_PROPERTIES_SIZE), str_size, | 55 | ID2P(LANG_PROPERTIES_SIZE), str_size, |
61 | ID2P(LANG_PROPERTIES_DATE), str_date, | 56 | ID2P(LANG_PROPERTIES_DATE), str_date, |
62 | ID2P(LANG_PROPERTIES_TIME), str_time, | 57 | ID2P(LANG_PROPERTIES_TIME), str_time, |
63 | ID2P(LANG_PROPERTIES_COMPOSER), str_composer, | ||
64 | ID2P(LANG_PROPERTIES_ARTIST), str_artist, | ||
65 | ID2P(LANG_PROPERTIES_ALBUMARTIST), str_albumartist, | ||
66 | ID2P(LANG_PROPERTIES_TITLE), str_title, | ||
67 | ID2P(LANG_PROPERTIES_ALBUM), str_album, | ||
68 | ID2P(LANG_PROPERTIES_GENRE), str_genre, | ||
69 | ID2P(LANG_PROPERTIES_COMMENT), str_comment, | ||
70 | ID2P(LANG_PROPERTIES_YEAR), str_year, | ||
71 | ID2P(LANG_PROPERTIES_DISCNUM), str_discnum, | ||
72 | ID2P(LANG_PROPERTIES_TRACKNUM), str_tracknum, | ||
73 | ID2P(LANG_PROPERTIES_DURATION), str_duration, | ||
74 | ID2P(LANG_PROPERTIES_BITRATE), str_bitrate, | ||
75 | ID2P(LANG_PROPERTIES_FREQUENCY), str_frequency, | ||
76 | }; | 58 | }; |
59 | |||
60 | #define NUM_DIR_PROPERTIES 4 | ||
77 | static const unsigned char* const props_dir[] = | 61 | static const unsigned char* const props_dir[] = |
78 | { | 62 | { |
79 | ID2P(LANG_PROPERTIES_PATH), str_dirname, | 63 | ID2P(LANG_PROPERTIES_PATH), str_dirname, |
@@ -107,7 +91,6 @@ static bool file_properties(const char* selected_file) | |||
107 | bool found = false; | 91 | bool found = false; |
108 | DIR* dir; | 92 | DIR* dir; |
109 | struct dirent* entry; | 93 | struct dirent* entry; |
110 | static struct mp3entry id3; | ||
111 | 94 | ||
112 | dir = rb->opendir(str_dirname); | 95 | dir = rb->opendir(str_dirname); |
113 | if (dir) | 96 | if (dir) |
@@ -128,81 +111,14 @@ static bool file_properties(const char* selected_file) | |||
128 | rb->snprintf(str_time, sizeof str_time, "%02d:%02d:%02d", | 111 | rb->snprintf(str_time, sizeof str_time, "%02d:%02d:%02d", |
129 | tm.tm_hour, tm.tm_min, tm.tm_sec); | 112 | tm.tm_hour, tm.tm_min, tm.tm_sec); |
130 | 113 | ||
131 | num_properties = 5; | ||
132 | |||
133 | int fd = rb->open(selected_file, O_RDONLY); | 114 | int fd = rb->open(selected_file, O_RDONLY); |
134 | if (fd >= 0 && | 115 | if (fd >= 0) |
135 | rb->get_metadata(&id3, fd, selected_file)) | ||
136 | { | 116 | { |
137 | long dur = id3.length / 1000; /* seconds */ | 117 | if (rb->get_metadata(&id3, fd, selected_file)) |
138 | rb->snprintf(str_composer, sizeof str_composer, | 118 | props_type = PROPS_ID3; |
139 | "%s", id3.composer ? id3.composer : ""); | 119 | |
140 | rb->snprintf(str_artist, sizeof str_artist, | 120 | rb->close(fd); |
141 | "%s", id3.artist ? id3.artist : ""); | ||
142 | rb->snprintf(str_albumartist, sizeof str_albumartist, | ||
143 | "%s", id3.albumartist ? id3.albumartist : ""); | ||
144 | rb->snprintf(str_title, sizeof str_title, | ||
145 | "%s", id3.title ? id3.title : ""); | ||
146 | rb->snprintf(str_album, sizeof str_album, | ||
147 | "%s", id3.album ? id3.album : ""); | ||
148 | rb->snprintf(str_genre, sizeof str_genre, | ||
149 | "%s", id3.genre_string ? id3.genre_string : ""); | ||
150 | rb->snprintf(str_comment, sizeof str_comment, | ||
151 | "%s", id3.comment ? id3.comment : ""); | ||
152 | |||
153 | if (id3.year_string) | ||
154 | rb->snprintf(str_year, sizeof str_year, | ||
155 | "%s", id3.year_string); | ||
156 | else if (id3.year) | ||
157 | rb->snprintf(str_year, sizeof str_year, | ||
158 | "%d", id3.year); | ||
159 | else | ||
160 | rb->snprintf(str_year, sizeof str_year, | ||
161 | "%s", ""); | ||
162 | |||
163 | if (id3.disc_string) | ||
164 | rb->snprintf(str_discnum, sizeof str_discnum, | ||
165 | "%s", id3.disc_string); | ||
166 | else if (id3.discnum) | ||
167 | rb->snprintf(str_discnum, sizeof str_discnum, | ||
168 | "%d", id3.discnum); | ||
169 | else | ||
170 | rb->snprintf(str_discnum, sizeof str_discnum, | ||
171 | "%s", ""); | ||
172 | |||
173 | if (id3.track_string) | ||
174 | rb->snprintf(str_tracknum, sizeof str_tracknum, | ||
175 | "%s", id3.track_string); | ||
176 | else if(id3.tracknum) | ||
177 | rb->snprintf(str_tracknum, sizeof str_tracknum, | ||
178 | "%d", id3.tracknum); | ||
179 | else | ||
180 | rb->snprintf(str_tracknum, sizeof str_tracknum, | ||
181 | "%s", ""); | ||
182 | |||
183 | rb->snprintf(str_bitrate, sizeof str_bitrate, | ||
184 | "%d kbps", id3.bitrate ? : 0); | ||
185 | rb->snprintf(str_frequency, sizeof str_frequency, | ||
186 | "%ld Hz", id3.frequency ? : 0); | ||
187 | num_properties += 12; | ||
188 | |||
189 | if (dur > 0) | ||
190 | { | ||
191 | nseconds = dur; | ||
192 | if (dur < 3600) | ||
193 | rb->snprintf(str_duration, sizeof str_duration, | ||
194 | "%d:%02d", (int)(dur / 60), | ||
195 | (int)(dur % 60)); | ||
196 | else | ||
197 | rb->snprintf(str_duration, sizeof str_duration, | ||
198 | "%d:%02d:%02d", | ||
199 | (int)(dur / 3600), | ||
200 | (int)(dur % 3600 / 60), | ||
201 | (int)(dur % 60)); | ||
202 | num_properties++; | ||
203 | } | ||
204 | } | 121 | } |
205 | rb->close(fd); | ||
206 | found = true; | 122 | found = true; |
207 | break; | 123 | break; |
208 | } | 124 | } |
@@ -265,7 +181,7 @@ static bool _dir_properties(DPS *dps) | |||
265 | rb->lcd_putsf(0,3,"Files: %d", dps->fc); | 181 | rb->lcd_putsf(0,3,"Files: %d", dps->fc); |
266 | log = human_size_log(dps->bc); | 182 | log = human_size_log(dps->bc); |
267 | rb->lcd_putsf(0,4,"Size: %lu %cB", (unsigned long)(dps->bc >> (10*log)), | 183 | rb->lcd_putsf(0,4,"Size: %lu %cB", (unsigned long)(dps->bc >> (10*log)), |
268 | rb->str(units[log])); | 184 | rb->str(units[log])); |
269 | rb->lcd_update(); | 185 | rb->lcd_update(); |
270 | } | 186 | } |
271 | 187 | ||
@@ -314,7 +230,6 @@ static bool dir_properties(const char* selected_file, DPS *dps) | |||
314 | nsize = (long) (dps->bc >> (log*10)); | 230 | nsize = (long) (dps->bc >> (log*10)); |
315 | size_unit = units[log]; | 231 | size_unit = units[log]; |
316 | rb->snprintf(str_size, sizeof str_size, "%ld %s", nsize, rb->str(size_unit)); | 232 | rb->snprintf(str_size, sizeof str_size, "%ld %s", nsize, rb->str(size_unit)); |
317 | num_properties = 4; | ||
318 | return true; | 233 | return true; |
319 | } | 234 | } |
320 | 235 | ||
@@ -328,35 +243,20 @@ static const char * get_props(int selected_item, void* data, | |||
328 | char *buffer, size_t buffer_len) | 243 | char *buffer, size_t buffer_len) |
329 | { | 244 | { |
330 | (void)data; | 245 | (void)data; |
331 | if(its_a_dir) | 246 | if (PROPS_DIR == props_type) |
332 | { | 247 | rb->strlcpy(buffer, selected_item >= (int)(ARRAY_SIZE(props_dir)) ? "ERROR" : |
333 | if(selected_item >= (int)(sizeof(props_dir) / sizeof(props_dir[0]))) | 248 | (char *) p2str(props_dir[selected_item]), buffer_len); |
334 | { | 249 | else if (PROPS_FILE == props_type) |
335 | rb->strlcpy(buffer, "ERROR", buffer_len); | 250 | rb->strlcpy(buffer, selected_item >= (int)(ARRAY_SIZE(props_file)) ? "ERROR" : |
336 | } | 251 | (char *) p2str(props_file[selected_item]), buffer_len); |
337 | else | 252 | |
338 | { | ||
339 | rb->strlcpy(buffer, p2str(props_dir[selected_item]), buffer_len); | ||
340 | } | ||
341 | } | ||
342 | else | ||
343 | { | ||
344 | if(selected_item >= (int)(sizeof(props_file) / sizeof(props_file[0]))) | ||
345 | { | ||
346 | rb->strlcpy(buffer, "ERROR", buffer_len); | ||
347 | } | ||
348 | else | ||
349 | { | ||
350 | rb->strlcpy(buffer, p2str(props_file[selected_item]), buffer_len); | ||
351 | } | ||
352 | } | ||
353 | return buffer; | 253 | return buffer; |
354 | } | 254 | } |
355 | 255 | ||
356 | static int speak_property_selection(int selected_item, void *data) | 256 | static int speak_property_selection(int selected_item, void *data) |
357 | { | 257 | { |
358 | DPS *dps = data; | 258 | DPS *dps = data; |
359 | int32_t id = P2ID((its_a_dir ? props_dir : props_file)[selected_item]); | 259 | int32_t id = P2ID((props_type == PROPS_DIR ? props_dir : props_file)[selected_item]); |
360 | rb->talk_id(id, false); | 260 | rb->talk_id(id, false); |
361 | switch (id) | 261 | switch (id) |
362 | { | 262 | { |
@@ -394,9 +294,6 @@ static int speak_property_selection(int selected_item, void *data) | |||
394 | case LANG_PROPERTIES_TIME: | 294 | case LANG_PROPERTIES_TIME: |
395 | rb->talk_time(&tm, true); | 295 | rb->talk_time(&tm, true); |
396 | break; | 296 | break; |
397 | case LANG_PROPERTIES_DURATION: | ||
398 | rb->talk_value_decimal(nseconds, UNIT_TIME, 0, true); | ||
399 | break; | ||
400 | case LANG_PROPERTIES_SUBDIRS: | 297 | case LANG_PROPERTIES_SUBDIRS: |
401 | rb->talk_number(dps->dc, true); | 298 | rb->talk_number(dps->dc, true); |
402 | break; | 299 | break; |
@@ -422,10 +319,10 @@ enum plugin_status plugin_start(const void* parameter) | |||
422 | #endif | 319 | #endif |
423 | 320 | ||
424 | static DPS dps = { | 321 | static DPS dps = { |
425 | .len = MAX_PATH, | 322 | .len = MAX_PATH, |
426 | .dc = 0, | 323 | .dc = 0, |
427 | .fc = 0, | 324 | .fc = 0, |
428 | .bc = 0, | 325 | .bc = 0, |
429 | }; | 326 | }; |
430 | 327 | ||
431 | /* determine if it's a file or a directory */ | 328 | /* determine if it's a file or a directory */ |
@@ -446,7 +343,7 @@ enum plugin_status plugin_start(const void* parameter) | |||
446 | if(!rb->strcmp(entry->d_name, str_filename)) | 343 | if(!rb->strcmp(entry->d_name, str_filename)) |
447 | { | 344 | { |
448 | struct dirinfo info = rb->dir_get_info(dir, entry); | 345 | struct dirinfo info = rb->dir_get_info(dir, entry); |
449 | its_a_dir = info.attribute & ATTR_DIRECTORY ? true : false; | 346 | props_type = info.attribute & ATTR_DIRECTORY ? PROPS_DIR : PROPS_FILE; |
450 | found = true; | 347 | found = true; |
451 | break; | 348 | break; |
452 | } | 349 | } |
@@ -464,7 +361,7 @@ enum plugin_status plugin_start(const void* parameter) | |||
464 | } | 361 | } |
465 | 362 | ||
466 | /* get the info depending on its_a_dir */ | 363 | /* get the info depending on its_a_dir */ |
467 | if(!(its_a_dir ? dir_properties(file, &dps) : file_properties(file))) | 364 | if(!(props_type == PROPS_DIR ? dir_properties(file, &dps) : file_properties(file))) |
468 | { | 365 | { |
469 | /* something went wrong (to do: tell user what it was (nesting,...) */ | 366 | /* something went wrong (to do: tell user what it was (nesting,...) */ |
470 | rb->splash(0, ID2P(LANG_PROPERTIES_FAIL)); | 367 | rb->splash(0, ID2P(LANG_PROPERTIES_FAIL)); |
@@ -475,40 +372,51 @@ enum plugin_status plugin_start(const void* parameter) | |||
475 | FOR_NB_SCREENS(i) | 372 | FOR_NB_SCREENS(i) |
476 | rb->viewportmanager_theme_enable(i, true, NULL); | 373 | rb->viewportmanager_theme_enable(i, true, NULL); |
477 | 374 | ||
478 | rb->gui_synclist_init(&properties_lists, &get_props, &dps, false, 2, NULL); | 375 | if (props_type == PROPS_ID3) |
479 | rb->gui_synclist_set_title(&properties_lists, rb->str(its_a_dir ? LANG_PROPERTIES_DIRECTORY_PROPERTIES : LANG_PROPERTIES_FILE_PROPERTIES), NOICON); | 376 | usb = rb->browse_id3(&id3, 0, 0); |
480 | rb->gui_synclist_set_icon_callback(&properties_lists, NULL); | 377 | else |
481 | if (rb->global_settings->talk_menu) | ||
482 | rb->gui_synclist_set_voice_callback(&properties_lists, speak_property_selection); | ||
483 | rb->gui_synclist_set_nb_items(&properties_lists, num_properties * 2); | ||
484 | rb->gui_synclist_limit_scroll(&properties_lists, true); | ||
485 | rb->gui_synclist_select_item(&properties_lists, 0); | ||
486 | rb->gui_synclist_draw(&properties_lists); | ||
487 | rb->gui_synclist_speak_item(&properties_lists); | ||
488 | |||
489 | while(!quit) | ||
490 | { | 378 | { |
491 | button = rb->get_action(CONTEXT_LIST, HZ); | 379 | rb->gui_synclist_init(&properties_lists, &get_props, &dps, false, 2, NULL); |
492 | /* HZ so the status bar redraws corectly */ | 380 | rb->gui_synclist_set_title(&properties_lists, |
493 | if (rb->gui_synclist_do_button(&properties_lists,&button,LIST_WRAP_UNLESS_HELD)) | 381 | rb->str(props_type == PROPS_DIR ? |
494 | continue; | 382 | LANG_PROPERTIES_DIRECTORY_PROPERTIES : |
495 | switch(button) | 383 | LANG_PROPERTIES_FILE_PROPERTIES), |
384 | NOICON); | ||
385 | rb->gui_synclist_set_icon_callback(&properties_lists, NULL); | ||
386 | if (rb->global_settings->talk_menu) | ||
387 | rb->gui_synclist_set_voice_callback(&properties_lists, speak_property_selection); | ||
388 | rb->gui_synclist_set_nb_items(&properties_lists, | ||
389 | 2 * (props_type == PROPS_FILE ? NUM_FILE_PROPERTIES : | ||
390 | NUM_DIR_PROPERTIES)); | ||
391 | rb->gui_synclist_limit_scroll(&properties_lists, true); | ||
392 | rb->gui_synclist_select_item(&properties_lists, 0); | ||
393 | rb->gui_synclist_draw(&properties_lists); | ||
394 | rb->gui_synclist_speak_item(&properties_lists); | ||
395 | |||
396 | while(!quit) | ||
496 | { | 397 | { |
497 | case ACTION_STD_CANCEL: | 398 | button = rb->get_action(CONTEXT_LIST, HZ); |
498 | quit = true; | 399 | /* HZ so the status bar redraws corectly */ |
499 | break; | 400 | if (rb->gui_synclist_do_button(&properties_lists,&button,LIST_WRAP_UNLESS_HELD)) |
500 | default: | 401 | continue; |
501 | if (rb->default_event_handler(button) == SYS_USB_CONNECTED) | 402 | switch(button) |
502 | { | 403 | { |
404 | case ACTION_STD_CANCEL: | ||
503 | quit = true; | 405 | quit = true; |
504 | usb = true; | 406 | break; |
505 | } | 407 | default: |
506 | break; | 408 | if (rb->default_event_handler(button) == SYS_USB_CONNECTED) |
409 | { | ||
410 | quit = true; | ||
411 | usb = true; | ||
412 | } | ||
413 | break; | ||
414 | } | ||
507 | } | 415 | } |
508 | } | 416 | } |
509 | 417 | ||
510 | FOR_NB_SCREENS(i) | 418 | FOR_NB_SCREENS(i) |
511 | rb->viewportmanager_theme_undo(i, false); | 419 | rb->viewportmanager_theme_undo(i, false); |
512 | 420 | ||
513 | return usb? PLUGIN_USB_CONNECTED: PLUGIN_OK; | 421 | return usb ? PLUGIN_USB_CONNECTED : PLUGIN_OK; |
514 | } | 422 | } |