summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Ferrare <kevin@rockbox.org>2005-11-16 02:12:25 +0000
committerKevin Ferrare <kevin@rockbox.org>2005-11-16 02:12:25 +0000
commit8517ed8939b7323be8371cd902544154ade984b9 (patch)
tree230698c2817e2d6b8dd7862295deeb2aa2b72b9f
parent5d8c1529a735254d2cc17e47d294b8835ba575b0 (diff)
downloadrockbox-8517ed8939b7323be8371cd902544154ade984b9.tar.gz
rockbox-8517ed8939b7323be8371cd902544154ade984b9.zip
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
-rw-r--r--apps/gui/icon.c20
-rw-r--r--apps/gui/icon.h8
-rw-r--r--apps/gui/list.c46
-rw-r--r--apps/gui/list.h64
-rw-r--r--apps/gui/scrollbar.c6
-rw-r--r--apps/gui/scrollbar.h5
-rw-r--r--apps/player/icons.h2
-rw-r--r--apps/playlist_viewer.c929
-rw-r--r--apps/recorder/icons.c2
-rw-r--r--apps/recorder/icons.h2
-rw-r--r--apps/screen_access.c14
11 files changed, 408 insertions, 690 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 @@
26void screen_put_iconxy(struct screen * display, int x, int y, ICON icon) 26void screen_put_iconxy(struct screen * display, int x, int y, ICON icon)
27{ 27{
28#ifdef HAVE_LCD_BITMAP 28#ifdef HAVE_LCD_BITMAP
29 if(icon==0)/* Don't display invalid icons */
30 return;
31 int xpos, ypos; 29 int xpos, ypos;
32 xpos = x*CURSOR_WIDTH; 30 xpos = x*CURSOR_WIDTH;
33 ypos = y*display->char_height + display->getymargin(); 31 ypos = y*display->char_height + display->getymargin();
32
34 if ( display->char_height > CURSOR_HEIGHT )/* center the cursor */ 33 if ( display->char_height > CURSOR_HEIGHT )/* center the cursor */
35 ypos += (display->char_height - CURSOR_HEIGHT) / 2; 34 ypos += (display->char_height - CURSOR_HEIGHT) / 2;
36 display->mono_bitmap(icon, xpos, ypos, CURSOR_WIDTH, CURSOR_HEIGHT); 35 if(icon==0)/* Don't display invalid icons */
36 screen_clear_area(display, xpos, ypos, CURSOR_WIDTH, CURSOR_HEIGHT);
37 else
38 display->mono_bitmap(icon, xpos, ypos, CURSOR_WIDTH, CURSOR_HEIGHT);
37#else 39#else
38 display->putc(x, y, icon); 40 if(icon==-1)
41 display->putc(x, y, ' ');
42 else
43 display->putc(x, y, icon);
39#endif 44#endif
40} 45}
41 46
42void screen_put_cursorxy(struct screen * display, int x, int y) 47void screen_put_cursorxy(struct screen * display, int x, int y, bool on)
43{ 48{
44#ifdef HAVE_LCD_BITMAP 49#ifdef HAVE_LCD_BITMAP
45 screen_put_iconxy(display, x, y, bitmap_icons_6x8[Icon_Cursor]); 50 screen_put_iconxy(display, x, y, on?bitmap_icons_6x8[Icon_Cursor]:0);
46#else 51#else
47 screen_put_iconxy(display, x, y, CURSOR_CHAR); 52 screen_put_iconxy(display, x, y, on?CURSOR_CHAR:-1);
48#endif 53#endif
54
49} 55}
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 @@
31#define CURSOR_CHAR 0x92 31#define CURSOR_CHAR 0x92
32#define CURSOR_WIDTH 6 32#define CURSOR_WIDTH 6
33#define CURSOR_HEIGHT 8 33#define CURSOR_HEIGHT 8
34
34/* 35/*
35 * Draws a cursor at a given position 36 * Draws a cursor at a given position, if th
36 * - screen : the screen where we put the cursor 37 * - screen : the screen where we put the cursor
37 * - x, y : the position, in character, not in pixel !! 38 * - x, y : the position, in character, not in pixel !!
39 * - on : true if the cursor must be shown, false if it must be erased
38 */ 40 */
39extern void screen_put_cursorxy(struct screen * screen, int x, int y); 41extern void screen_put_cursorxy(struct screen * screen, int x, int y, bool on);
40 42
41/* 43/*
42 * Put an icon on a screen at a given position 44 * Put an icon on a screen at a given position
43 * (the position is given in characters) 45 * (the position is given in characters)
46 * If the given icon is null (HAVE_LCD_BITMAP) or -1 otherwise, the icon
47 * at the given position will be erased
44 * - screen : the screen where we put our icon 48 * - screen : the screen where we put our icon
45 * - x, y : the position, in character, not in pixel !! 49 * - x, y : the position, in character, not in pixel !!
46 * - icon : the icon to put 50 * - 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 @@
40 40
41 41
42void gui_list_init(struct gui_list * gui_list, 42void gui_list_init(struct gui_list * gui_list,
43 void (*callback_get_item_icon) 43 list_get_icon callback_get_item_icon,
44 (int selected_item, void * data, ICON * icon), 44 list_get_name callback_get_item_name,
45 char * (*callback_get_item_name)
46 (int selected_item, void * data, char *buffer),
47 void * data 45 void * data
48 ) 46 )
49{ 47{
@@ -75,11 +73,10 @@ void gui_list_flash(struct gui_list * gui_list)
75 gui_list->cursor_flash_state=!gui_list->cursor_flash_state; 73 gui_list->cursor_flash_state=!gui_list->cursor_flash_state;
76 int selected_line=gui_list->selected_item-gui_list->start_item; 74 int selected_line=gui_list->selected_item-gui_list->start_item;
77#ifdef HAVE_LCD_BITMAP 75#ifdef HAVE_LCD_BITMAP
78 int cursor_xpos=global_settings.scrollbar?1:0;
79 int line_xpos=display->getxmargin();
80 int line_ypos=display->getymargin()+display->char_height*selected_line; 76 int line_ypos=display->getymargin()+display->char_height*selected_line;
81 if (global_settings.invert_cursor) 77 if (global_settings.invert_cursor)
82 { 78 {
79 int line_xpos=display->getxmargin();
83 display->set_drawmode(DRMODE_COMPLEMENT); 80 display->set_drawmode(DRMODE_COMPLEMENT);
84 display->fillrect(line_xpos, line_ypos, display->width, 81 display->fillrect(line_xpos, line_ypos, display->width,
85 display->char_height); 82 display->char_height);
@@ -88,19 +85,14 @@ void gui_list_flash(struct gui_list * gui_list)
88 } 85 }
89 else 86 else
90 { 87 {
91 if(gui_list->cursor_flash_state) 88 int cursor_xpos=(global_settings.scrollbar &&
92 screen_clear_area(display, cursor_xpos*SCROLLBAR_WIDTH, line_ypos, 89 display->nb_lines < gui_list->nb_items)?1:0;
93 CURSOR_WIDTH, CURSOR_HEIGHT); 90 screen_put_cursorxy(display, cursor_xpos, selected_line, gui_list->cursor_flash_state);
94 else
95 screen_put_cursorxy(display, cursor_xpos, selected_line);
96 } 91 }
97 display->update_rect(0, line_ypos,display->width, 92 display->update_rect(0, line_ypos,display->width,
98 display->char_height); 93 display->char_height);
99#else 94#else
100 if(gui_list->cursor_flash_state) 95 screen_put_cursorxy(display, 0, selected_line, gui_list->cursor_flash_state);
101 display->putc(0, selected_line, ' ');
102 else
103 screen_put_cursorxy(display, 0, selected_line);
104 gui_textarea_update(display); 96 gui_textarea_update(display);
105#endif 97#endif
106} 98}
@@ -199,7 +191,7 @@ void gui_list_draw(struct gui_list * gui_list)
199#endif 191#endif
200 192
201 if(draw_cursor) 193 if(draw_cursor)
202 screen_put_cursorxy(display, cursor_pos, i); 194 screen_put_cursorxy(display, cursor_pos, i, true);
203 } 195 }
204 else 196 else
205 {/* normal item */ 197 {/* normal item */
@@ -371,10 +363,8 @@ void gui_list_del_item(struct gui_list * gui_list)
371 */ 363 */
372void gui_synclist_init( 364void gui_synclist_init(
373 struct gui_synclist * lists, 365 struct gui_synclist * lists,
374 void (*callback_get_item_icon) 366 list_get_icon callback_get_item_icon,
375 (int selected_item, void * data, ICON * icon), 367 list_get_name callback_get_item_name,
376 char * (*callback_get_item_name)
377 (int selected_item, void * data, char *buffer),
378 void * data 368 void * data
379 ) 369 )
380{ 370{
@@ -472,7 +462,7 @@ void gui_synclist_flash(struct gui_synclist * lists)
472 gui_list_flash(&(lists->gui_list[i])); 462 gui_list_flash(&(lists->gui_list[i]));
473} 463}
474 464
475bool gui_synclist_do_button(struct gui_synclist * lists, unsigned button) 465unsigned gui_synclist_do_button(struct gui_synclist * lists, unsigned button)
476{ 466{
477 gui_synclist_limit_scroll(lists, true); 467 gui_synclist_limit_scroll(lists, true);
478 switch(button) 468 switch(button)
@@ -489,7 +479,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists, unsigned button)
489#endif 479#endif
490 gui_synclist_select_previous(lists); 480 gui_synclist_select_previous(lists);
491 gui_synclist_draw(lists); 481 gui_synclist_draw(lists);
492 return true; 482 return LIST_PREV;
493 483
494 case LIST_NEXT: 484 case LIST_NEXT:
495#ifdef LIST_RC_NEXT 485#ifdef LIST_RC_NEXT
@@ -504,7 +494,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists, unsigned button)
504#endif 494#endif
505 gui_synclist_select_next(lists); 495 gui_synclist_select_next(lists);
506 gui_synclist_draw(lists); 496 gui_synclist_draw(lists);
507 return true; 497 return LIST_NEXT;
508/* for pgup / pgdown, we are obliged to have a different behaviour depending on the screen 498/* for pgup / pgdown, we are obliged to have a different behaviour depending on the screen
509 * for which the user pressed the key since for example, remote and main screen doesn't 499 * for which the user pressed the key since for example, remote and main screen doesn't
510 * have the same number of lines*/ 500 * have the same number of lines*/
@@ -514,7 +504,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists, unsigned button)
514 case LIST_PGUP | BUTTON_REPEAT: 504 case LIST_PGUP | BUTTON_REPEAT:
515 gui_synclist_select_previous_page(lists, SCREEN_MAIN); 505 gui_synclist_select_previous_page(lists, SCREEN_MAIN);
516 gui_synclist_draw(lists); 506 gui_synclist_draw(lists);
517 return true; 507 return LIST_NEXT;
518#endif 508#endif
519 509
520#ifdef LIST_RC_PGUP 510#ifdef LIST_RC_PGUP
@@ -523,7 +513,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists, unsigned button)
523 case LIST_RC_PGUP | BUTTON_REPEAT: 513 case LIST_RC_PGUP | BUTTON_REPEAT:
524 gui_synclist_select_previous_page(lists, SCREEN_REMOTE); 514 gui_synclist_select_previous_page(lists, SCREEN_REMOTE);
525 gui_synclist_draw(lists); 515 gui_synclist_draw(lists);
526 return true; 516 return LIST_NEXT;
527#endif 517#endif
528 518
529#ifdef LIST_PGDN 519#ifdef LIST_PGDN
@@ -532,7 +522,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists, unsigned button)
532 case LIST_PGDN | BUTTON_REPEAT: 522 case LIST_PGDN | BUTTON_REPEAT:
533 gui_synclist_select_next_page(lists, SCREEN_MAIN); 523 gui_synclist_select_next_page(lists, SCREEN_MAIN);
534 gui_synclist_draw(lists); 524 gui_synclist_draw(lists);
535 return true; 525 return LIST_PREV;
536#endif 526#endif
537 527
538#ifdef LIST_RC_PGDN 528#ifdef LIST_RC_PGDN
@@ -541,8 +531,8 @@ bool gui_synclist_do_button(struct gui_synclist * lists, unsigned button)
541 case LIST_RC_PGDN | BUTTON_REPEAT: 531 case LIST_RC_PGDN | BUTTON_REPEAT:
542 gui_synclist_select_next_page(lists, SCREEN_REMOTE); 532 gui_synclist_select_next_page(lists, SCREEN_REMOTE);
543 gui_synclist_draw(lists); 533 gui_synclist_draw(lists);
544 return true; 534 return LIST_PREV;
545#endif 535#endif
546 } 536 }
547 return false; 537 return 0;
548} 538}
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 @@
33#define LIST_PREV BUTTON_UP 33#define LIST_PREV BUTTON_UP
34#define LIST_PGUP (BUTTON_ON | BUTTON_UP) 34#define LIST_PGUP (BUTTON_ON | BUTTON_UP)
35#define LIST_PGDN (BUTTON_ON | BUTTON_DOWN) 35#define LIST_PGDN (BUTTON_ON | BUTTON_DOWN)
36
37#ifdef CONFIG_REMOTE_KEYPAD
36#define LIST_RC_NEXT BUTTON_RC_FF 38#define LIST_RC_NEXT BUTTON_RC_FF
37#define LIST_RC_PREV BUTTON_RC_REW 39#define LIST_RC_PREV BUTTON_RC_REW
38#define LIST_RC_PGUP BUTTON_RC_SOURCE 40#define LIST_RC_PGUP BUTTON_RC_SOURCE
39#define LIST_RC_PGDN BUTTON_RC_BITRATE 41#define LIST_RC_PGDN BUTTON_RC_BITRATE
42#endif /* CONFIG_REMOTE_KEYPAD */
40 43
41#elif CONFIG_KEYPAD == RECORDER_PAD 44#elif CONFIG_KEYPAD == RECORDER_PAD
42#define LIST_NEXT BUTTON_DOWN 45#define LIST_NEXT BUTTON_DOWN
43#define LIST_PREV BUTTON_UP 46#define LIST_PREV BUTTON_UP
44#define LIST_PGUP (BUTTON_ON | BUTTON_UP) 47#define LIST_PGUP (BUTTON_ON | BUTTON_UP)
45#define LIST_PGDN (BUTTON_ON | BUTTON_DOWN) 48#define LIST_PGDN (BUTTON_ON | BUTTON_DOWN)
49
50#ifdef CONFIG_REMOTE_KEYPAD
46#define LIST_RC_NEXT BUTTON_RC_RIGHT 51#define LIST_RC_NEXT BUTTON_RC_RIGHT
47#define LIST_RC_PREV BUTTON_RC_LEFT 52#define LIST_RC_PREV BUTTON_RC_LEFT
53#endif /* CONFIG_REMOTE_KEYPAD */
48 54
49#elif CONFIG_KEYPAD == PLAYER_PAD 55#elif CONFIG_KEYPAD == PLAYER_PAD
50#define LIST_NEXT BUTTON_RIGHT 56#define LIST_NEXT BUTTON_RIGHT
51#define LIST_PREV BUTTON_LEFT 57#define LIST_PREV BUTTON_LEFT
58
59#ifdef CONFIG_REMOTE_KEYPAD
52#define LIST_RC_NEXT BUTTON_RC_RIGHT 60#define LIST_RC_NEXT BUTTON_RC_RIGHT
53#define LIST_RC_PREV BUTTON_RC_LEFT 61#define LIST_RC_PREV BUTTON_RC_LEFT
62#endif /* CONFIG_REMOTE_KEYPAD */
54 63
55#elif CONFIG_KEYPAD == ONDIO_PAD 64#elif CONFIG_KEYPAD == ONDIO_PAD
56#define LIST_NEXT BUTTON_DOWN 65#define LIST_NEXT BUTTON_DOWN
@@ -73,8 +82,21 @@
73 * tells it what to display. 82 * tells it what to display.
74 * There are two callback function : 83 * There are two callback function :
75 * one to get the text and one to get the icon 84 * one to get the text and one to get the icon
76 * Callback interface : 85 */
77 * 86
87/*
88 * Icon callback
89 * - selected_item : an integer that tells the number of the item to display
90 * - data : a void pointer to the data you gave to the list when
91 * you initialized it
92 * - icon : a pointer to the icon, the value inside it is used to display
93 * the icon after the function returns.
94 * Note : we use the ICON type because the real type depends of the plateform
95 */
96typedef void list_get_icon(int selected_item,
97 void * data,
98 ICON * icon);
99/*
78 * Text callback 100 * Text callback
79 * - selected_item : an integer that tells the number of the item to display 101 * - selected_item : an integer that tells the number of the item to display
80 * - data : a void pointer to the data you gave to the list when 102 * - data : a void pointer to the data you gave to the list when
@@ -84,15 +106,11 @@
84 * the return value of the function in all cases to avoid filling 106 * the return value of the function in all cases to avoid filling
85 * a buffer when it's not necessary) 107 * a buffer when it's not necessary)
86 * Returns a pointer to a string that contains the text to display 108 * Returns a pointer to a string that contains the text to display
87 *
88 * Icon callback
89 * - selected_item : an integer that tells the number of the item to display
90 * - data : a void pointer to the data you gave to the list when
91 * you initialized it
92 * - icon : a pointer to the icon, the value inside it is used to display
93 * the icon after the function returns.
94 * Note : we use the ICON type because the real type depends of the plateform
95 */ 109 */
110typedef char * list_get_name(int selected_item,
111 void * data,
112 char *buffer);
113
96struct gui_list 114struct gui_list
97{ 115{
98 int nb_items; 116 int nb_items;
@@ -100,13 +118,10 @@ struct gui_list
100 bool cursor_flash_state; 118 bool cursor_flash_state;
101 int start_item; /* the item that is displayed at the top of the screen */ 119 int start_item; /* the item that is displayed at the top of the screen */
102 120
103 void (*callback_get_item_icon) 121 list_get_icon *callback_get_item_icon;
104 (int selected_item, void * data, ICON * icon); 122 list_get_name *callback_get_item_name;
105 char * (*callback_get_item_name)
106 (int selected_item, void * data, char *buffer);
107 123
108 struct screen * display; 124 struct screen * display;
109 int line_scroll_limit;
110 /* defines wether the list should stop when reaching the top/bottom 125 /* defines wether the list should stop when reaching the top/bottom
111 * or should continue (by going to bottom/top) */ 126 * or should continue (by going to bottom/top) */
112 bool limit_scroll; 127 bool limit_scroll;
@@ -123,10 +138,8 @@ struct gui_list
123 * to a given item number 138 * to a given item number
124 */ 139 */
125extern void gui_list_init(struct gui_list * gui_list, 140extern void gui_list_init(struct gui_list * gui_list,
126 void (*callback_get_item_icon) 141 list_get_icon callback_get_item_icon,
127 (int selected_item, void * data, ICON * icon), 142 list_get_name callback_get_item_name,
128 char * (*callback_get_item_name)
129 (int selected_item, void * data, char *buffer),
130 void * data 143 void * data
131 ); 144 );
132 145
@@ -264,10 +277,8 @@ struct gui_synclist
264 277
265extern void gui_synclist_init( 278extern void gui_synclist_init(
266 struct gui_synclist * lists, 279 struct gui_synclist * lists,
267 void (*callback_get_item_icon) 280 list_get_icon callback_get_item_icon,
268 (int selected_item, void * data, ICON * icon), 281 list_get_name callback_get_item_name,
269 char * (*callback_get_item_name)
270 (int selected_item, void * data, char *buffer),
271 void * data 282 void * data
272 ); 283 );
273extern void gui_synclist_set_nb_items(struct gui_synclist * lists, int nb_items); 284extern 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);
295 306
296/* 307/*
297 * Do the action implied by the given button, 308 * Do the action implied by the given button,
298 * returns true if something has been done, false otherwise 309 * returns the action taken if any, 0 else
299 * - lists : the synchronized lists 310 * - lists : the synchronized lists
300 * - button : the keycode of a pressed button 311 * - button : the keycode of a pressed button
312 * returned value :
313 * - LIST_NEXT when moving forward (next item or pgup)
314 * - LIST_PREV when moving backward (previous item or pgdown)
301 */ 315 */
302extern bool gui_synclist_do_button(struct gui_synclist * lists, unsigned button); 316extern unsigned gui_synclist_do_button(struct gui_synclist * lists, unsigned button);
303 317
304#endif /* _GUI_LIST_H_ */ 318#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 @@
17 * 17 *
18 ****************************************************************************/ 18 ****************************************************************************/
19 19
20#include "config.h" 20#include "scrollbar.h"
21#include "lcd.h"
22#ifdef HAVE_LCD_BITMAP 21#ifdef HAVE_LCD_BITMAP
22#include "config.h"
23#include "limits.h" 23#include "limits.h"
24#include "scrollbar.h"
25#include "screen_access.h"
26 24
27void gui_scrollbar_draw(struct screen * screen, int x, int y, 25void gui_scrollbar_draw(struct screen * screen, int x, int y,
28 int width, int height, int items, 26 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 @@
19 19
20#ifndef _GUI_SCROLLBAR_H_ 20#ifndef _GUI_SCROLLBAR_H_
21#define _GUI_SCROLLBAR_H_ 21#define _GUI_SCROLLBAR_H_
22#include <lcd.h> 22#include "screen_access.h"
23#ifdef HAVE_LCD_BITMAP
24 23
25struct screen; 24#ifdef HAVE_LCD_BITMAP
26 25
27enum orientation { 26enum orientation {
28 VERTICAL, 27 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 @@
28#ifdef HAVE_LCD_CHARCELLS 28#ifdef HAVE_LCD_CHARCELLS
29 29
30enum { 30enum {
31 Icon_Queued = 'Q',
32 Icon_Moving = 'M',
31 Icon_Unknown = 0x90, 33 Icon_Unknown = 0x90,
32 Icon_Bookmark = 0x16, 34 Icon_Bookmark = 0x16,
33 Icon_Plugin, 35 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 @@
17 * KIND, either express or implied. 17 * KIND, either express or implied.
18 * 18 *
19 ****************************************************************************/ 19 ****************************************************************************/
20 20/*
21 * Kevin Ferrare 2005/10/16
22 * multi-screen support, rewrote a lot of code
23 */
21#include <string.h> 24#include <string.h>
22#include <sprintf.h> 25#include <sprintf.h>
23#include "playlist.h" 26#include "playlist.h"
@@ -35,76 +38,24 @@
35#include "misc.h" 38#include "misc.h"
36#include "action.h" 39#include "action.h"
37 40
38#ifdef HAVE_LCD_BITMAP
39#include "widgets.h"
40#endif
41
42#include "lang.h" 41#include "lang.h"
43 42
44#include "playlist_viewer.h" 43#include "playlist_viewer.h"
45 44#include "icon.h"
46/* Defines for LCD display purposes. Taken from tree.c */ 45#include "list.h"
47#ifdef HAVE_LCD_BITMAP 46#include "statusbar.h"
48 #define CURSOR_X (global_settings.scrollbar && \ 47#include "splash.h"
49 viewer.num_tracks>viewer.num_display_lines?1:0)
50 #define CURSOR_Y 0
51 #define CURSOR_WIDTH (global_settings.invert_cursor ? 0 : 4)
52
53 #define ICON_WIDTH ((viewer.char_width > 6) ? viewer.char_width : 6)
54
55 #define MARGIN_X ((global_settings.scrollbar && \
56 viewer.num_tracks > viewer.num_display_lines ? \
57 SCROLLBAR_WIDTH : 0) + CURSOR_WIDTH + \
58 (global_settings.playlist_viewer_icons ? \
59 ICON_WIDTH : 0))
60 #define MARGIN_Y (global_settings.statusbar ? STATUSBAR_HEIGHT : 0)
61
62 #define LINE_X 0
63 #define LINE_Y (global_settings.statusbar ? 1 : 0)
64
65 #define SCROLLBAR_X 0
66 #define SCROLLBAR_Y lcd_getymargin()
67 #define SCROLLBAR_WIDTH 6
68#else
69 #define MARGIN_X 0
70 #define MARGIN_Y 0
71 #define LINE_X 2
72 #define LINE_Y 0
73 #define CURSOR_X 0
74 #define CURSOR_Y 0
75#endif
76 48
77/* Maximum number of tracks we can have loaded at one time */ 49/* Maximum number of tracks we can have loaded at one time */
78#define MAX_PLAYLIST_ENTRIES 200 50#define MAX_PLAYLIST_ENTRIES 40
51
52/* The number of items between the selected one and the end/start of
53 * the buffer under which the buffer must reload */
54#define MIN_BUFFER_MARGIN screens[0].nb_lines
79 55
80/* Default playlist name for saving */ 56/* Default playlist name for saving */
81#define DEFAULT_VIEWER_PLAYLIST_NAME "/viewer.m3u" 57#define DEFAULT_VIEWER_PLAYLIST_NAME "/viewer.m3u"
82 58
83/* Index of track on display line _pos */
84#define INDEX(_pos) (viewer.first_display_index - viewer.first_index + (_pos))
85
86/* Global playlist viewer settings */
87struct playlist_viewer_info {
88 struct playlist_info* playlist; /* playlist being viewed */
89 char *name_buffer; /* Buffer used to store track names */
90 int buffer_size; /* Size of name buffer */
91
92 int num_display_lines; /* Number of lines on lcd */
93 int line_height; /* Height (in pixels) of display line */
94 int char_width; /* Width (in pixels) of a character */
95
96 int num_tracks; /* Number of tracks in playlist */
97 int current_playing_track; /* Index of current playing track */
98
99 int num_loaded; /* Number of track entries loaded in viewer */
100 int first_index; /* Index of first loaded track */
101 int last_index; /* Index of last loaded track */
102 int first_display_index; /* Index of first track on display */
103 int last_display_index; /* Index of last track on display */
104 int cursor_pos; /* Line number of cursor */
105
106 int move_track; /* Playlist index of track to move or -1 */
107};
108 59
109/* Information about a specific track */ 60/* Information about a specific track */
110struct playlist_entry { 61struct playlist_entry {
@@ -115,22 +66,60 @@ struct playlist_entry {
115 bool skipped; /* Is track marked as bad? */ 66 bool skipped; /* Is track marked as bad? */
116}; 67};
117 68
118static struct playlist_viewer_info viewer; 69enum direction
119static struct playlist_entry tracks[MAX_PLAYLIST_ENTRIES]; 70{
71 FORWARD,
72 BACKWARD
73};
74
75struct playlist_buffer
76{
77 char *name_buffer; /* Buffer used to store track names */
78 int buffer_size; /* Size of name buffer */
79
80 int first_index; /* Real index of first track loaded inside
81 the buffer */
82
83 enum direction direction; /* Direction of the buffer (if the buffer
84 was loaded BACKWARD, the last track in
85 the buffer has a real index < to the
86 real index of the the first track)*/
87
88 struct playlist_entry tracks[MAX_PLAYLIST_ENTRIES];
89 int num_loaded; /* Number of track entries loaded in buffer */
90};
91
92/* Global playlist viewer settings */
93struct playlist_viewer {
94 struct playlist_info* playlist; /* playlist being viewed */
95 int num_tracks; /* Number of tracks in playlist */
96 int current_playing_track; /* Index of current playing track */
97 int selected_track; /* The selected track, relative (first is 0)*/
98 int move_track; /* Playlist index of track to move or -1 */
99 struct playlist_buffer buffer;
100};
101
102static struct playlist_viewer viewer;
120 103
121/* Used when viewing playlists on disk */ 104/* Used when viewing playlists on disk */
122static struct playlist_info temp_playlist; 105static struct playlist_info temp_playlist;
123 106
124static bool initialize(char* filename, bool reload); 107void playlist_buffer_init(struct playlist_buffer * pb, char * names_buffer,
125static void load_playlist_entries(int start_index); 108 int names_buffer_size);
126static void load_playlist_entries_r(int end_index); 109void playlist_buffer_load_entries(struct playlist_buffer * pb, int index,
127static int load_entry(int index, int pos, char* p, int size); 110 enum direction direction);
111int playlist_entry_load(struct playlist_entry *entry, int index,
112 char* name_buffer, int remaining_size);
113
114struct playlist_entry * playlist_buffer_get_track(struct playlist_buffer * pb,
115 int index);
116
117static bool playlist_viewer_init(struct playlist_viewer * viewer,
118 char* filename, bool reload);
119
128static void format_name(char* dest, const char* src); 120static void format_name(char* dest, const char* src);
129static void format_line(const struct playlist_entry* track, char* str, int len); 121static void format_line(const struct playlist_entry* track, char* str, int len);
130static void display_playlist(void); 122
131static void update_display_line(int line, bool scroll);
132static void scroll_display(int lines);
133static void update_first_index(void);
134static bool update_playlist(bool force); 123static bool update_playlist(bool force);
135static int onplay_menu(int index); 124static int onplay_menu(int index);
136static bool viewer_menu(void); 125static bool viewer_menu(void);
@@ -139,8 +128,148 @@ static bool show_indices(void);
139static bool track_display(void); 128static bool track_display(void);
140static bool save_playlist(void); 129static bool save_playlist(void);
141 130
131void playlist_buffer_init(struct playlist_buffer * pb, char * names_buffer,
132 int names_buffer_size)
133{
134 pb->name_buffer=names_buffer;
135 pb->buffer_size=names_buffer_size;
136 pb->first_index=0;
137 pb->num_loaded=0;
138}
139/*
140 * Loads the entries following 'index' in the playlist buffer
141 */
142void playlist_buffer_load_entries(struct playlist_buffer * pb, int index,
143 enum direction direction)
144{
145 int num_entries = viewer.num_tracks;
146 char* p = pb->name_buffer;
147 int remaining = pb->buffer_size;
148 int i;
149
150 pb->first_index = index;
151 if (num_entries > MAX_PLAYLIST_ENTRIES)
152 num_entries = MAX_PLAYLIST_ENTRIES;
153
154 for(i=0; i<num_entries; i++)
155 {
156 int len = playlist_entry_load(&(pb->tracks[i]), index, p, remaining);
157 if (len < 0)
158 {
159 /* Out of name buffer space */
160 num_entries = i;
161 break;
162 }
163
164 p += len;
165 remaining -= len;
166
167 if(direction==FORWARD)
168 index++;
169 else
170 index--;
171 index+=viewer.num_tracks;
172 index%=viewer.num_tracks;
173 }
174 pb->direction=direction;
175 pb->num_loaded = i;
176}
177
178void playlist_buffer_load_entries_screen(struct playlist_buffer * pb,
179 enum direction direction)
180{
181 if(direction==FORWARD)
182 {
183 int min_start=viewer.selected_track-2*screens[0].nb_lines;
184 if(min_start<0)
185 min_start=0;
186 playlist_buffer_load_entries(pb, min_start, FORWARD);
187 }
188 else
189 {
190 int max_start=viewer.selected_track+2*screens[0].nb_lines;
191 max_start%=viewer.num_tracks;
192 playlist_buffer_load_entries(pb, max_start, BACKWARD);
193 }
194}
195
196int playlist_entry_load(struct playlist_entry *entry, int index,
197 char* name_buffer, int remaining_size)
198{
199 struct playlist_track_info info;
200 int len;
201
202 /* Playlist viewer orders songs based on display index. We need to
203 convert to real playlist index to access track */
204 index = (index + playlist_get_first_index(viewer.playlist)) %
205 viewer.num_tracks;
206 if (playlist_get_track_info(viewer.playlist, index, &info) < 0)
207 return -1;
208
209 len = strlen(info.filename) + 1;
210
211 if (len <= remaining_size)
212 {
213 strcpy(name_buffer, info.filename);
214
215 entry->name = name_buffer;
216 entry->index = info.index;
217 entry->display_index = info.display_index;
218 entry->queued = info.attr & PLAYLIST_ATTR_QUEUED;
219 entry->skipped = info.attr & PLAYLIST_ATTR_SKIPPED;
220 return len;
221 }
222 return -1;
223}
224
225int playlist_buffer_get_index(struct playlist_buffer * pb, int index )
226{
227 int buffer_index;
228 if(pb->direction==FORWARD)
229 {
230 if(index>=pb->first_index)
231 buffer_index=index-pb->first_index;
232 else /* rotation : track0 in buffer + requested track */
233 buffer_index=(viewer.num_tracks-pb->first_index)+(index);
234 }
235 else
236 {
237 if(index<=pb->first_index)
238 buffer_index=pb->first_index-index;
239 else /* rotation : track0 in buffer + dist from the last track
240 to the requested track (num_tracks-requested track) */
241 buffer_index=(pb->first_index)+(viewer.num_tracks-index);
242 }
243 return(buffer_index);
244}
245
246#define distance(a, b) \
247 a>b? (a) - (b) : (b) - (a)
248bool playlist_buffer_needs_reload(struct playlist_buffer * pb, int track_index)
249{
250 if(pb->num_loaded==viewer.num_tracks)
251 return(false);
252 int selected_index=playlist_buffer_get_index(pb, track_index);
253 int first_buffer_index=playlist_buffer_get_index(pb, pb->first_index);
254 int distance_beginning=distance(selected_index, first_buffer_index);
255 if(distance_beginning<MIN_BUFFER_MARGIN)
256 return(true);
257
258 if(pb->num_loaded - distance_beginning < MIN_BUFFER_MARGIN)
259 return(true);
260 return(false);
261}
262
263struct playlist_entry * playlist_buffer_get_track(struct playlist_buffer * pb,
264 int index)
265{
266 int buffer_index=playlist_buffer_get_index(pb, index);
267 return(&(pb->tracks[buffer_index]));
268}
269
142/* Initialize the playlist viewer. */ 270/* Initialize the playlist viewer. */
143static bool initialize(char* filename, bool reload) 271static bool playlist_viewer_init(struct playlist_viewer * viewer,
272 char* filename, bool reload)
144{ 273{
145 char* buffer; 274 char* buffer;
146 int buffer_size; 275 int buffer_size;
@@ -155,15 +284,15 @@ static bool initialize(char* filename, bool reload)
155 return false; 284 return false;
156 285
157 if (!filename) 286 if (!filename)
158 viewer.playlist = NULL; 287 viewer->playlist = NULL;
159 else 288 else
160 { 289 {
161 /* Viewing playlist on disk */ 290 /* Viewing playlist on disk */
162 char *dir, *file, *temp_ptr; 291 char *dir, *file, *temp_ptr;
163 char *index_buffer = NULL; 292 char *index_buffer = NULL;
164 int index_buffer_size = 0; 293 int index_buffer_size = 0;
165 294
166 viewer.playlist = &temp_playlist; 295 viewer->playlist = &temp_playlist;
167 296
168 /* Separate directory from filename */ 297 /* Separate directory from filename */
169 temp_ptr = strrchr(filename+1,'/'); 298 temp_ptr = strrchr(filename+1,'/');
@@ -187,7 +316,7 @@ static bool initialize(char* filename, bool reload)
187 index_buffer = buffer; 316 index_buffer = buffer;
188 } 317 }
189 318
190 playlist_create_ex(viewer.playlist, dir, file, index_buffer, 319 playlist_create_ex(viewer->playlist, dir, file, index_buffer,
191 index_buffer_size, buffer+index_buffer_size, 320 index_buffer_size, buffer+index_buffer_size,
192 buffer_size-index_buffer_size); 321 buffer_size-index_buffer_size);
193 322
@@ -197,201 +326,18 @@ static bool initialize(char* filename, bool reload)
197 buffer += index_buffer_size; 326 buffer += index_buffer_size;
198 buffer_size -= index_buffer_size; 327 buffer_size -= index_buffer_size;
199 } 328 }
329 playlist_buffer_init(&viewer->buffer, buffer, buffer_size );
200 330
201 viewer.name_buffer = buffer; 331 viewer->move_track = -1;
202 viewer.buffer_size = buffer_size;
203
204#ifdef HAVE_LCD_BITMAP
205 {
206 char icon_chars[] = "MQ"; /* characters used as icons */
207 unsigned int i;
208
209 viewer.char_width = 0;
210 viewer.line_height = 0;
211
212 /* Use icon characters to calculate largest possible width/height so
213 that we set proper margins */
214 for (i=0; i<sizeof(icon_chars); i++)
215 {
216 char str[2];
217 int w, h;
218
219 snprintf(str, sizeof(str), "%c", icon_chars[i]);
220 lcd_getstringsize(str, &w, &h);
221
222 if (w > viewer.char_width)
223 viewer.char_width = w;
224
225 if (h > viewer.line_height)
226 {
227 viewer.line_height = h;
228 viewer.num_display_lines = (LCD_HEIGHT - MARGIN_Y)/h;
229 }
230 }
231 }
232#else
233 viewer.num_display_lines = 2;
234 viewer.char_width = 1;
235 viewer.line_height = 1;
236#endif
237
238 viewer.move_track = -1;
239 332
240 if (!reload) 333 if (!reload)
241 { 334 viewer->selected_track = 0;
242 viewer.cursor_pos = 0;
243
244 if (!viewer.playlist)
245 /* Start displaying at current playing track */
246 viewer.first_display_index = playlist_get_display_index() - 1;
247 else
248 viewer.first_display_index = 0;
249
250 update_first_index();
251 }
252 335
253 if (!update_playlist(true)) 336 if (!update_playlist(true))
254 return false; 337 return false;
255
256 return true; 338 return true;
257} 339}
258 340
259/* Load tracks starting at start_index */
260static void load_playlist_entries(int start_index)
261{
262 int num_entries = viewer.num_tracks - start_index;
263 char* p = viewer.name_buffer;
264 int remaining = viewer.buffer_size;
265 int i;
266
267 viewer.first_index = start_index;
268
269 if (num_entries > MAX_PLAYLIST_ENTRIES)
270 num_entries = MAX_PLAYLIST_ENTRIES;
271
272 for(i=0; i<num_entries; i++, start_index++)
273 {
274 int len = load_entry(start_index, i, p, remaining);
275 if (len < 0)
276 {
277 /* Out of name buffer space */
278 num_entries = i;
279 break;
280 }
281
282 p += len;
283 remaining -= len;
284 }
285
286 viewer.num_loaded = num_entries;
287 viewer.last_index = viewer.first_index + (viewer.num_loaded - 1);
288}
289
290/* Load tracks in reverse, ending at end_index */
291static void load_playlist_entries_r(int end_index)
292{
293 int num_entries = end_index;
294 char* p = viewer.name_buffer;
295 int remaining = viewer.buffer_size;
296 int i;
297
298 viewer.last_index = end_index;
299
300 if (num_entries >= MAX_PLAYLIST_ENTRIES)
301 num_entries = MAX_PLAYLIST_ENTRIES-1;
302
303 for(i=num_entries; i>=0; i--, end_index--)
304 {
305 int len = load_entry(end_index, i, p, remaining);
306 if (len < 0)
307 {
308 int j;
309
310 /* Out of name buffer space */
311 num_entries -= i;
312
313 /* Shift loaded tracks up such that first track is index 0 */
314 for (j=0; j<num_entries; j++, i++)
315 {
316 tracks[j].name = tracks[i].name;
317 tracks[j].index = tracks[i].index;
318 tracks[j].display_index = tracks[i].display_index;
319 tracks[j].queued = tracks[i].queued;
320 }
321
322 break;
323 }
324
325 p += len;
326 remaining -= len;
327 }
328
329 viewer.first_index = viewer.last_index - num_entries;
330
331 num_entries++;
332 if (!viewer.first_index &&
333 num_entries < viewer.num_tracks &&
334 num_entries < MAX_PLAYLIST_ENTRIES)
335 {
336 /* Lets see if we can load more data at the end of the list */
337 int max = viewer.num_tracks;
338 if (max > MAX_PLAYLIST_ENTRIES)
339 max = MAX_PLAYLIST_ENTRIES;
340
341 for (i = num_entries; i<max; i++)
342 {
343 int len = load_entry(num_entries, num_entries, p, remaining);
344 if (len < 0)
345 /* Out of name buffer space */
346 break;
347
348 p += len;
349 remaining -= len;
350
351 num_entries++;
352 viewer.last_index++;
353 }
354 }
355
356 viewer.num_loaded = num_entries;
357}
358
359/* Load track at playlist index. pos is the position in the tracks array and
360 p is a pointer to the name buffer (max size), Returns -1 if buffer is
361 full. */
362static int load_entry(int index, int pos, char* p, int size)
363{
364 struct playlist_track_info info;
365 int len;
366 int result = 0;
367
368 /* Playlist viewer orders songs based on display index. We need to
369 convert to real playlist index to access track */
370 index = (index + playlist_get_first_index(viewer.playlist)) %
371 viewer.num_tracks;
372 if (playlist_get_track_info(viewer.playlist, index, &info) < 0)
373 return -1;
374
375 len = strlen(info.filename) + 1;
376
377 if (len <= size)
378 {
379 strcpy(p, info.filename);
380
381 tracks[pos].name = p;
382 tracks[pos].index = info.index;
383 tracks[pos].display_index = info.display_index;
384 tracks[pos].queued = info.attr & PLAYLIST_ATTR_QUEUED;
385 tracks[pos].skipped = info.attr & PLAYLIST_ATTR_SKIPPED;
386
387 result = len;
388 }
389 else
390 result = -1;
391
392 return result;
393}
394
395/* Format trackname for display purposes */ 341/* Format trackname for display purposes */
396static void format_name(char* dest, const char* src) 342static void format_name(char* dest, const char* src)
397{ 343{
@@ -403,10 +349,10 @@ static void format_name(char* dest, const char* src)
403 /* Only display the mp3 filename */ 349 /* Only display the mp3 filename */
404 char* p = strrchr(src, '/'); 350 char* p = strrchr(src, '/');
405 int len; 351 int len;
406 352
407 strcpy(dest, p+1); 353 strcpy(dest, p+1);
408 len = strlen(dest); 354 len = strlen(dest);
409 355
410 /* Remove the extension */ 356 /* Remove the extension */
411 if (!strcasecmp(&dest[len-4], ".mp3") || 357 if (!strcasecmp(&dest[len-4], ".mp3") ||
412 !strcasecmp(&dest[len-4], ".mp2") || 358 !strcasecmp(&dest[len-4], ".mp2") ||
@@ -441,205 +387,6 @@ static void format_line(const struct playlist_entry* track, char* str, int len)
441 387
442} 388}
443 389
444/* Display tracks on screen */
445static void display_playlist(void)
446{
447 int i;
448 int num_display_tracks =
449 viewer.last_display_index - viewer.first_display_index;
450
451 lcd_clear_display();
452
453#ifdef HAVE_LCD_BITMAP
454 lcd_setmargins(MARGIN_X, MARGIN_Y);
455 lcd_setfont(FONT_UI);
456#endif
457
458 for (i=0; i<=num_display_tracks; i++)
459 {
460 if (global_settings.playlist_viewer_icons)
461 {
462 /* Icons */
463 if (tracks[INDEX(i)].index == viewer.current_playing_track)
464 {
465 /* Current playing track */
466#ifdef HAVE_LCD_BITMAP
467 int offset=0;
468 if ( viewer.line_height > 8 )
469 offset = (viewer.line_height - 8) / 2;
470 lcd_mono_bitmap(bitmap_icons_6x8[Icon_Audio],
471 CURSOR_X * 6 + CURSOR_WIDTH,
472 MARGIN_Y+(i*viewer.line_height) + offset, 6, 8);
473#else
474 lcd_putc(LINE_X-1, i, Icon_Audio);
475#endif
476 }
477 else if (tracks[INDEX(i)].index == viewer.move_track)
478 {
479 /* Track we are moving */
480#ifdef HAVE_LCD_BITMAP
481 lcd_putsxy(CURSOR_X * 6 + CURSOR_WIDTH,
482 MARGIN_Y+(i*viewer.line_height), "M");
483#else
484 lcd_putc(LINE_X-1, i, 'M');
485#endif
486 }
487 else if (tracks[INDEX(i)].queued)
488 {
489 /* Queued track */
490#ifdef HAVE_LCD_BITMAP
491 lcd_putsxy(CURSOR_X * 6 + CURSOR_WIDTH,
492 MARGIN_Y+(i*viewer.line_height), "Q");
493#else
494 lcd_putc(LINE_X-1, i, 'Q');
495#endif
496 }
497 }
498
499 update_display_line(i, false);
500 }
501
502#ifdef HAVE_LCD_BITMAP
503 if (global_settings.scrollbar &&
504 (viewer.num_tracks > viewer.num_display_lines))
505 scrollbar(SCROLLBAR_X, SCROLLBAR_Y, SCROLLBAR_WIDTH - 1,
506 LCD_HEIGHT - SCROLLBAR_Y, viewer.num_tracks-1,
507 viewer.first_display_index, viewer.last_display_index,
508 VERTICAL);
509#endif
510
511 put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, true);
512 status_draw(true);
513}
514
515/* Scroll cursor or display by num lines */
516static void scroll_display(int lines)
517{
518 int new_index = viewer.first_display_index + viewer.cursor_pos + lines;
519 bool pagescroll = false;
520 bool wrap = false;
521
522 put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, false);
523
524 if (lines > 1 || lines < -1)
525 pagescroll = true;
526
527 if (new_index < 0)
528 {
529 /* Wrap around if not pageup */
530 if (pagescroll)
531 new_index = 0;
532 else
533 {
534 new_index += viewer.num_tracks;
535 viewer.cursor_pos = viewer.num_display_lines-1;
536 wrap = true;
537 }
538 }
539 else if (new_index >= viewer.num_tracks)
540 {
541 /* Wrap around if not pagedown */
542 if (pagescroll)
543 new_index = viewer.num_tracks - 1;
544 else
545 {
546 new_index -= viewer.num_tracks;
547 viewer.cursor_pos = 0;
548 wrap = true;
549 }
550 }
551
552 if (new_index >= viewer.first_display_index &&
553 new_index <= viewer.last_display_index)
554 {
555 /* Just update the cursor */
556 viewer.cursor_pos = new_index - viewer.first_display_index;
557 }
558 else
559 {
560 /* New track is outside of display */
561 if (wrap)
562 viewer.first_display_index = new_index;
563 else
564 viewer.first_display_index = viewer.first_display_index + lines;
565
566 if (viewer.first_display_index < 0)
567 viewer.first_display_index = 0;
568
569 viewer.last_display_index =
570 viewer.first_display_index + (viewer.num_display_lines - 1);
571 if (viewer.last_display_index >= viewer.num_tracks)
572 {
573 /* display as many tracks as possible on screen */
574 if (viewer.first_display_index > 0)
575 {
576 viewer.first_display_index -=
577 (viewer.last_display_index - viewer.num_tracks + 1);
578 if (viewer.first_display_index < 0)
579 viewer.first_display_index = 0;
580 }
581
582 viewer.last_display_index = viewer.num_tracks - 1;
583 }
584
585 if (viewer.cursor_pos >
586 (viewer.last_display_index - viewer.first_display_index))
587 viewer.cursor_pos =
588 viewer.last_display_index - viewer.first_display_index;
589
590 /* Load more data if needed */
591 if (viewer.first_display_index < viewer.first_index)
592 load_playlist_entries_r(viewer.last_display_index);
593 else if (viewer.last_display_index > viewer.last_index)
594 load_playlist_entries(viewer.first_display_index);
595
596 display_playlist();
597 }
598
599 put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, true);
600}
601
602/* Update lcd line. Scroll line if requested */
603static void update_display_line(int line, bool scroll)
604{
605 char str[MAX_PATH + 16];
606
607 format_line(&tracks[INDEX(line)], str, sizeof(str));
608
609 if (scroll)
610 {
611#ifdef HAVE_LCD_BITMAP
612 if (global_settings.invert_cursor)
613 lcd_puts_scroll_style(LINE_X, line, str, STYLE_INVERT);
614 else
615#endif
616 lcd_puts_scroll(LINE_X, line, str);
617 }
618 else
619 lcd_puts(LINE_X, line, str);
620}
621
622/* Update first index, if necessary, to put as much as possible on the
623 screen */
624static void update_first_index(void)
625{
626 /* viewer.num_tracks may be invalid at this point */
627 int num_tracks = playlist_amount_ex(viewer.playlist);
628
629 if ((num_tracks - viewer.first_display_index) < viewer.num_display_lines)
630 {
631 /* Try to display as much as possible */
632 int old_index = viewer.first_display_index;
633
634 viewer.first_display_index = num_tracks - viewer.num_display_lines;
635 if (viewer.first_display_index < 0)
636 viewer.first_display_index = 0;
637
638 /* Cursor should still point at current track */
639 viewer.cursor_pos += old_index - viewer.first_display_index;
640 }
641}
642
643/* Update playlist in case something has changed or forced */ 390/* Update playlist in case something has changed or forced */
644static bool update_playlist(bool force) 391static bool update_playlist(bool force)
645{ 392{
@@ -647,32 +394,18 @@ static bool update_playlist(bool force)
647 playlist_get_resume_info(&viewer.current_playing_track); 394 playlist_get_resume_info(&viewer.current_playing_track);
648 else 395 else
649 viewer.current_playing_track = -1; 396 viewer.current_playing_track = -1;
650 397 int nb_tracks=playlist_amount_ex(viewer.playlist);
651 if (force || playlist_amount_ex(viewer.playlist) != viewer.num_tracks) 398 force=force || nb_tracks != viewer.num_tracks;
399 if (force)
652 { 400 {
653 int index;
654
655 /* Reload tracks */ 401 /* Reload tracks */
656 viewer.num_tracks = playlist_amount_ex(viewer.playlist); 402 viewer.num_tracks = nb_tracks;
657 if (viewer.num_tracks < 0) 403 if (viewer.num_tracks < 0)
658 return false; 404 return false;
659 405 playlist_buffer_load_entries_screen(&viewer.buffer, FORWARD);
660 index = viewer.first_display_index; 406 if (viewer.buffer.num_loaded <= 0)
661
662 load_playlist_entries(index);
663
664 if (viewer.num_loaded <= 0)
665 return false; 407 return false;
666
667 viewer.first_display_index = viewer.first_index;
668 viewer.last_display_index =
669 viewer.first_index + viewer.num_display_lines - 1;
670 if (viewer.last_display_index >= viewer.num_tracks)
671 viewer.last_display_index = viewer.num_tracks - 1;
672 } 408 }
673
674 display_playlist();
675
676 return true; 409 return true;
677} 410}
678 411
@@ -683,7 +416,9 @@ static int onplay_menu(int index)
683{ 416{
684 struct menu_item items[3]; /* increase this if you add entries! */ 417 struct menu_item items[3]; /* increase this if you add entries! */
685 int m, i=0, result, ret = 0; 418 int m, i=0, result, ret = 0;
686 bool current = (tracks[index].index == viewer.current_playing_track); 419 struct playlist_entry * current_track=
420 playlist_buffer_get_track(&viewer.buffer, index);
421 bool current = (current_track->index == viewer.current_playing_track);
687 422
688 items[i].desc = ID2P(LANG_REMOVE); 423 items[i].desc = ID2P(LANG_REMOVE);
689 i++; 424 i++;
@@ -707,13 +442,14 @@ static int onplay_menu(int index)
707 { 442 {
708 case 0: 443 case 0:
709 /* delete track */ 444 /* delete track */
710 playlist_delete(viewer.playlist, tracks[index].index); 445 playlist_delete(viewer.playlist, current_track->index);
711
712 if (current) 446 if (current)
713 { 447 {
714 /* Start playing new track except if it's the last track 448 /* Start playing new track except if it's the last track
715 in the playlist and repeat mode is disabled */ 449 in the playlist and repeat mode is disabled */
716 if (tracks[index].display_index != viewer.num_tracks || 450 current_track=
451 playlist_buffer_get_track(&viewer.buffer, index);
452 if (current_track->display_index != viewer.num_tracks ||
717 global_settings.repeat_mode == REPEAT_ALL) 453 global_settings.repeat_mode == REPEAT_ALL)
718 { 454 {
719 talk_buffer_steal(); /* will use the mp3 buffer */ 455 talk_buffer_steal(); /* will use the mp3 buffer */
@@ -721,30 +457,26 @@ static int onplay_menu(int index)
721 viewer.current_playing_track = -1; 457 viewer.current_playing_track = -1;
722 } 458 }
723 } 459 }
724
725 ret = 1; 460 ret = 1;
726 break; 461 break;
727 case 1: 462 case 1:
728 /* move track */ 463 /* move track */
729 viewer.move_track = tracks[index].index; 464 viewer.move_track = current_track->index;
730 ret = 0; 465 ret = 0;
731 break; 466 break;
732 case 2: 467 case 2:
733 { 468 {
734 onplay(tracks[index].name, TREE_ATTR_MPA, CONTEXT_TREE); 469 onplay(current_track->name, TREE_ATTR_MPA, CONTEXT_TREE);
735 470
736 if (!viewer.playlist) 471 if (!viewer.playlist)
737 ret = 1; 472 ret = 1;
738 else 473 else
739 ret = 0; 474 ret = 0;
740
741 break; 475 break;
742 } 476 }
743 } 477 }
744 } 478 }
745
746 menu_exit(m); 479 menu_exit(m);
747
748 return ret; 480 return ret;
749} 481}
750 482
@@ -792,7 +524,7 @@ static bool track_display(void)
792 { STR(LANG_DISPLAY_TRACK_NAME_ONLY) }, 524 { STR(LANG_DISPLAY_TRACK_NAME_ONLY) },
793 { STR(LANG_DISPLAY_FULL_PATH) } 525 { STR(LANG_DISPLAY_FULL_PATH) }
794 }; 526 };
795 527
796 return set_option(str(LANG_TRACK_DISPLAY), 528 return set_option(str(LANG_TRACK_DISPLAY),
797 &global_settings.playlist_viewer_track_display, INT, names, 2, NULL); 529 &global_settings.playlist_viewer_track_display, INT, names, 2, NULL);
798} 530}
@@ -807,7 +539,6 @@ static bool save_playlist(void)
807 if (!kbd_input(filename, sizeof(filename))) 539 if (!kbd_input(filename, sizeof(filename)))
808 { 540 {
809 playlist_save(viewer.playlist, filename); 541 playlist_save(viewer.playlist, filename);
810
811 /* reload in case playlist was saved to cwd */ 542 /* reload in case playlist was saved to cwd */
812 reload_directory(); 543 reload_directory();
813 } 544 }
@@ -821,63 +552,89 @@ bool playlist_viewer(void)
821 return playlist_viewer_ex(NULL); 552 return playlist_viewer_ex(NULL);
822} 553}
823 554
555
556
557
558char * playlist_callback_name(int selected_item, void * data, char *buffer)
559{
560 struct playlist_viewer * local_viewer = (struct playlist_viewer *)data;
561 struct playlist_entry *track=
562 playlist_buffer_get_track(&(local_viewer->buffer), selected_item);
563 format_line(track, buffer, MAX_PATH);
564 return(buffer);
565}
566
567
568void playlist_callback_icons(int selected_item, void * data, ICON * icon)
569{
570 struct playlist_viewer * local_viewer=(struct playlist_viewer *)data;
571 struct playlist_entry *track=
572 playlist_buffer_get_track(&(local_viewer->buffer), selected_item);
573 if (track->index == local_viewer->current_playing_track)
574 {
575 /* Current playing track */
576#ifdef HAVE_LCD_BITMAP
577 *icon=bitmap_icons_6x8[Icon_Audio];
578#else
579 *icon=Icon_Audio;
580#endif
581 }
582 else if (track->index == local_viewer->move_track)
583 {
584 /* Track we are moving */
585#ifdef HAVE_LCD_BITMAP
586 *icon=bitmap_icons_6x8[Icon_Moving];
587#else
588 *icon=Icon_Moving;
589#endif
590 }
591 else if (track->queued)
592 {
593 /* Queued track */
594#ifdef HAVE_LCD_BITMAP
595 *icon=bitmap_icons_6x8[Icon_Queued];
596#else
597 *icon=Icon_Queued;
598#endif
599 }
600 else
601 *icon=0;
602}
603
604
605
824/* Main viewer function. Filename identifies playlist to be viewed. If NULL, 606/* Main viewer function. Filename identifies playlist to be viewed. If NULL,
825 view current playlist. */ 607 view current playlist. */
826bool playlist_viewer_ex(char* filename) 608bool playlist_viewer_ex(char* filename)
827{ 609{
828 bool ret = false; /* return value */ 610 bool ret = false; /* return value */
829 bool exit=false; /* exit viewer */ 611 bool exit=false; /* exit viewer */
830 bool update=true; /* update display */
831 bool cursor_on=true; /* used for flashing cursor */
832 int old_cursor_pos; /* last cursor position */
833 int button, lastbutton = BUTTON_NONE; 612 int button, lastbutton = BUTTON_NONE;
834 613 struct gui_synclist playlist_lists;
835 if (!initialize(filename, false)) 614 if (!playlist_viewer_init(&viewer, filename, false))
836 goto exit; 615 goto exit;
837 616
838 old_cursor_pos = viewer.cursor_pos; 617 gui_synclist_init(&playlist_lists, playlist_callback_icons,
839 618 playlist_callback_name, &viewer);
619 gui_synclist_set_nb_items(&playlist_lists, viewer.num_tracks);
620 gui_synclist_select_item(&playlist_lists, viewer.selected_track);
621 gui_synclist_draw(&playlist_lists);
840 while (!exit) 622 while (!exit)
841 { 623 {
842 int track; 624 int track;
843
844 if (!viewer.playlist && !(audio_status() & AUDIO_STATUS_PLAY)) 625 if (!viewer.playlist && !(audio_status() & AUDIO_STATUS_PLAY))
845 { 626 {
846 /* Play has stopped */ 627 /* Play has stopped */
847#ifdef HAVE_LCD_CHARCELLS 628#ifdef HAVE_LCD_CHARCELLS
848 splash(HZ, true, str(LANG_END_PLAYLIST_PLAYER)); 629 gui_syncsplash(HZ, true, str(LANG_END_PLAYLIST_PLAYER));
849#else 630#else
850 splash(HZ, true, str(LANG_END_PLAYLIST_RECORDER)); 631 gui_syncsplash(HZ, true, str(LANG_END_PLAYLIST_RECORDER));
851#endif 632#endif
852 goto exit; 633 goto exit;
853 } 634 }
854 635
855 if (viewer.move_track != -1 || !cursor_on) 636 if (viewer.move_track != -1)
856 { 637 gui_synclist_flash(&playlist_lists);
857 /* Flash cursor to identify that we are moving a track */
858 cursor_on = !cursor_on;
859#ifdef HAVE_LCD_BITMAP
860 if (global_settings.invert_cursor)
861 {
862 lcd_set_drawmode(DRMODE_COMPLEMENT);
863 lcd_fillrect(
864 MARGIN_X, MARGIN_Y+(viewer.cursor_pos*viewer.line_height),
865 LCD_WIDTH, viewer.line_height);
866 lcd_set_drawmode(DRMODE_SOLID);
867 lcd_invertscroll(LINE_X, viewer.cursor_pos);
868 }
869 else
870 put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos,
871 cursor_on);
872
873 lcd_update_rect(
874 0, MARGIN_Y + (viewer.cursor_pos * viewer.line_height),
875 LCD_WIDTH, viewer.line_height);
876#else
877 put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, cursor_on);
878 lcd_update();
879#endif
880 }
881 638
882 if (!viewer.playlist) 639 if (!viewer.playlist)
883 playlist_get_resume_info(&track); 640 playlist_get_resume_info(&track);
@@ -888,19 +645,27 @@ bool playlist_viewer_ex(char* filename)
888 playlist_amount_ex(viewer.playlist) != viewer.num_tracks) 645 playlist_amount_ex(viewer.playlist) != viewer.num_tracks)
889 { 646 {
890 /* Playlist has changed (new track started?) */ 647 /* Playlist has changed (new track started?) */
891 update_first_index();
892 if (!update_playlist(false)) 648 if (!update_playlist(false))
893 goto exit; 649 goto exit;
894 else 650 gui_synclist_set_nb_items(&playlist_lists, viewer.num_tracks);
895 update = true;
896
897 /* Abort move on playlist change */ 651 /* Abort move on playlist change */
898 viewer.move_track = -1; 652 viewer.move_track = -1;
899 } 653 }
900 654
901 /* Timeout so we can determine if play status has changed */ 655 /* Timeout so we can determine if play status has changed */
902 button = button_get_w_tmo(HZ/2); 656 button = button_get_w_tmo(HZ/2);
903 657 int list_action;
658 if( (list_action=gui_synclist_do_button(&playlist_lists, button))!=0 )
659 {
660 viewer.selected_track=gui_synclist_get_sel_pos(&playlist_lists);
661 if(playlist_buffer_needs_reload(&viewer.buffer, viewer.selected_track))
662 playlist_buffer_load_entries_screen(&viewer.buffer,
663 list_action==LIST_NEXT?
664 FORWARD
665 :
666 BACKWARD
667 );
668 }
904 switch (button) 669 switch (button)
905 { 670 {
906 case TREE_EXIT: 671 case TREE_EXIT:
@@ -910,48 +675,20 @@ bool playlist_viewer_ex(char* filename)
910 exit = true; 675 exit = true;
911 break; 676 break;
912 677
913 case TREE_PREV:
914 case TREE_PREV | BUTTON_REPEAT:
915 scroll_display(-1);
916 update = true;
917 break;
918
919 case TREE_NEXT:
920 case TREE_NEXT | BUTTON_REPEAT:
921 scroll_display(1);
922 update = true;
923 break;
924
925#ifdef TREE_PGUP
926 case TREE_PGUP:
927 case TREE_PGUP | BUTTON_REPEAT:
928 /* Pageup */
929 scroll_display(-viewer.num_display_lines);
930 update = true;
931 break;
932
933 case TREE_PGDN:
934 case TREE_PGDN | BUTTON_REPEAT:
935 /* Pagedown */
936 scroll_display(viewer.num_display_lines);
937 update = true;
938 break;
939#endif
940
941 case TREE_RUN: 678 case TREE_RUN:
942#ifdef TREE_RUN_PRE 679#ifdef TREE_RUN_PRE
943 if (lastbutton != TREE_RUN_PRE) 680 if (lastbutton != TREE_RUN_PRE)
944 break; 681 break;
945#endif 682#endif
683 struct playlist_entry * current_track=playlist_buffer_get_track(&viewer.buffer, viewer.selected_track);
946 if (viewer.move_track >= 0) 684 if (viewer.move_track >= 0)
947 { 685 {
948 /* Move track */ 686 /* Move track */
949 int ret; 687 int ret;
950 688
951 ret = playlist_move(viewer.playlist, viewer.move_track, 689 ret = playlist_move(viewer.playlist, viewer.move_track, current_track->index);
952 tracks[INDEX(viewer.cursor_pos)].index);
953 if (ret < 0) 690 if (ret < 0)
954 splash(HZ, true, str(LANG_MOVE_FAILED)); 691 gui_syncsplash(HZ, true, str(LANG_MOVE_FAILED));
955 692
956 update_playlist(true); 693 update_playlist(true);
957 viewer.move_track = -1; 694 viewer.move_track = -1;
@@ -959,7 +696,7 @@ bool playlist_viewer_ex(char* filename)
959 else if (!viewer.playlist) 696 else if (!viewer.playlist)
960 { 697 {
961 /* play new track */ 698 /* play new track */
962 playlist_start(tracks[INDEX(viewer.cursor_pos)].index, 0); 699 playlist_start(current_track->index, 0);
963 update_playlist(false); 700 update_playlist(false);
964 } 701 }
965 else 702 else
@@ -968,15 +705,14 @@ bool playlist_viewer_ex(char* filename)
968 if (playlist_set_current(viewer.playlist) < 0) 705 if (playlist_set_current(viewer.playlist) < 0)
969 goto exit; 706 goto exit;
970 707
971 playlist_start(tracks[INDEX(viewer.cursor_pos)].index, 0); 708 playlist_start(current_track->index, 0);
972 709
973 /* Our playlist is now the current list */ 710 /* Our playlist is now the current list */
974 if (!initialize(NULL, true)) 711 if (!playlist_viewer_init(&viewer, NULL, true))
975 goto exit; 712 goto exit;
976 } 713 }
714 gui_synclist_draw(&playlist_lists);
977 715
978 display_playlist();
979 update = true;
980 break; 716 break;
981 717
982 case TREE_CONTEXT: 718 case TREE_CONTEXT:
@@ -987,7 +723,7 @@ bool playlist_viewer_ex(char* filename)
987 /* ON+PLAY menu */ 723 /* ON+PLAY menu */
988 int ret; 724 int ret;
989 725
990 ret = onplay_menu(INDEX(viewer.cursor_pos)); 726 ret = onplay_menu(viewer.selected_track);
991 727
992 if (ret < 0) 728 if (ret < 0)
993 { 729 {
@@ -997,15 +733,12 @@ bool playlist_viewer_ex(char* filename)
997 else if (ret > 0) 733 else if (ret > 0)
998 { 734 {
999 /* Playlist changed */ 735 /* Playlist changed */
1000 update_first_index(); 736 gui_synclist_del_item(&playlist_lists);
1001 update_playlist(false); 737 update_playlist(true);
1002 if (viewer.num_tracks <= 0) 738 if (viewer.num_tracks <= 0)
1003 exit = true; 739 exit = true;
1004 } 740 }
1005 else 741 gui_synclist_draw(&playlist_lists);
1006 display_playlist();
1007
1008 update = true;
1009 break; 742 break;
1010 } 743 }
1011 744
@@ -1015,13 +748,11 @@ bool playlist_viewer_ex(char* filename)
1015 ret = true; 748 ret = true;
1016 goto exit; 749 goto exit;
1017 } 750 }
1018 751 gui_synclist_draw(&playlist_lists);
1019 display_playlist();
1020 update = true;
1021 break; 752 break;
1022 753
1023 case BUTTON_NONE: 754 case BUTTON_NONE:
1024 status_draw(false); 755 gui_syncstatusbar_draw(&statusbars, false);
1025 break; 756 break;
1026 757
1027 default: 758 default:
@@ -1032,36 +763,6 @@ bool playlist_viewer_ex(char* filename)
1032 } 763 }
1033 break; 764 break;
1034 } 765 }
1035
1036 if (update && !exit)
1037 {
1038 lcd_stop_scroll();
1039
1040 if (viewer.cursor_pos >
1041 (viewer.last_display_index - viewer.first_display_index))
1042 {
1043 /* Cursor position is invalid */
1044 put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, false);
1045 viewer.cursor_pos =
1046 viewer.last_display_index - viewer.first_display_index;
1047 put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, true);
1048 }
1049
1050 if (viewer.cursor_pos != old_cursor_pos &&
1051 old_cursor_pos <=
1052 (viewer.last_display_index - viewer.first_display_index))
1053 /* Stop scrolling previous line */
1054 update_display_line(old_cursor_pos, false);
1055
1056 /* Scroll line at new cursor position */
1057 update_display_line(viewer.cursor_pos, true);
1058
1059 lcd_update();
1060
1061 old_cursor_pos = viewer.cursor_pos;
1062 cursor_on = true;
1063 update = false;
1064 }
1065 lastbutton = button; 766 lastbutton = button;
1066 } 767 }
1067 768
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] =
47 { 0x4e, 0x51, 0x51, 0x40, 0x55, 0x55 }, /* Config file */ 47 { 0x4e, 0x51, 0x51, 0x40, 0x55, 0x55 }, /* Config file */
48 { 0x0a, 0x0a, 0x5f, 0x4e, 0x24, 0x18 }, /* Plugin file */ 48 { 0x0a, 0x0a, 0x5f, 0x4e, 0x24, 0x18 }, /* Plugin file */
49 { 0xff, 0x81, 0xaf, 0xaa, 0x8c, 0xf8 }, /* Bookmark file */ 49 { 0xff, 0x81, 0xaf, 0xaa, 0x8c, 0xf8 }, /* Bookmark file */
50 { 0x77, 0x55, 0x55, 0x55, 0x55, 0x77 }, /* Queued Item */
51 { 0x3e, 0x41, 0x3e, 0x1c, 0x1c, 0x08 }, /* Moving Item */
50}; 52};
51 53
52const unsigned char bitmap_icons_7x8[][7] = 54const 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 {
44 Icon_Config, 44 Icon_Config,
45 Icon_Plugin, 45 Icon_Plugin,
46 Icon_Bookmark, 46 Icon_Bookmark,
47 Icon_Queued,
48 Icon_Moving,
47 LastIcon 49 LastIcon
48}; 50};
49 51
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)
150 gui_textarea_update_nblines(screen); 150 gui_textarea_update_nblines(screen);
151} 151}
152 152
153void screen_access_init(void)
154{
155 int i;
156 FOR_NB_SCREENS(i)
157 screen_init(&screens[i], i);
158}
159
160#ifdef HAVE_LCD_BITMAP 153#ifdef HAVE_LCD_BITMAP
161void screen_clear_area(struct screen * display, int xstart, int ystart, 154void screen_clear_area(struct screen * display, int xstart, int ystart,
162 int width, int height) 155 int width, int height)
@@ -166,3 +159,10 @@ void screen_clear_area(struct screen * display, int xstart, int ystart,
166 display->set_drawmode(DRMODE_SOLID); 159 display->set_drawmode(DRMODE_SOLID);
167} 160}
168#endif 161#endif
162
163void screen_access_init(void)
164{
165 int i;
166 FOR_NB_SCREENS(i)
167 screen_init(&screens[i], i);
168}