diff options
Diffstat (limited to 'apps/plugins')
-rw-r--r-- | apps/plugins/properties.c | 146 |
1 files changed, 111 insertions, 35 deletions
diff --git a/apps/plugins/properties.c b/apps/plugins/properties.c index 3bddc24d69..686b4d6d1a 100644 --- a/apps/plugins/properties.c +++ b/apps/plugins/properties.c | |||
@@ -37,32 +37,44 @@ char str_artist[MAX_PATH]; | |||
37 | char str_album[MAX_PATH]; | 37 | char str_album[MAX_PATH]; |
38 | char str_duration[32]; | 38 | char str_duration[32]; |
39 | 39 | ||
40 | unsigned nseconds; | ||
41 | unsigned long nsize; | ||
42 | int32_t size_unit; | ||
43 | struct tm tm; | ||
44 | |||
40 | int num_properties; | 45 | int num_properties; |
41 | 46 | ||
42 | static const char* props_file[] = | 47 | static const unsigned char* const props_file[] = |
43 | { | 48 | { |
44 | "[Path]", str_dirname, | 49 | ID2P(LANG_PROPERTIES_PATH), str_dirname, |
45 | "[Filename]", str_filename, | 50 | ID2P(LANG_PROPERTIES_FILENAME), str_filename, |
46 | "[Size]", str_size, | 51 | ID2P(LANG_PROPERTIES_SIZE), str_size, |
47 | "[Date]", str_date, | 52 | ID2P(LANG_PROPERTIES_DATE), str_date, |
48 | "[Time]", str_time, | 53 | ID2P(LANG_PROPERTIES_TIME), str_time, |
49 | "[Artist]", str_artist, | 54 | ID2P(LANG_PROPERTIES_ARTIST), str_artist, |
50 | "[Title]", str_title, | 55 | ID2P(LANG_PROPERTIES_TITLE), str_title, |
51 | "[Album]", str_album, | 56 | ID2P(LANG_PROPERTIES_ALBUM), str_album, |
52 | "[Duration]", str_duration, | 57 | ID2P(LANG_PROPERTIES_DURATION), str_duration, |
53 | }; | 58 | }; |
54 | static const char* props_dir[] = | 59 | static const unsigned char* const props_dir[] = |
55 | { | 60 | { |
56 | "[Path]", str_dirname, | 61 | ID2P(LANG_PROPERTIES_PATH), str_dirname, |
57 | "[Subdirs]", str_dircount, | 62 | ID2P(LANG_PROPERTIES_SUBDIRS), str_dircount, |
58 | "[Files]", str_filecount, | 63 | ID2P(LANG_PROPERTIES_FILES), str_filecount, |
59 | "[Size]", str_size, | 64 | ID2P(LANG_PROPERTIES_SIZE), str_size, |
65 | }; | ||
66 | |||
67 | static const int32_t units[] = | ||
68 | { | ||
69 | LANG_BYTE, | ||
70 | LANG_KIBIBYTE, | ||
71 | LANG_MEBIBYTE, | ||
72 | LANG_GIBIBYTE | ||
60 | }; | 73 | }; |
61 | 74 | ||
62 | static const char human_size_prefix[4] = { '\0', 'K', 'M', 'G' }; | ||
63 | static unsigned human_size_log(unsigned long long size) | 75 | static unsigned human_size_log(unsigned long long size) |
64 | { | 76 | { |
65 | const size_t n = sizeof(human_size_prefix)/sizeof(human_size_prefix[0]); | 77 | const size_t n = sizeof(units)/sizeof(units[0]); |
66 | 78 | ||
67 | unsigned i; | 79 | unsigned i; |
68 | /* margin set at 10K boundary: 10239 B +1 => 10 KB */ | 80 | /* margin set at 10K boundary: 10239 B +1 => 10 KB */ |
@@ -89,9 +101,9 @@ static bool file_properties(const char* selected_file) | |||
89 | { | 101 | { |
90 | unsigned log; | 102 | unsigned log; |
91 | log = human_size_log((unsigned long)info.size); | 103 | log = human_size_log((unsigned long)info.size); |
92 | rb->snprintf(str_size, sizeof str_size, "%lu %cB", | 104 | nsize = ((unsigned long)info.size) >> (log*10); |
93 | ((unsigned long)info.size) >> (log*10), human_size_prefix[log]); | 105 | size_unit = units[log]; |
94 | struct tm tm; | 106 | rb->snprintf(str_size, sizeof str_size, "%lu %s", nsize, rb->str(size_unit)); |
95 | rb->gmtime_r(&info.mtime, &tm); | 107 | rb->gmtime_r(&info.mtime, &tm); |
96 | rb->snprintf(str_date, sizeof str_date, "%04d/%02d/%02d", | 108 | rb->snprintf(str_date, sizeof str_date, "%04d/%02d/%02d", |
97 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); | 109 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); |
@@ -119,6 +131,7 @@ static bool file_properties(const char* selected_file) | |||
119 | 131 | ||
120 | if (dur > 0) | 132 | if (dur > 0) |
121 | { | 133 | { |
134 | nseconds = dur; | ||
122 | if (dur < 3600) | 135 | if (dur < 3600) |
123 | rb->snprintf(str_duration, sizeof str_duration, | 136 | rb->snprintf(str_duration, sizeof str_duration, |
124 | "%d:%02d", (int)(dur / 60), | 137 | "%d:%02d", (int)(dur / 60), |
@@ -181,8 +194,6 @@ static bool _dir_properties(DPS *dps) | |||
181 | 194 | ||
182 | if (info.attribute & ATTR_DIRECTORY) | 195 | if (info.attribute & ATTR_DIRECTORY) |
183 | { | 196 | { |
184 | unsigned log; | ||
185 | |||
186 | if (!rb->strcmp((char *)entry->d_name, ".") || | 197 | if (!rb->strcmp((char *)entry->d_name, ".") || |
187 | !rb->strcmp((char *)entry->d_name, "..")) | 198 | !rb->strcmp((char *)entry->d_name, "..")) |
188 | continue; /* skip these */ | 199 | continue; /* skip these */ |
@@ -190,16 +201,16 @@ static bool _dir_properties(DPS *dps) | |||
190 | dps->dc++; /* new directory */ | 201 | dps->dc++; /* new directory */ |
191 | if (*rb->current_tick - lasttick > (HZ/8)) | 202 | if (*rb->current_tick - lasttick > (HZ/8)) |
192 | { | 203 | { |
204 | unsigned log = human_size_log(dps->bc); | ||
193 | lasttick = *rb->current_tick; | 205 | lasttick = *rb->current_tick; |
194 | rb->lcd_clear_display(); | 206 | rb->lcd_clear_display(); |
195 | rb->lcd_puts(0,0,"SCANNING..."); | 207 | rb->lcd_puts(0,0,"SCANNING..."); |
196 | rb->lcd_puts(0,1,dps->dirname); | 208 | rb->lcd_puts(0,1,dps->dirname); |
197 | rb->lcd_puts(0,2,entry->d_name); | 209 | rb->lcd_putsf(0,2,"Directories: %d", dps->dc); |
198 | rb->lcd_putsf(0,3,"Directories: %d", dps->dc); | 210 | rb->lcd_putsf(0,3,"Files: %d", dps->fc); |
199 | rb->lcd_putsf(0,4,"Files: %d", dps->fc); | ||
200 | log = human_size_log(dps->bc); | 211 | log = human_size_log(dps->bc); |
201 | rb->lcd_putsf(0,5,"Size: %lu %cB", (unsigned long)(dps->bc >> (10*log)), | 212 | rb->lcd_putsf(0,4,"Size: %lu %cB", (unsigned long)(dps->bc >> (10*log)), |
202 | human_size_prefix[log]); | 213 | rb->str(units[log])); |
203 | rb->lcd_update(); | 214 | rb->lcd_update(); |
204 | } | 215 | } |
205 | 216 | ||
@@ -245,12 +256,19 @@ static bool dir_properties(const char* selected_file, DPS *dps) | |||
245 | rb->snprintf(str_dircount, sizeof str_dircount, "%d", dps->dc); | 256 | rb->snprintf(str_dircount, sizeof str_dircount, "%d", dps->dc); |
246 | rb->snprintf(str_filecount, sizeof str_filecount, "%d", dps->fc); | 257 | rb->snprintf(str_filecount, sizeof str_filecount, "%d", dps->fc); |
247 | log = human_size_log(dps->bc); | 258 | log = human_size_log(dps->bc); |
248 | rb->snprintf(str_size, sizeof str_size, "%ld %cB", | 259 | nsize = (long) (dps->bc >> (log*10)); |
249 | (long) (dps->bc >> (log*10)), human_size_prefix[log]); | 260 | size_unit = units[log]; |
261 | rb->snprintf(str_size, sizeof str_size, "%ld %s", nsize, rb->str(size_unit)); | ||
250 | num_properties = 4; | 262 | num_properties = 4; |
251 | return true; | 263 | return true; |
252 | } | 264 | } |
253 | 265 | ||
266 | static const unsigned char* p2str(const unsigned char* p) | ||
267 | { | ||
268 | int id = P2ID(p); | ||
269 | return (id != -1) ? rb->str(id) : p; | ||
270 | } | ||
271 | |||
254 | static const char * get_props(int selected_item, void* data, | 272 | static const char * get_props(int selected_item, void* data, |
255 | char *buffer, size_t buffer_len) | 273 | char *buffer, size_t buffer_len) |
256 | { | 274 | { |
@@ -263,7 +281,7 @@ static const char * get_props(int selected_item, void* data, | |||
263 | } | 281 | } |
264 | else | 282 | else |
265 | { | 283 | { |
266 | rb->strlcpy(buffer, props_dir[selected_item], buffer_len); | 284 | rb->strlcpy(buffer, p2str(props_dir[selected_item]), buffer_len); |
267 | } | 285 | } |
268 | } | 286 | } |
269 | else | 287 | else |
@@ -274,12 +292,69 @@ static const char * get_props(int selected_item, void* data, | |||
274 | } | 292 | } |
275 | else | 293 | else |
276 | { | 294 | { |
277 | rb->strlcpy(buffer, props_file[selected_item], buffer_len); | 295 | rb->strlcpy(buffer, p2str(props_file[selected_item]), buffer_len); |
278 | } | 296 | } |
279 | } | 297 | } |
280 | return buffer; | 298 | return buffer; |
281 | } | 299 | } |
282 | 300 | ||
301 | static int speak_property_selection(int selected_item, void *data) | ||
302 | { | ||
303 | DPS *dps = data; | ||
304 | int32_t id = P2ID((its_a_dir ? props_dir : props_file)[selected_item]); | ||
305 | rb->talk_id(id, false); | ||
306 | switch (id) | ||
307 | { | ||
308 | case LANG_PROPERTIES_PATH: | ||
309 | if (str_dirname[0] == '/') | ||
310 | { | ||
311 | char *start = str_dirname; | ||
312 | char *ptr; | ||
313 | while (0 != (ptr = rb->strchr(start, '/'))) | ||
314 | { | ||
315 | *ptr = '\0'; | ||
316 | rb->talk_dir_or_spell(str_dirname, NULL, true); | ||
317 | *ptr = '/'; | ||
318 | rb->talk_id(VOICE_CHAR_SLASH, true); | ||
319 | start = ptr + 1; | ||
320 | } | ||
321 | if (*start) | ||
322 | rb->talk_dir_or_spell(str_dirname, NULL, true); | ||
323 | } | ||
324 | else | ||
325 | { | ||
326 | rb->talk_spell(str_dirname, true); | ||
327 | } | ||
328 | break; | ||
329 | case LANG_PROPERTIES_FILENAME: | ||
330 | rb->talk_file_or_spell(str_dirname, str_filename, NULL, true); | ||
331 | break; | ||
332 | case LANG_PROPERTIES_SIZE: | ||
333 | rb->talk_number(nsize, true); | ||
334 | rb->talk_id(size_unit, true); | ||
335 | break; | ||
336 | case LANG_PROPERTIES_DATE: | ||
337 | rb->talk_date(&tm, true); | ||
338 | break; | ||
339 | case LANG_PROPERTIES_TIME: | ||
340 | rb->talk_time(&tm, true); | ||
341 | break; | ||
342 | case LANG_PROPERTIES_DURATION: | ||
343 | rb->talk_value(nseconds, UNIT_TIME, true); | ||
344 | break; | ||
345 | case LANG_PROPERTIES_SUBDIRS: | ||
346 | rb->talk_number(dps->dc, true); | ||
347 | break; | ||
348 | case LANG_PROPERTIES_FILES: | ||
349 | rb->talk_number(dps->fc, true); | ||
350 | break; | ||
351 | default: | ||
352 | rb->talk_spell(props_file[selected_item + 1], true); | ||
353 | break; | ||
354 | } | ||
355 | return 0; | ||
356 | } | ||
357 | |||
283 | enum plugin_status plugin_start(const void* parameter) | 358 | enum plugin_status plugin_start(const void* parameter) |
284 | { | 359 | { |
285 | struct gui_synclist properties_lists; | 360 | struct gui_synclist properties_lists; |
@@ -337,7 +412,7 @@ enum plugin_status plugin_start(const void* parameter) | |||
337 | if(!(its_a_dir ? dir_properties(file, &dps) : file_properties(file))) | 412 | if(!(its_a_dir ? dir_properties(file, &dps) : file_properties(file))) |
338 | { | 413 | { |
339 | /* something went wrong (to do: tell user what it was (nesting,...) */ | 414 | /* something went wrong (to do: tell user what it was (nesting,...) */ |
340 | rb->splash(0, "Failed to gather information"); | 415 | rb->splash(0, ID2P(LANG_PROPERTIES_FAIL)); |
341 | rb->action_userabort(TIMEOUT_BLOCK); | 416 | rb->action_userabort(TIMEOUT_BLOCK); |
342 | return PLUGIN_OK; | 417 | return PLUGIN_OK; |
343 | } | 418 | } |
@@ -348,14 +423,15 @@ enum plugin_status plugin_start(const void* parameter) | |||
348 | #endif | 423 | #endif |
349 | 424 | ||
350 | rb->gui_synclist_init(&properties_lists, &get_props, &dps, false, 2, NULL); | 425 | rb->gui_synclist_init(&properties_lists, &get_props, &dps, false, 2, NULL); |
351 | rb->gui_synclist_set_title(&properties_lists, its_a_dir ? | 426 | rb->gui_synclist_set_title(&properties_lists, rb->str(its_a_dir ? LANG_PROPERTIES_DIRECTORY_PROPERTIES : LANG_PROPERTIES_FILE_PROPERTIES), NOICON); |
352 | "Directory properties" : | ||
353 | "File properties", NOICON); | ||
354 | rb->gui_synclist_set_icon_callback(&properties_lists, NULL); | 427 | rb->gui_synclist_set_icon_callback(&properties_lists, NULL); |
428 | if (rb->global_settings->talk_menu) | ||
429 | rb->gui_synclist_set_voice_callback(&properties_lists, speak_property_selection); | ||
355 | rb->gui_synclist_set_nb_items(&properties_lists, num_properties * 2); | 430 | rb->gui_synclist_set_nb_items(&properties_lists, num_properties * 2); |
356 | rb->gui_synclist_limit_scroll(&properties_lists, true); | 431 | rb->gui_synclist_limit_scroll(&properties_lists, true); |
357 | rb->gui_synclist_select_item(&properties_lists, 0); | 432 | rb->gui_synclist_select_item(&properties_lists, 0); |
358 | rb->gui_synclist_draw(&properties_lists); | 433 | rb->gui_synclist_draw(&properties_lists); |
434 | rb->gui_synclist_speak_item(&properties_lists); | ||
359 | 435 | ||
360 | while(!quit) | 436 | while(!quit) |
361 | { | 437 | { |