From 00acdfa6ef624e1d13b461210ddd71dd589d192e Mon Sep 17 00:00:00 2001 From: Hardeep Sidhu Date: Wed, 10 Dec 2003 00:11:25 +0000 Subject: [PATCH] Added viewer for currently playing playlist. Accessed from Menu->Playlist Options->View Current Playlist. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4124 a1c6a512-1295-4272-9138-f99709370657 --- apps/lang/english.lang | 17 +- apps/playlist.c | 171 ++++++- apps/playlist.h | 18 + apps/playlist_menu.c | 8 +- apps/playlist_viewer.c | 848 ++++++++++++++++++++++++++++++++ apps/playlist_viewer.h | 26 + apps/wps.c | 29 +- firmware/drivers/lcd-recorder.c | 23 + firmware/export/lcd.h | 1 + uisimulator/win32/Makefile | 5 +- uisimulator/win32/rockbox.dsp | 4 + uisimulator/x11/Makefile | 5 +- 12 files changed, 1111 insertions(+), 44 deletions(-) create mode 100644 apps/playlist_viewer.c create mode 100644 apps/playlist_viewer.h diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 0a1cfaeb51..ce2b300d8c 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -1660,7 +1660,7 @@ new: id: LANG_SAVE_DYNAMIC_PLAYLIST desc: in playlist menu. -eng: "Save Dynamic Playlist" +eng: "Save Current Playlist" new: id: LANG_PLAYLIST_MENU @@ -1827,3 +1827,18 @@ id: LANG_FM_BUTTONBAR_RECORD desc: in main menu eng: "Record" new: + +id: LANG_VIEW_DYNAMIC_PLAYLIST +desc: in playlist menu. +eng: "View Current Playlist" +new: + +id: LANG_MOVE +desc: The verb/action Move +eng: "Move" +new: + +id: LANG_MOVE_FAILED +desc: Error message displayed in playlist viewer +eng: "Move failed" +new: diff --git a/apps/playlist.c b/apps/playlist.c index f834a3d5e7..1ededb2ba9 100644 --- a/apps/playlist.c +++ b/apps/playlist.c @@ -146,6 +146,7 @@ static int format_track_path(char *dest, char *src, int buf_length, int max, static void display_playlist_count(int count, char *fmt); static void display_buffer_full(void); static int flush_pending_control(void); +static int rotate_index(int index); /* * remove any files and indices associated with the playlist @@ -679,11 +680,7 @@ static int get_next_index(int steps) { case REPEAT_OFF: { - /* Rotate indices such that first_index is considered index 0 to - simplify next calculation */ - current_index -= playlist.first_index; - if (current_index < 0) - current_index += playlist.amount; + current_index = rotate_index(current_index); next_index = current_index+steps; if ((next_index < 0) || (next_index >= playlist.amount)) @@ -992,6 +989,18 @@ static int flush_pending_control(void) return result; } +/* + * Rotate indices such that first_index is index 0 + */ +static int rotate_index(int index) +{ + index -= playlist.first_index; + if (index < 0) + index += playlist.amount; + + return index; +} + /* * Initialize playlist entries at startup */ @@ -1604,21 +1613,104 @@ int playlist_insert_playlist(char *filename, int position, bool queue) return result; } -/* delete track at specified index */ +/* + * Delete track at specified index. If index is PLAYLIST_DELETE_CURRENT then + * we want to delete the current playing track. + */ int playlist_delete(int index) { - int result; - + int result = 0; + if (playlist.control_fd < 0) { splash(HZ*2, 0, true, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); return -1; } + if (index == PLAYLIST_DELETE_CURRENT) + index = playlist.index; + + result = remove_track_from_playlist(index, true); + + if (result != -1) + mpeg_flush_and_reload_tracks(); + + return result; +} + +/* + * Move track at index to new_index. Tracks between the two are shifted + * appropriately. Returns 0 on success and -1 on failure. + */ +int playlist_move(int index, int new_index) +{ + int result; + int seek; + bool control_file; + bool queue; + bool current = false; + int r = rotate_index(new_index); + char filename[MAX_PATH]; + + if (index == new_index) + return -1; + + if (index == playlist.index) + /* Moving the current track */ + current = true; + + control_file = playlist.indices[index] & PLAYLIST_INSERT_TYPE_MASK; + queue = playlist.indices[index] & PLAYLIST_QUEUE_MASK; + seek = playlist.indices[index] & PLAYLIST_SEEK_MASK; + + if (get_filename(seek, control_file, filename, sizeof(filename)) < 0) + return -1; + + /* Delete track from original position */ result = remove_track_from_playlist(index, true); if (result != -1) - mpeg_flush_and_reload_tracks(); + { + /* We want to insert the track at the position that was specified by + new_index. This may be different then new_index because of the + shifting that occurred after the delete */ + if (r == 0) + /* First index */ + new_index = PLAYLIST_PREPEND; + else if (r == playlist.amount) + /* Append */ + new_index = PLAYLIST_INSERT_LAST; + else + /* Calculate index of desired position */ + new_index = (r+playlist.first_index)%playlist.amount; + + result = add_track_to_playlist(filename, new_index, queue, -1); + + if (result != -1) + { + if (current) + { + /* Moved the current track */ + switch (new_index) + { + case PLAYLIST_PREPEND: + playlist.index = playlist.first_index; + break; + case PLAYLIST_INSERT_LAST: + playlist.index = playlist.first_index - 1; + if (playlist.index < 0) + playlist.index += playlist.amount; + break; + default: + playlist.index = new_index; + break; + } + } + + fsync(playlist.control_fd); + mpeg_flush_and_reload_tracks(); + } + } return result; } @@ -1763,21 +1855,13 @@ int playlist_next(int steps) index = get_next_index(steps); playlist.index = index; - if (playlist.last_insert_pos >= 0) + if (playlist.last_insert_pos >= 0 && steps > 0) { /* check to see if we've gone beyond the last inserted track */ - int rot_index = index; - int rot_last_pos = playlist.last_insert_pos; + int cur = rotate_index(index); + int last_pos = rotate_index(playlist.last_insert_pos); - rot_index -= playlist.first_index; - if (rot_index < 0) - rot_index += playlist.amount; - - rot_last_pos -= playlist.first_index; - if (rot_last_pos < 0) - rot_last_pos += playlist.amount; - - if (rot_index > rot_last_pos) + if (cur > last_pos) { /* reset last inserted track */ playlist.last_insert_pos = -1; @@ -1826,16 +1910,18 @@ int playlist_get_resume_info(short *resume_index) index into the playlist */ int playlist_get_display_index(void) { - int index = playlist.index; - /* first_index should always be index 0 for display purposes */ - index -= playlist.first_index; - if (index < 0) - index += playlist.amount; + int index = rotate_index(playlist.index); return (index+1); } +/* returns index of first track in playlist */ +int playlist_get_first_index(void) +{ + return playlist.first_index; +} + /* returns number of tracks in playlist (includes queued/inserted tracks) */ int playlist_amount(void) { @@ -1860,6 +1946,39 @@ char *playlist_name(char *buf, int buf_size) return buf; } +/* Fills info structure with information about track at specified index. + Returns 0 on success and -1 on failure */ +int playlist_get_track_info(int index, struct playlist_track_info* info) +{ + int seek; + bool control_file; + + if (index < 0 || index >= playlist.amount) + return -1; + + control_file = playlist.indices[index] & PLAYLIST_INSERT_TYPE_MASK; + seek = playlist.indices[index] & PLAYLIST_SEEK_MASK; + + if (get_filename(seek, control_file, info->filename, + sizeof(info->filename)) < 0) + return -1; + + info->attr = 0; + + if (control_file) + { + if (playlist.indices[index] & PLAYLIST_QUEUE_MASK) + info->attr |= PLAYLIST_ATTR_QUEUED; + else + info->attr |= PLAYLIST_ATTR_INSERTED; + } + + info->index = index; + info->display_index = rotate_index(index) + 1; + + return 0; +} + /* save the current dynamic playlist to specified file */ int playlist_save(char *filename) { diff --git a/apps/playlist.h b/apps/playlist.h index 45ecba505c..82d67bf0bb 100644 --- a/apps/playlist.h +++ b/apps/playlist.h @@ -47,6 +47,17 @@ struct playlist_info struct mutex control_mutex; /* mutex for control file access */ }; +#define PLAYLIST_ATTR_QUEUED 0x01 +#define PLAYLIST_ATTR_INSERTED 0x02 + +struct playlist_track_info +{ + char filename[MAX_PATH]; /* path name of mp3 file */ + int attr; /* playlist attributes for track */ + int index; /* index of track in playlist */ + int display_index; /* index of track for display */ +}; + void playlist_init(void); int playlist_create(char *dir, char *file); int playlist_resume(void); @@ -56,6 +67,7 @@ int playlist_insert_directory(char *dirname, int position, bool queue, bool recurse); int playlist_insert_playlist(char *filename, int position, bool queue); int playlist_delete(int index); +int playlist_move(int index, int new_index); int playlist_shuffle(int random_seed, int start_index); int playlist_randomise(unsigned int seed, bool start_current); int playlist_sort(bool start_current); @@ -65,8 +77,10 @@ char *playlist_peek(int steps); int playlist_next(int steps); int playlist_get_resume_info(short *resume_index); int playlist_get_display_index(void); +int playlist_get_first_index(void); int playlist_amount(void); char *playlist_name(char *buf, int buf_size); +int playlist_get_track_info(int index, struct playlist_track_info* info); int playlist_save(char *filename); enum { @@ -76,4 +90,8 @@ enum { PLAYLIST_INSERT_FIRST = -4 }; +enum { + PLAYLIST_DELETE_CURRENT = -1 +}; + #endif /* __PLAYLIST_H__ */ diff --git a/apps/playlist_menu.c b/apps/playlist_menu.c index 4223e3cf72..f4e4867a92 100644 --- a/apps/playlist_menu.c +++ b/apps/playlist_menu.c @@ -25,6 +25,7 @@ #include "playlist.h" #include "tree.h" #include "settings.h" +#include "playlist_viewer.h" #include "lang.h" @@ -64,9 +65,10 @@ bool playlist_menu(void) bool result; struct menu_items items[] = { - { str(LANG_CREATE_PLAYLIST), create_playlist }, - { str(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist }, - { str(LANG_RECURSE_DIRECTORY), recurse_directory }, + { str(LANG_CREATE_PLAYLIST), create_playlist }, + { str(LANG_VIEW_DYNAMIC_PLAYLIST), playlist_viewer }, + { str(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist }, + { str(LANG_RECURSE_DIRECTORY), recurse_directory }, }; m = menu_init( items, sizeof items / sizeof(struct menu_items) ); 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 @@ +/*************************************************************************** + * + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2003 Hardeep Sidhu + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include +#include "playlist.h" +#include "mpeg.h" +#include "screens.h" +#include "status.h" +#include "settings.h" +#include "icons.h" +#include "menu.h" +#include "plugin.h" + +#ifdef HAVE_LCD_BITMAP +#include "widgets.h" +#endif + +#include "lang.h" + +/* Defines for LCD display purposes. Taken from tree.c */ +#ifdef HAVE_LCD_BITMAP + #define CURSOR_X (global_settings.scrollbar && \ + viewer.num_tracks>viewer.num_display_lines?1:0) + #define CURSOR_Y 0 + #define CURSOR_WIDTH (global_settings.invert_cursor ? 0 : 4) + + #define ICON_WIDTH ((viewer.char_width > 6) ? viewer.char_width : 6) + + #define MARGIN_X ((global_settings.scrollbar && \ + viewer.num_tracks > viewer.num_display_lines ? \ + SCROLLBAR_WIDTH : 0) + CURSOR_WIDTH + ICON_WIDTH) + #define MARGIN_Y (global_settings.statusbar ? STATUSBAR_HEIGHT : 0) + + #define LINE_X 0 + #define LINE_Y (global_settings.statusbar ? 1 : 0) + + #define SCROLLBAR_X 0 + #define SCROLLBAR_Y lcd_getymargin() + #define SCROLLBAR_WIDTH 6 +#else + #define MARGIN_X 0 + #define MARGIN_Y 0 + #define LINE_X 2 + #define LINE_Y 0 + #define CURSOR_X 0 + #define CURSOR_Y 0 +#endif + +/* Maximum number of tracks we can have loaded at one time */ +#define MAX_PLAYLIST_ENTRIES 200 + +/* Index of track on display line _pos */ +#define INDEX(_pos) (viewer.first_display_index - viewer.first_index + (_pos)) + +/* Global playlist viewer settings */ +struct playlist_viewer_info { + char *name_buffer; /* Buffer used to store track names */ + int buffer_size; /* Size of name buffer */ + + int num_display_lines; /* Number of lines on lcd */ + int line_height; /* Height (in pixels) of display line */ + int char_width; /* Width (in pixels) of a character */ + + int num_tracks; /* Number of tracks in playlist */ + short current_playing_track;/* Index of current playing track */ + + int num_loaded; /* Number of track entries loaded in viewer */ + int first_index; /* Index of first loaded track */ + int last_index; /* Index of last loaded track */ + int first_display_index; /* Index of first track on display */ + int last_display_index; /* Index of last track on display */ + int cursor_pos; /* Line number of cursor */ + + int move_track; /* Playlist index of track to move or -1 */ +}; + +/* Information about a specific track */ +struct playlist_entry { + char *name; /* Formatted track name */ + int index; /* Playlist index */ + int display_index; /* Display index */ + bool queued; /* Is track queued? */ +}; + +static struct playlist_viewer_info viewer; +static struct playlist_entry tracks[MAX_PLAYLIST_ENTRIES]; + +#ifdef HAVE_LCD_BITMAP +extern unsigned char bitmap_icons_6x8[LastIcon][6]; +#endif + +static bool initialize(void); +static void load_playlist_entries(int start_index); +static void load_playlist_entries_r(int end_index); +static int load_entry(int index, int pos, char* p, int size); +static void format_name(char* dest, char* src); +static void display_playlist(void); +static void update_display_line(int line, bool scroll); +static void scroll_display(int lines); +static void update_first_index(void); +static bool update_playlist(bool force); +static int onplay_menu(int index); + +/* Initialize the playlist viewer */ +static bool initialize(void) +{ + if (!(mpeg_status() & MPEG_STATUS_PLAY)) + /* Nothing is playing, exit */ + return false; + + viewer.name_buffer = plugin_get_buffer(&viewer.buffer_size); + if (!viewer.name_buffer) + return false; + +#ifdef HAVE_LCD_BITMAP + { + char icon_chars[] = "MQ"; /* characters used as icons */ + unsigned int i; + + viewer.char_width = 0; + viewer.line_height = 0; + + /* Use icon characters to calculate largest possible width/height so + that we set proper margins */ + for (i=0; i viewer.char_width) + viewer.char_width = w; + + if (h > viewer.line_height) + { + viewer.line_height = h; + viewer.num_display_lines = (LCD_HEIGHT - MARGIN_Y)/h; + } + } + } +#else + viewer.num_display_lines = 2; + viewer.char_width = 1; + viewer.line_height = 1; +#endif + + viewer.cursor_pos = 0; + viewer.move_track = -1; + + /* Start displaying at current playing track */ + viewer.first_display_index = playlist_get_display_index() - 1; + update_first_index(); + + if (!update_playlist(true)) + return false; + + return true; +} + +/* Load tracks starting at start_index */ +static void load_playlist_entries(int start_index) +{ + int num_entries = viewer.num_tracks - start_index; + char* p = viewer.name_buffer; + int remaining = viewer.buffer_size; + int i; + + viewer.first_index = start_index; + + if (num_entries > MAX_PLAYLIST_ENTRIES) + num_entries = MAX_PLAYLIST_ENTRIES; + + for(i=0; i MAX_PLAYLIST_ENTRIES) + num_entries = MAX_PLAYLIST_ENTRIES; + + for(i=num_entries; i>=0; i--, end_index--) + { + int len = load_entry(end_index, i, p, remaining); + if (len < 0) + { + int j; + + /* Out of name buffer space */ + num_entries -= i; + + /* Shift loaded tracks up such that first track is index 0 */ + for (j=0; j MAX_PLAYLIST_ENTRIES) + max = MAX_PLAYLIST_ENTRIES; + + for (i = num_entries; i 8 ) + offset = (viewer.line_height - 8) / 2; + lcd_bitmap(bitmap_icons_6x8[File], + CURSOR_X * 6 + CURSOR_WIDTH, + MARGIN_Y+(i*viewer.line_height) + offset, + 6, 8, true); +#else + lcd_putc(LINE_X-1, i, File); +#endif + } + else if (tracks[INDEX(i)].index == viewer.move_track) + { + /* Track we are moving */ +#ifdef HAVE_LCD_BITMAP + lcd_putsxy(CURSOR_X * 6 + CURSOR_WIDTH, + MARGIN_Y+(i*viewer.line_height), "M"); +#else + lcd_putc(LINE_X-1, i, 'M'); +#endif + } + else if (tracks[INDEX(i)].queued) + { + /* Queued track */ +#ifdef HAVE_LCD_BITMAP + lcd_putsxy(CURSOR_X * 6 + CURSOR_WIDTH, + MARGIN_Y+(i*viewer.line_height), "Q"); +#else + lcd_putc(LINE_X-1, i, 'Q'); +#endif + } + + update_display_line(i, false); + } + +#ifdef HAVE_LCD_BITMAP + if (global_settings.scrollbar && + (viewer.num_tracks > viewer.num_display_lines)) + scrollbar(SCROLLBAR_X, SCROLLBAR_Y, SCROLLBAR_WIDTH - 1, + LCD_HEIGHT - SCROLLBAR_Y, viewer.num_tracks-1, + viewer.first_display_index, viewer.last_display_index, + VERTICAL); +#endif + + put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, true); + status_draw(true); +} + +/* Scroll cursor or display by num lines */ +static void scroll_display(int lines) +{ + int new_index = viewer.first_display_index + viewer.cursor_pos + lines; + bool pagescroll = false; + bool wrap = false; + + put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, false); + + if (lines > 1 || lines < -1) + pagescroll = true; + + if (new_index < 0) + { + /* Wrap around if not pageup */ + if (pagescroll) + new_index = 0; + else + { + new_index += viewer.num_tracks; + viewer.cursor_pos = viewer.num_display_lines-1; + wrap = true; + } + } + else if (new_index >= viewer.num_tracks) + { + /* Wrap around if not pagedown */ + if (pagescroll) + new_index = viewer.num_tracks - 1; + else + { + new_index -= viewer.num_tracks; + viewer.cursor_pos = 0; + wrap = true; + } + } + + if (new_index >= viewer.first_display_index && + new_index <= viewer.last_display_index) + { + /* Just update the cursor */ + viewer.cursor_pos = new_index - viewer.first_display_index; + } + else + { + /* New track is outside of display */ + if (wrap) + viewer.first_display_index = new_index; + else + viewer.first_display_index = viewer.first_display_index + lines; + + if (viewer.first_display_index < 0) + viewer.first_display_index = 0; + + viewer.last_display_index = + viewer.first_display_index + (viewer.num_display_lines - 1); + if (viewer.last_display_index >= viewer.num_tracks) + { + /* display as many tracks as possible on screen */ + if (viewer.first_display_index > 0) + { + viewer.first_display_index -= + (viewer.last_display_index - viewer.num_tracks + 1); + if (viewer.first_display_index < 0) + viewer.first_display_index = 0; + } + + viewer.last_display_index = viewer.num_tracks - 1; + } + + if (viewer.cursor_pos > + (viewer.last_display_index - viewer.first_display_index)) + viewer.cursor_pos = + viewer.last_display_index - viewer.first_display_index; + + /* Load more data if needed */ + if (viewer.first_display_index < viewer.first_index) + load_playlist_entries_r(viewer.last_display_index); + else if (viewer.last_display_index > viewer.last_index) + load_playlist_entries(viewer.first_display_index); + + display_playlist(); + } + + put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, true); +} + +/* Update lcd line. Scroll line if requested */ +static void update_display_line(int line, bool scroll) +{ + char str[MAX_PATH + 16]; + + snprintf(str, sizeof(str), "%d. %s", + tracks[INDEX(line)].display_index, + tracks[INDEX(line)].name); + + if (scroll) + { +#ifdef HAVE_LCD_BITMAP + if (global_settings.invert_cursor) + lcd_puts_scroll_style(LINE_X, line, str, STYLE_INVERT); + else +#endif + lcd_puts_scroll(LINE_X, line, str); + } + else + lcd_puts(LINE_X, line, str); +} + +/* Update first index, if necessary, to put as much as possible on the + screen */ +static void update_first_index(void) +{ + /* viewer.num_tracks may be invalid at this point */ + int num_tracks = playlist_amount(); + + if ((num_tracks - viewer.first_display_index) < viewer.num_display_lines) + { + /* Try to display as much as possible */ + int old_index = viewer.first_display_index; + + viewer.first_display_index = num_tracks - viewer.num_display_lines; + if (viewer.first_display_index < 0) + viewer.first_display_index = 0; + + /* Cursor should still point at current track */ + viewer.cursor_pos += old_index - viewer.first_display_index; + } +} + +/* Update playlist in case something has changed or forced */ +static bool update_playlist(bool force) +{ + playlist_get_resume_info(&viewer.current_playing_track); + + if (force || playlist_amount() != viewer.num_tracks) + { + int index; + + /* Reload tracks */ + viewer.num_tracks = playlist_amount(); + if (viewer.num_tracks < 0) + return false; + + index = viewer.first_display_index; + + load_playlist_entries(index); + + if (viewer.num_loaded <= 0) + return false; + + viewer.first_display_index = viewer.first_index; + viewer.last_display_index = + viewer.first_index + viewer.num_display_lines - 1; + if (viewer.last_display_index >= viewer.num_tracks) + viewer.last_display_index = viewer.num_tracks - 1; + } + + display_playlist(); + + return true; +} + +/* Menu of playlist commands. Invoked via ON+PLAY on main viewer screen. + Returns -1 if USB attached, 0 if no playlist change, and 1 if playlist + changed. */ +static int onplay_menu(int index) +{ + struct menu_items menu[2]; /* increase this if you add entries! */ + int m, i=0, result, ret = 0; + bool current = (tracks[index].index == viewer.current_playing_track); + + menu[i].desc = str(LANG_DELETE); + i++; + + menu[i].desc = str(LANG_MOVE); + i++; + + m = menu_init(menu, i); + result = menu_show(m); + if (result == MENU_ATTACHED_USB) + ret = -1; + else if (result >= 0) + { + /* Abort current move */ + viewer.move_track = -1; + + switch (result) + { + case 0: + /* delete track */ + if (current) + mpeg_stop(); + + playlist_delete(tracks[index].index); + + if (current) + { + /* Start playing new track except if it's the last track + in the playlist and repeat mode is disabled */ + if (tracks[index].display_index != viewer.num_tracks || + global_settings.repeat_mode == REPEAT_ALL) + { + mpeg_play(0); + viewer.current_playing_track = -1; + } + } + + ret = 1; + break; + case 1: + /* move track */ + viewer.move_track = tracks[index].index; + ret = 0; + break; + } + } + + menu_exit(m); + + return ret; +} + +/* Main viewer function */ +bool playlist_viewer(void) +{ + bool exit=false; /* exit viewer */ + bool update=true; /* update display */ + bool cursor_on=true; /* used for flashing cursor */ + int old_cursor_pos; /* last cursor position */ + int button; + + if (!initialize()) + return false; + + old_cursor_pos = viewer.cursor_pos; + + while (!exit) + { + short track; + + /* Timeout so we can determine if play status has changed */ + button = button_get_w_tmo(HZ/2); + + if (!(mpeg_status() & MPEG_STATUS_PLAY)) + { + /* Play has stopped */ +#ifdef HAVE_LCD_CHARCELLS + splash(HZ, 0, true, str(LANG_END_PLAYLIST_PLAYER)); +#else + splash(HZ, 0, true, str(LANG_END_PLAYLIST_RECORDER)); +#endif + status_set_playmode(STATUS_STOP); + return false;; + } + + if (viewer.move_track != -1 || !cursor_on) + { + /* Flash cursor to identify that we are moving a track */ + cursor_on = !cursor_on; +#ifdef HAVE_LCD_BITMAP + if (global_settings.invert_cursor) + { + lcd_invertrect( + MARGIN_X, MARGIN_Y+(viewer.cursor_pos*viewer.line_height), + LCD_WIDTH, viewer.line_height); + lcd_invertscroll(LINE_X, viewer.cursor_pos); + } + else + put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, + cursor_on); + + lcd_update_rect( + 0, MARGIN_Y + (viewer.cursor_pos * viewer.line_height), + LCD_WIDTH, viewer.line_height); +#else + put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, cursor_on); + lcd_update(); +#endif + } + + playlist_get_resume_info(&track); + + if (track != viewer.current_playing_track || + playlist_amount() != viewer.num_tracks) + { + /* Playlist has changed (new track started?) */ + update_first_index(); + if (!update_playlist(false)) + exit = true; + else + update = true; + + /* Abort move on playlist change */ + viewer.move_track = -1; + } + + switch (button) + { +#ifdef HAVE_RECORDER_KEYPAD + case BUTTON_OFF: + case BUTTON_LEFT: +#else + case BUTTON_STOP: +#endif + exit = true; + break; + +#ifdef HAVE_RECORDER_KEYPAD + case BUTTON_UP: + case BUTTON_UP | BUTTON_REPEAT: +#else + case BUTTON_LEFT: + case BUTTON_LEFT | BUTTON_REPEAT: +#endif + scroll_display(-1); + update = true; + break; + +#ifdef HAVE_RECORDER_KEYPAD + case BUTTON_DOWN: + case BUTTON_DOWN | BUTTON_REPEAT: +#else + case BUTTON_RIGHT: + case BUTTON_RIGHT | BUTTON_REPEAT: +#endif + scroll_display(1); + update = true; + break; + +#ifdef HAVE_RECORDER_KEYPAD + case BUTTON_ON | BUTTON_UP: + case BUTTON_ON | BUTTON_UP | BUTTON_REPEAT: +#else + case BUTTON_ON | BUTTON_LEFT: + case BUTTON_ON | BUTTON_LEFT | BUTTON_REPEAT: +#endif + /* Pageup */ + scroll_display(-viewer.num_display_lines); + update = true; + break; + +#ifdef HAVE_RECORDER_KEYPAD + case BUTTON_ON | BUTTON_DOWN: + case BUTTON_ON | BUTTON_DOWN | BUTTON_REPEAT: +#else + case BUTTON_ON | BUTTON_RIGHT: + case BUTTON_ON | BUTTON_RIGHT | BUTTON_REPEAT: +#endif + /* Pagedown */ + scroll_display(viewer.num_display_lines); + update = true; + break; + +#ifdef HAVE_RECORDER_KEYPAD + case BUTTON_RIGHT: +#endif + case BUTTON_PLAY: + if (viewer.move_track >= 0) + { + /* Move track */ + int ret; + + ret = playlist_move(viewer.move_track, + tracks[INDEX(viewer.cursor_pos)].index); + if (ret < 0) + splash(HZ, 0, true, str(LANG_MOVE_FAILED)); + + update_playlist(true); + viewer.move_track = -1; + } + else + { + /* Stop current track and play new track */ + mpeg_stop(); + playlist_start(tracks[INDEX(viewer.cursor_pos)].index, 0); + status_set_playmode(STATUS_PLAY); + update_playlist(false); + } + + display_playlist(); + update = true; + break; + + case BUTTON_ON | BUTTON_PLAY: + { + /* ON+PLAY menu */ + int ret; + + ret = onplay_menu(INDEX(viewer.cursor_pos)); + + if (ret < 0) + /* USB attached */ + return true; + else if (ret > 0) + { + /* Playlist changed */ + update_first_index(); + update_playlist(true); + if (viewer.num_tracks <= 0) + exit = true; + } + else + display_playlist(); + + update = true; + break; + } + case SYS_USB_CONNECTED: + usb_screen(); + return true; + } + + if (update && !exit) + { + lcd_stop_scroll(); + + if (viewer.cursor_pos > + (viewer.last_display_index - viewer.first_display_index)) + { + /* Cursor position is invalid */ + put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, false); + viewer.cursor_pos = + viewer.last_display_index - viewer.first_display_index; + put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, true); + } + + if (viewer.cursor_pos != old_cursor_pos && + old_cursor_pos <= + (viewer.last_display_index - viewer.first_display_index)) + /* Stop scrolling previous line */ + update_display_line(old_cursor_pos, false); + + /* Scroll line at new cursor position */ + update_display_line(viewer.cursor_pos, true); + + lcd_update(); + + old_cursor_pos = viewer.cursor_pos; + cursor_on = true; + update = false; + } + } + + return false; +} diff --git a/apps/playlist_viewer.h b/apps/playlist_viewer.h new file mode 100644 index 0000000000..ecc5197566 --- /dev/null +++ b/apps/playlist_viewer.h @@ -0,0 +1,26 @@ +/*************************************************************************** + * + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2003 Hardeep Sidhu + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef _PLAYLIST_VIEWER_H_ +#define _PLAYLIST_VIEWER_H_ + +bool playlist_viewer(void); + +#endif diff --git a/apps/wps.c b/apps/wps.c index 7044369ed5..a39f2ba30c 100644 --- a/apps/wps.c +++ b/apps/wps.c @@ -578,8 +578,6 @@ static bool menu(void) status_set_param(false); #endif - wps_display(id3); - wps_refresh(id3, 0, WPS_REFRESH_ALL); return false; } @@ -627,6 +625,7 @@ int wps_show(void) bool ignore_keyup = true; bool restore = false; bool exit = false; + bool update_track = false; id3 = NULL; current_track_path[0] = '\0'; @@ -902,6 +901,7 @@ int wps_show(void) if (menu()) return SYS_USB_CONNECTED; + update_track = true; restore = true; break; @@ -939,18 +939,24 @@ int wps_show(void) return SYS_USB_CONNECTED; case BUTTON_NONE: /* Timeout */ - if (update()) - { - /* set dir browser to current playing song */ - if (global_settings.browse_current && - current_track_path[0] != '\0') - set_current_file(current_track_path); - - return 0; - } + update_track = true; break; } + if (update_track) + { + if (update()) + { + /* set dir browser to current playing song */ + if (global_settings.browse_current && + current_track_path[0] != '\0') + set_current_file(current_track_path); + + return 0; + } + update_track = false; + } + if (exit) { #ifdef HAVE_LCD_CHARCELLS status_set_record(false); @@ -975,7 +981,6 @@ int wps_show(void) return 0; } - if ( button ) ata_spin(); diff --git a/firmware/drivers/lcd-recorder.c b/firmware/drivers/lcd-recorder.c index 597c7d246a..a409c9fc63 100644 --- a/firmware/drivers/lcd-recorder.c +++ b/firmware/drivers/lcd-recorder.c @@ -543,6 +543,29 @@ void lcd_invertrect (int x, int y, int nx, int ny) INVERT_PIXEL((x + i), (y + j)); } +/* Reverse the invert setting of the scrolling line (if any) at given char + position. Setting will go into affect next time line scrolls. */ +void lcd_invertscroll(int x, int y) +{ + struct scrollinfo* s; + int index; + + for ( index = 0; index < SCROLLABLE_LINES; index++ ) { + /* is this a scrolling line? */ + if ( !(scrolling_lines&(1<startx == x && s->starty == y) + { + /* Found the line */ + s->invert = !s->invert; + break; + } + } +} + void lcd_drawline( int x1, int y1, int x2, int y2 ) { int numpixels; diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h index 3f3ea972c3..f4fa3372cf 100644 --- a/firmware/export/lcd.h +++ b/firmware/export/lcd.h @@ -126,6 +126,7 @@ extern void lcd_clearrect (int x, int y, int nx, int ny); extern void lcd_fillrect (int x, int y, int nx, int ny); extern void lcd_drawrect (int x, int y, int nx, int ny); extern void lcd_invertrect (int x, int y, int nx, int ny); +extern void lcd_invertscroll(int x, int y); extern void lcd_drawline( int x1, int y1, int x2, int y2 ); extern void lcd_clearline( int x1, int y1, int x2, int y2 ); extern void lcd_drawpixel(int x, int y); diff --git a/uisimulator/win32/Makefile b/uisimulator/win32/Makefile index cc5ac73ae2..f7b562c0b1 100644 --- a/uisimulator/win32/Makefile +++ b/uisimulator/win32/Makefile @@ -101,7 +101,7 @@ FIRMSRCS = $(LCDSRSC) id3.c mp3data.c usb.c mpeg.c powermgmt.c power.c \ APPS = main.c tree.c menu.c credits.c main_menu.c icons.c language.c \ playlist.c wps.c wps-display.c settings.c status.c \ screens.c peakmeter.c sleeptimer.c keyboard.c onplay.c\ - misc.c plugin.c + misc.c plugin.c playlist_viewer.c MENUS = settings_menu.c sound_menu.c playlist_menu.c @@ -200,6 +200,9 @@ $(OBJDIR)/onplay.o: $(APPDIR)/onplay.c $(OBJDIR)/playlist.o: $(APPDIR)/playlist.c $(CC) $(APPCFLAGS) -c $< -o $@ +$(OBJDIR)/playlist_viewer.o: $(APPDIR)/playlist_viewer.c + $(CC) $(APPCFLAGS) -c $< -o $@ + $(OBJDIR)/plugin.o: $(APPDIR)/plugin.c plugin-win32.h $(CC) $(APPCFLAGS) -c $< -o $@ diff --git a/uisimulator/win32/rockbox.dsp b/uisimulator/win32/rockbox.dsp index dd1ada6dd3..ebfb98fa93 100644 --- a/uisimulator/win32/rockbox.dsp +++ b/uisimulator/win32/rockbox.dsp @@ -365,6 +365,10 @@ SOURCE=..\..\apps\playlist_menu.c # End Source File # Begin Source File +SOURCE=..\..\apps\playlist_viewer.c +# End Source File +# Begin Source File + SOURCE=..\..\apps\plugin.c # End Source File # Begin Source File diff --git a/uisimulator/x11/Makefile b/uisimulator/x11/Makefile index 94f4581865..c4b47790a5 100644 --- a/uisimulator/x11/Makefile +++ b/uisimulator/x11/Makefile @@ -101,7 +101,7 @@ FIRMSRCS = $(LCDSRSC) id3.c debug.c usb.c mpeg.c power.c\ APPS = main.c tree.c menu.c credits.c main_menu.c language.c\ playlist.c wps.c wps-display.c settings.c status.c icons.c\ screens.c peakmeter.c sleeptimer.c keyboard.c onplay.c\ - misc.c plugin.c + misc.c plugin.c playlist_viewer.c MENUS = settings_menu.c sound_menu.c playlist_menu.c @@ -197,6 +197,9 @@ $(OBJDIR)/onplay.o: $(APPDIR)/onplay.c $(OBJDIR)/playlist.o: $(APPDIR)/playlist.c $(CC) $(APPCFLAGS) -c $< -o $@ +$(OBJDIR)/playlist_viewer.o: $(APPDIR)/playlist_viewer.c + $(CC) $(APPCFLAGS) -c $< -o $@ + $(OBJDIR)/build.lang: $(APPDIR)/lang/$(LANGUAGE).lang perl $(TOOLSDIR)/uplang $(APPDIR)/lang/english.lang $< > $@