From 8517ed8939b7323be8371cd902544154ade984b9 Mon Sep 17 00:00:00 2001 From: Kevin Ferrare Date: Wed, 16 Nov 2005 02:12:25 +0000 Subject: [PATCH] Multi screen support for playlist viewer, some fixes in other gui files git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7901 a1c6a512-1295-4272-9138-f99709370657 --- apps/gui/icon.c | 20 +- apps/gui/icon.h | 8 +- apps/gui/list.c | 46 +- apps/gui/list.h | 64 +-- apps/gui/scrollbar.c | 8 +- apps/gui/scrollbar.h | 5 +- apps/player/icons.h | 2 + apps/playlist_viewer.c | 929 ++++++++++++++--------------------------- apps/recorder/icons.c | 2 + apps/recorder/icons.h | 2 + apps/screen_access.c | 14 +- 11 files changed, 409 insertions(+), 691 deletions(-) diff --git a/apps/gui/icon.c b/apps/gui/icon.c index db69b4b128..0cdee11b8e 100644 --- a/apps/gui/icon.c +++ b/apps/gui/icon.c @@ -26,24 +26,30 @@ void screen_put_iconxy(struct screen * display, int x, int y, ICON icon) { #ifdef HAVE_LCD_BITMAP - if(icon==0)/* Don't display invalid icons */ - return; int xpos, ypos; xpos = x*CURSOR_WIDTH; ypos = y*display->char_height + display->getymargin(); + if ( display->char_height > CURSOR_HEIGHT )/* center the cursor */ ypos += (display->char_height - CURSOR_HEIGHT) / 2; - display->mono_bitmap(icon, xpos, ypos, CURSOR_WIDTH, CURSOR_HEIGHT); + if(icon==0)/* Don't display invalid icons */ + screen_clear_area(display, xpos, ypos, CURSOR_WIDTH, CURSOR_HEIGHT); + else + display->mono_bitmap(icon, xpos, ypos, CURSOR_WIDTH, CURSOR_HEIGHT); #else - display->putc(x, y, icon); + if(icon==-1) + display->putc(x, y, ' '); + else + display->putc(x, y, icon); #endif } -void screen_put_cursorxy(struct screen * display, int x, int y) +void screen_put_cursorxy(struct screen * display, int x, int y, bool on) { #ifdef HAVE_LCD_BITMAP - screen_put_iconxy(display, x, y, bitmap_icons_6x8[Icon_Cursor]); + screen_put_iconxy(display, x, y, on?bitmap_icons_6x8[Icon_Cursor]:0); #else - screen_put_iconxy(display, x, y, CURSOR_CHAR); + screen_put_iconxy(display, x, y, on?CURSOR_CHAR:-1); #endif + } diff --git a/apps/gui/icon.h b/apps/gui/icon.h index 1208820558..a9ae058ce9 100644 --- a/apps/gui/icon.h +++ b/apps/gui/icon.h @@ -31,16 +31,20 @@ #define CURSOR_CHAR 0x92 #define CURSOR_WIDTH 6 #define CURSOR_HEIGHT 8 + /* - * Draws a cursor at a given position + * Draws a cursor at a given position, if th * - screen : the screen where we put the cursor * - x, y : the position, in character, not in pixel !! + * - on : true if the cursor must be shown, false if it must be erased */ -extern void screen_put_cursorxy(struct screen * screen, int x, int y); +extern void screen_put_cursorxy(struct screen * screen, int x, int y, bool on); /* * Put an icon on a screen at a given position * (the position is given in characters) + * If the given icon is null (HAVE_LCD_BITMAP) or -1 otherwise, the icon + * at the given position will be erased * - screen : the screen where we put our icon * - x, y : the position, in character, not in pixel !! * - icon : the icon to put diff --git a/apps/gui/list.c b/apps/gui/list.c index c0b6ce24f9..df398eaa58 100644 --- a/apps/gui/list.c +++ b/apps/gui/list.c @@ -40,10 +40,8 @@ void gui_list_init(struct gui_list * gui_list, - void (*callback_get_item_icon) - (int selected_item, void * data, ICON * icon), - char * (*callback_get_item_name) - (int selected_item, void * data, char *buffer), + list_get_icon callback_get_item_icon, + list_get_name callback_get_item_name, void * data ) { @@ -75,11 +73,10 @@ void gui_list_flash(struct gui_list * gui_list) gui_list->cursor_flash_state=!gui_list->cursor_flash_state; int selected_line=gui_list->selected_item-gui_list->start_item; #ifdef HAVE_LCD_BITMAP - int cursor_xpos=global_settings.scrollbar?1:0; - int line_xpos=display->getxmargin(); int line_ypos=display->getymargin()+display->char_height*selected_line; if (global_settings.invert_cursor) { + int line_xpos=display->getxmargin(); display->set_drawmode(DRMODE_COMPLEMENT); display->fillrect(line_xpos, line_ypos, display->width, display->char_height); @@ -88,19 +85,14 @@ void gui_list_flash(struct gui_list * gui_list) } else { - if(gui_list->cursor_flash_state) - screen_clear_area(display, cursor_xpos*SCROLLBAR_WIDTH, line_ypos, - CURSOR_WIDTH, CURSOR_HEIGHT); - else - screen_put_cursorxy(display, cursor_xpos, selected_line); + int cursor_xpos=(global_settings.scrollbar && + display->nb_lines < gui_list->nb_items)?1:0; + screen_put_cursorxy(display, cursor_xpos, selected_line, gui_list->cursor_flash_state); } display->update_rect(0, line_ypos,display->width, display->char_height); #else - if(gui_list->cursor_flash_state) - display->putc(0, selected_line, ' '); - else - screen_put_cursorxy(display, 0, selected_line); + screen_put_cursorxy(display, 0, selected_line, gui_list->cursor_flash_state); gui_textarea_update(display); #endif } @@ -199,7 +191,7 @@ void gui_list_draw(struct gui_list * gui_list) #endif if(draw_cursor) - screen_put_cursorxy(display, cursor_pos, i); + screen_put_cursorxy(display, cursor_pos, i, true); } else {/* normal item */ @@ -371,10 +363,8 @@ void gui_list_del_item(struct gui_list * gui_list) */ void gui_synclist_init( struct gui_synclist * lists, - void (*callback_get_item_icon) - (int selected_item, void * data, ICON * icon), - char * (*callback_get_item_name) - (int selected_item, void * data, char *buffer), + list_get_icon callback_get_item_icon, + list_get_name callback_get_item_name, void * data ) { @@ -472,7 +462,7 @@ void gui_synclist_flash(struct gui_synclist * lists) gui_list_flash(&(lists->gui_list[i])); } -bool gui_synclist_do_button(struct gui_synclist * lists, unsigned button) +unsigned gui_synclist_do_button(struct gui_synclist * lists, unsigned button) { gui_synclist_limit_scroll(lists, true); switch(button) @@ -489,7 +479,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists, unsigned button) #endif gui_synclist_select_previous(lists); gui_synclist_draw(lists); - return true; + return LIST_PREV; case LIST_NEXT: #ifdef LIST_RC_NEXT @@ -504,7 +494,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists, unsigned button) #endif gui_synclist_select_next(lists); gui_synclist_draw(lists); - return true; + return LIST_NEXT; /* for pgup / pgdown, we are obliged to have a different behaviour depending on the screen * for which the user pressed the key since for example, remote and main screen doesn't * have the same number of lines*/ @@ -514,7 +504,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists, unsigned button) case LIST_PGUP | BUTTON_REPEAT: gui_synclist_select_previous_page(lists, SCREEN_MAIN); gui_synclist_draw(lists); - return true; + return LIST_NEXT; #endif #ifdef LIST_RC_PGUP @@ -523,7 +513,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists, unsigned button) case LIST_RC_PGUP | BUTTON_REPEAT: gui_synclist_select_previous_page(lists, SCREEN_REMOTE); gui_synclist_draw(lists); - return true; + return LIST_NEXT; #endif #ifdef LIST_PGDN @@ -532,7 +522,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists, unsigned button) case LIST_PGDN | BUTTON_REPEAT: gui_synclist_select_next_page(lists, SCREEN_MAIN); gui_synclist_draw(lists); - return true; + return LIST_PREV; #endif #ifdef LIST_RC_PGDN @@ -541,8 +531,8 @@ bool gui_synclist_do_button(struct gui_synclist * lists, unsigned button) case LIST_RC_PGDN | BUTTON_REPEAT: gui_synclist_select_next_page(lists, SCREEN_REMOTE); gui_synclist_draw(lists); - return true; + return LIST_PREV; #endif } - return false; + return 0; } diff --git a/apps/gui/list.h b/apps/gui/list.h index e587942c94..42a8677637 100644 --- a/apps/gui/list.h +++ b/apps/gui/list.h @@ -33,24 +33,33 @@ #define LIST_PREV BUTTON_UP #define LIST_PGUP (BUTTON_ON | BUTTON_UP) #define LIST_PGDN (BUTTON_ON | BUTTON_DOWN) + +#ifdef CONFIG_REMOTE_KEYPAD #define LIST_RC_NEXT BUTTON_RC_FF #define LIST_RC_PREV BUTTON_RC_REW #define LIST_RC_PGUP BUTTON_RC_SOURCE #define LIST_RC_PGDN BUTTON_RC_BITRATE +#endif /* CONFIG_REMOTE_KEYPAD */ #elif CONFIG_KEYPAD == RECORDER_PAD #define LIST_NEXT BUTTON_DOWN #define LIST_PREV BUTTON_UP #define LIST_PGUP (BUTTON_ON | BUTTON_UP) #define LIST_PGDN (BUTTON_ON | BUTTON_DOWN) + +#ifdef CONFIG_REMOTE_KEYPAD #define LIST_RC_NEXT BUTTON_RC_RIGHT #define LIST_RC_PREV BUTTON_RC_LEFT +#endif /* CONFIG_REMOTE_KEYPAD */ #elif CONFIG_KEYPAD == PLAYER_PAD #define LIST_NEXT BUTTON_RIGHT #define LIST_PREV BUTTON_LEFT + +#ifdef CONFIG_REMOTE_KEYPAD #define LIST_RC_NEXT BUTTON_RC_RIGHT #define LIST_RC_PREV BUTTON_RC_LEFT +#endif /* CONFIG_REMOTE_KEYPAD */ #elif CONFIG_KEYPAD == ONDIO_PAD #define LIST_NEXT BUTTON_DOWN @@ -73,8 +82,21 @@ * tells it what to display. * There are two callback function : * one to get the text and one to get the icon - * Callback interface : - * + */ + +/* + * Icon callback + * - selected_item : an integer that tells the number of the item to display + * - data : a void pointer to the data you gave to the list when + * you initialized it + * - icon : a pointer to the icon, the value inside it is used to display + * the icon after the function returns. + * Note : we use the ICON type because the real type depends of the plateform + */ +typedef void list_get_icon(int selected_item, + void * data, + ICON * icon); +/* * Text callback * - selected_item : an integer that tells the number of the item to display * - data : a void pointer to the data you gave to the list when @@ -84,15 +106,11 @@ * the return value of the function in all cases to avoid filling * a buffer when it's not necessary) * Returns a pointer to a string that contains the text to display - * - * Icon callback - * - selected_item : an integer that tells the number of the item to display - * - data : a void pointer to the data you gave to the list when - * you initialized it - * - icon : a pointer to the icon, the value inside it is used to display - * the icon after the function returns. - * Note : we use the ICON type because the real type depends of the plateform */ +typedef char * list_get_name(int selected_item, + void * data, + char *buffer); + struct gui_list { int nb_items; @@ -100,13 +118,10 @@ struct gui_list bool cursor_flash_state; int start_item; /* the item that is displayed at the top of the screen */ - void (*callback_get_item_icon) - (int selected_item, void * data, ICON * icon); - char * (*callback_get_item_name) - (int selected_item, void * data, char *buffer); + list_get_icon *callback_get_item_icon; + list_get_name *callback_get_item_name; struct screen * display; - int line_scroll_limit; /* defines wether the list should stop when reaching the top/bottom * or should continue (by going to bottom/top) */ bool limit_scroll; @@ -123,10 +138,8 @@ struct gui_list * to a given item number */ extern void gui_list_init(struct gui_list * gui_list, - void (*callback_get_item_icon) - (int selected_item, void * data, ICON * icon), - char * (*callback_get_item_name) - (int selected_item, void * data, char *buffer), + list_get_icon callback_get_item_icon, + list_get_name callback_get_item_name, void * data ); @@ -264,10 +277,8 @@ struct gui_synclist extern void gui_synclist_init( struct gui_synclist * lists, - void (*callback_get_item_icon) - (int selected_item, void * data, ICON * icon), - char * (*callback_get_item_name) - (int selected_item, void * data, char *buffer), + list_get_icon callback_get_item_icon, + list_get_name callback_get_item_name, void * data ); extern void gui_synclist_set_nb_items(struct gui_synclist * lists, int nb_items); @@ -295,10 +306,13 @@ extern void gui_synclist_flash(struct gui_synclist * lists); /* * Do the action implied by the given button, - * returns true if something has been done, false otherwise + * returns the action taken if any, 0 else * - lists : the synchronized lists * - button : the keycode of a pressed button + * returned value : + * - LIST_NEXT when moving forward (next item or pgup) + * - LIST_PREV when moving backward (previous item or pgdown) */ -extern bool gui_synclist_do_button(struct gui_synclist * lists, unsigned button); +extern unsigned gui_synclist_do_button(struct gui_synclist * lists, unsigned button); #endif /* _GUI_LIST_H_ */ diff --git a/apps/gui/scrollbar.c b/apps/gui/scrollbar.c index 837b084b62..73c523f56a 100644 --- a/apps/gui/scrollbar.c +++ b/apps/gui/scrollbar.c @@ -17,12 +17,10 @@ * ****************************************************************************/ -#include "config.h" -#include "lcd.h" -#ifdef HAVE_LCD_BITMAP -#include "limits.h" #include "scrollbar.h" -#include "screen_access.h" +#ifdef HAVE_LCD_BITMAP +#include "config.h" +#include "limits.h" void gui_scrollbar_draw(struct screen * screen, int x, int y, int width, int height, int items, diff --git a/apps/gui/scrollbar.h b/apps/gui/scrollbar.h index 3c562b415f..d7d0be7a7e 100644 --- a/apps/gui/scrollbar.h +++ b/apps/gui/scrollbar.h @@ -19,10 +19,9 @@ #ifndef _GUI_SCROLLBAR_H_ #define _GUI_SCROLLBAR_H_ -#include -#ifdef HAVE_LCD_BITMAP +#include "screen_access.h" -struct screen; +#ifdef HAVE_LCD_BITMAP enum orientation { VERTICAL, diff --git a/apps/player/icons.h b/apps/player/icons.h index dbce79586b..89aa5f7984 100644 --- a/apps/player/icons.h +++ b/apps/player/icons.h @@ -28,6 +28,8 @@ #ifdef HAVE_LCD_CHARCELLS enum { + Icon_Queued = 'Q', + Icon_Moving = 'M', Icon_Unknown = 0x90, Icon_Bookmark = 0x16, Icon_Plugin, diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c index 70c1cf8995..58f27409b1 100644 --- a/apps/playlist_viewer.c +++ b/apps/playlist_viewer.c @@ -17,7 +17,10 @@ * KIND, either express or implied. * ****************************************************************************/ - +/* + * Kevin Ferrare 2005/10/16 + * multi-screen support, rewrote a lot of code + */ #include #include #include "playlist.h" @@ -35,76 +38,24 @@ #include "misc.h" #include "action.h" -#ifdef HAVE_LCD_BITMAP -#include "widgets.h" -#endif - #include "lang.h" #include "playlist_viewer.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 + \ - (global_settings.playlist_viewer_icons ? \ - ICON_WIDTH : 0)) - #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 +#include "icon.h" +#include "list.h" +#include "statusbar.h" +#include "splash.h" /* Maximum number of tracks we can have loaded at one time */ -#define MAX_PLAYLIST_ENTRIES 200 +#define MAX_PLAYLIST_ENTRIES 40 + +/* The number of items between the selected one and the end/start of + * the buffer under which the buffer must reload */ +#define MIN_BUFFER_MARGIN screens[0].nb_lines /* Default playlist name for saving */ #define DEFAULT_VIEWER_PLAYLIST_NAME "/viewer.m3u" -/* 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 { - struct playlist_info* playlist; /* playlist being viewed */ - 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 */ - int 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 { @@ -115,22 +66,60 @@ struct playlist_entry { bool skipped; /* Is track marked as bad? */ }; -static struct playlist_viewer_info viewer; -static struct playlist_entry tracks[MAX_PLAYLIST_ENTRIES]; +enum direction +{ + FORWARD, + BACKWARD +}; + +struct playlist_buffer +{ + char *name_buffer; /* Buffer used to store track names */ + int buffer_size; /* Size of name buffer */ + + int first_index; /* Real index of first track loaded inside + the buffer */ + + enum direction direction; /* Direction of the buffer (if the buffer + was loaded BACKWARD, the last track in + the buffer has a real index < to the + real index of the the first track)*/ + + struct playlist_entry tracks[MAX_PLAYLIST_ENTRIES]; + int num_loaded; /* Number of track entries loaded in buffer */ +}; + +/* Global playlist viewer settings */ +struct playlist_viewer { + struct playlist_info* playlist; /* playlist being viewed */ + int num_tracks; /* Number of tracks in playlist */ + int current_playing_track; /* Index of current playing track */ + int selected_track; /* The selected track, relative (first is 0)*/ + int move_track; /* Playlist index of track to move or -1 */ + struct playlist_buffer buffer; +}; + +static struct playlist_viewer viewer; /* Used when viewing playlists on disk */ static struct playlist_info temp_playlist; -static bool initialize(char* filename, bool reload); -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); +void playlist_buffer_init(struct playlist_buffer * pb, char * names_buffer, + int names_buffer_size); +void playlist_buffer_load_entries(struct playlist_buffer * pb, int index, + enum direction direction); +int playlist_entry_load(struct playlist_entry *entry, int index, + char* name_buffer, int remaining_size); + +struct playlist_entry * playlist_buffer_get_track(struct playlist_buffer * pb, + int index); + +static bool playlist_viewer_init(struct playlist_viewer * viewer, + char* filename, bool reload); + static void format_name(char* dest, const char* src); static void format_line(const struct playlist_entry* track, char* str, int len); -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); static bool viewer_menu(void); @@ -139,8 +128,148 @@ static bool show_indices(void); static bool track_display(void); static bool save_playlist(void); +void playlist_buffer_init(struct playlist_buffer * pb, char * names_buffer, + int names_buffer_size) +{ + pb->name_buffer=names_buffer; + pb->buffer_size=names_buffer_size; + pb->first_index=0; + pb->num_loaded=0; +} +/* + * Loads the entries following 'index' in the playlist buffer + */ +void playlist_buffer_load_entries(struct playlist_buffer * pb, int index, + enum direction direction) +{ + int num_entries = viewer.num_tracks; + char* p = pb->name_buffer; + int remaining = pb->buffer_size; + int i; + + pb->first_index = index; + if (num_entries > MAX_PLAYLIST_ENTRIES) + num_entries = MAX_PLAYLIST_ENTRIES; + + for(i=0; itracks[i]), index, p, remaining); + if (len < 0) + { + /* Out of name buffer space */ + num_entries = i; + break; + } + + p += len; + remaining -= len; + + if(direction==FORWARD) + index++; + else + index--; + index+=viewer.num_tracks; + index%=viewer.num_tracks; + } + pb->direction=direction; + pb->num_loaded = i; +} + +void playlist_buffer_load_entries_screen(struct playlist_buffer * pb, + enum direction direction) +{ + if(direction==FORWARD) + { + int min_start=viewer.selected_track-2*screens[0].nb_lines; + if(min_start<0) + min_start=0; + playlist_buffer_load_entries(pb, min_start, FORWARD); + } + else + { + int max_start=viewer.selected_track+2*screens[0].nb_lines; + max_start%=viewer.num_tracks; + playlist_buffer_load_entries(pb, max_start, BACKWARD); + } +} + +int playlist_entry_load(struct playlist_entry *entry, int index, + char* name_buffer, int remaining_size) +{ + struct playlist_track_info info; + int len; + + /* Playlist viewer orders songs based on display index. We need to + convert to real playlist index to access track */ + index = (index + playlist_get_first_index(viewer.playlist)) % + viewer.num_tracks; + if (playlist_get_track_info(viewer.playlist, index, &info) < 0) + return -1; + + len = strlen(info.filename) + 1; + + if (len <= remaining_size) + { + strcpy(name_buffer, info.filename); + + entry->name = name_buffer; + entry->index = info.index; + entry->display_index = info.display_index; + entry->queued = info.attr & PLAYLIST_ATTR_QUEUED; + entry->skipped = info.attr & PLAYLIST_ATTR_SKIPPED; + return len; + } + return -1; +} + +int playlist_buffer_get_index(struct playlist_buffer * pb, int index ) +{ + int buffer_index; + if(pb->direction==FORWARD) + { + if(index>=pb->first_index) + buffer_index=index-pb->first_index; + else /* rotation : track0 in buffer + requested track */ + buffer_index=(viewer.num_tracks-pb->first_index)+(index); + } + else + { + if(index<=pb->first_index) + buffer_index=pb->first_index-index; + else /* rotation : track0 in buffer + dist from the last track + to the requested track (num_tracks-requested track) */ + buffer_index=(pb->first_index)+(viewer.num_tracks-index); + } + return(buffer_index); +} + +#define distance(a, b) \ + a>b? (a) - (b) : (b) - (a) +bool playlist_buffer_needs_reload(struct playlist_buffer * pb, int track_index) +{ + if(pb->num_loaded==viewer.num_tracks) + return(false); + int selected_index=playlist_buffer_get_index(pb, track_index); + int first_buffer_index=playlist_buffer_get_index(pb, pb->first_index); + int distance_beginning=distance(selected_index, first_buffer_index); + if(distance_beginningnum_loaded - distance_beginning < MIN_BUFFER_MARGIN) + return(true); + return(false); +} + +struct playlist_entry * playlist_buffer_get_track(struct playlist_buffer * pb, + int index) +{ + int buffer_index=playlist_buffer_get_index(pb, index); + return(&(pb->tracks[buffer_index])); +} + /* Initialize the playlist viewer. */ -static bool initialize(char* filename, bool reload) +static bool playlist_viewer_init(struct playlist_viewer * viewer, + char* filename, bool reload) { char* buffer; int buffer_size; @@ -155,15 +284,15 @@ static bool initialize(char* filename, bool reload) return false; if (!filename) - viewer.playlist = NULL; + viewer->playlist = NULL; else { /* Viewing playlist on disk */ char *dir, *file, *temp_ptr; char *index_buffer = NULL; int index_buffer_size = 0; - - viewer.playlist = &temp_playlist; + + viewer->playlist = &temp_playlist; /* Separate directory from filename */ temp_ptr = strrchr(filename+1,'/'); @@ -187,7 +316,7 @@ static bool initialize(char* filename, bool reload) index_buffer = buffer; } - playlist_create_ex(viewer.playlist, dir, file, index_buffer, + playlist_create_ex(viewer->playlist, dir, file, index_buffer, index_buffer_size, buffer+index_buffer_size, buffer_size-index_buffer_size); @@ -197,201 +326,18 @@ static bool initialize(char* filename, bool reload) buffer += index_buffer_size; buffer_size -= index_buffer_size; } + playlist_buffer_init(&viewer->buffer, buffer, buffer_size ); - viewer.name_buffer = buffer; - viewer.buffer_size = buffer_size; - -#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.move_track = -1; + viewer->move_track = -1; if (!reload) - { - viewer.cursor_pos = 0; - - if (!viewer.playlist) - /* Start displaying at current playing track */ - viewer.first_display_index = playlist_get_display_index() - 1; - else - viewer.first_display_index = 0; - - update_first_index(); - } + viewer->selected_track = 0; 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-1; - - 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_mono_bitmap(bitmap_icons_6x8[Icon_Audio], - CURSOR_X * 6 + CURSOR_WIDTH, - MARGIN_Y+(i*viewer.line_height) + offset, 6, 8); -#else - lcd_putc(LINE_X-1, i, Icon_Audio); -#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]; - - format_line(&tracks[INDEX(line)], str, sizeof(str)); - - 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_ex(viewer.playlist); - - 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) { @@ -647,32 +394,18 @@ static bool update_playlist(bool force) playlist_get_resume_info(&viewer.current_playing_track); else viewer.current_playing_track = -1; - - if (force || playlist_amount_ex(viewer.playlist) != viewer.num_tracks) + int nb_tracks=playlist_amount_ex(viewer.playlist); + force=force || nb_tracks != viewer.num_tracks; + if (force) { - int index; - /* Reload tracks */ - viewer.num_tracks = playlist_amount_ex(viewer.playlist); + viewer.num_tracks = nb_tracks; if (viewer.num_tracks < 0) return false; - - index = viewer.first_display_index; - - load_playlist_entries(index); - - if (viewer.num_loaded <= 0) + playlist_buffer_load_entries_screen(&viewer.buffer, FORWARD); + if (viewer.buffer.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; } @@ -683,7 +416,9 @@ static int onplay_menu(int index) { struct menu_item items[3]; /* increase this if you add entries! */ int m, i=0, result, ret = 0; - bool current = (tracks[index].index == viewer.current_playing_track); + struct playlist_entry * current_track= + playlist_buffer_get_track(&viewer.buffer, index); + bool current = (current_track->index == viewer.current_playing_track); items[i].desc = ID2P(LANG_REMOVE); i++; @@ -707,13 +442,14 @@ static int onplay_menu(int index) { case 0: /* delete track */ - playlist_delete(viewer.playlist, tracks[index].index); - + playlist_delete(viewer.playlist, current_track->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 || + current_track= + playlist_buffer_get_track(&viewer.buffer, index); + if (current_track->display_index != viewer.num_tracks || global_settings.repeat_mode == REPEAT_ALL) { talk_buffer_steal(); /* will use the mp3 buffer */ @@ -721,30 +457,26 @@ static int onplay_menu(int index) viewer.current_playing_track = -1; } } - ret = 1; break; case 1: /* move track */ - viewer.move_track = tracks[index].index; + viewer.move_track = current_track->index; ret = 0; break; case 2: { - onplay(tracks[index].name, TREE_ATTR_MPA, CONTEXT_TREE); + onplay(current_track->name, TREE_ATTR_MPA, CONTEXT_TREE); if (!viewer.playlist) ret = 1; else ret = 0; - break; } } } - menu_exit(m); - return ret; } @@ -792,7 +524,7 @@ static bool track_display(void) { STR(LANG_DISPLAY_TRACK_NAME_ONLY) }, { STR(LANG_DISPLAY_FULL_PATH) } }; - + return set_option(str(LANG_TRACK_DISPLAY), &global_settings.playlist_viewer_track_display, INT, names, 2, NULL); } @@ -807,7 +539,6 @@ static bool save_playlist(void) if (!kbd_input(filename, sizeof(filename))) { playlist_save(viewer.playlist, filename); - /* reload in case playlist was saved to cwd */ reload_directory(); } @@ -821,63 +552,89 @@ bool playlist_viewer(void) return playlist_viewer_ex(NULL); } + + + +char * playlist_callback_name(int selected_item, void * data, char *buffer) +{ + struct playlist_viewer * local_viewer = (struct playlist_viewer *)data; + struct playlist_entry *track= + playlist_buffer_get_track(&(local_viewer->buffer), selected_item); + format_line(track, buffer, MAX_PATH); + return(buffer); +} + + +void playlist_callback_icons(int selected_item, void * data, ICON * icon) +{ + struct playlist_viewer * local_viewer=(struct playlist_viewer *)data; + struct playlist_entry *track= + playlist_buffer_get_track(&(local_viewer->buffer), selected_item); + if (track->index == local_viewer->current_playing_track) + { + /* Current playing track */ +#ifdef HAVE_LCD_BITMAP + *icon=bitmap_icons_6x8[Icon_Audio]; +#else + *icon=Icon_Audio; +#endif + } + else if (track->index == local_viewer->move_track) + { + /* Track we are moving */ +#ifdef HAVE_LCD_BITMAP + *icon=bitmap_icons_6x8[Icon_Moving]; +#else + *icon=Icon_Moving; +#endif + } + else if (track->queued) + { + /* Queued track */ +#ifdef HAVE_LCD_BITMAP + *icon=bitmap_icons_6x8[Icon_Queued]; +#else + *icon=Icon_Queued; +#endif + } + else + *icon=0; +} + + + /* Main viewer function. Filename identifies playlist to be viewed. If NULL, view current playlist. */ bool playlist_viewer_ex(char* filename) { bool ret = false; /* return value */ 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, lastbutton = BUTTON_NONE; - - if (!initialize(filename, false)) + struct gui_synclist playlist_lists; + if (!playlist_viewer_init(&viewer, filename, false)) goto exit; - old_cursor_pos = viewer.cursor_pos; - + gui_synclist_init(&playlist_lists, playlist_callback_icons, + playlist_callback_name, &viewer); + gui_synclist_set_nb_items(&playlist_lists, viewer.num_tracks); + gui_synclist_select_item(&playlist_lists, viewer.selected_track); + gui_synclist_draw(&playlist_lists); while (!exit) { int track; - if (!viewer.playlist && !(audio_status() & AUDIO_STATUS_PLAY)) { /* Play has stopped */ #ifdef HAVE_LCD_CHARCELLS - splash(HZ, true, str(LANG_END_PLAYLIST_PLAYER)); + gui_syncsplash(HZ, true, str(LANG_END_PLAYLIST_PLAYER)); #else - splash(HZ, true, str(LANG_END_PLAYLIST_RECORDER)); + gui_syncsplash(HZ, true, str(LANG_END_PLAYLIST_RECORDER)); #endif goto exit; } - 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_set_drawmode(DRMODE_COMPLEMENT); - lcd_fillrect( - MARGIN_X, MARGIN_Y+(viewer.cursor_pos*viewer.line_height), - LCD_WIDTH, viewer.line_height); - lcd_set_drawmode(DRMODE_SOLID); - 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 - } + if (viewer.move_track != -1) + gui_synclist_flash(&playlist_lists); if (!viewer.playlist) playlist_get_resume_info(&track); @@ -888,19 +645,27 @@ bool playlist_viewer_ex(char* filename) playlist_amount_ex(viewer.playlist) != viewer.num_tracks) { /* Playlist has changed (new track started?) */ - update_first_index(); if (!update_playlist(false)) goto exit; - else - update = true; - + gui_synclist_set_nb_items(&playlist_lists, viewer.num_tracks); /* Abort move on playlist change */ viewer.move_track = -1; } /* Timeout so we can determine if play status has changed */ button = button_get_w_tmo(HZ/2); - + int list_action; + if( (list_action=gui_synclist_do_button(&playlist_lists, button))!=0 ) + { + viewer.selected_track=gui_synclist_get_sel_pos(&playlist_lists); + if(playlist_buffer_needs_reload(&viewer.buffer, viewer.selected_track)) + playlist_buffer_load_entries_screen(&viewer.buffer, + list_action==LIST_NEXT? + FORWARD + : + BACKWARD + ); + } switch (button) { case TREE_EXIT: @@ -910,48 +675,20 @@ bool playlist_viewer_ex(char* filename) exit = true; break; - case TREE_PREV: - case TREE_PREV | BUTTON_REPEAT: - scroll_display(-1); - update = true; - break; - - case TREE_NEXT: - case TREE_NEXT | BUTTON_REPEAT: - scroll_display(1); - update = true; - break; - -#ifdef TREE_PGUP - case TREE_PGUP: - case TREE_PGUP | BUTTON_REPEAT: - /* Pageup */ - scroll_display(-viewer.num_display_lines); - update = true; - break; - - case TREE_PGDN: - case TREE_PGDN | BUTTON_REPEAT: - /* Pagedown */ - scroll_display(viewer.num_display_lines); - update = true; - break; -#endif - case TREE_RUN: #ifdef TREE_RUN_PRE if (lastbutton != TREE_RUN_PRE) break; #endif + struct playlist_entry * current_track=playlist_buffer_get_track(&viewer.buffer, viewer.selected_track); if (viewer.move_track >= 0) { /* Move track */ int ret; - ret = playlist_move(viewer.playlist, viewer.move_track, - tracks[INDEX(viewer.cursor_pos)].index); + ret = playlist_move(viewer.playlist, viewer.move_track, current_track->index); if (ret < 0) - splash(HZ, true, str(LANG_MOVE_FAILED)); + gui_syncsplash(HZ, true, str(LANG_MOVE_FAILED)); update_playlist(true); viewer.move_track = -1; @@ -959,7 +696,7 @@ bool playlist_viewer_ex(char* filename) else if (!viewer.playlist) { /* play new track */ - playlist_start(tracks[INDEX(viewer.cursor_pos)].index, 0); + playlist_start(current_track->index, 0); update_playlist(false); } else @@ -968,15 +705,14 @@ bool playlist_viewer_ex(char* filename) if (playlist_set_current(viewer.playlist) < 0) goto exit; - playlist_start(tracks[INDEX(viewer.cursor_pos)].index, 0); + playlist_start(current_track->index, 0); /* Our playlist is now the current list */ - if (!initialize(NULL, true)) + if (!playlist_viewer_init(&viewer, NULL, true)) goto exit; } + gui_synclist_draw(&playlist_lists); - display_playlist(); - update = true; break; case TREE_CONTEXT: @@ -987,7 +723,7 @@ bool playlist_viewer_ex(char* filename) /* ON+PLAY menu */ int ret; - ret = onplay_menu(INDEX(viewer.cursor_pos)); + ret = onplay_menu(viewer.selected_track); if (ret < 0) { @@ -997,15 +733,12 @@ bool playlist_viewer_ex(char* filename) else if (ret > 0) { /* Playlist changed */ - update_first_index(); - update_playlist(false); + gui_synclist_del_item(&playlist_lists); + update_playlist(true); if (viewer.num_tracks <= 0) exit = true; } - else - display_playlist(); - - update = true; + gui_synclist_draw(&playlist_lists); break; } @@ -1015,13 +748,11 @@ bool playlist_viewer_ex(char* filename) ret = true; goto exit; } - - display_playlist(); - update = true; + gui_synclist_draw(&playlist_lists); break; case BUTTON_NONE: - status_draw(false); + gui_syncstatusbar_draw(&statusbars, false); break; default: @@ -1032,36 +763,6 @@ bool playlist_viewer_ex(char* filename) } break; } - - 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; - } lastbutton = button; } diff --git a/apps/recorder/icons.c b/apps/recorder/icons.c index 148235f040..66ac3cb727 100644 --- a/apps/recorder/icons.c +++ b/apps/recorder/icons.c @@ -47,6 +47,8 @@ const unsigned char bitmap_icons_6x8[LastIcon][6] = { 0x4e, 0x51, 0x51, 0x40, 0x55, 0x55 }, /* Config file */ { 0x0a, 0x0a, 0x5f, 0x4e, 0x24, 0x18 }, /* Plugin file */ { 0xff, 0x81, 0xaf, 0xaa, 0x8c, 0xf8 }, /* Bookmark file */ + { 0x77, 0x55, 0x55, 0x55, 0x55, 0x77 }, /* Queued Item */ + { 0x3e, 0x41, 0x3e, 0x1c, 0x1c, 0x08 }, /* Moving Item */ }; const unsigned char bitmap_icons_7x8[][7] = diff --git a/apps/recorder/icons.h b/apps/recorder/icons.h index c8241b4871..52234731b0 100644 --- a/apps/recorder/icons.h +++ b/apps/recorder/icons.h @@ -44,6 +44,8 @@ enum icons_6x8 { Icon_Config, Icon_Plugin, Icon_Bookmark, + Icon_Queued, + Icon_Moving, LastIcon }; diff --git a/apps/screen_access.c b/apps/screen_access.c index 1d2535fb66..dfaba4d0f2 100644 --- a/apps/screen_access.c +++ b/apps/screen_access.c @@ -150,13 +150,6 @@ void screen_init(struct screen * screen, enum screen_type screen_type) gui_textarea_update_nblines(screen); } -void screen_access_init(void) -{ - int i; - FOR_NB_SCREENS(i) - screen_init(&screens[i], i); -} - #ifdef HAVE_LCD_BITMAP void screen_clear_area(struct screen * display, int xstart, int ystart, int width, int height) @@ -166,3 +159,10 @@ void screen_clear_area(struct screen * display, int xstart, int ystart, display->set_drawmode(DRMODE_SOLID); } #endif + +void screen_access_init(void) +{ + int i; + FOR_NB_SCREENS(i) + screen_init(&screens[i], i); +}