From 7da9477bc3401cbd90b2984f625f96f451ecaf6b Mon Sep 17 00:00:00 2001 From: Linus Nielsen Feltzing Date: Fri, 28 Oct 2005 00:00:00 +0000 Subject: Initial multi screen support by Kévin Ferrare (Patch #1318081) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7666 a1c6a512-1295-4272-9138-f99709370657 --- apps/SOURCES | 9 + apps/dbtree.c | 67 ++-- apps/filetree.c | 47 ++- apps/gui/buttonbar.c | 126 +++++++ apps/gui/buttonbar.h | 81 +++++ apps/gui/icon.c | 49 +++ apps/gui/icon.h | 51 +++ apps/gui/list.c | 499 +++++++++++++++++++++++++++ apps/gui/list.h | 232 +++++++++++++ apps/gui/scrollbar.c | 106 ++++++ apps/gui/scrollbar.h | 49 +++ apps/gui/splash.c | 216 ++++++++++++ apps/gui/splash.h | 39 +++ apps/gui/statusbar.c | 508 +++++++++++++++++++++++++++ apps/gui/statusbar.h | 107 ++++++ apps/status.c | 16 +- apps/status.h | 19 +- apps/tree.c | 942 ++++++++++++++++++--------------------------------- apps/tree.h | 33 +- apps/wps.h | 12 +- 20 files changed, 2506 insertions(+), 702 deletions(-) create mode 100644 apps/gui/buttonbar.c create mode 100644 apps/gui/buttonbar.h create mode 100644 apps/gui/icon.c create mode 100644 apps/gui/icon.h create mode 100644 apps/gui/list.c create mode 100644 apps/gui/list.h create mode 100644 apps/gui/scrollbar.c create mode 100644 apps/gui/scrollbar.h create mode 100644 apps/gui/splash.c create mode 100644 apps/gui/splash.h create mode 100644 apps/gui/statusbar.c create mode 100644 apps/gui/statusbar.h (limited to 'apps') diff --git a/apps/SOURCES b/apps/SOURCES index 26af159d5a..07c121f5a3 100644 --- a/apps/SOURCES +++ b/apps/SOURCES @@ -31,6 +31,15 @@ database.c filetree.c wps-display.c wps.c + +screen_access.c +gui/buttonbar.c +gui/icon.c +gui/list.c +gui/scrollbar.c +gui/splash.c +gui/statusbar.c + #ifdef HAVE_LCD_CHARCELLS player/icons.c player/keyboard.c diff --git a/apps/dbtree.c b/apps/dbtree.c index e3704ac381..9ea0706245 100644 --- a/apps/dbtree.c +++ b/apps/dbtree.c @@ -43,6 +43,7 @@ #include "lang.h" #include "keyboard.h" #include "autoconf.h" +#include "list.h" static int db_play_folder(struct tree_context* c); static int db_search(struct tree_context* c, char* string); @@ -69,17 +70,18 @@ int db_load(struct tree_context* c) c->filesindir = 0; return 0; } - + c->dentry_size = 2; c->dirfull = false; - DEBUGF("db_load() table: %d extra: 0x%x firstpos: %d\n", table, extra, c->firstpos); + DEBUGF("db_load() table: %d extra: 0x%x firstpos: %d\n", table, extra, + c->firstpos); if (!table) { table = root; c->currtable = table; } - + switch (table) { case root: { static const int tables[] = {allartists, allalbums, allsongs, @@ -138,28 +140,28 @@ int db_load(struct tree_context* c) return i; case allsongs: - DEBUGF("dbload table allsongs\n"); + DEBUGF("dbload table allsongs\n"); offset = tagdbheader.songstart + c->firstpos * SONGENTRY_SIZE; itemcount = tagdbheader.songcount; stringlen = tagdbheader.songlen; break; case allalbums: - DEBUGF("dbload table allalbums\n"); + DEBUGF("dbload table allalbums\n"); offset = tagdbheader.albumstart + c->firstpos * ALBUMENTRY_SIZE; itemcount = tagdbheader.albumcount; stringlen = tagdbheader.albumlen; break; case allartists: - DEBUGF("dbload table allartists\n"); + DEBUGF("dbload table allartists\n"); offset = tagdbheader.artiststart + c->firstpos * ARTISTENTRY_SIZE; itemcount = tagdbheader.artistcount; stringlen = tagdbheader.artistlen; break; case albums4artist: - DEBUGF("dbload table albums4artist\n"); + DEBUGF("dbload table albums4artist\n"); /* 'extra' is offset to the artist */ safeplacelen = tagdbheader.albumarraylen * 4; safeplace = (void*)(end_of_nbuf - safeplacelen); @@ -199,13 +201,13 @@ int db_load(struct tree_context* c) break; case songs4artist: - DEBUGF("dbload table songs4artist\n"); + DEBUGF("dbload table songs4artist\n"); /* 'extra' is offset to the artist, used as filter */ offset = tagdbheader.songstart + c->firstpos * SONGENTRY_SIZE; itemcount = tagdbheader.songcount; stringlen = tagdbheader.songlen; break; - + default: DEBUGF("Unsupported table %d\n", table); return -1; @@ -248,7 +250,8 @@ int db_load(struct tree_context* c) case songs4album: case songs4artist: rc = read(tagdb_fd, intbuf, 12); - skip = SONGENTRY_SIZE-stringlen-12; /* skip the rest of the song info */ + /* skip the rest of the song info */ + skip = SONGENTRY_SIZE-stringlen-12; if (rc < 12) { DEBUGF("%d read(%d) returned %d\n", i, 12, rc); return -1; @@ -287,7 +290,7 @@ int db_load(struct tree_context* c) if(table==songs4artist) c->dirlength=hits; - + /* next name is stored immediately after this */ nptr = (void*)nptr + strlen((char*)nptr) + 1; if ((void*)nptr + stringlen > (void*)end_of_nbuf) { @@ -314,7 +317,7 @@ int db_load(struct tree_context* c) dptr[1] = extra; /* offset to artist */ hits++; } - + c->filesindir = hits; return hits; @@ -350,7 +353,7 @@ static int db_search(struct tree_context* c, char* string) count = tagdbheader.songcount; size = SONGENTRY_SIZE; break; - + default: DEBUGF("Invalid table %d\n", c->currtable); return 0; @@ -384,7 +387,7 @@ static int db_search(struct tree_context* c, char* string) c->dirfull = true; break; } - + nptr += strlen(nptr) + 1; while ((unsigned long)nptr & 3) nptr++; @@ -403,25 +406,24 @@ static int db_search(struct tree_context* c, char* string) int db_enter(struct tree_context* c) { int rc = 0; - int offset = (c->dircursor + c->dirstart) * c->dentry_size + 1; + int offset = (c->selected_item) * c->dentry_size + 1; int newextra = ((int*)c->dircache)[offset]; if (c->dirlevel >= MAX_DIR_LEVELS) return 0; - - c->dirpos[c->dirlevel] = c->dirstart; - c->cursorpos[c->dirlevel] = c->dircursor; + + c->selected_item_history[c->dirlevel]=c->selected_item; c->table_history[c->dirlevel] = c->currtable; c->extra_history[c->dirlevel] = c->currextra; c->pos_history[c->dirlevel] = c->firstpos; c->dirlevel++; - + switch (c->currtable) { case root: c->currtable = newextra; c->currextra = newextra; break; - + case allartists: case searchartists: c->currtable = albums4artist; @@ -457,13 +459,13 @@ int db_enter(struct tree_context* c) else c->currtable = newextra; break; - + default: c->dirlevel--; break; } - - c->dirstart = c->dircursor = c->firstpos = 0; + c->selected_item=0; + gui_synclist_select_item(&tree_lists, c->selected_item); return rc; } @@ -471,8 +473,8 @@ int db_enter(struct tree_context* c) void db_exit(struct tree_context* c) { c->dirlevel--; - c->dirstart = c->dirpos[c->dirlevel]; - c->dircursor = c->cursorpos[c->dirlevel]; + c->selected_item=c->selected_item_history[c->dirlevel]; + gui_synclist_select_item(&tree_lists, c->selected_item); c->currtable = c->table_history[c->dirlevel]; c->currextra = c->extra_history[c->dirlevel]; c->firstpos = c->pos_history[c->dirlevel]; @@ -481,9 +483,8 @@ void db_exit(struct tree_context* c) int db_get_filename(struct tree_context* c, char *buf, int buflen) { int rc; - int filenum = c->dircursor + c->dirstart; - int pathoffset = ((int*)c->dircache)[filenum * c->dentry_size + 1]; - + int pathoffset = ((int*)c->dircache)[c->selected_item * c->dentry_size + 1]; + lseek(tagdb_fd, pathoffset, SEEK_SET); rc = read(tagdb_fd, buf, buflen); @@ -498,7 +499,6 @@ static int db_play_folder(struct tree_context* c) { char buf[MAX_PATH]; int rc, i; - int filenum = c->dircursor + c->dirstart; if (playlist_create(NULL, NULL) < 0) { DEBUGF("Failed creating playlist\n"); @@ -506,7 +506,7 @@ static int db_play_folder(struct tree_context* c) } /* TODO: add support for very long tables */ - + for (i=0; i < c->filesindir; i++) { int pathoffset = ((int*)c->dircache)[i * c->dentry_size + 1]; lseek(tagdb_fd, pathoffset, SEEK_SET); @@ -520,11 +520,12 @@ static int db_play_folder(struct tree_context* c) } if (global_settings.playlist_shuffle) - filenum = playlist_shuffle(current_tick, filenum); + c->selected_item = playlist_shuffle(current_tick, c->selected_item); if (!global_settings.play_selected) - filenum = 0; + c->selected_item = 0; + gui_synclist_select_item(&tree_lists, c->selected_item); - playlist_start(filenum,0); + playlist_start(c->selected_item,0); return 0; } diff --git a/apps/filetree.c b/apps/filetree.c index 37a66c60ee..e8b8df73ad 100644 --- a/apps/filetree.c +++ b/apps/filetree.c @@ -79,12 +79,12 @@ static void check_file_thumbnails(struct tree_context* c) struct dircache_entry *entry; struct entry* dircache = c->dircache; DIRCACHED *dir; - + dir = opendir_cached(c->currdir); if(!dir) return; - - for (i=0; i < c->filesindir; i++) /* mark all files as non talking, except the .talk ones */ + /* mark all files as non talking, except the .talk ones */ + for (i=0; i < c->filesindir; i++) { if (dircache[i].attr & ATTR_DIRECTORY) continue; /* we're not touching directories */ @@ -100,7 +100,7 @@ static void check_file_thumbnails(struct tree_context* c) dircache[i].attr |= TREE_ATTR_THUMBNAIL; /* set */ } } - + while((entry = readdir_cached(dir)) != 0) /* walk directory */ { int ext_pos; @@ -110,13 +110,13 @@ static void check_file_thumbnails(struct tree_context* c) || (entry->attribute & ATTR_DIRECTORY) /* no file */ || strcasecmp(&entry->d_name[ext_pos], file_thumbnail_ext)) { /* or doesn't end with ".talk", no candidate */ - continue; + continue; } - + /* terminate the (disposable) name in dir buffer, this truncates off the ".talk" without needing an extra buffer */ entry->d_name[ext_pos] = '\0'; - + /* search corresponding file in dir cache */ for (i=0; i < c->filesindir; i++) { @@ -187,7 +187,7 @@ static int compare(const void* p1, const void* p2) return 0; /* never reached */ } -/* load and sort directory into dircache. returns NULL on failure. */ +/* load and sort directory into dircache. returns NULL on failure. */ int ft_load(struct tree_context* c, const char* tempdir) { int i; @@ -256,7 +256,7 @@ int ft_load(struct tree_context* c, const char* tempdir) boot_cluster = entry->startcluster; } #endif - + /* filter out non-visible files */ if ((!(dptr->attr & ATTR_DIRECTORY) && ( (*c->dirfilter == SHOW_PLAYLIST && @@ -289,7 +289,7 @@ int ft_load(struct tree_context* c, const char* tempdir) name_buffer_used += len + 1; if (dptr->attr & ATTR_DIRECTORY) /* count the remaining dirs */ - c->dirsindir++; + c->dirsindir++; } c->filesindir = i; c->dirlength = i; @@ -297,7 +297,7 @@ int ft_load(struct tree_context* c, const char* tempdir) qsort(c->dircache,i,sizeof(struct entry),compare); - /* If thumbnail talking is enabled, make an extra run to mark files with + /* If thumbnail talking is enabled, make an extra run to mark files with associated thumbnails, so we don't do unsuccessful spinups later. */ if (global_settings.talk_file == 3) check_file_thumbnails(c); /* map .talk to ours */ @@ -310,7 +310,7 @@ int ft_enter(struct tree_context* c) int rc = 0; char buf[MAX_PATH]; struct entry *dircache = c->dircache; - struct entry* file = &dircache[c->dircursor + c->dirstart]; + struct entry* file = &dircache[c->selected_item]; bool reload_dir = false; bool start_wps = false; bool exit_func = false; @@ -322,13 +322,10 @@ int ft_enter(struct tree_context* c) if (file->attr & ATTR_DIRECTORY) { memcpy(c->currdir, buf, sizeof(c->currdir)); - if ( c->dirlevel < MAX_DIR_LEVELS ) { - c->dirpos[c->dirlevel] = c->dirstart; - c->cursorpos[c->dirlevel] = c->dircursor; - } + if ( c->dirlevel < MAX_DIR_LEVELS ) + c->selected_item_history[c->dirlevel] = c->selected_item; c->dirlevel++; - c->dircursor=0; - c->dirstart=0; + c->selected_item=0; } else { int seed = current_tick; @@ -357,8 +354,7 @@ int ft_enter(struct tree_context* c) if (playlist_create(c->currdir, NULL) != -1) { - start_index = - ft_build_playlist(c, c->dircursor + c->dirstart); + start_index = ft_build_playlist(c, c->selected_item); if (global_settings.playlist_shuffle) { start_index = playlist_shuffle(seed, start_index); @@ -497,14 +493,13 @@ int ft_exit(struct tree_context* c) exit_func = true; c->dirlevel--; - if ( c->dirlevel < MAX_DIR_LEVELS ) { - c->dirstart = c->dirpos[c->dirlevel]; - c->dircursor = c->cursorpos[c->dirlevel]; - } + if ( c->dirlevel < MAX_DIR_LEVELS ) + c->selected_item=c->selected_item_history[c->dirlevel]; else - c->dirstart = c->dircursor = 0; + c->selected_item=0; - if (c->dirstart == -1) + /* if undefined position */ + if (c->selected_item == -1) strcpy(lastfile, buf); } else diff --git a/apps/gui/buttonbar.c b/apps/gui/buttonbar.c new file mode 100644 index 0000000000..be87b1b81f --- /dev/null +++ b/apps/gui/buttonbar.c @@ -0,0 +1,126 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) Linus Nielsen Feltzing (2002), Kévin FERRARE (2005) + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" +#include "buttonbar.h" + +#ifdef HAS_BUTTONBAR + +#include "lcd.h" +#include "font.h" +#include "string.h" +#include "settings.h" + +void gui_buttonbar_init(struct gui_buttonbar * buttonbar) +{ + gui_buttonbar_unset(buttonbar); +} + +void gui_buttonbar_set_display(struct gui_buttonbar * buttonbar, + struct screen * display) +{ + buttonbar->display = display; +} + +void gui_buttonbar_draw_button(struct gui_buttonbar * buttonbar, int num) +{ + int xpos, ypos, button_width, text_width; + int fw, fh; + struct screen * display = buttonbar->display; + + display->setfont(FONT_SYSFIXED); + display->getstringsize("M", &fw, &fh); + + button_width = display->width/BUTTONBAR_MAX_BUTTONS; + xpos = num * button_width; + ypos = display->height - fh; + + if(buttonbar->caption[num][0] != 0) + { + /* center the text */ + text_width = fw * strlen(buttonbar->caption[num]); + display->putsxy(xpos + (button_width - text_width)/2, + ypos, buttonbar->caption[num]); + } + + display->set_drawmode(DRMODE_COMPLEMENT); + display->fillrect(xpos, ypos, button_width - 1, fh); + display->set_drawmode(DRMODE_SOLID); + display->setfont(FONT_UI); +} + +void gui_buttonbar_set(struct gui_buttonbar * buttonbar, + const char *caption1, + const char *caption2, + const char *caption3) +{ + gui_buttonbar_unset(buttonbar); + if(caption1) + { + strncpy(buttonbar->caption[0], caption1, 7); + buttonbar->caption[0][7] = 0; + } + if(caption2) + { + strncpy(buttonbar->caption[1], caption2, 7); + buttonbar->caption[1][7] = 0; + } + if(caption3) + { + strncpy(buttonbar->caption[2], caption3, 7); + buttonbar->caption[2][7] = 0; + } +} + +void gui_buttonbar_unset(struct gui_buttonbar * buttonbar) +{ + int i; + for(i = 0;i < BUTTONBAR_MAX_BUTTONS;++i) + buttonbar->caption[i][0] = 0; +} + +void gui_buttonbar_draw(struct gui_buttonbar * buttonbar) +{ + struct screen * display = buttonbar->display; + int i; + + display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); + display->fillrect(0, display->height - BUTTONBAR_HEIGHT, + display->width, BUTTONBAR_HEIGHT); + display->set_drawmode(DRMODE_SOLID); + + for(i = 0;i < BUTTONBAR_MAX_BUTTONS;++i) + gui_buttonbar_draw_button(buttonbar, i); + display->update_rect(0, display->height - BUTTONBAR_HEIGHT, + display->width, BUTTONBAR_HEIGHT); +} + +bool gui_buttonbar_isset(struct gui_buttonbar * buttonbar) +{ + /* If all buttons are unset, the button bar is considered disabled */ + if(!global_settings.buttonbar) + return(false); + int i; + for(i = 0;i < BUTTONBAR_MAX_BUTTONS;++i) + if(buttonbar->caption[i] != 0) + return true; + return false; +} + +#endif /* HAS_BUTTONBAR */ diff --git a/apps/gui/buttonbar.h b/apps/gui/buttonbar.h new file mode 100644 index 0000000000..ee7b8d02c4 --- /dev/null +++ b/apps/gui/buttonbar.h @@ -0,0 +1,81 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 by Kévin FERRARE + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef _GUI_BUTTONBAR_H_ +#define _GUI_BUTTONBAR_H_ +#include "config.h" +#include "button.h" +#if CONFIG_KEYPAD == RECORDER_PAD + +#define HAS_BUTTONBAR +#define BUTTONBAR_HEIGHT 8 +#define BUTTONBAR_MAX_BUTTONS 3 +#define BUTTONBAR_CAPTION_LENGTH 8 +#include "screen_access.h" + +struct gui_buttonbar +{ + char caption[BUTTONBAR_MAX_BUTTONS][BUTTONBAR_CAPTION_LENGTH]; + struct screen * display; +}; + +/* + * Initializes the buttonbar + * - buttonbar : the buttonbar + */ +extern void gui_buttonbar_init(struct gui_buttonbar * buttonbar); + +/* + * Attach the buttonbar to a screen + * - buttonbar : the buttonbar + * - display : the display to attach the buttonbar + */ +extern void gui_buttonbar_set_display(struct gui_buttonbar * buttonbar, + struct screen * display); + +/* + * Set the caption of the items of the buttonbar + * - buttonbar : the buttonbar + * - caption1,2,3 : the first, second and thirds items of the bar + */ +extern void gui_buttonbar_set(struct gui_buttonbar * buttonbar, + const char *caption1, + const char *caption2, + const char *caption3); + +/* + * Disable the buttonbar + * - buttonbar : the buttonbar + */ +extern void gui_buttonbar_unset(struct gui_buttonbar * buttonbar); + +/* + * Draw the buttonbar on it's attached screen + * - buttonbar : the buttonbar + */ +extern void gui_buttonbar_draw(struct gui_buttonbar * buttonbar); + +/* + * Returns true if the buttonbar has something to display, false otherwise + * - buttonbar : the buttonbar + */ +extern bool gui_buttonbar_isset(struct gui_buttonbar * buttonbar); + +#endif /* CONFIG_KEYPAD == RECORDER_PAD */ +#endif /* _GUI_BUTTONBAR_H_ */ diff --git a/apps/gui/icon.c b/apps/gui/icon.c new file mode 100644 index 0000000000..4d174d3427 --- /dev/null +++ b/apps/gui/icon.c @@ -0,0 +1,49 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) Robert E. Hak(2002), Kévin FERRARE (2005) + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" +#include "icon.h" +#include "screen_access.h" +#include "icons.h" + +/* Count in letter positions, NOT pixels */ +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); +#else + display->putc(x, y, icon); +#endif +} + +void screen_put_cursorxy(struct screen * display, int x, int y) +{ +#ifdef HAVE_LCD_BITMAP + screen_put_iconxy(display, x, y, bitmap_icons_6x8[Icon_Cursor]); +#else + screen_put_iconxy(display, x, y, CURSOR_CHAR); +#endif +} diff --git a/apps/gui/icon.h b/apps/gui/icon.h new file mode 100644 index 0000000000..46faf0972f --- /dev/null +++ b/apps/gui/icon.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 by Kévin FERRARE + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef _GUI_ICON_H_ +#define _GUI_ICON_H_ +#include "lcd.h" +#include "screen_access.h" +/* Defines a type for the icons since it's not the same thing on + * char-based displays and bitmap displays */ +#ifdef HAVE_LCD_BITMAP + #define ICON const unsigned char * +#else + #define ICON unsigned short +#endif + +#define CURSOR_CHAR 0x92 +#define CURSOR_WIDTH 6 +#define CURSOR_HEIGHT 8 +/* + * Draws a cursor at a given position + * - screen : the screen where we put the cursor + * - x, y : the position, in character, not in pixel !! + */ +extern void screen_put_cursorxy(struct screen * screen, int x, int y); + +/* + * Put an icon on a screen at a given position + * (the position is given in characters) + * - screen : the screen where we put our icon + * - x, y : the position, in character, not in pixel !! + * - icon : the icon to put + */ +extern void screen_put_iconxy(struct screen * screen, int x, int y, ICON icon); + +#endif /*_GUI_ICON_H_*/ diff --git a/apps/gui/list.c b/apps/gui/list.c new file mode 100644 index 0000000000..bb3eb7caaa --- /dev/null +++ b/apps/gui/list.c @@ -0,0 +1,499 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 by Kévin FERRARE + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" +#include "lcd.h" +#include "font.h" +#include "button.h" +#include "sprintf.h" +#include "settings.h" +#include "kernel.h" + +#include "screen_access.h" +#include "list.h" +#include "scrollbar.h" +#include "statusbar.h" + +#ifdef HAVE_LCD_CHARCELLS +#define SCROLL_LIMIT 1 +#else +#define SCROLL_LIMIT 2 +#endif + + + +void gui_list_init(struct gui_list * gui_list, + void (*callback_get_item_icon)(int selected_item, ICON * icon), + char * (*callback_get_item_name)(int selected_item, char *buffer)) +{ + gui_list->callback_get_item_icon = callback_get_item_icon; + gui_list->callback_get_item_name = callback_get_item_name; + gui_list->display = NULL; + gui_list_set_nb_items(gui_list, 0); + gui_list->selected_item = 0; + gui_list->start_item = 0; +} + +void gui_list_set_nb_items(struct gui_list * gui_list, int nb_items) +{ + gui_list->nb_items = nb_items; +} + +void gui_list_set_display(struct gui_list * gui_list, struct screen * display) +{ + if(gui_list->display != 0) /* we switched from a previous display */ + gui_list->display->stop_scroll(); + gui_list->display = display; +#ifdef HAVE_LCD_CHARCELLS + display->double_height(false); +#endif + gui_list_put_selection_in_screen(gui_list, false); +} + +void gui_list_put_selection_in_screen(struct gui_list * gui_list, + bool put_from_end) +{ + struct screen * display = gui_list->display; + if(put_from_end) + { + int list_end = gui_list->selected_item + SCROLL_LIMIT - 1; + if(list_end > gui_list->nb_items) + list_end = gui_list->nb_items; + gui_list->start_item = list_end - display->nb_lines; + } + else + { + int list_start = gui_list->selected_item - SCROLL_LIMIT + 1; + if(list_start + display->nb_lines > gui_list->nb_items) + list_start = gui_list->nb_items - display->nb_lines; + gui_list->start_item = list_start; + } + if(gui_list->start_item < 0) + gui_list->start_item = 0; +} + +void gui_list_get_selected_item_name(struct gui_list * gui_list, char *buffer) +{ + gui_list->callback_get_item_name(gui_list->selected_item, buffer); +} + +int gui_list_get_selected_item_position(struct gui_list * gui_list) +{ + return gui_list->selected_item; +} + +void gui_list_draw(struct gui_list * gui_list) +{ + struct screen * display=gui_list->display; + int cursor_pos = 0; + int icon_pos = 1; + int text_pos; + bool draw_icons = (gui_list->callback_get_item_icon != NULL && + global_settings.show_icons) ; + bool draw_cursor; + int i; + + /* Adjust the position of icon, cursor, text */ +#ifdef HAVE_LCD_BITMAP + bool draw_scrollbar = (global_settings.scrollbar && + display->nb_lines < gui_list->nb_items); + + int list_y_start = screen_get_text_y_start(gui_list->display); + int list_y_end = screen_get_text_y_end(gui_list->display); + + draw_cursor = !global_settings.invert_cursor; + text_pos = 0; /* here it's in pixels */ + if(draw_scrollbar) + { + ++cursor_pos; + ++icon_pos; + text_pos += SCROLLBAR_WIDTH; + } + if(!draw_cursor) + { + --icon_pos; + } + else + text_pos += CURSOR_WIDTH; + + if(draw_icons) + text_pos += 8; +#else + draw_cursor = true; + if(draw_icons) + text_pos = 2; /* here it's in chars */ + else + text_pos = 1; +#endif + /* The drawing part */ +#ifdef HAVE_LCD_BITMAP + /* clear the drawing area */ + display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); + display->fillrect(0, list_y_start, + display->width, list_y_end - list_y_start); + display->set_drawmode(DRMODE_SOLID); + + /* FIXME: should not be handled here, but rather in the + * code that changes fonts */ + screen_update_nblines(display); + + display->stop_scroll(); + display->setmargins(text_pos, list_y_start); +#else + display->clear_display(); +#endif + + for(i = 0;i < display->nb_lines;++i) + { + char entry_buffer[MAX_PATH]; + char * entry_name; + int current_item = gui_list->start_item + i; + + /* When there are less items to display than the + * current available space on the screen, we stop*/ + if(current_item >= gui_list->nb_items) + break; + entry_name = gui_list->callback_get_item_name(current_item, + entry_buffer); + if(current_item == gui_list->selected_item) + { + /* The selected item must be displayed scrolling */ +#ifdef HAVE_LCD_BITMAP + if (global_settings.invert_cursor)/* Display inverted-line-style*/ + display->puts_scroll_style(0, i, entry_name, STYLE_INVERT); + else + display->puts_scroll(0, i, entry_name); +#else + display->puts_scroll(text_pos, i, entry_name); +#endif + + if(draw_cursor) + screen_put_cursorxy(display, cursor_pos, i); + } + else + {/* normal item */ +#ifdef HAVE_LCD_BITMAP + display->puts(0, i, entry_name); +#else + display->puts(text_pos, i, entry_name); +#endif + } + /* Icons display */ + if(draw_icons) + { + ICON icon; + gui_list->callback_get_item_icon(current_item, &icon); + screen_put_iconxy(display, icon_pos, i, icon); + } + } +#ifdef HAVE_LCD_BITMAP + /* Draw the scrollbar if needed*/ + if(draw_scrollbar) + { + int scrollbar_y_end = display->char_height * + display->nb_lines + list_y_start; + gui_scrollbar_draw(display, 0, list_y_start, SCROLLBAR_WIDTH-1, + scrollbar_y_end - list_y_start, gui_list->nb_items, + gui_list->start_item, + gui_list->start_item + display->nb_lines, VERTICAL); + } + display->update_rect(0, list_y_start, display->width, + list_y_end - list_y_start); +#else +#ifdef SIMULATOR + display->update(); +#endif +#endif +} + +void gui_list_select_item(struct gui_list * gui_list, int item_number) +{ + if( item_number > gui_list->nb_items-1 || item_number < 0 ) + return; + gui_list->selected_item = item_number; + gui_list_put_selection_in_screen(gui_list, false); +} + +void gui_list_select_next(struct gui_list * gui_list) +{ + int item_pos; + int end_item; + int nb_lines = gui_list->display->nb_lines; + + ++gui_list->selected_item; + + if( gui_list->selected_item >= gui_list->nb_items ) + { + /* we have already reached the bottom of the list */ + gui_list->selected_item = 0; + gui_list->start_item = 0; + } + else + { + item_pos = gui_list->selected_item - gui_list->start_item; + end_item = gui_list->start_item + nb_lines; + /* we start scrolling vertically when reaching the line + * (nb_lines-SCROLL_LIMIT) + * and when we are not in the last part of the list*/ + if( item_pos > nb_lines-SCROLL_LIMIT && end_item < gui_list->nb_items ) + ++gui_list->start_item; + } +} + +void gui_list_select_previous(struct gui_list * gui_list) +{ + int item_pos; + int nb_lines = gui_list->display->nb_lines; + + --gui_list->selected_item; + if( gui_list->selected_item < 0 ) + { + /* we have aleady reached the top of the list */ + int start; + gui_list->selected_item = gui_list->nb_items-1; + start = gui_list->nb_items-nb_lines; + if( start < 0 ) + gui_list->start_item = 0; + else + gui_list->start_item = start; + } + else + { + item_pos = gui_list->selected_item - gui_list->start_item; + if( item_pos < SCROLL_LIMIT-1 && gui_list->start_item > 0 ) + --gui_list->start_item; + } +} + +void gui_list_select_next_page(struct gui_list * gui_list, int nb_lines) +{ + if(gui_list->selected_item == gui_list->nb_items-1) + gui_list->selected_item = 0; + else + { + gui_list->selected_item += nb_lines; + if(gui_list->selected_item > gui_list->nb_items-1) + gui_list->selected_item = gui_list->nb_items-1; + } + gui_list_put_selection_in_screen(gui_list, true); +} + +void gui_list_select_previous_page(struct gui_list * gui_list, int nb_lines) +{ + if(gui_list->selected_item == 0) + gui_list->selected_item = gui_list->nb_items - 1; + else + { + gui_list->selected_item -= nb_lines; + if(gui_list->selected_item < 0) + gui_list->selected_item = 0; + } + gui_list_put_selection_in_screen(gui_list, false); +} + +void gui_list_add_item(struct gui_list * gui_list) +{ + ++gui_list->nb_items; + /* if only one item in the list, select it */ + if(gui_list->nb_items == 1) + gui_list->selected_item = 0; +} + +void gui_list_del_item(struct gui_list * gui_list) +{ + int nb_lines = gui_list->display->nb_lines; + + if(gui_list->nb_items > 0) + { + int dist_selected_from_end = gui_list->nb_items + - gui_list->selected_item - 1; + int dist_start_from_end = gui_list->nb_items + - gui_list->start_item - 1; + if(dist_selected_from_end == 0) + { + /* Oops we are removing the selected item, + select the previous one */ + --gui_list->selected_item; + } + --gui_list->nb_items; + + /* scroll the list if needed */ + if( (dist_start_from_end < nb_lines) && (gui_list->start_item != 0) ) + --gui_list->start_item; + } +} + +/* + * Synchronized lists stuffs + */ +void gui_synclist_init( + struct gui_synclist * lists, + void (*callback_get_item_icon)(int selected_item, ICON * icon), + char * (*callback_get_item_name)(int selected_item, char *buffer) + ) +{ + int i; + for(i = 0;i < NB_SCREENS;i++) + { + gui_list_init(&(lists->gui_list[i]), callback_get_item_icon, + callback_get_item_name); + gui_list_set_display(&(lists->gui_list[i]), &(screens[i])); + } +} + +void gui_synclist_set_nb_items(struct gui_synclist * lists, int nb_items) +{ + int i; + for(i = 0;i < NB_SCREENS;i++) + { + gui_list_set_nb_items(&(lists->gui_list[i]), nb_items); + } +} + +void gui_synclist_get_selected_item_name(struct gui_synclist * lists, + char *buffer) +{ + gui_list_get_selected_item_name(&(lists->gui_list[0]), buffer); +} + +int gui_synclist_get_selected_item_position(struct gui_synclist * lists) +{ + return gui_list_get_selected_item_position(&(lists->gui_list[0])); +} + +void gui_synclist_draw(struct gui_synclist * lists) +{ + int i; + for(i = 0;i < NB_SCREENS;i++) + gui_list_draw(&(lists->gui_list[i])); +} + +void gui_synclist_select_item(struct gui_synclist * lists, int item_number) +{ + int i; + for(i = 0;i < NB_SCREENS;i++) + gui_list_select_item(&(lists->gui_list[i]), item_number); +} + +void gui_synclist_select_next(struct gui_synclist * lists) +{ + int i; + for(i = 0;i < NB_SCREENS;i++) + gui_list_select_next(&(lists->gui_list[i])); +} + +void gui_synclist_select_previous(struct gui_synclist * lists) +{ + int i; + for(i = 0;i < NB_SCREENS;i++) + gui_list_select_previous(&(lists->gui_list[i])); +} + +void gui_synclist_select_next_page(struct gui_synclist * lists, + enum screen_type screen) +{ + int i; + for(i = 0;i < NB_SCREENS;i++) + gui_list_select_next_page(&(lists->gui_list[i]), + screens[screen].nb_lines); +} + +void gui_synclist_select_previous_page(struct gui_synclist * lists, + enum screen_type screen) +{ + int i; + for(i = 0;i < NB_SCREENS;i++) + gui_list_select_previous_page(&(lists->gui_list[i]), + screens[screen].nb_lines); +} + +void gui_synclist_add_item(struct gui_synclist * lists) +{ + int i; + for(i = 0;i < NB_SCREENS;i++) + gui_list_add_item(&(lists->gui_list[i])); +} + +void gui_synclist_del_item(struct gui_synclist * lists) +{ + int i; + for(i = 0;i < NB_SCREENS;i++) + gui_list_del_item(&(lists->gui_list[i])); +} + +bool gui_synclist_do_button(struct gui_synclist * lists, unsigned button) +{ + switch(button) + { + case LIST_PREV: + case LIST_PREV | BUTTON_REPEAT: +#ifdef LIST_RC_PREV + case LIST_RC_PREV: + case LIST_RC_PREV | BUTTON_REPEAT: +#endif + gui_synclist_select_previous(lists); + gui_synclist_draw(lists); + return true; + + case LIST_NEXT: + case LIST_NEXT | BUTTON_REPEAT: +#ifdef LIST_RC_NEXT + case LIST_RC_NEXT: + case LIST_RC_NEXT | BUTTON_REPEAT: +#endif + gui_synclist_select_next(lists); + gui_synclist_draw(lists); + return true; +/* 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*/ +#ifdef LIST_PGUP + case LIST_PGUP: + case LIST_PGUP | BUTTON_REPEAT: + gui_synclist_select_previous_page(lists, SCREEN_MAIN); + gui_synclist_draw(lists); + return true; +#endif + +#ifdef LIST_RC_PGUP + case LIST_RC_PGUP: + case LIST_RC_PGUP | BUTTON_REPEAT: + gui_synclist_select_previous_page(lists, SCREEN_REMOTE); + gui_synclist_draw(lists); + return true; +#endif + +#ifdef LIST_PGDN + case LIST_PGDN: + case LIST_PGDN | BUTTON_REPEAT: + gui_synclist_select_next_page(lists, SCREEN_MAIN); + gui_synclist_draw(lists); + return true; +#endif + +#ifdef LIST_RC_PGDN + case LIST_RC_PGDN: + case LIST_RC_PGDN | BUTTON_REPEAT: + gui_synclist_select_next_page(lists, SCREEN_REMOTE); + gui_synclist_draw(lists); + return true; +#endif + } + return false; +} diff --git a/apps/gui/list.h b/apps/gui/list.h new file mode 100644 index 0000000000..fd553f381c --- /dev/null +++ b/apps/gui/list.h @@ -0,0 +1,232 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 by Kévin FERRARE + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef _GUI_LIST_H_ +#define _GUI_LIST_H_ + +#include "config.h" +#include "icon.h" +#include "screen_access.h" + +#define SCROLLBAR_WIDTH 6 + +/* Key assignement */ +#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ + (CONFIG_KEYPAD == IRIVER_H300_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) +#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 + +#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) +#define LIST_RC_NEXT BUTTON_RC_RIGHT +#define LIST_RC_PREV BUTTON_RC_LEFT + +#elif CONFIG_KEYPAD == PLAYER_PAD +#define LIST_NEXT BUTTON_RIGHT +#define LIST_PREV BUTTON_LEFT +#define LIST_RC_NEXT BUTTON_RC_RIGHT +#define LIST_RC_PREV BUTTON_RC_LEFT + +#elif CONFIG_KEYPAD == ONDIO_PAD +#define LIST_NEXT BUTTON_DOWN +#define LIST_PREV BUTTON_UP + +#elif CONFIG_KEYPAD == GMINI100_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) +#endif + + +struct gui_list +{ + int nb_items; + int selected_item; + int start_item; /* the item that is displayed at the top of the screen */ + + void (*callback_get_item_icon)(int selected_item, ICON * icon); + char * (*callback_get_item_name)(int selected_item, char *buffer); + + struct screen * display; + int line_scroll_limit; +}; + +/* + * Initializes a scrolling list + * - gui_list : the list structure to initialize + * - callback_get_item_icon : pointer to a function that associates an icon + * to a given item number + * - callback_get_item_name : pointer to a function that associates a label + * to a given item number + */ +extern void gui_list_init(struct gui_list * gui_list, + void (*callback_get_item_icon)(int selected_item, ICON * icon), + char * (*callback_get_item_name)(int selected_item, char *buffer) + ); + +/* + * Sets the numburs of items the list can currently display + * note that the list's context like the currently pointed item is resetted + * - gui_list : the list structure to initialize + * - nb_items : the numbers of items you want + */ +extern void gui_list_set_nb_items(struct gui_list * gui_list, int nb_items); + +/* + * Puts the selection in the screen + * - gui_list : the list structure + * - put_from_end : if true, selection will be put as close from + * the end of the list as possible, else, it's + * from the beginning + */ +extern void gui_list_put_selection_in_screen(struct gui_list * gui_list, + bool put_from_end); + +/* + * Attach the scrolling list to a screen + * (The previous screen attachement is lost) + * - gui_list : the list structure + * - display : the screen to attach + */ +extern void gui_list_set_display(struct gui_list * gui_list, + struct screen * display); + +/* + * Gives the name of the selected object + * - gui_list : the list structure + * - buffer : a buffer which is filled with the name + */ +extern void gui_list_get_selected_item_name(struct gui_list * gui_list, + char *buffer); + +/* + * Gives the position of the selected item + * - gui_list : the list structure + * Returns the position + */ +extern int gui_list_get_selected_item_position(struct gui_list * gui_list); + +/* + * Selects an item in the list + * - gui_list : the list structure + * - item_number : the number of the item which will be selected + */ +extern void gui_list_select_item(struct gui_list * gui_list, int item_number); + +/* + * Draws the list on the attached screen + * - gui_list : the list structure + */ +extern void gui_list_draw(struct gui_list * gui_list); + +/* + * Selects the next item in the list + * (Item 0 gets selected if the end of the list is reached) + * - gui_list : the list structure + */ +extern void gui_list_select_next(struct gui_list * gui_list); + +/* + * Selects the previous item in the list + * (Last item in the list gets selected if the list beginning is reached) + * - gui_list : the list structure + */ +extern void gui_list_select_previous(struct gui_list * gui_list); + +/* + * Go to next page if any, else selects the last item in the list + * - gui_list : the list structure + * - nb_lines : the number of lines to try to move the cursor + */ +extern void gui_list_select_next_page(struct gui_list * gui_list, + int nb_lines); + +/* + * Go to previous page if any, else selects the first item in the list + * - gui_list : the list structure + * - nb_lines : the number of lines to try to move the cursor + */ +extern void gui_list_select_previous_page(struct gui_list * gui_list, + int nb_lines); + +/* + * Adds an item to the list (the callback will be asked for one more item) + * - gui_list : the list structure + */ +extern void gui_list_add_item(struct gui_list * gui_list); + +/* + * Removes an item to the list (the callback will be asked for one less item) + * - gui_list : the list structure + */ +extern void gui_list_del_item(struct gui_list * gui_list); + + +/* + * This part handles as many lists as there are connected screens + * (the api is similar to the ones above) + * The lists on the screens are synchronized ; + * theirs items and selected items are the same, but of course, + * they can be displayed on screens with different sizes + * The final aim is to let the programmer handle many lists in one + * function call and make its code independant from the number of screens + */ +struct gui_synclist +{ + struct gui_list gui_list[NB_SCREENS]; +}; + +extern void gui_synclist_init(struct gui_synclist * lists, + void (*callback_get_item_icon)(int selected_item, ICON * icon), + char * (*callback_get_item_name)(int selected_item, char *buffer) + ); +extern void gui_synclist_set_nb_items(struct gui_synclist * lists, int nb_items); +extern void gui_synclist_get_selected_item_name(struct gui_synclist * lists, + char *buffer); +extern int gui_synclist_get_selected_item_position(struct gui_synclist * lists); +extern void gui_synclist_draw(struct gui_synclist * lists); +extern void gui_synclist_select_item(struct gui_synclist * lists, + int item_number); +extern void gui_synclist_select_next(struct gui_synclist * lists); +extern void gui_synclist_select_previous(struct gui_synclist * lists); +extern void gui_synclist_select_next_page(struct gui_synclist * lists, + enum screen_type screen); +extern void gui_synclist_select_previous_page(struct gui_synclist * lists, + enum screen_type screen); +extern void gui_synclist_add_item(struct gui_synclist * lists); +extern void gui_synclist_del_item(struct gui_synclist * lists); +/* + * Do the action implied by the given button, + * returns true if something has been done, false otherwise + * - lists : the synchronized lists + * - button : the keycode of a pressed button + */ +extern bool 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 new file mode 100644 index 0000000000..9d5717f1a7 --- /dev/null +++ b/apps/gui/scrollbar.c @@ -0,0 +1,106 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) Markus Braun (2002), Kévin FERRARE (2005) + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" +#include "lcd.h" +#ifdef HAVE_LCD_BITMAP +#include "limits.h" +#include "scrollbar.h" +#include "screen_access.h" + +void gui_scrollbar_draw(struct screen * screen, int x, int y, + int width, int height, int items, + int min_shown, int max_shown, + enum orientation orientation) +{ + int min; + int max; + int inner_len; + int start; + int size; + + /* draw box */ + screen->drawrect(x, y, width, height); + + screen->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); + + /* clear edge pixels */ + screen->drawpixel(x, y); + screen->drawpixel((x + width - 1), y); + screen->drawpixel(x, (y + height - 1)); + screen->drawpixel((x + width - 1), (y + height - 1)); + + /* clear pixels in progress bar */ + screen->fillrect(x + 1, y + 1, width - 2, height - 2); + + /* min should be min */ + if(min_shown < max_shown) { + min = min_shown; + max = max_shown; + } + else { + min = max_shown; + max = min_shown; + } + + /* limit min and max */ + if(min < 0) + min = 0; + if(min > items) + min = items; + + if(max < 0) + max = 0; + if(max > items) + max = items; + + if (orientation == VERTICAL) + inner_len = height - 2; + else + inner_len = width - 2; + + /* avoid overflows */ + while (items > (INT_MAX / inner_len)) { + items >>= 1; + min >>= 1; + max >>= 1; + } + + /* calc start and end of the knob */ + if (items > 0 && items > (max - min)) { + size = inner_len * (max - min) / items; + if (size == 0) { /* width of knob is null */ + size = 1; + start = (inner_len - 1) * min / items; + } else { + start = (inner_len - size) * min / (items - (max - min)); + } + } else { /* if null draw full bar */ + size = inner_len; + start = 0; + } + + screen->set_drawmode(DRMODE_SOLID); + + if(orientation == VERTICAL) + screen->fillrect(x + 1, y + start + 1, width - 2, size); + else + screen->fillrect(x + start + 1, y + 1, size, height - 2); +} +#endif /* HAVE_LCD_BITMAP */ diff --git a/apps/gui/scrollbar.h b/apps/gui/scrollbar.h new file mode 100644 index 0000000000..51c08352ba --- /dev/null +++ b/apps/gui/scrollbar.h @@ -0,0 +1,49 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 Kévin FERRARE + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef _GUI_SCROLLBAR_H_ +#define _GUI_SCROLLBAR_H_ +#include +#ifdef HAVE_LCD_BITMAP + +struct screen; + +enum orientation { + VERTICAL, + HORIZONTAL +}; + +/* + * Draws a scrollbar on the given screen + * - screen : the screen to put the scrollbar on + * - x : x start position of the scrollbar + * - y : y start position of the scrollbar + * - width : you won't guess =(^o^)= + * - height : I won't tell you either ! + * - items : total number of items on the screen + * - min_shown : index of the starting item on the screen + * - max_shown : index of the last item on the screen + * - orientation : either VERTICAL or HORIZONTAL + */ +extern void gui_scrollbar_draw(struct screen * screen, int x, int y, + int width, int height, int items, + int min_shown, int max_shown, + enum orientation orientation); +#endif /* HAVE_LCD_BITMAP */ +#endif /* _GUI_SCROLLBAR_H_ */ diff --git a/apps/gui/splash.c b/apps/gui/splash.c new file mode 100644 index 0000000000..a3cbb198df --- /dev/null +++ b/apps/gui/splash.c @@ -0,0 +1,216 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) Daniel Stenberg (2002), Kévin FERRARE (2005) + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "stdarg.h" +#include "string.h" +#include "stdio.h" +#include "kernel.h" +#include "screen_access.h" + + +#ifdef HAVE_LCD_BITMAP + +#define SPACE 3 /* pixels between words */ +#define MAXLETTERS 128 /* 16*8 */ +#define MAXLINES 10 + +#else + +#define SPACE 1 /* one letter space */ +#define MAXLETTERS 22 /* 11 * 2 */ +#define MAXLINES 2 + +#endif + + +void internal_splash(struct screen * screen, + bool center, const char *fmt, va_list ap) +{ + char *next; + char *store=NULL; + int x=0; + int y=0; + int w, h; + unsigned char splash_buf[MAXLETTERS]; + unsigned char widths[MAXLINES]; + int line=0; + bool first=true; +#ifdef HAVE_LCD_BITMAP + int maxw=0; +#endif + +#ifdef HAVE_LCD_CHARCELLS + screen->double_height (false); +#endif + vsnprintf( splash_buf, sizeof(splash_buf), fmt, ap ); + + if(center) { + /* first a pass to measure sizes */ + next = strtok_r(splash_buf, " ", &store); + while (next) { +#ifdef HAVE_LCD_BITMAP + screen->getstringsize(next, &w, &h); +#else + w = strlen(next); + h = 1; /* store height in characters */ +#endif + if(!first) { + if(x+w> screen->width) { + /* Too wide, wrap */ + y+=h; + line++; + if((y > (screen->height-h)) || (line > screen->nb_lines)) + /* STOP */ + break; + x=0; + first=true; + } + } + else + first = false; + + /* think of it as if the text was written here at position x,y + being w pixels/chars wide and h high */ + + x += w+SPACE; + widths[line]=x-SPACE; /* don't count the trailing space */ +#ifdef HAVE_LCD_BITMAP + /* store the widest line */ + if(widths[line]>maxw) + maxw = widths[line]; +#endif + next = strtok_r(NULL, " ", &store); + } + +#ifdef HAVE_LCD_BITMAP + /* Start displaying the message at position y. The reason for the + added h here is that it isn't added until the end of lines in the + loop above and we always break the loop in the middle of a line. */ + y = (screen->height - (y+h) )/2; +#else + y = 0; /* vertical center on 2 lines would be silly */ +#endif + first=true; + + /* Now recreate the string again since the strtok_r() above has ruined + the one we already have! Here's room for improvements! */ + vsnprintf( splash_buf, sizeof(splash_buf), fmt, ap ); + } + va_end( ap ); + + if(center) + { + x = (screen->width-widths[0])/2; + if(x < 0) + x = 0; + } + +#ifdef HAVE_LCD_BITMAP + /* If we center the display, then just clear the box we need and put + a nice little frame and put the text in there! */ + if(center && (y > 2)) { + int xx = (screen->width-maxw)/2 - 2; + /* The new graphics routines handle clipping, so no need to check */ +#if LCD_DEPTH > 1 +#ifdef HAVE_LCD_COLOR + screen->set_background((struct rgb){LCD_MAX_RED-1, LCD_MAX_GREEN-1, + LCD_MAX_BLUE-1}); +#else + if(screen->depth>1) + screen->set_background(LCD_MAX_LEVEL-1); +#endif +#endif + screen->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); + screen->fillrect(xx, y-2, maxw+4, screen->height-y*2+4); + screen->set_drawmode(DRMODE_SOLID); + screen->drawrect(xx, y-2, maxw+4, screen->height-y*2+4); + } + else +#endif + screen->clear_display(); + line=0; + next = strtok_r(splash_buf, " ", &store); + while (next) { +#ifdef HAVE_LCD_BITMAP + screen->getstringsize(next, &w, &h); +#else + w = strlen(next); + h = 1; +#endif + if(!first) { + if(x+w> screen->width) { + /* too wide */ + y+=h; + line++; /* goto next line */ + first=true; + if(y > (screen->height-h)) + /* STOP */ + break; + if(center) { + x = (screen->width-widths[line])/2; + if(x < 0) + x = 0; + } + else + x=0; + } + } + else + first=false; +#ifdef HAVE_LCD_BITMAP + screen->putsxy(x, y, next); +#else + screen->puts(x, y, next); +#endif + x += w+SPACE; /* pixels space! */ + next = strtok_r(NULL, " ", &store); + } + +#if defined(HAVE_LCD_BITMAP) && (LCD_DEPTH > 1) + if(screen->depth > 1) + screen->set_background(LCD_WHITE); +#endif +#if defined(HAVE_LCD_BITMAP) || defined(SIMULATOR) + screen->update(); +#endif +} + +void gui_splash(struct screen * screen, int ticks, + bool center, const char *fmt, ...) +{ + va_list ap; + va_start( ap, fmt ); + internal_splash(screen, center, fmt, ap); + va_end( ap ); + + if(ticks) + sleep(ticks); +} + +void gui_syncsplash(int ticks, bool center, const char *fmt, ...) +{ + va_list ap; + int i; + va_start( ap, fmt ); + for(i=0;i ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 by Kévin FERRARE + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* + * Puts a splash message on the given screen for a given period + * - screen : the screen to put the splash on + * - ticks : how long the splash is displayed (in rb ticks) + * - center : FALSE means left-justified, TRUE means + * horizontal and vertical center + * - fmt : what to say *printf style + */ +extern void gui_splash(struct screen * screen, int ticks, + bool center, const char *fmt, ...); + +/* + * Puts a splash message on all the screens for a given period + * - ticks : how long the splash is displayed (in rb ticks) + * - center : FALSE means left-justified, TRUE means + * horizontal and vertical center + * - fmt : what to say *printf style + */ +extern void gui_syncsplash(int ticks, bool center, + const char *fmt, ...); diff --git a/apps/gui/statusbar.c b/apps/gui/statusbar.c new file mode 100644 index 0000000000..5ddc194610 --- /dev/null +++ b/apps/gui/statusbar.c @@ -0,0 +1,508 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) Robert E. Hak (2002), Linus Nielsen Feltzing (2002), Kévin FERRARE (2005) + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" +#include "screen_access.h" +#include "lcd.h" +#include "font.h" +#include "kernel.h" +#include "string.h" /* for memcmp oO*/ +#include "sprintf.h" +#include "sound.h" +#include "power.h" +#include "settings.h" +#include "icons.h" +#include "powermgmt.h" +#include "button.h" + +#include "status.h" /* needed for battery_state global var */ +#include "wps.h" /* for keys_locked */ +#include "statusbar.h" + + +/* FIXME: should be removed from icon.h to avoid redefinition, + but still needed for compatibility with old system */ +#define STATUSBAR_X_POS 0 +#define STATUSBAR_Y_POS 0 /* MUST be a multiple of 8 */ +#define STATUSBAR_HEIGHT 8 +#define STATUSBAR_BATTERY_X_POS 0 +#define STATUSBAR_BATTERY_WIDTH 18 +#define STATUSBAR_PLUG_X_POS STATUSBAR_X_POS + \ + STATUSBAR_BATTERY_WIDTH +2 +#define STATUSBAR_PLUG_WIDTH 7 +#define STATUSBAR_VOLUME_X_POS STATUSBAR_X_POS + \ + STATUSBAR_BATTERY_WIDTH + \ + STATUSBAR_PLUG_WIDTH +2+2 +#define STATUSBAR_VOLUME_WIDTH 16 +#define STATUSBAR_PLAY_STATE_X_POS STATUSBAR_X_POS + \ + STATUSBAR_BATTERY_WIDTH + \ + STATUSBAR_PLUG_WIDTH + \ + STATUSBAR_VOLUME_WIDTH+2+2+2 +#define STATUSBAR_PLAY_STATE_WIDTH 7 +#define STATUSBAR_PLAY_MODE_X_POS STATUSBAR_X_POS + \ + STATUSBAR_BATTERY_WIDTH + \ + STATUSBAR_PLUG_WIDTH + \ + STATUSBAR_VOLUME_WIDTH + \ + STATUSBAR_PLAY_STATE_WIDTH + \ + 2+2+2+2 +#define STATUSBAR_PLAY_MODE_WIDTH 7 +#define STATUSBAR_SHUFFLE_X_POS STATUSBAR_X_POS + \ + STATUSBAR_BATTERY_WIDTH + \ + STATUSBAR_PLUG_WIDTH + \ + STATUSBAR_VOLUME_WIDTH + \ + STATUSBAR_PLAY_STATE_WIDTH + \ + STATUSBAR_PLAY_MODE_WIDTH + \ + 2+2+2+2+2 +#define STATUSBAR_SHUFFLE_WIDTH 7 +#define STATUSBAR_LOCK_X_POS STATUSBAR_X_POS + \ + STATUSBAR_BATTERY_WIDTH + \ + STATUSBAR_PLUG_WIDTH + \ + STATUSBAR_VOLUME_WIDTH + \ + STATUSBAR_PLAY_STATE_WIDTH + \ + STATUSBAR_PLAY_MODE_WIDTH + \ + STATUSBAR_SHUFFLE_WIDTH + \ + 2+2+2+2+2+2 +#define STATUSBAR_LOCK_WIDTH 5 +#define STATUSBAR_DISK_WIDTH 12 +#define STATUSBAR_DISK_X_POS(statusbar_width) statusbar_width - \ + STATUSBAR_DISK_WIDTH +#define STATUSBAR_TIME_X_END(statusbar_width) statusbar_width-1 + +void gui_statusbar_init(struct gui_statusbar * bar) +{ + bar->last_volume = -1; /* -1 means "first update ever" */ + bar->battery_icon_switch_tick = 0; +#ifdef HAVE_USB_POWER + bar->battery_charge_step = 0; +#endif +} + +void gui_statusbar_set_screen(struct gui_statusbar * bar, + struct screen * display) +{ + bar->display = display; + gui_statusbar_draw(bar, false); +} + +void gui_statusbar_draw(struct gui_statusbar * bar, bool force_redraw) +{ +#ifdef HAVE_LCD_BITMAP + if(!global_settings.statusbar) + return; +#endif + + struct screen * display = bar->display; + +#ifdef HAVE_LCD_BITMAP + struct tm* tm; /* For Time */ +#else + (void)force_redraw; /* players always "redraw" */ +#endif + + bar->info.volume = sound_val2phys(SOUND_VOLUME, global_settings.volume); + bar->info.inserted = charger_inserted(); + bar->info.battlevel = battery_level(); + bar->info.battery_safe = battery_level_safe(); + +#ifdef HAVE_LCD_BITMAP + tm = get_time(); + bar->info.hour = tm->tm_hour; + bar->info.minute = tm->tm_min; + bar->info.shuffle = global_settings.playlist_shuffle; +#if CONFIG_KEYPAD == IRIVER_H100_PAD + bar->info.keylock = button_hold(); +#else + bar->info.keylock = keys_locked; +#endif + bar->info.repeat = global_settings.repeat_mode; + bar->info.playmode = current_playmode(); +#if CONFIG_LED == LED_VIRTUAL + bar->info.led = led_read(HZ/2); /* delay should match polling interval */ +#endif +#ifdef HAVE_USB_POWER + bar->info.usb_power = usb_powered(); +#endif + + /* only redraw if forced to, or info has changed */ + if (force_redraw || + bar->info.inserted || + !bar->info.battery_safe || + bar->info.redraw_volume || + memcmp(&(bar->info), &(bar->lastinfo), sizeof(struct status_info))) + { + display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); + display->fillrect(0,0,display->width,8); + display->set_drawmode(DRMODE_SOLID); + +#else + + /* players always "redraw" */ + { +#endif + +#ifdef HAVE_CHARGING + if (bar->info.inserted) { + battery_state = true; +#if defined(HAVE_CHARGE_CTRL) || CONFIG_BATTERY == BATT_LIION2200 + /* zero battery run time if charging */ + if (charge_state > 0) { + global_settings.runtime = 0; + lasttime = current_tick; + } + + /* animate battery if charging */ + if ((charge_state == 1) || + (charge_state == 2)) { +#else + global_settings.runtime = 0; + lasttime = current_tick; + { +#endif + /* animate in three steps (34% per step for a better look) */ + bar->info.battlevel = bar->battery_charge_step * 34; + if (bar->info.battlevel > 100) + bar->info.battlevel = 100; + if(TIME_AFTER(current_tick, bar->battery_icon_switch_tick)) { + bar->battery_charge_step=(bar->battery_charge_step+1)%4; + bar->battery_icon_switch_tick = current_tick + HZ; + } + } + } + else +#endif /* HAVE_CHARGING */ + { + if (bar->info.battery_safe) + battery_state = true; + else { + /* blink battery if level is low */ + if(TIME_AFTER(current_tick, bar->battery_icon_switch_tick) && + (bar->info.battlevel > -1)) { + bar->battery_icon_switch_tick = current_tick+HZ; + battery_state = !battery_state; + } + } + } +#ifdef HAVE_LCD_BITMAP + if (battery_state) + gui_statusbar_icon_battery(display, bar->info.battlevel); + /* draw power plug if charging */ + if (bar->info.inserted) + display->mono_bitmap(bitmap_icons_7x8[Icon_Plug], + STATUSBAR_PLUG_X_POS, + STATUSBAR_Y_POS, STATUSBAR_PLUG_WIDTH, + STATUSBAR_HEIGHT); +#ifdef HAVE_USB_POWER + else if (bar->info.usb_power) + display->mono_bitmap(bitmap_icons_7x8[Icon_USBPlug], + STATUSBAR_PLUG_X_POS, + STATUSBAR_Y_POS, STATUSBAR_PLUG_WIDTH, + STATUSBAR_HEIGHT); +#endif + + bar->info.redraw_volume = gui_statusbar_icon_volume(bar, + bar->info.volume); + gui_statusbar_icon_play_state(display, current_playmode() + + Icon_Play); + switch (bar->info.repeat) { +#ifdef AB_REPEAT_ENABLE + case REPEAT_AB: + gui_statusbar_icon_play_mode(display, Icon_RepeatAB); + break; +#endif + + case REPEAT_ONE: + gui_statusbar_icon_play_mode(display, Icon_RepeatOne); + break; + + case REPEAT_ALL: + case REPEAT_SHUFFLE: + gui_statusbar_icon_play_mode(display, Icon_Repeat); + break; + } + if (bar->info.shuffle) + gui_statusbar_icon_shuffle(display); + if (bar->info.keylock) + gui_statusbar_icon_lock(display); +#ifdef HAVE_RTC + gui_statusbar_time(display, bar->info.hour, bar->info.minute); +#endif +#if CONFIG_LED == LED_VIRTUAL + if (bar->info.led) + statusbar_led(); +#endif + display->update_rect(0, 0, display->width, STATUSBAR_HEIGHT); + bar->lastinfo = bar->info; +#endif + } + + +#ifndef HAVE_LCD_BITMAP + if (bar->info.battlevel > -1) + display->icon(ICON_BATTERY, battery_state); + display->icon(ICON_BATTERY_1, bar->info.battlevel > 25); + display->icon(ICON_BATTERY_2, bar->info.battlevel > 50); + display->icon(ICON_BATTERY_3, bar->info.battlevel > 75); + + display->icon(ICON_VOLUME, true); + display->icon(ICON_VOLUME_1, bar->info.volume > 10); + display->icon(ICON_VOLUME_2, bar->info.volume > 30); + display->icon(ICON_VOLUME_3, bar->info.volume > 50); + display->icon(ICON_VOLUME_4, bar->info.volume > 70); + display->icon(ICON_VOLUME_5, bar->info.volume > 90); + + display->icon(ICON_PLAY, current_playmode() == STATUS_PLAY); + display->icon(ICON_PAUSE, current_playmode() == STATUS_PAUSE); + + display->icon(ICON_REPEAT, global_settings.repeat_mode != REPEAT_OFF); + display->icon(ICON_1, global_settings.repeat_mode == REPEAT_ONE); + + display->icon(ICON_RECORD, record); + display->icon(ICON_AUDIO, audio); + display->icon(ICON_PARAM, param); + display->icon(ICON_USB, usb); +#endif +} + +#ifdef HAVE_LCD_BITMAP +/* from icon.c */ +/* + * Print battery icon to status bar + */ +void gui_statusbar_icon_battery(struct screen * display, int percent) +{ + int fill; + char buffer[5]; + unsigned int width, height; + + /* fill battery */ + fill = percent; + if (fill < 0) + fill = 0; + if (fill > 100) + fill = 100; + +#if defined(HAVE_CHARGE_CTRL) && !defined(SIMULATOR) /* Rec v1 target only */ + /* show graphical animation when charging instead of numbers */ + if ((global_settings.battery_display) && + (charge_state != 1) && + (percent > -1)) { +#else /* all others */ + if (global_settings.battery_display && (percent > -1)) { +#endif + /* Numeric display */ + display->setfont(FONT_SYSFIXED); + snprintf(buffer, sizeof(buffer), "%3d", fill); + display->getstringsize(buffer, &width, &height); + if (height <= STATUSBAR_HEIGHT) + display->putsxy(STATUSBAR_BATTERY_X_POS + + STATUSBAR_BATTERY_WIDTH / 2 + - width/2, STATUSBAR_Y_POS, buffer); + display->setfont(FONT_UI); + + } + else { + /* draw battery */ + display->drawrect(STATUSBAR_BATTERY_X_POS, STATUSBAR_Y_POS, 17, 7); + display->vline(STATUSBAR_BATTERY_X_POS + 17, STATUSBAR_Y_POS + 2, + STATUSBAR_Y_POS + 4); + + fill = fill * 15 / 100; + display->fillrect(STATUSBAR_BATTERY_X_POS + 1, STATUSBAR_Y_POS + 1, + fill, 5); + } + + if (percent == -1) { + display->setfont(FONT_SYSFIXED); + display->putsxy(STATUSBAR_BATTERY_X_POS + STATUSBAR_BATTERY_WIDTH / 2 + - 4, STATUSBAR_Y_POS, "?"); + display->setfont(FONT_UI); + } +} + +/* + * Print volume gauge to status bar + */ +bool gui_statusbar_icon_volume(struct gui_statusbar * bar, int percent) +{ + int i; + int volume; + int vol; + char buffer[4]; + unsigned int width, height; + bool needs_redraw = false; + int type = global_settings.volume_type; + struct screen * display=bar->display; + + volume = percent; + if (volume < 0) + volume = 0; + if (volume > 100) + volume = 100; + + if (volume == 0) { + display->mono_bitmap(bitmap_icons_7x8[Icon_Mute], + STATUSBAR_VOLUME_X_POS + STATUSBAR_VOLUME_WIDTH / 2 - 4, + STATUSBAR_Y_POS, 7, STATUSBAR_HEIGHT); + } + else { + /* We want to redraw the icon later on */ + if (bar->last_volume != volume && bar->last_volume >= 0) { + bar->volume_icon_switch_tick = current_tick + HZ; + } + + /* If the timeout hasn't yet been reached, we show it numerically + and tell the caller that we want to be called again */ + if (TIME_BEFORE(current_tick,bar->volume_icon_switch_tick)) { + type = 1; + needs_redraw = true; + } + + /* display volume level numerical? */ + if (type) + { + display->setfont(FONT_SYSFIXED); + snprintf(buffer, sizeof(buffer), "%2d", percent); + display->getstringsize(buffer, &width, &height); + if (height <= STATUSBAR_HEIGHT) + { + display->putsxy(STATUSBAR_VOLUME_X_POS + + STATUSBAR_VOLUME_WIDTH / 2 + - width/2, STATUSBAR_Y_POS, buffer); + } + display->setfont(FONT_UI); + } else { + /* display volume bar */ + vol = volume * 14 / 100; + for(i=0; i < vol; i++) { + display->vline(STATUSBAR_VOLUME_X_POS + i, + STATUSBAR_Y_POS + 6 - i / 2, + STATUSBAR_Y_POS + 6); + } + } + } + bar->last_volume = volume; + + return needs_redraw; +} + +/* + * Print play state to status bar + */ +void gui_statusbar_icon_play_state(struct screen * display, int state) +{ + display->mono_bitmap(bitmap_icons_7x8[state], STATUSBAR_PLAY_STATE_X_POS, + STATUSBAR_Y_POS, STATUSBAR_PLAY_STATE_WIDTH, + STATUSBAR_HEIGHT); +} + +/* + * Print play mode to status bar + */ +void gui_statusbar_icon_play_mode(struct screen * display, int mode) +{ + display->mono_bitmap(bitmap_icons_7x8[mode], STATUSBAR_PLAY_MODE_X_POS, + STATUSBAR_Y_POS, STATUSBAR_PLAY_MODE_WIDTH, + STATUSBAR_HEIGHT); +} + +/* + * Print shuffle mode to status bar + */ +void gui_statusbar_icon_shuffle(struct screen * display) +{ + display->mono_bitmap(bitmap_icons_7x8[Icon_Shuffle], + STATUSBAR_SHUFFLE_X_POS, STATUSBAR_Y_POS, + STATUSBAR_SHUFFLE_WIDTH, STATUSBAR_HEIGHT); +} + +/* + * Print lock when keys are locked + */ +void gui_statusbar_icon_lock(struct screen * display) +{ + display->mono_bitmap(bitmap_icons_5x8[Icon_Lock], STATUSBAR_LOCK_X_POS, + STATUSBAR_Y_POS, 5, 8); +} + +#if CONFIG_LED == LED_VIRTUAL +/* + * no real LED: disk activity in status bar + */ +void gui_statusbar_led(struct screen * display) +{ + display->mono_bitmap(bitmap_icon_disk, STATUSBAR_DISK_X_POS, + STATUSBAR_Y_POS, STATUSBAR_DISK_WIDTH(screen->width), + STATUSBAR_HEIGHT); +} +#endif + + +#ifdef HAVE_RTC +/* + * Print time to status bar + */ +void gui_statusbar_time(struct screen * display, int hour, int minute) +{ + unsigned char buffer[6]; + unsigned int width, height; + if ( hour >= 0 && + hour <= 23 && + minute >= 0 && + minute <= 59 ) { + if ( global_settings.timeformat ) { /* 12 hour clock */ + hour %= 12; + if ( hour == 0 ) { + hour += 12; + } + } + snprintf(buffer, sizeof(buffer), "%02d:%02d", hour, minute); + } + else { + strncpy(buffer, "--:--", sizeof buffer); + } + display->setfont(FONT_SYSFIXED); + display->getstringsize(buffer, &width, &height); + if (height <= STATUSBAR_HEIGHT) { + display->putsxy(STATUSBAR_TIME_X_END(display->width) - width, + STATUSBAR_Y_POS, buffer); + } + display->setfont(FONT_UI); + +} +#endif + +#endif /* HAVE_LCD_BITMAP */ + +void gui_syncstatusbar_init(struct gui_syncstatusbar * bars) +{ + int i; + for(i = 0;i < NB_SCREENS;++i) { + gui_statusbar_init( &(bars->statusbars[i]) ); + gui_statusbar_set_screen( &(bars->statusbars[i]), &(screens[i]) ); + } +} + +void gui_syncstatusbar_draw(struct gui_syncstatusbar * bars, + bool force_redraw) +{ + int i; + for(i = 0;i < NB_SCREENS;++i) { + gui_statusbar_draw( &(bars->statusbars[i]), force_redraw ); + } +} diff --git a/apps/gui/statusbar.h b/apps/gui/statusbar.h new file mode 100644 index 0000000000..434d679e29 --- /dev/null +++ b/apps/gui/statusbar.h @@ -0,0 +1,107 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 by Kévin FERRARE + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef _GUI_STATUSBAR_H_ +#define _GUI_STATUSBAR_H_ + +#include "config.h" +#include "status.h" + +struct status_info { + int battlevel; + int volume; + int hour; + int minute; + int playmode; + int repeat; + bool inserted; + bool shuffle; + bool keylock; + bool battery_safe; + bool redraw_volume; /* true if the volume gauge needs updating */ +#if CONFIG_LED == LED_VIRTUAL + bool led; /* disk LED simulation in the status bar */ +#endif +#ifdef HAVE_USB_POWER + bool usb_power; +#endif +}; + +struct gui_statusbar +{ + /* Volume icon stuffs */ + long volume_icon_switch_tick; + int last_volume; + + long battery_icon_switch_tick; + +#ifdef HAVE_CHARGING + int battery_charge_step; +#endif + + struct status_info info; + struct status_info lastinfo; + + struct screen * display; +}; + +/* + * Initializes a status bar + * - bar : the bar to initialize + */ +extern void gui_statusbar_init(struct gui_statusbar * bar); + +/* + * Attach the status bar to a screen + * (The previous screen attachement is lost) + * - bar : the statusbar structure + * - display : the screen to attach + */ +extern void gui_statusbar_set_screen(struct gui_statusbar * bar, struct screen * display); + +/* + * Draws the status bar on the attached screen + * - bar : the statusbar structure + */ +extern void gui_statusbar_draw(struct gui_statusbar * bar, bool force_redraw); + +void gui_statusbar_icon_battery(struct screen * display, int percent); +bool gui_statusbar_icon_volume(struct gui_statusbar * bar, int percent); +void gui_statusbar_icon_play_state(struct screen * display, int state); +void gui_statusbar_icon_play_mode(struct screen * display, int mode); +void gui_statusbar_icon_shuffle(struct screen * display); +void gui_statusbar_icon_lock(struct screen * display); +#if CONFIG_LED == LED_VIRTUAL +void gui_statusbar_led(struct screen * display); +#endif + +#ifdef HAVE_RTC +void gui_statusbar_time(struct screen * display, int hour, int minute); +#endif + + +struct gui_syncstatusbar +{ + struct gui_statusbar statusbars[NB_SCREENS]; +}; + +extern void gui_syncstatusbar_init(struct gui_syncstatusbar * bars); +extern void gui_syncstatusbar_draw(struct gui_syncstatusbar * bars, bool force_redraw); + +#endif /*_GUI_STATUSBAR_H_*/ diff --git a/apps/status.c b/apps/status.c index ca4b21833e..9f43c6551d 100644 --- a/apps/status.c +++ b/apps/status.c @@ -43,12 +43,12 @@ #endif #include "usb.h" -static enum playmode ff_mode; +enum playmode ff_mode; -static long switch_tick; -static bool battery_state = true; +long switch_tick; +bool battery_state = true; #ifdef HAVE_CHARGING -static int battery_charge_step = 0; +int battery_charge_step = 0; #endif struct status_info { @@ -123,10 +123,10 @@ int current_playmode(void) } #if defined(HAVE_LCD_CHARCELLS) -static bool record = false; -static bool audio = false; -static bool param = false; -static bool usb = false; +bool record = false; +bool audio = false; +bool param = false; +bool usb = false; void status_set_record(bool b) { diff --git a/apps/status.h b/apps/status.h index 0d8c80d7a8..29316f98b1 100644 --- a/apps/status.h +++ b/apps/status.h @@ -19,6 +19,21 @@ #ifndef _STATUS_H #define _STATUS_H +extern enum playmode ff_mode; + +extern long switch_tick; +extern bool battery_state; +#ifdef HAVE_CHARGING +extern int battery_charge_step; +#endif + +#if defined(HAVE_LCD_CHARCELLS) +extern bool record; +extern bool audio; +extern bool param; +extern bool usb; +#endif + enum playmode { STATUS_PLAY, @@ -33,10 +48,12 @@ enum playmode void status_init(void); void status_set_ffmode(enum playmode mode); enum playmode status_get_ffmode(void); +int current_playmode(void); + #ifdef HAVE_LCD_BITMAP bool statusbar(bool state); #if CONFIG_KEYPAD == RECORDER_PAD -void buttonbar_set(const char* caption1, const char* caption2, +void buttonbar_set(const char* caption1, const char* caption2, const char* caption3); void buttonbar_unset(void); bool buttonbar_isset(void); diff --git a/apps/tree.c b/apps/tree.c index 8d68814315..7d4ee7f703 100644 --- a/apps/tree.c +++ b/apps/tree.c @@ -63,6 +63,12 @@ #include "rtc.h" #include "dircache.h" +/* gui api */ +#include "list.h" +#include "statusbar.h" +#include "splash.h" +#include "buttonbar.h" + #ifdef HAVE_LCD_BITMAP #include "widgets.h" #endif @@ -99,6 +105,14 @@ const struct filetype filetypes[] = { #endif /* #ifndef SIMULATOR */ }; +struct gui_synclist tree_lists; + +/* I put it here because other files doesn't use it yet, + * but should be elsewhere since it will be used mostly everywhere */ +struct gui_syncstatusbar statusbars; +#ifdef HAS_BUTTONBAR +struct gui_buttonbar tree_buttonbar; +#endif static struct tree_context tc; bool boot_changed = false; @@ -112,17 +126,77 @@ static bool reload_dir = false; static bool start_wps = false; static bool dirbrowse(void); -static int curr_context = false; +static int curr_context = false;/* id3db or tree*/ + +/* + * removes the extension of filename (if it doesn't start with a .) + * puts the result in buffer + */ +char * strip_extension(char * filename, char * buffer) +{ + int dotpos; + char * dot=strrchr(filename, '.'); + if(dot!=0 && filename[0]!='.') + { + dotpos = dot-filename; + strncpy(buffer, filename, dotpos); + buffer[dotpos]='\0'; + return(buffer); + } + else + return(filename); +} +char * tree_get_filename(int selected_item, char *buffer) +{ + char *name; + int attr=0; + bool id3db = *tc.dirfilter == SHOW_ID3DB; + if (id3db) { + name = ((char**)tc.dircache)[selected_item * tc.dentry_size]; + } + else { + struct entry* dc = tc.dircache; + struct entry* e = &dc[selected_item]; + name = e->name; + attr = e->attr; + } + /* if any file filter is on, and if it's not a directory, + * strip the extension */ + + if ( (*tc.dirfilter != SHOW_ID3DB) && !(attr & ATTR_DIRECTORY) + && (*tc.dirfilter != SHOW_ALL) ) + { + return(strip_extension(name, buffer)); + } + return(name); +} + + +void tree_get_fileicon(int selected_item, ICON * icon) +{ + bool id3db = *tc.dirfilter == SHOW_ID3DB; + if (id3db) { + *icon = db_get_icon(&tc); + } + else { + struct entry* dc = tc.dircache; + struct entry* e = &dc[selected_item]; + *icon = filetype_get_icon(e->attr); + } +} bool check_rockboxdir(void) { DIR *dir = opendir(ROCKBOX_DIR); if(!dir) { - lcd_clear_display(); - splash(HZ*2, true, str(LANG_NO_ROCKBOX_DIR)); - lcd_clear_display(); - splash(HZ*2, true, str(LANG_INSTALLATION_INCOMPLETE)); + int i; + for(i = 0;i < NB_SCREENS;++i) + screens[i].clear_display(); + gui_syncsplash(HZ*2, true, str(LANG_NO_ROCKBOX_DIR)); + for(i = 0;i < NB_SCREENS;++i) + screens[i].clear_display(); + gui_syncsplash(HZ*2, true, str(LANG_INSTALLATION_INCOMPLETE)); return false; } closedir(dir); @@ -131,16 +205,28 @@ bool check_rockboxdir(void) void browse_root(void) { + /* essential to all programs that wants to display things */ + screen_access_init(); + filetype_init(); check_rockboxdir(); strcpy(tc.currdir, "/"); + #ifdef HAVE_LCD_CHARCELLS - lcd_double_height(false); + int i; + for(i = 0;i < NB_SCREENS;++i) + screens[i].double_height(false); #endif +#ifdef HAS_BUTTONBAR + gui_buttonbar_init(&tree_buttonbar); + /* since archos only have one screen, no need to create more than that */ + gui_buttonbar_set_display(&tree_buttonbar, &(screens[SCREEN_MAIN]) ); +#endif + gui_syncstatusbar_init(&statusbars); + gui_synclist_init(&tree_lists, &tree_get_fileicon, &tree_get_filename); #ifndef SIMULATOR dirbrowse(); - #else if (!dirbrowse()) { DEBUGF("No filesystem found. Have you forgotten to create it?\n"); @@ -159,126 +245,35 @@ struct tree_context* tree_get_context(void) return &tc; } -#ifdef HAVE_LCD_BITMAP - -/* pixel margins */ -#define MARGIN_X (global_settings.scrollbar && \ - tc.filesindir > tree_max_on_screen ? SCROLLBAR_WIDTH : 0) + \ - CURSOR_WIDTH + (global_settings.show_icons && ICON_WIDTH > 0 ? ICON_WIDTH :0) -#define MARGIN_Y (global_settings.statusbar ? STATUSBAR_HEIGHT : 0) - -/* position the entry-list starts at */ -#define LINE_X 0 -#define LINE_Y (global_settings.statusbar ? 1 : 0) - -#define CURSOR_X (global_settings.scrollbar && \ - tc.filesindir > tree_max_on_screen ? 1 : 0) -#define CURSOR_Y 0 /* the cursor is not positioned in regard to - the margins, so this is the amount of lines - we add to the cursor Y position to position - it on a line */ -#define CURSOR_WIDTH (global_settings.invert_cursor ? 0 : 4) - -#define ICON_WIDTH 6 - -#define SCROLLBAR_X 0 -#define SCROLLBAR_Y lcd_getymargin() -#define SCROLLBAR_WIDTH 6 - -#else /* HAVE_LCD_BITMAP */ - -#define TREE_MAX_ON_SCREEN 2 -#define TREE_MAX_LEN_DISPLAY 11 /* max length that fits on screen */ -#define LINE_X 2 /* X position the entry-list starts at */ -#define LINE_Y 0 /* Y position the entry-list starts at */ - -#define CURSOR_X 0 -#define CURSOR_Y 0 /* not really used for players */ - -#endif /* HAVE_LCD_BITMAP */ - /* talkbox hovering delay, to avoid immediate disk activity */ #define HOVER_DELAY (HZ/2) - -static void showfileline(int line, char* name, int attr, bool scroll) +/* + * Returns the position of a given file in the current directory + * returns -1 if not found + */ +int tree_get_file_position(char * filename) { - int xpos = LINE_X; - char* dotpos = NULL; - -#ifdef HAVE_LCD_CHARCELLS - if (!global_settings.show_icons) - xpos--; -#endif - - /* if any file filter is on, strip the extension */ - if (*tc.dirfilter != SHOW_ID3DB && - *tc.dirfilter != SHOW_ALL && - !(attr & ATTR_DIRECTORY)) + int i; + /* use lastfile to determine the selected item (default=0) */ + for (i=0; i < tc.filesindir; i++) { - dotpos = strrchr(name, '.'); - if (dotpos) { - *dotpos = 0; - } + struct entry* dc = tc.dircache; + struct entry* e = &dc[i]; + if (!strcasecmp(e->name, filename)) + return(i); } - - if(scroll) { -#ifdef HAVE_LCD_BITMAP - lcd_setfont(FONT_UI); - if (global_settings.invert_cursor) - lcd_puts_scroll_style(xpos, line, name, STYLE_INVERT); - else -#endif - lcd_puts_scroll(xpos, line, name); - } else - lcd_puts(xpos, line, name); - - /* Restore the dot before the extension if it was removed */ - if (dotpos) - *dotpos = '.'; -} - -#ifdef HAVE_LCD_BITMAP -static int recalc_screen_height(void) -{ - int fw, fh; - int height = LCD_HEIGHT; - - lcd_setfont(FONT_UI); - lcd_getstringsize("A", &fw, &fh); - if(global_settings.statusbar) - height -= STATUSBAR_HEIGHT; - -#if CONFIG_KEYPAD == RECORDER_PAD - if(global_settings.buttonbar) - height -= BUTTONBAR_HEIGHT; -#endif - - return height / fh; + return(-1);/* no file can match, returns undefined */ } -#endif -static int showdir(void) +/* + * Called when a new dir is loaded (for example when returning from other apps ...) + * also completely redraws the tree + */ +static int update_dir(void) { - struct entry *dircache = tc.dircache; - int i; - int tree_max_on_screen; - int start = tc.dirstart; bool id3db = *tc.dirfilter == SHOW_ID3DB; - bool newdir = false; -#ifdef HAVE_LCD_BITMAP - const char* icon; - int line_height; - int fw, fh; - lcd_setfont(FONT_UI); - lcd_getstringsize("A", &fw, &fh); - tree_max_on_screen = recalc_screen_height(); - line_height = fh; -#else - int icon; - tree_max_on_screen = TREE_MAX_ON_SCREEN; -#endif - - /* new file dir? load it */ + bool changed = false; + /* Checks for changes */ if (id3db) { if (tc.currtable != lasttable || tc.currextra != lastextra || @@ -286,151 +281,73 @@ static int showdir(void) { if (db_load(&tc) < 0) return -1; + lasttable = tc.currtable; lastextra = tc.currextra; lastfirstpos = tc.firstpos; - newdir = true; + changed = true; } } else { + /* if the tc.currdir has been changed, reload it ...*/ if (strncmp(tc.currdir, lastdir, sizeof(lastdir)) || reload_dir) { - if (ft_load(&tc, NULL) < 0) + + if (ft_load(&tc, NULL) < 0) return -1; strcpy(lastdir, tc.currdir); - newdir = true; + changed = true; } } - - if (newdir && !id3db && - (tc.dirfull || tc.filesindir == global_settings.max_files_in_dir) ) + /* if selected item is undefined */ + if (tc.selected_item == -1) { -#ifdef HAVE_LCD_CHARCELLS - lcd_double_height(false); -#endif - lcd_clear_display(); - lcd_puts(0,0,str(LANG_SHOWDIR_ERROR_BUFFER)); - lcd_puts(0,1,str(LANG_SHOWDIR_ERROR_FULL)); - lcd_update(); - sleep(HZ*2); - lcd_clear_display(); - } - - if (start == -1) - { - int diff_files; - - /* use lastfile to determine start (default=0) */ - start = 0; - - for (i=0; i < tc.filesindir; i++) - { - struct entry *dircache = tc.dircache; - - if (!strcasecmp(dircache[i].name, lastfile)) - { - start = i; - break; - } - } - - diff_files = tc.filesindir - start; - if (diff_files < tree_max_on_screen) - { - int oldstart = start; - - start -= (tree_max_on_screen - diff_files); - if (start < 0) - start = 0; + /* use lastfile to determine the selected item */ + tc.selected_item = tree_get_file_position(lastfile); - tc.dircursor = oldstart - start; - } - - tc.dirstart = start; + /* If the file doesn't exists, select the first one (default) */ + if(tc.selected_item < 0) + tc.selected_item = 0; + changed = true; } - - /* The cursor might point to an invalid line, for example if someone - deleted the last file in the dir */ - if (tc.filesindir) + if (changed) { - while (start + tc.dircursor >= tc.filesindir) + if(!id3db && (tc.dirfull || + tc.filesindir == global_settings.max_files_in_dir) ) { - if (start) - start--; - else - if (tc.dircursor) - tc.dircursor--; - } - tc.dirstart = start; - } - + /* dir full */ + int i; + for(i = 0;i < NB_SCREENS;++i) + { #ifdef HAVE_LCD_CHARCELLS - lcd_stop_scroll(); - lcd_double_height(false); -#endif - lcd_clear_display(); -#ifdef HAVE_LCD_BITMAP - lcd_setmargins(MARGIN_X,MARGIN_Y); /* leave room for cursor and icon */ - lcd_setfont(FONT_UI); + screens[i].double_height(false); #endif - - - for ( i=start; i < start+tree_max_on_screen && i < tc.filesindir; i++ ) { - int line = i - start; - char* name; - int attr = 0; - - if (id3db) { - name = ((char**)tc.dircache)[i * tc.dentry_size]; - icon = db_get_icon(&tc); - } - else { - struct entry* dc = tc.dircache; - struct entry* e = &dc[i]; - name = e->name; - attr = e->attr; - icon = filetype_get_icon(dircache[i].attr); - } - - - if (icon && global_settings.show_icons) { -#ifdef HAVE_LCD_BITMAP - int offset=0; - if ( line_height > 8 ) - offset = (line_height - 8) / 2; - lcd_mono_bitmap(icon, - CURSOR_X * 6 + CURSOR_WIDTH, - MARGIN_Y+(i-start)*line_height + offset, 6, 8); -#else - if (icon < 0 ) - icon = Icon_Unknown; - lcd_putc(LINE_X-1, i-start, icon); + screens[i].clear_display(); + screens[i].puts(0,0,str(LANG_SHOWDIR_ERROR_BUFFER)); + screens[i].puts(0,1,str(LANG_SHOWDIR_ERROR_FULL)); +#if defined(HAVE_LCD_BITMAP) || defined(SIMULATOR) + screens[i].update(); #endif + } + sleep(HZ*2); + for(i = 0;i < NB_SCREENS;++i) + screens[i].clear_display(); } - - showfileline(line, name, attr, false); /* no scroll */ } - -#ifdef HAVE_LCD_BITMAP - if (global_settings.scrollbar && (tc.dirlength > tree_max_on_screen)) - scrollbar(SCROLLBAR_X, SCROLLBAR_Y, SCROLLBAR_WIDTH - 1, - tree_max_on_screen * line_height, tc.dirlength, - start + tc.firstpos, - start + tc.firstpos + tree_max_on_screen, VERTICAL); - -#if CONFIG_KEYPAD == RECORDER_PAD + gui_synclist_set_nb_items(&tree_lists, tc.filesindir); + gui_synclist_select_item(&tree_lists, tc.selected_item); + gui_synclist_draw(&tree_lists); + gui_syncstatusbar_draw(&statusbars, true); +#ifdef HAS_BUTTONBAR if (global_settings.buttonbar) { if (*tc.dirfilter < NUM_FILTER_MODES) - buttonbar_set(str(LANG_DIRBROWSE_F1), + gui_buttonbar_set(&tree_buttonbar, str(LANG_DIRBROWSE_F1), str(LANG_DIRBROWSE_F2), str(LANG_DIRBROWSE_F3)); else - buttonbar_set("<<<", "", ""); - buttonbar_draw(); + gui_buttonbar_set(&tree_buttonbar, "<<<", "", ""); + gui_buttonbar_draw(&tree_buttonbar); } #endif -#endif - status_draw(true); - return tc.filesindir; } @@ -468,7 +385,6 @@ void reload_directory(void) static void start_resume(bool just_powered_on) { bool do_resume = false; - if ( global_settings.resume_index != -1 ) { DEBUGF("Resume index %X offset %X\n", global_settings.resume_index, @@ -486,7 +402,7 @@ static void start_resume(bool just_powered_on) do_resume = true; if (! do_resume) return; - + if (playlist_resume() != -1) { playlist_start(global_settings.resume_index, @@ -496,23 +412,23 @@ static void start_resume(bool just_powered_on) } else return; } else if (! just_powered_on) { - splash(HZ*2, true, str(LANG_NOTHING_TO_RESUME)); + gui_syncsplash(HZ*2, true, str(LANG_NOTHING_TO_RESUME)); } } +/* Selects a file and update tree context properly */ void set_current_file(char *path) { char *name; - unsigned int i; + int i; /* in ID3DB mode it is a bad idea to call this function */ /* (only happens with `follow playlist') */ if( *tc.dirfilter == SHOW_ID3DB ) - { return; - } /* separate directory from filename */ + /* gets the directory's name and put it into tc.currdir */ name = strrchr(path+1,'/'); if (name) { @@ -528,24 +444,27 @@ void set_current_file(char *path) } strcpy(lastfile, name); + + /* undefined item selected */ + tc.selected_item = -1; - tc.dircursor = 0; - tc.dirstart = -1; - + /* If we changed dir we must recalculate the dirlevel + and adjust the selected history properly */ if (strncmp(tc.currdir,lastdir,sizeof(lastdir))) { - tc.dirlevel = 0; - tc.dirpos[tc.dirlevel] = -1; - tc.cursorpos[tc.dirlevel] = 0; + tc.dirlevel = 0; + tc.selected_item_history[tc.dirlevel] = -1; /* use '/' to calculate dirlevel */ - for (i=1; i NUM_FILTER_MODES && numentries==0) { - splash(HZ*2, true, str(LANG_NO_FILES)); + gui_syncsplash(HZ*2, true, str(LANG_NO_FILES)); return false; /* No files found for rockbox_browser() */ } - update_all = true; - - put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); } while(1) { struct entry *dircache = tc.dircache; - bool restore = false; button = button_get_w_tmo(HZ/5); @@ -651,15 +557,18 @@ static bool dirbrowse(void) if (boot_changed) { bool stop = false; unsigned int button; - - lcd_clear_display(); - lcd_puts(0,0,str(LANG_BOOT_CHANGED)); - lcd_puts(0,1,str(LANG_REBOOT_NOW)); + int i; + for(i = 0;i < NB_SCREENS;++i) + { + screens[i].clear_display(); + screens[i].puts(0,0,str(LANG_BOOT_CHANGED)); + screens[i].puts(0,1,str(LANG_REBOOT_NOW)); #ifdef HAVE_LCD_BITMAP - lcd_puts(0,3,str(LANG_CONFIRM_WITH_PLAY_RECORDER)); - lcd_puts(0,4,str(LANG_CANCEL_WITH_ANY_RECORDER)); - lcd_update(); + screens[i].puts(0,3,str(LANG_CONFIRM_WITH_PLAY_RECORDER)); + screens[i].puts(0,4,str(LANG_CANCEL_WITH_ANY_RECORDER)); + screens[i].update(); #endif + } while (!stop) { button = button_get(true); switch (button) { @@ -683,6 +592,7 @@ static bool dirbrowse(void) boot_changed = false; } #endif + need_update = gui_synclist_do_button(&tree_lists, button); switch ( button ) { #ifdef TREE_ENTER @@ -702,33 +612,17 @@ static bool dirbrowse(void) && (lastbutton != TREE_RUN_PRE))) break; #endif - if ( !numentries ) + /* nothing to do if no files to display */ + if ( numentries == 0 ) break; - if (id3db) - i = db_enter(&tc); - else - i = ft_enter(&tc); - - switch (i) + switch (id3db?db_enter(&tc):ft_enter(&tc)) { case 1: reload_dir = true; break; case 2: start_wps = true; break; case 3: exit_func = true; break; default: break; } - -#ifdef HAVE_LCD_BITMAP - /* maybe we have a new font */ - tree_max_on_screen = recalc_screen_height(); -#endif - /* make sure cursor is on screen */ - while ( tc.dircursor > tree_max_on_screen ) - { - tc.dircursor--; - tc.dirstart++; - } - restore = true; break; @@ -741,8 +635,8 @@ static bool dirbrowse(void) exit_func = true; break; } - - if (!tc.dirlevel) + /* if we are in /, nothing to do */ + if (tc.dirlevel == 0) break; if (id3db) @@ -783,169 +677,6 @@ static bool dirbrowse(void) break; #endif #endif - - case TREE_PREV: - case TREE_PREV | BUTTON_REPEAT: -#ifdef TREE_RC_PREV - case TREE_RC_PREV: - case TREE_RC_PREV | BUTTON_REPEAT: -#endif - if (!tc.filesindir) - break; - - /* start scrolling when at 1/3 of the screen */ - if (tc.dircursor >= - tree_max_on_screen - (2 * tree_max_on_screen) / 3 - || (tc.dirstart == 0 && tc.dircursor > 0)) { - put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false); - tc.dircursor--; - put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); - } - else { - if (tc.dirstart || tc.firstpos) { - if (tc.dirstart) - tc.dirstart--; - else { - if (tc.firstpos > max_files/2) { - tc.firstpos -= max_files/2; - tc.dirstart += max_files/2; - tc.dirstart--; - } - else { - tc.dirstart = tc.firstpos - 1; - tc.firstpos = 0; - } - } - restore = true; - } - else { - if (button & BUTTON_REPEAT) - break; - if (numentries < tree_max_on_screen) { - put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, - false); - tc.dircursor = numentries - 1; - put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, - true); - } - else if (id3db && tc.dirfull) { - /* load last dir segment */ - /* use max_files/2 in case names are longer than - AVERAGE_FILE_LENGTH */ - tc.firstpos = tc.dirlength - max_files/2; - tc.dirstart = tc.firstpos; - tc.dircursor = tree_max_on_screen - 1; - numentries = showdir(); - update_all = true; - put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, - true); - } - else { - tc.dirstart = numentries - tree_max_on_screen; - tc.dircursor = tree_max_on_screen - 1; - restore = true; - } - } - } - need_update = true; - break; - - case TREE_NEXT: - case TREE_NEXT | BUTTON_REPEAT: -#ifdef TREE_RC_NEXT - case TREE_RC_NEXT: - case TREE_RC_NEXT | BUTTON_REPEAT: -#endif - if (!tc.filesindir) - break; - - if (tc.dircursor + tc.dirstart + 1 < numentries ) { - /* start scrolling when at 2/3 of the screen */ - if(tc.dircursor < (2 * tree_max_on_screen) / 3 || - numentries - tc.dirstart <= tree_max_on_screen) { - put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false); - tc.dircursor++; - put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); - } - else { - tc.dirstart++; - restore = true; - } - } - else if (id3db && (tc.firstpos || tc.dirfull)) { - if (tc.dircursor + tc.dirstart + tc.firstpos + 1 >= tc.dirlength) { - /* wrap and load first dir segment */ - if (button & BUTTON_REPEAT) - break; - tc.firstpos = tc.dirstart = tc.dircursor = 0; - } - else { - /* load next dir segment */ - tc.firstpos += tc.dirstart; - tc.dirstart = 0; - } - restore = true; - } - else { - if (button & BUTTON_REPEAT) - break; - if(numentries < tree_max_on_screen) { - put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false); - tc.dirstart = tc.dircursor = 0; - put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); - } - else { - tc.dirstart = tc.dircursor = 0; - numentries = showdir(); - update_all=true; - put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); - } - } - need_update = true; - break; - -#ifdef TREE_PGUP - case TREE_PGUP: - case TREE_PGUP | BUTTON_REPEAT: - if (tc.dirstart) { - tc.dirstart -= tree_max_on_screen; - if ( tc.dirstart < 0 ) - tc.dirstart = 0; - } - else if (tc.firstpos) { - if (tc.firstpos > max_files/2) { - tc.firstpos -= max_files/2; - tc.dirstart += max_files/2; - tc.dirstart -= tree_max_on_screen; - } - else { - tc.dirstart = tc.firstpos - tree_max_on_screen; - tc.firstpos = 0; - } - } - else - tc.dircursor = 0; - restore = true; - break; - - case TREE_PGDN: - case TREE_PGDN | BUTTON_REPEAT: - if ( tc.dirstart < numentries - tree_max_on_screen ) { - tc.dirstart += tree_max_on_screen; - if ( tc.dirstart > numentries - tree_max_on_screen ) - tc.dirstart = numentries - tree_max_on_screen; - } - else if (id3db && tc.dirfull) { - /* load next dir segment */ - tc.firstpos += tc.dirstart; - tc.dirstart = 0; - } - else - tc.dircursor = numentries - tc.dirstart - 1; - restore = true; - break; -#endif - case TREE_MENU: #ifdef TREE_RC_MENU case TREE_RC_MENU: @@ -957,7 +688,9 @@ static bool dirbrowse(void) /* don't enter menu from plugin browser */ if (*tc.dirfilter < NUM_FILTER_MODES) { - lcd_stop_scroll(); + int i; + for(i = 0;i < NB_SCREENS;++i) + screens[i].stop_scroll(); if (main_menu()) reload_dir = true; restore = true; @@ -1017,7 +750,7 @@ static bool dirbrowse(void) { if (quick_screen(curr_context, BUTTON_F3)) reload_dir = true; - tree_max_on_screen = recalc_screen_height(); + screen_access_update_nb_lines(); restore = true; } break; @@ -1052,20 +785,19 @@ static bool dirbrowse(void) } else { - attr = dircache[tc.dircursor+tc.dirstart].attr; + attr = dircache[tc.selected_item].attr; - if (currdir[1]) + if (currdir[1]) /* Not in / */ snprintf(buf, sizeof buf, "%s/%s", currdir, - dircache[tc.dircursor+tc.dirstart].name); - else + dircache[tc.selected_item].name); + else /* In / */ snprintf(buf, sizeof buf, "/%s", - dircache[tc.dircursor+tc.dirstart].name); + dircache[tc.selected_item].name); } - onplay_result = onplay(buf, attr, curr_context); } - + switch (onplay_result) { case ONPLAY_OK: @@ -1099,22 +831,22 @@ static bool dirbrowse(void) } } else - { - DEBUGF("Playing file thumbnail: %s/%s%s\n", + { + DEBUGF("Playing file thumbnail: %s/%s%s\n", currdir, dircache[lasti].name, file_thumbnail_ext); - /* no fallback necessary, we knew in advance + /* no fallback necessary, we knew in advance that the file exists */ ft_play_filename(currdir, dircache[lasti].name); } thumbnail_time = -1; /* job done */ } - status_draw(false); + gui_syncstatusbar_draw(&statusbars, false); break; #ifdef HAVE_HOTSWAP case SYS_FS_CHANGED: if (!id3db) - reload_dir = true; + reload_dir = true; /* The 'dir no longer valid' situation will be caught later * by checking the showdir() result. */ break; @@ -1139,18 +871,20 @@ static bool dirbrowse(void) lastbutton = button; } - if (start_wps) + if (start_wps && audio_status() ) { - lcd_stop_scroll(); + int i; + for(i = 0;i < NB_SCREENS;++i) + screens[i].stop_scroll(); if (wps_show() == SYS_USB_CONNECTED) reload_dir = true; #ifdef HAVE_HOTSWAP - else + else if (!id3db) /* Try reload to catch 'no longer valid' case. */ reload_dir = true; #endif #ifdef HAVE_LCD_BITMAP - tree_max_on_screen = recalc_screen_height(); + screen_access_update_nb_lines(); #endif id3db = check_changed_id3mode(id3db); restore = true; @@ -1174,8 +908,9 @@ static bool dirbrowse(void) } if (! reload_dir ) { - tc.dircursor = 0; - tc.dirstart = 0; + gui_synclist_select_item(&tree_lists, 0); + gui_synclist_draw(&tree_lists); + tc.selected_item = 0; lastdir[0] = 0; } @@ -1190,132 +925,88 @@ static bool dirbrowse(void) if (restore || reload_dir) { /* restore display */ - #ifdef HAVE_LCD_BITMAP - tree_max_on_screen = recalc_screen_height(); + screen_access_update_nb_lines(); #endif - - /* We need to adjust if the number of lines on screen have - changed because of a status bar change */ - if(CURSOR_Y+LINE_Y+tc.dircursor>tree_max_on_screen) { - tc.dirstart++; - tc.dircursor--; - } -#ifdef HAVE_LCD_BITMAP - /* the sub-screen might've ruined the margins */ - lcd_setmargins(MARGIN_X,MARGIN_Y); /* leave room for cursor and - icon */ - lcd_setfont(FONT_UI); -#endif - numentries = showdir(); + numentries = update_dir(); if (currdir[1] && (numentries < 0)) { /* not in root and reload failed */ reload_root = true; /* try root */ reload_dir = false; goto check_rescan; } - update_all = true; - put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); - need_update = true; reload_dir = false; } + if(need_update) { + tc.selected_item = gui_synclist_get_selected_item_position(&tree_lists); + need_update=false; + if ( numentries > 0 ) { + /* Voice the file if changed */ + if(lasti != tc.selected_item || restore) { + lasti = tc.selected_item; + thumbnail_time = -1; /* Cancel whatever we were + about to say */ + + /* Directory? */ + if (dircache[tc.selected_item].attr & ATTR_DIRECTORY) + { + /* play directory thumbnail */ + switch (global_settings.talk_dir) { + case 1: /* dirs as numbers */ + talk_id(VOICE_DIR, false); + talk_number(tc.selected_item+1, true); + break; - if ( (numentries > 0) && need_update) { - i = tc.dirstart+tc.dircursor; - - /* if MP3 filter is on, cut off the extension */ - if(lasti!=i || restore) { - char* name; - int attr = 0; - - if (id3db) - name = ((char**)tc.dircache)[lasti * tc.dentry_size]; - else { - struct entry* dc = tc.dircache; - struct entry* e = &dc[lasti]; - name = e->name; - attr = e->attr; - } - - lcd_stop_scroll(); - - /* So if lastdircursor and dircursor differ, and then full - screen was not refreshed, restore the previous line */ - if ((lastdircursor != tc.dircursor) && !update_all ) { - showfileline(lastdircursor, name, attr, false); /* no scroll */ - } - lasti=i; - lastdircursor=tc.dircursor; - thumbnail_time = -1; /* cancel whatever we were about to say */ - - if (id3db) - name = ((char**)tc.dircache)[lasti * tc.dentry_size]; - else { - struct entry* dc = tc.dircache; - struct entry* e = &dc[lasti]; - name = e->name; - attr = e->attr; - } - showfileline(tc.dircursor, name, attr, true); /* scroll please */ - need_update = true; - - if (dircache[i].attr & ATTR_DIRECTORY) /* directory? */ - { - /* play directory thumbnail */ - switch (global_settings.talk_dir) { - case 1: /* dirs as numbers */ - talk_id(VOICE_DIR, false); - talk_number(i+1, true); - break; - - case 2: /* dirs spelled */ - talk_spell(dircache[i].name, false); - break; + case 2: /* dirs spelled */ + talk_spell(dircache[tc.selected_item].name, + false); + break; - case 3: /* thumbnail clip */ - /* "schedule" a thumbnail, to have a little dalay */ - thumbnail_time = current_tick + HOVER_DELAY; - break; + case 3: /* thumbnail clip */ + /* "schedule" a thumbnail, to have a little + delay */ + thumbnail_time = current_tick + HOVER_DELAY; + break; - default: - break; + default: + break; + } } - } - else /* file */ - { - switch (global_settings.talk_file) { - case 1: /* files as numbers */ - ft_play_filenumber(i-tc.dirsindir+1, - dircache[i].attr & TREE_ATTR_MASK); - break; + else /* file */ + { + switch (global_settings.talk_file) { + case 1: /* files as numbers */ + ft_play_filenumber( + tc.selected_item-tc.dirsindir+1, + dircache[tc.selected_item].attr & + TREE_ATTR_MASK); + break; - case 2: /* files spelled */ - talk_spell(dircache[i].name, false); - break; + case 2: /* files spelled */ + talk_spell(dircache[tc.selected_item].name, + false); + break; - case 3: /* thumbnail clip */ - /* "schedule" a thumbnail, to have a little delay */ - if (dircache[i].attr & TREE_ATTR_THUMBNAIL) - thumbnail_time = current_tick + HOVER_DELAY; - else - /* spell the number as fallback */ - talk_spell(dircache[i].name, false); - break; + case 3: /* thumbnail clip */ + /* "schedule" a thumbnail, to have a little + delay */ + if (dircache[tc.selected_item].attr & + TREE_ATTR_THUMBNAIL) + thumbnail_time = current_tick + HOVER_DELAY; + else + /* spell the number as fallback */ + talk_spell(dircache[tc.selected_item].name, + false); + break; - default: - break; + default: + break; + } } } } } - - if(need_update) { - lcd_update(); - - need_update = false; - update_all = false; - } } return true; @@ -1369,7 +1060,7 @@ static bool add_dir(char* dirname, int len, int fd) int x = strlen(entry->d_name); unsigned int i; char *cp = strrchr(entry->d_name,'.'); - + if (cp) { cp++; @@ -1379,6 +1070,7 @@ static bool add_dir(char* dirname, int len, int fd) if (!strcasecmp(cp, filetypes[i].extension)) { char buf[8]; + int i; write(fd, dirname, strlen(dirname)); write(fd, "/", 1); write(fd, entry->d_name, x); @@ -1387,8 +1079,11 @@ static bool add_dir(char* dirname, int len, int fd) plsize++; snprintf(buf, sizeof buf, "%d", plsize); #ifdef HAVE_LCD_BITMAP - lcd_puts(0,4,buf); - lcd_update(); + for(i = 0;i < NB_SCREENS;++i) + { + screens[i].puts(0,4,buf); + screens[i].update(); + } #else x = 10; if (plsize > 999) @@ -1401,7 +1096,8 @@ static bool add_dir(char* dirname, int len, int fd) x=9; } } - lcd_puts(x,0,buf); + for(i = 0;i < NB_SCREENS;++i) + screens[i].puts(x,0,buf); #endif break; } @@ -1418,16 +1114,20 @@ static bool add_dir(char* dirname, int len, int fd) bool create_playlist(void) { int fd; + int i; char filename[MAX_PATH]; snprintf(filename, sizeof filename, "%s.m3u", tc.currdir[1] ? tc.currdir : "/root"); - - lcd_clear_display(); - lcd_puts(0,0,str(LANG_CREATING)); - lcd_puts_scroll(0,1,filename); - lcd_update(); - + for(i = 0;i < NB_SCREENS;++i) + { + screens[i].clear_display(); + screens[i].puts(0,0,str(LANG_CREATING)); + screens[i].puts_scroll(0,1,filename); +#if defined(HAVE_LCD_BITMAP) || defined(SIMULATOR) + screens[i].update(); +#endif + } fd = creat(filename,0); if (fd < 0) return false; @@ -1435,7 +1135,7 @@ bool create_playlist(void) #ifdef HAVE_ADJUSTABLE_CPU_FREQ cpu_boost(true); #endif - + snprintf(filename, sizeof(filename), "%s", tc.currdir[1] ? tc.currdir : "/"); plsize = 0; @@ -1445,7 +1145,7 @@ bool create_playlist(void) #ifdef HAVE_ADJUSTABLE_CPU_FREQ cpu_boost(false); #endif - + sleep(HZ); return true; @@ -1460,12 +1160,10 @@ bool rockbox_browse(const char *root, int dirfilter) memcpy(tc.currdir, root, sizeof(tc.currdir)); start_wps = false; tc.dirfilter = &dirfilter; - + dirbrowse(); tc = backup; - reload_dir = true; - return false; } @@ -1474,7 +1172,7 @@ void tree_init(void) /* We copy the settings value in case it is changed by the user. We can't use it until the next reboot. */ max_files = global_settings.max_files_in_dir; - + /* initialize tree context struct */ memset(&tc, 0, sizeof(tc)); tc.dirfilter = &global_settings.dirfilter; @@ -1498,7 +1196,7 @@ void bookmark_play(char *resume_file, int index, int offset, int seed, { /* Playlist playback */ char* slash; - // check that the file exists + /* check that the file exists */ int fd = open(resume_file, O_RDONLY); if(fd<0) return; @@ -1538,7 +1236,7 @@ void bookmark_play(char *resume_file, int index, int offset, int seed, if ((strcmp(strrchr(playlist_peek(index) + 1,'/') + 1, filename))) { - for ( i=0; i < playlist_amount(); i++ ) + for ( i=0; i < playlist_amount(); i++ ) { if ((strcmp(strrchr(playlist_peek(i) + 1,'/') + 1, filename)) == 0) @@ -1599,7 +1297,7 @@ int ft_play_dirname(int start_index) } close(fd); - + DEBUGF("Found: %s\n", dirname_mp3_filename); talk_file(dirname_mp3_filename, false); @@ -1639,9 +1337,7 @@ void tree_flush(void) if (global_settings.dircache) { if (dircache_is_enabled()) - { global_settings.dircache_size = dircache_get_cache_size(); - } dircache_disable(); } else @@ -1659,21 +1355,27 @@ void tree_restore(void) #ifdef HAVE_DIRCACHE if (global_settings.dircache) { - int font_w, font_h; - /* Print "Scanning disk..." to the display. */ - lcd_getstringsize("A", &font_w, &font_h); - lcd_putsxy((LCD_WIDTH/2) - ((strlen(str(LANG_DIRCACHE_BUILDING))*font_w)/2), - LCD_HEIGHT-font_h*3, str(LANG_DIRCACHE_BUILDING)); - lcd_update(); - + int i; + for(i = 0;i < NB_SCREENS;++i) + { + screens[i].putsxy((LCD_WIDTH/2) - + ((strlen(str(LANG_DIRCACHE_BUILDING)) * + screens[i].char_width)/2), + LCD_HEIGHT-screens[i].char_height*3, + str(LANG_DIRCACHE_BUILDING)); + screens[i].update(); + } dircache_build(global_settings.dircache_size); - /* Clean the text when we are done. */ - lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); - lcd_fillrect(0, LCD_HEIGHT-font_h*3, LCD_WIDTH, font_h); - lcd_set_drawmode(DRMODE_SOLID); - lcd_update(); + for(i=0;i #include +/*FIXME: don't forget to remove PGUP, PGDOW, NEXT, PREV + * when everything will be working with gui_list */ #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ (CONFIG_KEYPAD == IRIVER_H300_PAD) #define TREE_NEXT BUTTON_DOWN @@ -43,8 +45,11 @@ #define TREE_POWER_BTN BUTTON_ON #define TREE_QUICK (BUTTON_MODE | BUTTON_REPEAT) +/* Remote keys */ #define TREE_RC_NEXT BUTTON_RC_FF #define TREE_RC_PREV BUTTON_RC_REW +#define TREE_RC_PGUP BUTTON_RC_SOURCE +#define TREE_RC_PGDN BUTTON_RC_BITRATE #define TREE_RC_EXIT BUTTON_RC_STOP #define TREE_RC_RUN (BUTTON_RC_MENU | BUTTON_REL) #define TREE_RC_RUN_PRE BUTTON_RC_MENU @@ -137,27 +142,36 @@ struct filetype { int icon; int voiceclip; }; - + /* browser context for file or db */ struct tree_context { + /* The directory we are browsing */ + char currdir[MAX_PATH]; + /* the number of directories we have crossed from / */ int dirlevel; - int dircursor; - int dirstart; + /* The currently selected file/id3dbitem index (old dircursor+dirfile) */ + int selected_item; + /* The selected item in each directory crossed + * (used when we want to return back to a previouws directory)*/ + int selected_item_history[MAX_DIR_LEVELS]; + int firstpos; /* which dir entry is on first position in dir buffer */ int pos_history[MAX_DIR_LEVELS]; - int dirpos[MAX_DIR_LEVELS]; - int cursorpos[MAX_DIR_LEVELS]; - char currdir[MAX_PATH]; /* file use */ + int dirpos[MAX_DIR_LEVELS]; /* the dirstart history */ + int cursorpos[MAX_DIR_LEVELS]; /* the dircursor history */ + int *dirfilter; /* file use */ - int filesindir; + int filesindir; /* The number of files in the dircache */ int dirsindir; /* file use */ int dirlength; /* total number of entries in dir, incl. those not loaded */ int table_history[MAX_DIR_LEVELS]; /* db use */ int extra_history[MAX_DIR_LEVELS]; /* db use */ int currtable; /* db use */ int currextra; /* db use */ - + /* A big buffer with plenty of entry structs, + * contains all files and dirs in the current + * dir (with filters applied) */ void* dircache; int dircache_size; char* name_buffer; @@ -196,4 +210,7 @@ struct tree_context* tree_get_context(void); void tree_flush(void); void tree_restore(void); + +extern struct gui_synclist tree_lists; +extern struct gui_syncstatusbar statusbars; #endif diff --git a/apps/wps.h b/apps/wps.h index 6f0d601876..e32bd3c815 100644 --- a/apps/wps.h +++ b/apps/wps.h @@ -19,7 +19,7 @@ #ifndef _WPS_H #define _WPS_H #include "id3.h" -#include "playlist.h" +#include "playlist.h" /* button definitions */ #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ @@ -33,7 +33,7 @@ #define WPS_INCVOL BUTTON_UP #define WPS_DECVOL BUTTON_DOWN #define WPS_PAUSE (BUTTON_ON | BUTTON_REL) -#define WPS_PAUSE_PRE BUTTON_ON +#define WPS_PAUSE_PRE BUTTON_ON #define WPS_MENU (BUTTON_MODE | BUTTON_REL) #define WPS_MENU_PRE BUTTON_MODE #define WPS_BROWSE (BUTTON_SELECT | BUTTON_REL) @@ -53,10 +53,10 @@ #define WPS_RC_INCVOL BUTTON_RC_VOL_UP #define WPS_RC_DECVOL BUTTON_RC_VOL_DOWN #define WPS_RC_EXIT BUTTON_RC_STOP -#define WPS_RC_MENU (BUTTON_RC_MENU | BUTTON_REL) -#define WPS_RC_MENU_PRE BUTTON_RC_MENU -#define WPS_RC_BROWSE (BUTTON_RC_MODE | BUTTON_REL) -#define WPS_RC_BROWSE_PRE BUTTON_RC_MODE +#define WPS_RC_MENU (BUTTON_RC_MODE | BUTTON_REL) +#define WPS_RC_MENU_PRE BUTTON_RC_MODE +#define WPS_RC_BROWSE (BUTTON_RC_MENU | BUTTON_REL) +#define WPS_RC_BROWSE_PRE BUTTON_RC_MENU #elif CONFIG_KEYPAD == RECORDER_PAD #define WPS_NEXT (BUTTON_RIGHT | BUTTON_REL) -- cgit v1.2.3