Initial multi screen support by Kévin Ferrare (Patch #1318081)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7666 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/SOURCES b/apps/SOURCES
index 26af159..07c121f 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -31,6 +31,15 @@
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 e3704ac..9ea0706 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
dptr[1] = extra; /* offset to artist */
hits++;
}
-
+
c->filesindir = hits;
return hits;
@@ -350,7 +353,7 @@
count = tagdbheader.songcount;
size = SONGENTRY_SIZE;
break;
-
+
default:
DEBUGF("Invalid table %d\n", c->currtable);
return 0;
@@ -384,7 +387,7 @@
c->dirfull = true;
break;
}
-
+
nptr += strlen(nptr) + 1;
while ((unsigned long)nptr & 3)
nptr++;
@@ -403,25 +406,24 @@
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 @@
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 @@
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 @@
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 @@
{
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 @@
}
/* 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 @@
}
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 37a66c6..e8b8df7 100644
--- a/apps/filetree.c
+++ b/apps/filetree.c
@@ -79,12 +79,12 @@
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 @@
dircache[i].attr |= TREE_ATTR_THUMBNAIL; /* set */
}
}
-
+
while((entry = readdir_cached(dir)) != 0) /* walk directory */
{
int ext_pos;
@@ -110,13 +110,13 @@
|| (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 @@
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 @@
boot_cluster = entry->startcluster;
}
#endif
-
+
/* filter out non-visible files */
if ((!(dptr->attr & ATTR_DIRECTORY) && (
(*c->dirfilter == SHOW_PLAYLIST &&
@@ -289,7 +289,7 @@
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 @@
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 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 @@
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 @@
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 @@
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 0000000..be87b1b
--- /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 0000000..ee7b8d0
--- /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 0000000..4d174d3
--- /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 0000000..46faf09
--- /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 0000000..bb3eb7c
--- /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 0000000..fd553f3
--- /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 0000000..9d5717f
--- /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 0000000..51c0835
--- /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 <lcd.h>
+#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 0000000..a3cbb19
--- /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<NB_SCREENS;++i)
+ internal_splash(&(screens[i]), center, fmt, ap);
+ va_end( ap );
+
+ if(ticks)
+ sleep(ticks);
+}
diff --git a/apps/gui/splash.h b/apps/gui/splash.h
new file mode 100644
index 0000000..b0d55db
--- /dev/null
+++ b/apps/gui/splash.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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.
+ *
+ ****************************************************************************/
+
+/*
+ * 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 0000000..5ddc194
--- /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 0000000..434d679
--- /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 ca4b218..9f43c65 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 @@
}
#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 0d8c80d..29316f9 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 @@
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 8d68814..7d4ee7f 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 @@
#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 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 @@
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 @@
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))
- {
- dotpos = strrchr(name, '.');
- if (dotpos) {
- *dotpos = 0;
- }
- }
-
- 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;
-}
-#endif
-
-static int showdir(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
+ /* use lastfile to determine the selected item (default=0) */
+ for (i=0; i < tc.filesindir; i++)
+ {
+ struct entry* dc = tc.dircache;
+ struct entry* e = &dc[i];
+ if (!strcasecmp(e->name, filename))
+ return(i);
+ }
+ return(-1);/* no file can match, returns undefined */
+}
- /* new file dir? load it */
+/*
+ * Called when a new dir is loaded (for example when returning from other apps ...)
+ * also completely redraws the tree
+ */
+static int update_dir(void)
+{
+ bool id3db = *tc.dirfilter == SHOW_ID3DB;
+ bool changed = false;
+ /* Checks for changes */
if (id3db) {
if (tc.currtable != lasttable ||
tc.currextra != lastextra ||
@@ -286,151 +281,73 @@
{
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();
+ /* use lastfile to determine the selected item */
+ tc.selected_item = tree_get_file_position(lastfile);
+
+ /* If the file doesn't exists, select the first one (default) */
+ if(tc.selected_item < 0)
+ tc.selected_item = 0;
+ changed = true;
}
-
- if (start == -1)
+ if (changed)
{
- int diff_files;
-
- /* use lastfile to determine start (default=0) */
- start = 0;
-
- for (i=0; i < tc.filesindir; i++)
+ if(!id3db && (tc.dirfull ||
+ tc.filesindir == global_settings.max_files_in_dir) )
{
- struct entry *dircache = tc.dircache;
-
- if (!strcasecmp(dircache[i].name, lastfile))
+ /* dir full */
+ int i;
+ for(i = 0;i < NB_SCREENS;++i)
{
- 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;
-
- tc.dircursor = oldstart - start;
- }
-
- tc.dirstart = start;
- }
-
- /* The cursor might point to an invalid line, for example if someone
- deleted the last file in the dir */
- if (tc.filesindir)
- {
- while (start + tc.dircursor >= tc.filesindir)
- {
- if (start)
- start--;
- else
- if (tc.dircursor)
- tc.dircursor--;
- }
- tc.dirstart = start;
- }
-
#ifdef HAVE_LCD_CHARCELLS
- lcd_stop_scroll();
- lcd_double_height(false);
+ screens[i].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].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
-
-
- 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);
+ }
+ sleep(HZ*2);
+ for(i = 0;i < NB_SCREENS;++i)
+ screens[i].clear_display();
}
- 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);
-#endif
- }
-
- 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 @@
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 @@
do_resume = true;
if (! do_resume) return;
-
+
if (playlist_resume() != -1)
{
playlist_start(global_settings.resume_index,
@@ -496,23 +412,23 @@
}
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 @@
}
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<strlen(path)+1; i++)
+ /* FIXME : strlen(path) : crazy oO better to store it at
+ the beginning */
+ int path_len = strlen(path) + 1;
+ for (i = 1; i < path_len; i++)
{
if (path[i] == '/')
{
tc.dirlevel++;
- tc.dirpos[tc.dirlevel] = -1;
- tc.cursorpos[tc.dirlevel] = 0;
+ tc.selected_item_history[tc.dirlevel] = -1;
}
}
}
@@ -567,24 +486,20 @@
}
return currmode;
}
-
+/* main loop, handles key events */
static bool dirbrowse(void)
{
int numentries=0;
char buf[MAX_PATH];
- int i;
- int lasti=-1;
+ int lasti = -1;
unsigned button;
- int tree_max_on_screen;
bool reload_root = false;
int lastfilter = *tc.dirfilter;
bool lastsortcase = global_settings.sort_case;
- int lastdircursor=-1;
bool need_update = true;
bool exit_func = false;
long thumbnail_time = -1; /* for delaying a thumbnail */
- bool update_all = false; /* set this to true when the whole file list
- has been refreshed on screen */
+
unsigned lastbutton = 0;
char* currdir = tc.currdir; /* just a shortcut */
bool id3db = *tc.dirfilter == SHOW_ID3DB;
@@ -593,15 +508,10 @@
curr_context=CONTEXT_ID3DB;
else
curr_context=CONTEXT_TREE;
-
#ifdef HAVE_LCD_BITMAP
- tree_max_on_screen = recalc_screen_height();
-#else
- tree_max_on_screen = TREE_MAX_ON_SCREEN;
+ screen_access_update_nb_lines();
#endif
-
- tc.dircursor=0;
- tc.dirstart=0;
+ tc.selected_item = 0;
tc.dirlevel=0;
tc.firstpos=0;
lasttable = -1;
@@ -624,25 +534,21 @@
start_resume(true);
}
-
+ /* If we don't need to show the wps, draw the dir */
if (!start_wps) {
- numentries = showdir();
+ numentries = update_dir();
if (numentries == -1)
return false; /* currdir is not a directory */
-
+
if (*tc.dirfilter > 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 @@
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 @@
boot_changed = false;
}
#endif
+ need_update = gui_synclist_do_button(&tree_lists, button);
switch ( button ) {
#ifdef TREE_ENTER
@@ -702,33 +612,17 @@
&& (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 @@
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 @@
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 @@
/* 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 @@
{
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 @@
}
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 @@
}
}
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 @@
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 @@
}
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 @@
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 */
- if ( (numentries > 0) && need_update) {
- i = tc.dirstart+tc.dircursor;
+ /* 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 MP3 filter is on, cut off the extension */
- if(lasti!=i || restore) {
- char* name;
- int attr = 0;
+ case 2: /* dirs spelled */
+ talk_spell(dircache[tc.selected_item].name,
+ false);
+ break;
- 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 3: /* thumbnail clip */
- /* "schedule" a thumbnail, to have a little dalay */
- thumbnail_time = current_tick + HOVER_DELAY;
- 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;
-
- case 2: /* files spelled */
- talk_spell(dircache[i].name, false);
- break;
-
- case 3: /* thumbnail clip */
- /* "schedule" a thumbnail, to have a little delay */
- if (dircache[i].attr & TREE_ATTR_THUMBNAIL)
+ case 3: /* thumbnail clip */
+ /* "schedule" a thumbnail, to have a little
+ delay */
thumbnail_time = current_tick + HOVER_DELAY;
- else
- /* spell the number as fallback */
- talk_spell(dircache[i].name, false);
- break;
+ break;
- default:
- break;
+ default:
+ 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[tc.selected_item].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;
+ }
}
}
}
}
-
- if(need_update) {
- lcd_update();
-
- need_update = false;
- update_all = false;
- }
}
return true;
@@ -1369,7 +1060,7 @@
int x = strlen(entry->d_name);
unsigned int i;
char *cp = strrchr(entry->d_name,'.');
-
+
if (cp) {
cp++;
@@ -1379,6 +1070,7 @@
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 @@
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 @@
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 @@
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 @@
#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 @@
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
cpu_boost(false);
#endif
-
+
sleep(HZ);
return true;
@@ -1460,12 +1160,10 @@
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 @@
/* 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 @@
{
/* 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 @@
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 @@
}
close(fd);
-
+
DEBUGF("Found: %s\n", dirname_mp3_filename);
talk_file(dirname_mp3_filename, false);
@@ -1639,9 +1337,7 @@
if (global_settings.dircache)
{
if (dircache_is_enabled())
- {
global_settings.dircache_size = dircache_get_cache_size();
- }
dircache_disable();
}
else
@@ -1659,21 +1355,27 @@
#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<NB_SCREENS;++i)
+ {
+ screens[i].set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
+ screens[i].fillrect(0, LCD_HEIGHT-screens[i].char_height*3,
+ LCD_WIDTH, screens[i].char_height);
+ screens[i].set_drawmode(DRMODE_SOLID);
+ screens[i].update();
+ }
}
#endif
}
diff --git a/apps/tree.h b/apps/tree.h
index a6c41f2..04532c8 100644
--- a/apps/tree.h
+++ b/apps/tree.h
@@ -23,6 +23,8 @@
#include <applimits.h>
#include <file.h>
+/*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 @@
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 @@
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 6f0d601..e32bd3c 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)
diff --git a/tools/configure b/tools/configure
index 4a0a4ee..ad66ba8 100755
--- a/tools/configure
+++ b/tools/configure
@@ -412,7 +412,7 @@
shcc
tool="$rootdir/tools/scramble"
output="archos.mod"
- appextra="player"
+ appextra="player:gui"
archosrom="$pwd/rombox.ucl"
flash="$pwd/rockbox.ucl"
plugins="yes"
@@ -425,7 +425,7 @@
shcc
tool="$rootdir/tools/scramble"
output="ajbrec.ajz"
- appextra="recorder"
+ appextra="recorder:gui"
archosrom="$pwd/rombox.ucl"
flash="$pwd/rockbox.ucl"
plugins="yes"
@@ -438,7 +438,7 @@
shcc
tool="$rootdir/tools/scramble -fm"
output="ajbrec.ajz"
- appextra="recorder"
+ appextra="recorder:gui"
archosrom="$pwd/rombox.ucl"
flash="$pwd/rockbox.ucl"
plugins="yes"
@@ -451,7 +451,7 @@
shcc
tool="$rootdir/tools/scramble -v2"
output="ajbrec.ajz"
- appextra="recorder"
+ appextra="recorder:gui"
archosrom="$pwd/rombox.ucl"
flash="$pwd/rockbox.ucl"
plugins="yes"
@@ -465,7 +465,7 @@
calmrisccc
tool="cp" # might work for now!
output="rockbox.gmini"
- appextra="recorder"
+ appextra="recorder:gui"
archosrom=""
flash=""
plugins="" # disabled for now, enable later on
@@ -479,7 +479,7 @@
calmrisccc
tool="cp" # might work for now!
output="rockbox.gmini"
- appextra="recorder"
+ appextra="recorder:gui"
archosrom=""
flash=""
plugins="" # disabled for now, enable later on
@@ -492,7 +492,7 @@
shcc
tool="$rootdir/tools/scramble -osp"
output="ajbrec.ajz"
- appextra="recorder"
+ appextra="recorder:gui"
archosrom="$pwd/rombox.ucl"
flash="$pwd/rockbox.ucl"
plugins="yes"
@@ -505,7 +505,7 @@
shcc
tool="$rootdir/tools/scramble -ofm"
output="ajbrec.ajz"
- appextra="recorder"
+ appextra="recorder:gui"
archosrom="$pwd/rombox.ucl"
flash="$pwd/rockbox.ucl"
plugins="yes"
@@ -519,7 +519,7 @@
coldfirecc
tool="$rootdir/tools/scramble -add=h120"
output="rockbox.iriver"
- appextra="recorder"
+ appextra="recorder:gui"
archosrom=""
flash=""
plugins="yes"
@@ -533,7 +533,7 @@
coldfirecc
tool="$rootdir/tools/scramble -add=h300"
output="rockbox.iriver"
- appextra="recorder"
+ appextra="recorder:gui"
archosrom=""
flash=""
plugins="yes"
@@ -547,7 +547,7 @@
coldfirecc
tool="$rootdir/tools/scramble -add=h100"
output="rockbox.iriver"
- appextra="recorder"
+ appextra="recorder:gui"
archosrom=""
flash=""
plugins="yes"
@@ -561,7 +561,7 @@
coldfirecc
tool="$rootdir/tools/scramble -add=x5" # wrong, must be fixed
output="rockbox.iaudio"
- appextra="recorder"
+ appextra="recorder:gui"
archosrom=""
flash=""
plugins="yes"