diff options
Diffstat (limited to 'apps/playlist_viewer.c')
-rw-r--r-- | apps/playlist_viewer.c | 848 |
1 files changed, 848 insertions, 0 deletions
diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c new file mode 100644 index 0000000000..555c9a7128 --- /dev/null +++ b/apps/playlist_viewer.c | |||
@@ -0,0 +1,848 @@ | |||
1 | /*************************************************************************** | ||
2 | * | ||
3 | * __________ __ ___. | ||
4 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
5 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
6 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
7 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
8 | * \/ \/ \/ \/ \/ | ||
9 | * $Id$ | ||
10 | * | ||
11 | * Copyright (C) 2003 Hardeep Sidhu | ||
12 | * | ||
13 | * All files in this archive are subject to the GNU General Public License. | ||
14 | * See the file COPYING in the source tree root for full license agreement. | ||
15 | * | ||
16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
17 | * KIND, either express or implied. | ||
18 | * | ||
19 | ****************************************************************************/ | ||
20 | |||
21 | #include <string.h> | ||
22 | #include <sprintf.h> | ||
23 | #include "playlist.h" | ||
24 | #include "mpeg.h" | ||
25 | #include "screens.h" | ||
26 | #include "status.h" | ||
27 | #include "settings.h" | ||
28 | #include "icons.h" | ||
29 | #include "menu.h" | ||
30 | #include "plugin.h" | ||
31 | |||
32 | #ifdef HAVE_LCD_BITMAP | ||
33 | #include "widgets.h" | ||
34 | #endif | ||
35 | |||
36 | #include "lang.h" | ||
37 | |||
38 | /* Defines for LCD display purposes. Taken from tree.c */ | ||
39 | #ifdef HAVE_LCD_BITMAP | ||
40 | #define CURSOR_X (global_settings.scrollbar && \ | ||
41 | viewer.num_tracks>viewer.num_display_lines?1:0) | ||
42 | #define CURSOR_Y 0 | ||
43 | #define CURSOR_WIDTH (global_settings.invert_cursor ? 0 : 4) | ||
44 | |||
45 | #define ICON_WIDTH ((viewer.char_width > 6) ? viewer.char_width : 6) | ||
46 | |||
47 | #define MARGIN_X ((global_settings.scrollbar && \ | ||
48 | viewer.num_tracks > viewer.num_display_lines ? \ | ||
49 | SCROLLBAR_WIDTH : 0) + CURSOR_WIDTH + ICON_WIDTH) | ||
50 | #define MARGIN_Y (global_settings.statusbar ? STATUSBAR_HEIGHT : 0) | ||
51 | |||
52 | #define LINE_X 0 | ||
53 | #define LINE_Y (global_settings.statusbar ? 1 : 0) | ||
54 | |||
55 | #define SCROLLBAR_X 0 | ||
56 | #define SCROLLBAR_Y lcd_getymargin() | ||
57 | #define SCROLLBAR_WIDTH 6 | ||
58 | #else | ||
59 | #define MARGIN_X 0 | ||
60 | #define MARGIN_Y 0 | ||
61 | #define LINE_X 2 | ||
62 | #define LINE_Y 0 | ||
63 | #define CURSOR_X 0 | ||
64 | #define CURSOR_Y 0 | ||
65 | #endif | ||
66 | |||
67 | /* Maximum number of tracks we can have loaded at one time */ | ||
68 | #define MAX_PLAYLIST_ENTRIES 200 | ||
69 | |||
70 | /* Index of track on display line _pos */ | ||
71 | #define INDEX(_pos) (viewer.first_display_index - viewer.first_index + (_pos)) | ||
72 | |||
73 | /* Global playlist viewer settings */ | ||
74 | struct playlist_viewer_info { | ||
75 | char *name_buffer; /* Buffer used to store track names */ | ||
76 | int buffer_size; /* Size of name buffer */ | ||
77 | |||
78 | int num_display_lines; /* Number of lines on lcd */ | ||
79 | int line_height; /* Height (in pixels) of display line */ | ||
80 | int char_width; /* Width (in pixels) of a character */ | ||
81 | |||
82 | int num_tracks; /* Number of tracks in playlist */ | ||
83 | short current_playing_track;/* Index of current playing track */ | ||
84 | |||
85 | int num_loaded; /* Number of track entries loaded in viewer */ | ||
86 | int first_index; /* Index of first loaded track */ | ||
87 | int last_index; /* Index of last loaded track */ | ||
88 | int first_display_index; /* Index of first track on display */ | ||
89 | int last_display_index; /* Index of last track on display */ | ||
90 | int cursor_pos; /* Line number of cursor */ | ||
91 | |||
92 | int move_track; /* Playlist index of track to move or -1 */ | ||
93 | }; | ||
94 | |||
95 | /* Information about a specific track */ | ||
96 | struct playlist_entry { | ||
97 | char *name; /* Formatted track name */ | ||
98 | int index; /* Playlist index */ | ||
99 | int display_index; /* Display index */ | ||
100 | bool queued; /* Is track queued? */ | ||
101 | }; | ||
102 | |||
103 | static struct playlist_viewer_info viewer; | ||
104 | static struct playlist_entry tracks[MAX_PLAYLIST_ENTRIES]; | ||
105 | |||
106 | #ifdef HAVE_LCD_BITMAP | ||
107 | extern unsigned char bitmap_icons_6x8[LastIcon][6]; | ||
108 | #endif | ||
109 | |||
110 | static bool initialize(void); | ||
111 | static void load_playlist_entries(int start_index); | ||
112 | static void load_playlist_entries_r(int end_index); | ||
113 | static int load_entry(int index, int pos, char* p, int size); | ||
114 | static void format_name(char* dest, char* src); | ||
115 | static void display_playlist(void); | ||
116 | static void update_display_line(int line, bool scroll); | ||
117 | static void scroll_display(int lines); | ||
118 | static void update_first_index(void); | ||
119 | static bool update_playlist(bool force); | ||
120 | static int onplay_menu(int index); | ||
121 | |||
122 | /* Initialize the playlist viewer */ | ||
123 | static bool initialize(void) | ||
124 | { | ||
125 | if (!(mpeg_status() & MPEG_STATUS_PLAY)) | ||
126 | /* Nothing is playing, exit */ | ||
127 | return false; | ||
128 | |||
129 | viewer.name_buffer = plugin_get_buffer(&viewer.buffer_size); | ||
130 | if (!viewer.name_buffer) | ||
131 | return false; | ||
132 | |||
133 | #ifdef HAVE_LCD_BITMAP | ||
134 | { | ||
135 | char icon_chars[] = "MQ"; /* characters used as icons */ | ||
136 | unsigned int i; | ||
137 | |||
138 | viewer.char_width = 0; | ||
139 | viewer.line_height = 0; | ||
140 | |||
141 | /* Use icon characters to calculate largest possible width/height so | ||
142 | that we set proper margins */ | ||
143 | for (i=0; i<sizeof(icon_chars); i++) | ||
144 | { | ||
145 | char str[2]; | ||
146 | int w, h; | ||
147 | |||
148 | snprintf(str, sizeof(str), "%c", icon_chars[i]); | ||
149 | lcd_getstringsize(str, &w, &h); | ||
150 | |||
151 | if (w > viewer.char_width) | ||
152 | viewer.char_width = w; | ||
153 | |||
154 | if (h > viewer.line_height) | ||
155 | { | ||
156 | viewer.line_height = h; | ||
157 | viewer.num_display_lines = (LCD_HEIGHT - MARGIN_Y)/h; | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | #else | ||
162 | viewer.num_display_lines = 2; | ||
163 | viewer.char_width = 1; | ||
164 | viewer.line_height = 1; | ||
165 | #endif | ||
166 | |||
167 | viewer.cursor_pos = 0; | ||
168 | viewer.move_track = -1; | ||
169 | |||
170 | /* Start displaying at current playing track */ | ||
171 | viewer.first_display_index = playlist_get_display_index() - 1; | ||
172 | update_first_index(); | ||
173 | |||
174 | if (!update_playlist(true)) | ||
175 | return false; | ||
176 | |||
177 | return true; | ||
178 | } | ||
179 | |||
180 | /* Load tracks starting at start_index */ | ||
181 | static void load_playlist_entries(int start_index) | ||
182 | { | ||
183 | int num_entries = viewer.num_tracks - start_index; | ||
184 | char* p = viewer.name_buffer; | ||
185 | int remaining = viewer.buffer_size; | ||
186 | int i; | ||
187 | |||
188 | viewer.first_index = start_index; | ||
189 | |||
190 | if (num_entries > MAX_PLAYLIST_ENTRIES) | ||
191 | num_entries = MAX_PLAYLIST_ENTRIES; | ||
192 | |||
193 | for(i=0; i<num_entries; i++, start_index++) | ||
194 | { | ||
195 | int len = load_entry(start_index, i, p, remaining); | ||
196 | if (len < 0) | ||
197 | { | ||
198 | /* Out of name buffer space */ | ||
199 | num_entries = i; | ||
200 | break; | ||
201 | } | ||
202 | |||
203 | p += len; | ||
204 | remaining -= len; | ||
205 | } | ||
206 | |||
207 | viewer.num_loaded = num_entries; | ||
208 | viewer.last_index = viewer.first_index + (viewer.num_loaded - 1); | ||
209 | } | ||
210 | |||
211 | /* Load tracks in reverse, ending at end_index */ | ||
212 | static void load_playlist_entries_r(int end_index) | ||
213 | { | ||
214 | int num_entries = end_index; | ||
215 | char* p = viewer.name_buffer; | ||
216 | int remaining = viewer.buffer_size; | ||
217 | int i; | ||
218 | |||
219 | viewer.last_index = end_index; | ||
220 | |||
221 | if (num_entries > MAX_PLAYLIST_ENTRIES) | ||
222 | num_entries = MAX_PLAYLIST_ENTRIES; | ||
223 | |||
224 | for(i=num_entries; i>=0; i--, end_index--) | ||
225 | { | ||
226 | int len = load_entry(end_index, i, p, remaining); | ||
227 | if (len < 0) | ||
228 | { | ||
229 | int j; | ||
230 | |||
231 | /* Out of name buffer space */ | ||
232 | num_entries -= i; | ||
233 | |||
234 | /* Shift loaded tracks up such that first track is index 0 */ | ||
235 | for (j=0; j<num_entries; j++, i++) | ||
236 | { | ||
237 | tracks[j].name = tracks[i].name; | ||
238 | tracks[j].index = tracks[i].index; | ||
239 | tracks[j].display_index = tracks[i].display_index; | ||
240 | tracks[j].queued = tracks[i].queued; | ||
241 | } | ||
242 | |||
243 | break; | ||
244 | } | ||
245 | |||
246 | p += len; | ||
247 | remaining -= len; | ||
248 | } | ||
249 | |||
250 | viewer.first_index = viewer.last_index - num_entries; | ||
251 | |||
252 | num_entries++; | ||
253 | if (!viewer.first_index && | ||
254 | num_entries < viewer.num_tracks && | ||
255 | num_entries < MAX_PLAYLIST_ENTRIES) | ||
256 | { | ||
257 | /* Lets see if we can load more data at the end of the list */ | ||
258 | int max = viewer.num_tracks; | ||
259 | if (max > MAX_PLAYLIST_ENTRIES) | ||
260 | max = MAX_PLAYLIST_ENTRIES; | ||
261 | |||
262 | for (i = num_entries; i<max; i++) | ||
263 | { | ||
264 | int len = load_entry(num_entries, num_entries, p, remaining); | ||
265 | if (len < 0) | ||
266 | /* Out of name buffer space */ | ||
267 | break; | ||
268 | |||
269 | p += len; | ||
270 | remaining -= len; | ||
271 | |||
272 | num_entries++; | ||
273 | viewer.last_index++; | ||
274 | } | ||
275 | } | ||
276 | |||
277 | viewer.num_loaded = num_entries; | ||
278 | } | ||
279 | |||
280 | /* Load track at playlist index. pos is the position in the tracks array and | ||
281 | p is a pointer to the name buffer (max size), Returns -1 if buffer is | ||
282 | full. */ | ||
283 | static int load_entry(int index, int pos, char* p, int size) | ||
284 | { | ||
285 | struct playlist_track_info info; | ||
286 | int len; | ||
287 | int result = 0; | ||
288 | char name[MAX_PATH]; | ||
289 | |||
290 | /* Playlist viewer orders songs based on display index. We need to | ||
291 | convert to real playlist index to access track */ | ||
292 | index = (index + playlist_get_first_index()) % viewer.num_tracks; | ||
293 | if (playlist_get_track_info(index, &info) < 0) | ||
294 | return -1; | ||
295 | |||
296 | format_name(name, info.filename); | ||
297 | |||
298 | len = strlen(name) + 1; | ||
299 | |||
300 | if (len <= size) | ||
301 | { | ||
302 | strcpy(p, name); | ||
303 | |||
304 | tracks[pos].name = p; | ||
305 | tracks[pos].index = info.index; | ||
306 | tracks[pos].display_index = info.display_index; | ||
307 | tracks[pos].queued = info.attr & PLAYLIST_ATTR_QUEUED; | ||
308 | |||
309 | result = len; | ||
310 | } | ||
311 | else | ||
312 | result = -1; | ||
313 | |||
314 | return result; | ||
315 | } | ||
316 | |||
317 | /* Format trackname for display purposes */ | ||
318 | static void format_name(char* dest, char* src) | ||
319 | { | ||
320 | char* p = strrchr(src, '/'); | ||
321 | int len; | ||
322 | |||
323 | /* Only display the mp3 filename */ | ||
324 | strcpy(dest, p+1); | ||
325 | len = strlen(dest); | ||
326 | |||
327 | /* Remove the extension */ | ||
328 | if (!strcasecmp(&dest[len-4], ".mp3") || | ||
329 | !strcasecmp(&dest[len-4], ".mp2") || | ||
330 | !strcasecmp(&dest[len-4], ".mpa")) | ||
331 | dest[len-4] = '\0'; | ||
332 | } | ||
333 | |||
334 | /* Display tracks on screen */ | ||
335 | static void display_playlist(void) | ||
336 | { | ||
337 | int i; | ||
338 | int num_display_tracks = | ||
339 | viewer.last_display_index - viewer.first_display_index; | ||
340 | |||
341 | lcd_clear_display(); | ||
342 | |||
343 | #ifdef HAVE_LCD_BITMAP | ||
344 | lcd_setmargins(MARGIN_X, MARGIN_Y); | ||
345 | lcd_setfont(FONT_UI); | ||
346 | #endif | ||
347 | |||
348 | for (i=0; i<=num_display_tracks; i++) | ||
349 | { | ||
350 | /* Icons */ | ||
351 | if (tracks[INDEX(i)].index == viewer.current_playing_track) | ||
352 | { | ||
353 | /* Current playing track */ | ||
354 | #ifdef HAVE_LCD_BITMAP | ||
355 | int offset=0; | ||
356 | if ( viewer.line_height > 8 ) | ||
357 | offset = (viewer.line_height - 8) / 2; | ||
358 | lcd_bitmap(bitmap_icons_6x8[File], | ||
359 | CURSOR_X * 6 + CURSOR_WIDTH, | ||
360 | MARGIN_Y+(i*viewer.line_height) + offset, | ||
361 | 6, 8, true); | ||
362 | #else | ||
363 | lcd_putc(LINE_X-1, i, File); | ||
364 | #endif | ||
365 | } | ||
366 | else if (tracks[INDEX(i)].index == viewer.move_track) | ||
367 | { | ||
368 | /* Track we are moving */ | ||
369 | #ifdef HAVE_LCD_BITMAP | ||
370 | lcd_putsxy(CURSOR_X * 6 + CURSOR_WIDTH, | ||
371 | MARGIN_Y+(i*viewer.line_height), "M"); | ||
372 | #else | ||
373 | lcd_putc(LINE_X-1, i, 'M'); | ||
374 | #endif | ||
375 | } | ||
376 | else if (tracks[INDEX(i)].queued) | ||
377 | { | ||
378 | /* Queued track */ | ||
379 | #ifdef HAVE_LCD_BITMAP | ||
380 | lcd_putsxy(CURSOR_X * 6 + CURSOR_WIDTH, | ||
381 | MARGIN_Y+(i*viewer.line_height), "Q"); | ||
382 | #else | ||
383 | lcd_putc(LINE_X-1, i, 'Q'); | ||
384 | #endif | ||
385 | } | ||
386 | |||
387 | update_display_line(i, false); | ||
388 | } | ||
389 | |||
390 | #ifdef HAVE_LCD_BITMAP | ||
391 | if (global_settings.scrollbar && | ||
392 | (viewer.num_tracks > viewer.num_display_lines)) | ||
393 | scrollbar(SCROLLBAR_X, SCROLLBAR_Y, SCROLLBAR_WIDTH - 1, | ||
394 | LCD_HEIGHT - SCROLLBAR_Y, viewer.num_tracks-1, | ||
395 | viewer.first_display_index, viewer.last_display_index, | ||
396 | VERTICAL); | ||
397 | #endif | ||
398 | |||
399 | put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, true); | ||
400 | status_draw(true); | ||
401 | } | ||
402 | |||
403 | /* Scroll cursor or display by num lines */ | ||
404 | static void scroll_display(int lines) | ||
405 | { | ||
406 | int new_index = viewer.first_display_index + viewer.cursor_pos + lines; | ||
407 | bool pagescroll = false; | ||
408 | bool wrap = false; | ||
409 | |||
410 | put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, false); | ||
411 | |||
412 | if (lines > 1 || lines < -1) | ||
413 | pagescroll = true; | ||
414 | |||
415 | if (new_index < 0) | ||
416 | { | ||
417 | /* Wrap around if not pageup */ | ||
418 | if (pagescroll) | ||
419 | new_index = 0; | ||
420 | else | ||
421 | { | ||
422 | new_index += viewer.num_tracks; | ||
423 | viewer.cursor_pos = viewer.num_display_lines-1; | ||
424 | wrap = true; | ||
425 | } | ||
426 | } | ||
427 | else if (new_index >= viewer.num_tracks) | ||
428 | { | ||
429 | /* Wrap around if not pagedown */ | ||
430 | if (pagescroll) | ||
431 | new_index = viewer.num_tracks - 1; | ||
432 | else | ||
433 | { | ||
434 | new_index -= viewer.num_tracks; | ||
435 | viewer.cursor_pos = 0; | ||
436 | wrap = true; | ||
437 | } | ||
438 | } | ||
439 | |||
440 | if (new_index >= viewer.first_display_index && | ||
441 | new_index <= viewer.last_display_index) | ||
442 | { | ||
443 | /* Just update the cursor */ | ||
444 | viewer.cursor_pos = new_index - viewer.first_display_index; | ||
445 | } | ||
446 | else | ||
447 | { | ||
448 | /* New track is outside of display */ | ||
449 | if (wrap) | ||
450 | viewer.first_display_index = new_index; | ||
451 | else | ||
452 | viewer.first_display_index = viewer.first_display_index + lines; | ||
453 | |||
454 | if (viewer.first_display_index < 0) | ||
455 | viewer.first_display_index = 0; | ||
456 | |||
457 | viewer.last_display_index = | ||
458 | viewer.first_display_index + (viewer.num_display_lines - 1); | ||
459 | if (viewer.last_display_index >= viewer.num_tracks) | ||
460 | { | ||
461 | /* display as many tracks as possible on screen */ | ||
462 | if (viewer.first_display_index > 0) | ||
463 | { | ||
464 | viewer.first_display_index -= | ||
465 | (viewer.last_display_index - viewer.num_tracks + 1); | ||
466 | if (viewer.first_display_index < 0) | ||
467 | viewer.first_display_index = 0; | ||
468 | } | ||
469 | |||
470 | viewer.last_display_index = viewer.num_tracks - 1; | ||
471 | } | ||
472 | |||
473 | if (viewer.cursor_pos > | ||
474 | (viewer.last_display_index - viewer.first_display_index)) | ||
475 | viewer.cursor_pos = | ||
476 | viewer.last_display_index - viewer.first_display_index; | ||
477 | |||
478 | /* Load more data if needed */ | ||
479 | if (viewer.first_display_index < viewer.first_index) | ||
480 | load_playlist_entries_r(viewer.last_display_index); | ||
481 | else if (viewer.last_display_index > viewer.last_index) | ||
482 | load_playlist_entries(viewer.first_display_index); | ||
483 | |||
484 | display_playlist(); | ||
485 | } | ||
486 | |||
487 | put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, true); | ||
488 | } | ||
489 | |||
490 | /* Update lcd line. Scroll line if requested */ | ||
491 | static void update_display_line(int line, bool scroll) | ||
492 | { | ||
493 | char str[MAX_PATH + 16]; | ||
494 | |||
495 | snprintf(str, sizeof(str), "%d. %s", | ||
496 | tracks[INDEX(line)].display_index, | ||
497 | tracks[INDEX(line)].name); | ||
498 | |||
499 | if (scroll) | ||
500 | { | ||
501 | #ifdef HAVE_LCD_BITMAP | ||
502 | if (global_settings.invert_cursor) | ||
503 | lcd_puts_scroll_style(LINE_X, line, str, STYLE_INVERT); | ||
504 | else | ||
505 | #endif | ||
506 | lcd_puts_scroll(LINE_X, line, str); | ||
507 | } | ||
508 | else | ||
509 | lcd_puts(LINE_X, line, str); | ||
510 | } | ||
511 | |||
512 | /* Update first index, if necessary, to put as much as possible on the | ||
513 | screen */ | ||
514 | static void update_first_index(void) | ||
515 | { | ||
516 | /* viewer.num_tracks may be invalid at this point */ | ||
517 | int num_tracks = playlist_amount(); | ||
518 | |||
519 | if ((num_tracks - viewer.first_display_index) < viewer.num_display_lines) | ||
520 | { | ||
521 | /* Try to display as much as possible */ | ||
522 | int old_index = viewer.first_display_index; | ||
523 | |||
524 | viewer.first_display_index = num_tracks - viewer.num_display_lines; | ||
525 | if (viewer.first_display_index < 0) | ||
526 | viewer.first_display_index = 0; | ||
527 | |||
528 | /* Cursor should still point at current track */ | ||
529 | viewer.cursor_pos += old_index - viewer.first_display_index; | ||
530 | } | ||
531 | } | ||
532 | |||
533 | /* Update playlist in case something has changed or forced */ | ||
534 | static bool update_playlist(bool force) | ||
535 | { | ||
536 | playlist_get_resume_info(&viewer.current_playing_track); | ||
537 | |||
538 | if (force || playlist_amount() != viewer.num_tracks) | ||
539 | { | ||
540 | int index; | ||
541 | |||
542 | /* Reload tracks */ | ||
543 | viewer.num_tracks = playlist_amount(); | ||
544 | if (viewer.num_tracks < 0) | ||
545 | return false; | ||
546 | |||
547 | index = viewer.first_display_index; | ||
548 | |||
549 | load_playlist_entries(index); | ||
550 | |||
551 | if (viewer.num_loaded <= 0) | ||
552 | return false; | ||
553 | |||
554 | viewer.first_display_index = viewer.first_index; | ||
555 | viewer.last_display_index = | ||
556 | viewer.first_index + viewer.num_display_lines - 1; | ||
557 | if (viewer.last_display_index >= viewer.num_tracks) | ||
558 | viewer.last_display_index = viewer.num_tracks - 1; | ||
559 | } | ||
560 | |||
561 | display_playlist(); | ||
562 | |||
563 | return true; | ||
564 | } | ||
565 | |||
566 | /* Menu of playlist commands. Invoked via ON+PLAY on main viewer screen. | ||
567 | Returns -1 if USB attached, 0 if no playlist change, and 1 if playlist | ||
568 | changed. */ | ||
569 | static int onplay_menu(int index) | ||
570 | { | ||
571 | struct menu_items menu[2]; /* increase this if you add entries! */ | ||
572 | int m, i=0, result, ret = 0; | ||
573 | bool current = (tracks[index].index == viewer.current_playing_track); | ||
574 | |||
575 | menu[i].desc = str(LANG_DELETE); | ||
576 | i++; | ||
577 | |||
578 | menu[i].desc = str(LANG_MOVE); | ||
579 | i++; | ||
580 | |||
581 | m = menu_init(menu, i); | ||
582 | result = menu_show(m); | ||
583 | if (result == MENU_ATTACHED_USB) | ||
584 | ret = -1; | ||
585 | else if (result >= 0) | ||
586 | { | ||
587 | /* Abort current move */ | ||
588 | viewer.move_track = -1; | ||
589 | |||
590 | switch (result) | ||
591 | { | ||
592 | case 0: | ||
593 | /* delete track */ | ||
594 | if (current) | ||
595 | mpeg_stop(); | ||
596 | |||
597 | playlist_delete(tracks[index].index); | ||
598 | |||
599 | if (current) | ||
600 | { | ||
601 | /* Start playing new track except if it's the last track | ||
602 | in the playlist and repeat mode is disabled */ | ||
603 | if (tracks[index].display_index != viewer.num_tracks || | ||
604 | global_settings.repeat_mode == REPEAT_ALL) | ||
605 | { | ||
606 | mpeg_play(0); | ||
607 | viewer.current_playing_track = -1; | ||
608 | } | ||
609 | } | ||
610 | |||
611 | ret = 1; | ||
612 | break; | ||
613 | case 1: | ||
614 | /* move track */ | ||
615 | viewer.move_track = tracks[index].index; | ||
616 | ret = 0; | ||
617 | break; | ||
618 | } | ||
619 | } | ||
620 | |||
621 | menu_exit(m); | ||
622 | |||
623 | return ret; | ||
624 | } | ||
625 | |||
626 | /* Main viewer function */ | ||
627 | bool playlist_viewer(void) | ||
628 | { | ||
629 | bool exit=false; /* exit viewer */ | ||
630 | bool update=true; /* update display */ | ||
631 | bool cursor_on=true; /* used for flashing cursor */ | ||
632 | int old_cursor_pos; /* last cursor position */ | ||
633 | int button; | ||
634 | |||
635 | if (!initialize()) | ||
636 | return false; | ||
637 | |||
638 | old_cursor_pos = viewer.cursor_pos; | ||
639 | |||
640 | while (!exit) | ||
641 | { | ||
642 | short track; | ||
643 | |||
644 | /* Timeout so we can determine if play status has changed */ | ||
645 | button = button_get_w_tmo(HZ/2); | ||
646 | |||
647 | if (!(mpeg_status() & MPEG_STATUS_PLAY)) | ||
648 | { | ||
649 | /* Play has stopped */ | ||
650 | #ifdef HAVE_LCD_CHARCELLS | ||
651 | splash(HZ, 0, true, str(LANG_END_PLAYLIST_PLAYER)); | ||
652 | #else | ||
653 | splash(HZ, 0, true, str(LANG_END_PLAYLIST_RECORDER)); | ||
654 | #endif | ||
655 | status_set_playmode(STATUS_STOP); | ||
656 | return false;; | ||
657 | } | ||
658 | |||
659 | if (viewer.move_track != -1 || !cursor_on) | ||
660 | { | ||
661 | /* Flash cursor to identify that we are moving a track */ | ||
662 | cursor_on = !cursor_on; | ||
663 | #ifdef HAVE_LCD_BITMAP | ||
664 | if (global_settings.invert_cursor) | ||
665 | { | ||
666 | lcd_invertrect( | ||
667 | MARGIN_X, MARGIN_Y+(viewer.cursor_pos*viewer.line_height), | ||
668 | LCD_WIDTH, viewer.line_height); | ||
669 | lcd_invertscroll(LINE_X, viewer.cursor_pos); | ||
670 | } | ||
671 | else | ||
672 | put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, | ||
673 | cursor_on); | ||
674 | |||
675 | lcd_update_rect( | ||
676 | 0, MARGIN_Y + (viewer.cursor_pos * viewer.line_height), | ||
677 | LCD_WIDTH, viewer.line_height); | ||
678 | #else | ||
679 | put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, cursor_on); | ||
680 | lcd_update(); | ||
681 | #endif | ||
682 | } | ||
683 | |||
684 | playlist_get_resume_info(&track); | ||
685 | |||
686 | if (track != viewer.current_playing_track || | ||
687 | playlist_amount() != viewer.num_tracks) | ||
688 | { | ||
689 | /* Playlist has changed (new track started?) */ | ||
690 | update_first_index(); | ||
691 | if (!update_playlist(false)) | ||
692 | exit = true; | ||
693 | else | ||
694 | update = true; | ||
695 | |||
696 | /* Abort move on playlist change */ | ||
697 | viewer.move_track = -1; | ||
698 | } | ||
699 | |||
700 | switch (button) | ||
701 | { | ||
702 | #ifdef HAVE_RECORDER_KEYPAD | ||
703 | case BUTTON_OFF: | ||
704 | case BUTTON_LEFT: | ||
705 | #else | ||
706 | case BUTTON_STOP: | ||
707 | #endif | ||
708 | exit = true; | ||
709 | break; | ||
710 | |||
711 | #ifdef HAVE_RECORDER_KEYPAD | ||
712 | case BUTTON_UP: | ||
713 | case BUTTON_UP | BUTTON_REPEAT: | ||
714 | #else | ||
715 | case BUTTON_LEFT: | ||
716 | case BUTTON_LEFT | BUTTON_REPEAT: | ||
717 | #endif | ||
718 | scroll_display(-1); | ||
719 | update = true; | ||
720 | break; | ||
721 | |||
722 | #ifdef HAVE_RECORDER_KEYPAD | ||
723 | case BUTTON_DOWN: | ||
724 | case BUTTON_DOWN | BUTTON_REPEAT: | ||
725 | #else | ||
726 | case BUTTON_RIGHT: | ||
727 | case BUTTON_RIGHT | BUTTON_REPEAT: | ||
728 | #endif | ||
729 | scroll_display(1); | ||
730 | update = true; | ||
731 | break; | ||
732 | |||
733 | #ifdef HAVE_RECORDER_KEYPAD | ||
734 | case BUTTON_ON | BUTTON_UP: | ||
735 | case BUTTON_ON | BUTTON_UP | BUTTON_REPEAT: | ||
736 | #else | ||
737 | case BUTTON_ON | BUTTON_LEFT: | ||
738 | case BUTTON_ON | BUTTON_LEFT | BUTTON_REPEAT: | ||
739 | #endif | ||
740 | /* Pageup */ | ||
741 | scroll_display(-viewer.num_display_lines); | ||
742 | update = true; | ||
743 | break; | ||
744 | |||
745 | #ifdef HAVE_RECORDER_KEYPAD | ||
746 | case BUTTON_ON | BUTTON_DOWN: | ||
747 | case BUTTON_ON | BUTTON_DOWN | BUTTON_REPEAT: | ||
748 | #else | ||
749 | case BUTTON_ON | BUTTON_RIGHT: | ||
750 | case BUTTON_ON | BUTTON_RIGHT | BUTTON_REPEAT: | ||
751 | #endif | ||
752 | /* Pagedown */ | ||
753 | scroll_display(viewer.num_display_lines); | ||
754 | update = true; | ||
755 | break; | ||
756 | |||
757 | #ifdef HAVE_RECORDER_KEYPAD | ||
758 | case BUTTON_RIGHT: | ||
759 | #endif | ||
760 | case BUTTON_PLAY: | ||
761 | if (viewer.move_track >= 0) | ||
762 | { | ||
763 | /* Move track */ | ||
764 | int ret; | ||
765 | |||
766 | ret = playlist_move(viewer.move_track, | ||
767 | tracks[INDEX(viewer.cursor_pos)].index); | ||
768 | if (ret < 0) | ||
769 | splash(HZ, 0, true, str(LANG_MOVE_FAILED)); | ||
770 | |||
771 | update_playlist(true); | ||
772 | viewer.move_track = -1; | ||
773 | } | ||
774 | else | ||
775 | { | ||
776 | /* Stop current track and play new track */ | ||
777 | mpeg_stop(); | ||
778 | playlist_start(tracks[INDEX(viewer.cursor_pos)].index, 0); | ||
779 | status_set_playmode(STATUS_PLAY); | ||
780 | update_playlist(false); | ||
781 | } | ||
782 | |||
783 | display_playlist(); | ||
784 | update = true; | ||
785 | break; | ||
786 | |||
787 | case BUTTON_ON | BUTTON_PLAY: | ||
788 | { | ||
789 | /* ON+PLAY menu */ | ||
790 | int ret; | ||
791 | |||
792 | ret = onplay_menu(INDEX(viewer.cursor_pos)); | ||
793 | |||
794 | if (ret < 0) | ||
795 | /* USB attached */ | ||
796 | return true; | ||
797 | else if (ret > 0) | ||
798 | { | ||
799 | /* Playlist changed */ | ||
800 | update_first_index(); | ||
801 | update_playlist(true); | ||
802 | if (viewer.num_tracks <= 0) | ||
803 | exit = true; | ||
804 | } | ||
805 | else | ||
806 | display_playlist(); | ||
807 | |||
808 | update = true; | ||
809 | break; | ||
810 | } | ||
811 | case SYS_USB_CONNECTED: | ||
812 | usb_screen(); | ||
813 | return true; | ||
814 | } | ||
815 | |||
816 | if (update && !exit) | ||
817 | { | ||
818 | lcd_stop_scroll(); | ||
819 | |||
820 | if (viewer.cursor_pos > | ||
821 | (viewer.last_display_index - viewer.first_display_index)) | ||
822 | { | ||
823 | /* Cursor position is invalid */ | ||
824 | put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, false); | ||
825 | viewer.cursor_pos = | ||
826 | viewer.last_display_index - viewer.first_display_index; | ||
827 | put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, true); | ||
828 | } | ||
829 | |||
830 | if (viewer.cursor_pos != old_cursor_pos && | ||
831 | old_cursor_pos <= | ||
832 | (viewer.last_display_index - viewer.first_display_index)) | ||
833 | /* Stop scrolling previous line */ | ||
834 | update_display_line(old_cursor_pos, false); | ||
835 | |||
836 | /* Scroll line at new cursor position */ | ||
837 | update_display_line(viewer.cursor_pos, true); | ||
838 | |||
839 | lcd_update(); | ||
840 | |||
841 | old_cursor_pos = viewer.cursor_pos; | ||
842 | cursor_on = true; | ||
843 | update = false; | ||
844 | } | ||
845 | } | ||
846 | |||
847 | return false; | ||
848 | } | ||