diff options
author | Björn Stenberg <bjorn@haxx.se> | 2005-01-18 22:45:00 +0000 |
---|---|---|
committer | Björn Stenberg <bjorn@haxx.se> | 2005-01-18 22:45:00 +0000 |
commit | 84c7d8802106266c94d0a30827dff418a2fcac6d (patch) | |
tree | 17a4d8a7f5375584783925dd3b44203245413755 /apps | |
parent | f9c06226d6c3f756437dc45d573d23f14699e728 (diff) | |
download | rockbox-84c7d8802106266c94d0a30827dff418a2fcac6d.tar.gz rockbox-84c7d8802106266c94d0a30827dff418a2fcac6d.zip |
Added support for very large tables in ID3 database.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5595 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r-- | apps/dbtree.c | 81 | ||||
-rw-r--r-- | apps/dbtree.h | 6 | ||||
-rw-r--r-- | apps/filetree.c | 15 | ||||
-rw-r--r-- | apps/filetree.h | 2 | ||||
-rw-r--r-- | apps/playlist.c | 4 | ||||
-rw-r--r-- | apps/tree.c | 202 | ||||
-rw-r--r-- | apps/tree.h | 5 |
7 files changed, 194 insertions, 121 deletions
diff --git a/apps/dbtree.c b/apps/dbtree.c index 68a211a836..abe8aed647 100644 --- a/apps/dbtree.c +++ b/apps/dbtree.c | |||
@@ -121,18 +121,21 @@ int db_init(void) | |||
121 | return 0; | 121 | return 0; |
122 | } | 122 | } |
123 | 123 | ||
124 | int db_load(struct tree_context* c, bool* dir_buffer_full) | 124 | int db_load(struct tree_context* c) |
125 | { | 125 | { |
126 | int i, offset, len, rc; | 126 | int i, offset, rc; |
127 | int dcachesize = global_settings.max_files_in_dir * sizeof(struct entry); | 127 | int dcachesize = global_settings.max_files_in_dir * sizeof(struct entry); |
128 | int max_items, itemcount, stringlen; | 128 | int max_items, itemcount, stringlen; |
129 | unsigned int* nptr = (void*) c->name_buffer; | 129 | unsigned int* nptr = (void*) c->name_buffer; |
130 | unsigned int* dptr = c->dircache; | 130 | unsigned int* dptr = c->dircache; |
131 | unsigned int* safeplace = NULL; | 131 | unsigned int* safeplace = NULL; |
132 | int safeplacelen = 0; | ||
132 | 133 | ||
133 | int table = c->currtable; | 134 | int table = c->currtable; |
134 | int extra = c->currextra; | 135 | int extra = c->currextra; |
135 | 136 | ||
137 | char* end_of_nbuf = c->name_buffer + c->name_buffer_size; | ||
138 | |||
136 | if (!initialized) { | 139 | if (!initialized) { |
137 | DEBUGF("ID3 database is not initialized.\n"); | 140 | DEBUGF("ID3 database is not initialized.\n"); |
138 | c->filesindir = 0; | 141 | c->filesindir = 0; |
@@ -140,8 +143,9 @@ int db_load(struct tree_context* c, bool* dir_buffer_full) | |||
140 | } | 143 | } |
141 | 144 | ||
142 | c->dentry_size = 2 * sizeof(int); | 145 | c->dentry_size = 2 * sizeof(int); |
143 | 146 | c->dirfull = false; | |
144 | DEBUGF("db_load(%d, %x)\n", table, extra); | 147 | |
148 | DEBUGF("db_load(%d, %x, %d)\n", table, extra, c->firstpos); | ||
145 | 149 | ||
146 | if (!table) { | 150 | if (!table) { |
147 | table = allartists; | 151 | table = allartists; |
@@ -150,51 +154,50 @@ int db_load(struct tree_context* c, bool* dir_buffer_full) | |||
150 | 154 | ||
151 | switch (table) { | 155 | switch (table) { |
152 | case allsongs: | 156 | case allsongs: |
153 | offset = songstart; | 157 | offset = songstart + c->firstpos * (songlen + 12); |
154 | itemcount = songcount; | 158 | itemcount = songcount; |
155 | stringlen = songlen; | 159 | stringlen = songlen; |
156 | break; | 160 | break; |
157 | 161 | ||
158 | case allalbums: | 162 | case allalbums: |
159 | offset = albumstart; | 163 | offset = albumstart + |
164 | c->firstpos * (albumlen + 4 + songarraylen * 4); | ||
160 | itemcount = albumcount; | 165 | itemcount = albumcount; |
161 | stringlen = albumlen; | 166 | stringlen = albumlen; |
162 | break; | 167 | break; |
163 | 168 | ||
164 | case allartists: | 169 | case allartists: |
165 | offset = artiststart; | 170 | offset = artiststart + |
171 | c->firstpos * (artistlen + albumarraylen * 4); | ||
166 | itemcount = artistcount; | 172 | itemcount = artistcount; |
167 | stringlen = artistlen; | 173 | stringlen = artistlen; |
168 | break; | 174 | break; |
169 | 175 | ||
170 | case albums: | 176 | case albums4artist: |
171 | /* 'extra' is offset to the artist */ | 177 | /* 'extra' is offset to the artist */ |
172 | len = albumarraylen * 4; | 178 | safeplacelen = albumarraylen * 4; |
173 | safeplace = (void*)(c->name_buffer + c->name_buffer_size - len); | 179 | safeplace = (void*)(end_of_nbuf - safeplacelen); |
174 | //DEBUGF("Seeking to %x\n", extra + artistlen); | ||
175 | lseek(fd, extra + artistlen, SEEK_SET); | 180 | lseek(fd, extra + artistlen, SEEK_SET); |
176 | rc = read(fd, safeplace, len); | 181 | rc = read(fd, safeplace, safeplacelen); |
177 | if (rc < len) | 182 | if (rc < safeplacelen) |
178 | return -1; | 183 | return -1; |
179 | 184 | ||
180 | #ifdef LITTLE_ENDIAN | 185 | #ifdef LITTLE_ENDIAN |
181 | for (i=0; i<albumarraylen; i++) | 186 | for (i=0; i<albumarraylen; i++) |
182 | safeplace[i] = BE32(safeplace[i]); | 187 | safeplace[i] = BE32(safeplace[i]); |
183 | #endif | 188 | #endif |
184 | |||
185 | offset = safeplace[0]; | 189 | offset = safeplace[0]; |
186 | itemcount = albumarraylen; | 190 | itemcount = albumarraylen; |
187 | stringlen = albumlen; | 191 | stringlen = albumlen; |
188 | break; | 192 | break; |
189 | 193 | ||
190 | case songs: | 194 | case songs4album: |
191 | /* 'extra' is offset to the album */ | 195 | /* 'extra' is offset to the album */ |
192 | len = songarraylen * 4; | 196 | safeplacelen = songarraylen * 4; |
193 | safeplace = (void*)(c->name_buffer + c->name_buffer_size - len); | 197 | safeplace = (void*)(end_of_nbuf - safeplacelen); |
194 | //DEBUGF("Seeking to %x\n", extra + albumlen + 4); | ||
195 | lseek(fd, extra + albumlen + 4, SEEK_SET); | 198 | lseek(fd, extra + albumlen + 4, SEEK_SET); |
196 | rc = read(fd, safeplace, len); | 199 | rc = read(fd, safeplace, safeplacelen); |
197 | if (rc < len) | 200 | if (rc < safeplacelen) |
198 | return -1; | 201 | return -1; |
199 | 202 | ||
200 | #ifdef LITTLE_ENDIAN | 203 | #ifdef LITTLE_ENDIAN |
@@ -211,6 +214,10 @@ int db_load(struct tree_context* c, bool* dir_buffer_full) | |||
211 | return -1; | 214 | return -1; |
212 | } | 215 | } |
213 | max_items = dcachesize / c->dentry_size; | 216 | max_items = dcachesize / c->dentry_size; |
217 | end_of_nbuf -= safeplacelen; | ||
218 | |||
219 | c->dirlength = itemcount; | ||
220 | itemcount -= c->firstpos; | ||
214 | 221 | ||
215 | if (!safeplace) { | 222 | if (!safeplace) { |
216 | //DEBUGF("Seeking to %x\n", offset); | 223 | //DEBUGF("Seeking to %x\n", offset); |
@@ -222,8 +229,7 @@ int db_load(struct tree_context* c, bool* dir_buffer_full) | |||
222 | the rest is table specific. see below. */ | 229 | the rest is table specific. see below. */ |
223 | 230 | ||
224 | if (itemcount > max_items) | 231 | if (itemcount > max_items) |
225 | if (dir_buffer_full) | 232 | c->dirfull = true; |
226 | *dir_buffer_full = true; | ||
227 | 233 | ||
228 | if (max_items > itemcount) { | 234 | if (max_items > itemcount) { |
229 | max_items = itemcount; | 235 | max_items = itemcount; |
@@ -233,8 +239,10 @@ int db_load(struct tree_context* c, bool* dir_buffer_full) | |||
233 | int rc, skip=0; | 239 | int rc, skip=0; |
234 | 240 | ||
235 | if (safeplace) { | 241 | if (safeplace) { |
236 | if (!safeplace[i]) | 242 | if (!safeplace[i]) { |
243 | c->dirlength = i; | ||
237 | break; | 244 | break; |
245 | } | ||
238 | //DEBUGF("Seeking to %x\n", safeplace[i]); | 246 | //DEBUGF("Seeking to %x\n", safeplace[i]); |
239 | lseek(fd, safeplace[i], SEEK_SET); | 247 | lseek(fd, safeplace[i], SEEK_SET); |
240 | offset = safeplace[i]; | 248 | offset = safeplace[i]; |
@@ -252,15 +260,15 @@ int db_load(struct tree_context* c, bool* dir_buffer_full) | |||
252 | dptr[0] = (unsigned int)nptr; | 260 | dptr[0] = (unsigned int)nptr; |
253 | 261 | ||
254 | switch (table) { | 262 | switch (table) { |
255 | case songs: | ||
256 | case allsongs: | 263 | case allsongs: |
264 | case songs4album: | ||
257 | /* save offset of this song */ | 265 | /* save offset of this song */ |
258 | skip = 12; | 266 | skip = 12; |
259 | dptr[1] = offset; | 267 | dptr[1] = offset; |
260 | break; | 268 | break; |
261 | 269 | ||
262 | case allalbums: | 270 | case allalbums: |
263 | case albums: | 271 | case albums4artist: |
264 | /* save offset of this album */ | 272 | /* save offset of this album */ |
265 | skip = songarraylen * 4 + 4; | 273 | skip = songarraylen * 4 + 4; |
266 | dptr[1] = offset; | 274 | dptr[1] = offset; |
@@ -273,15 +281,14 @@ int db_load(struct tree_context* c, bool* dir_buffer_full) | |||
273 | break; | 281 | break; |
274 | } | 282 | } |
275 | 283 | ||
276 | //DEBUGF("%x: %s\n", dptr[1], dptr[0]); | ||
277 | |||
278 | if (skip) | 284 | if (skip) |
279 | lseek(fd, skip, SEEK_CUR); | 285 | lseek(fd, skip, SEEK_CUR); |
280 | 286 | ||
281 | /* next name is stored immediately after this */ | 287 | /* next name is stored immediately after this */ |
282 | nptr = (void*)nptr + strlen((char*)nptr) + 1; | 288 | nptr = (void*)nptr + strlen((char*)nptr) + 1; |
283 | if ((void*)nptr > (void*)c->name_buffer + c->name_buffer_size) { | 289 | if ((void*)nptr > (void*)end_of_nbuf) { |
284 | DEBUGF("Name buffer overflow (%d)\n",i); | 290 | DEBUGF("Name buffer overflow (%d)\n",i); |
291 | c->dirfull = true; | ||
285 | break; | 292 | break; |
286 | } | 293 | } |
287 | dptr = (void*)dptr + c->dentry_size; | 294 | dptr = (void*)dptr + c->dentry_size; |
@@ -299,11 +306,12 @@ void db_enter(struct tree_context* c) | |||
299 | { | 306 | { |
300 | switch (c->currtable) { | 307 | switch (c->currtable) { |
301 | case allartists: | 308 | case allartists: |
302 | case albums: | 309 | case albums4artist: |
303 | c->dirpos[c->dirlevel] = c->dirstart; | 310 | c->dirpos[c->dirlevel] = c->dirstart; |
304 | c->cursorpos[c->dirlevel] = c->dircursor; | 311 | c->cursorpos[c->dirlevel] = c->dircursor; |
305 | c->table_history[c->dirlevel] = c->currtable; | 312 | c->table_history[c->dirlevel] = c->currtable; |
306 | c->extra_history[c->dirlevel] = c->currextra; | 313 | c->extra_history[c->dirlevel] = c->currextra; |
314 | c->pos_history[c->dirlevel] = c->firstpos; | ||
307 | c->dirlevel++; | 315 | c->dirlevel++; |
308 | break; | 316 | break; |
309 | 317 | ||
@@ -313,16 +321,16 @@ void db_enter(struct tree_context* c) | |||
313 | 321 | ||
314 | switch (c->currtable) { | 322 | switch (c->currtable) { |
315 | case allartists: | 323 | case allartists: |
316 | c->currtable = albums; | 324 | c->currtable = albums4artist; |
317 | c->currextra = ((int*)c->dircache)[(c->dircursor + c->dirstart)*2 + 1]; | 325 | c->currextra = ((int*)c->dircache)[(c->dircursor + c->dirstart)*2 + 1]; |
318 | break; | 326 | break; |
319 | 327 | ||
320 | case albums: | 328 | case albums4artist: |
321 | c->currtable = songs; | 329 | c->currtable = songs4album; |
322 | c->currextra = ((int*)c->dircache)[(c->dircursor + c->dirstart)*2 + 1]; | 330 | c->currextra = ((int*)c->dircache)[(c->dircursor + c->dirstart)*2 + 1]; |
323 | break; | 331 | break; |
324 | 332 | ||
325 | case songs: | 333 | case songs4album: |
326 | splash(HZ,true,"No playing implemented yet"); | 334 | splash(HZ,true,"No playing implemented yet"); |
327 | #if 0 | 335 | #if 0 |
328 | /* find filenames, build playlist, play */ | 336 | /* find filenames, build playlist, play */ |
@@ -334,7 +342,7 @@ void db_enter(struct tree_context* c) | |||
334 | break; | 342 | break; |
335 | } | 343 | } |
336 | 344 | ||
337 | c->dirstart = c->dircursor = 0; | 345 | c->dirstart = c->dircursor = c->firstpos = 0; |
338 | } | 346 | } |
339 | 347 | ||
340 | void db_exit(struct tree_context* c) | 348 | void db_exit(struct tree_context* c) |
@@ -344,6 +352,7 @@ void db_exit(struct tree_context* c) | |||
344 | c->dircursor = c->cursorpos[c->dirlevel]; | 352 | c->dircursor = c->cursorpos[c->dirlevel]; |
345 | c->currtable = c->table_history[c->dirlevel]; | 353 | c->currtable = c->table_history[c->dirlevel]; |
346 | c->currextra = c->extra_history[c->dirlevel]; | 354 | c->currextra = c->extra_history[c->dirlevel]; |
355 | c->firstpos = c->pos_history[c->dirlevel]; | ||
347 | } | 356 | } |
348 | 357 | ||
349 | #ifdef HAVE_LCD_BITMAP | 358 | #ifdef HAVE_LCD_BITMAP |
@@ -354,7 +363,7 @@ const char* db_get_icon(struct tree_context* c) | |||
354 | switch (c->currtable) | 363 | switch (c->currtable) |
355 | { | 364 | { |
356 | case allsongs: | 365 | case allsongs: |
357 | case songs: | 366 | case songs4album: |
358 | icon = File; | 367 | icon = File; |
359 | break; | 368 | break; |
360 | 369 | ||
@@ -372,7 +381,7 @@ int db_get_icon(struct tree_context* c) | |||
372 | switch (c->currtable) | 381 | switch (c->currtable) |
373 | { | 382 | { |
374 | case allsongs: | 383 | case allsongs: |
375 | case songs: | 384 | case songs4album: |
376 | icon = File; | 385 | icon = File; |
377 | break; | 386 | break; |
378 | 387 | ||
diff --git a/apps/dbtree.h b/apps/dbtree.h index 414aa6f19f..5fa09b0eaf 100644 --- a/apps/dbtree.h +++ b/apps/dbtree.h | |||
@@ -21,13 +21,13 @@ | |||
21 | 21 | ||
22 | #include "tree.h" | 22 | #include "tree.h" |
23 | 23 | ||
24 | enum table { invalid, allsongs, allalbums, allartists, albums, songs }; | 24 | enum table { invalid, allsongs, allalbums, allartists, |
25 | albums4artist, songs4album }; | ||
25 | 26 | ||
26 | int db_init(void); | 27 | int db_init(void); |
27 | void db_enter(struct tree_context* c); | 28 | void db_enter(struct tree_context* c); |
28 | void db_exit(struct tree_context* c); | 29 | void db_exit(struct tree_context* c); |
29 | int db_load(struct tree_context* c, | 30 | int db_load(struct tree_context* c); |
30 | bool* dir_buffer_full); | ||
31 | #ifdef HAVE_LCD_BITMAP | 31 | #ifdef HAVE_LCD_BITMAP |
32 | const char* db_get_icon(struct tree_context* c); | 32 | const char* db_get_icon(struct tree_context* c); |
33 | #else | 33 | #else |
diff --git a/apps/filetree.c b/apps/filetree.c index 09c2a2dcc0..a46ffbb2bc 100644 --- a/apps/filetree.c +++ b/apps/filetree.c | |||
@@ -184,9 +184,8 @@ static int compare(const void* p1, const void* p2) | |||
184 | } | 184 | } |
185 | 185 | ||
186 | /* load and sort directory into dircache. returns NULL on failure. */ | 186 | /* load and sort directory into dircache. returns NULL on failure. */ |
187 | int ft_load(struct tree_context* c, bool *buffer_full) | 187 | int ft_load(struct tree_context* c) |
188 | { | 188 | { |
189 | extern char lastdir[]; /* from tree.c */ | ||
190 | int i; | 189 | int i; |
191 | int name_buffer_used = 0; | 190 | int name_buffer_used = 0; |
192 | DIR *dir = opendir(c->currdir); | 191 | DIR *dir = opendir(c->currdir); |
@@ -194,13 +193,13 @@ int ft_load(struct tree_context* c, bool *buffer_full) | |||
194 | return -1; /* not a directory */ | 193 | return -1; /* not a directory */ |
195 | 194 | ||
196 | c->dirsindir = 0; | 195 | c->dirsindir = 0; |
197 | if (buffer_full) | 196 | c->dirfull = false; |
198 | *buffer_full = false; | ||
199 | 197 | ||
200 | for ( i=0; i < global_settings.max_files_in_dir; i++ ) { | 198 | for ( i=0; i < global_settings.max_files_in_dir; i++ ) { |
201 | int len; | 199 | int len; |
202 | struct dirent *entry = readdir(dir); | 200 | struct dirent *entry = readdir(dir); |
203 | struct entry* dptr = (struct entry*)(c->dircache + i * sizeof(struct entry)); | 201 | struct entry* dptr = |
202 | (struct entry*)(c->dircache + i * sizeof(struct entry)); | ||
204 | if (!entry) | 203 | if (!entry) |
205 | break; | 204 | break; |
206 | 205 | ||
@@ -268,8 +267,7 @@ int ft_load(struct tree_context* c, bool *buffer_full) | |||
268 | 267 | ||
269 | if (len > c->name_buffer_size - name_buffer_used - 1) { | 268 | if (len > c->name_buffer_size - name_buffer_used - 1) { |
270 | /* Tell the world that we ran out of buffer space */ | 269 | /* Tell the world that we ran out of buffer space */ |
271 | if (buffer_full) | 270 | c->dirfull = true; |
272 | *buffer_full = true; | ||
273 | break; | 271 | break; |
274 | } | 272 | } |
275 | dptr->name = &c->name_buffer[name_buffer_used]; | 273 | dptr->name = &c->name_buffer[name_buffer_used]; |
@@ -281,10 +279,9 @@ int ft_load(struct tree_context* c, bool *buffer_full) | |||
281 | c->dirsindir++; | 279 | c->dirsindir++; |
282 | } | 280 | } |
283 | c->filesindir = i; | 281 | c->filesindir = i; |
282 | c->dirlength = i; | ||
284 | closedir(dir); | 283 | closedir(dir); |
285 | 284 | ||
286 | strcpy(lastdir, c->currdir); | ||
287 | |||
288 | qsort(c->dircache,i,sizeof(struct entry),compare); | 285 | qsort(c->dircache,i,sizeof(struct entry),compare); |
289 | 286 | ||
290 | /* If thumbnail talking is enabled, make an extra run to mark files with | 287 | /* If thumbnail talking is enabled, make an extra run to mark files with |
diff --git a/apps/filetree.h b/apps/filetree.h index fcf8b64af2..143b75ad66 100644 --- a/apps/filetree.h +++ b/apps/filetree.h | |||
@@ -20,7 +20,7 @@ | |||
20 | #define FILETREE_H | 20 | #define FILETREE_H |
21 | #include "tree.h" | 21 | #include "tree.h" |
22 | 22 | ||
23 | int ft_load(struct tree_context* c, bool *buffer_full); | 23 | int ft_load(struct tree_context* c); |
24 | int ft_play_filenumber(int pos, int attr); | 24 | int ft_play_filenumber(int pos, int attr); |
25 | int ft_play_dirname(int start_index); | 25 | int ft_play_dirname(int start_index); |
26 | void ft_play_filename(char *dir, char *file); | 26 | void ft_play_filename(char *dir, char *file); |
diff --git a/apps/playlist.c b/apps/playlist.c index aa8415a86f..4506ec5f54 100644 --- a/apps/playlist.c +++ b/apps/playlist.c | |||
@@ -545,7 +545,7 @@ static int add_directory_to_playlist(struct playlist_info* playlist, | |||
545 | /* use the tree browser dircache to load files */ | 545 | /* use the tree browser dircache to load files */ |
546 | global_settings.dirfilter = SHOW_ALL; | 546 | global_settings.dirfilter = SHOW_ALL; |
547 | strncpy(tc->currdir, dirname, sizeof(tc->currdir)); | 547 | strncpy(tc->currdir, dirname, sizeof(tc->currdir)); |
548 | num_files = ft_load(tc, NULL); | 548 | num_files = ft_load(tc); |
549 | files = (struct entry*) tc->dircache; | 549 | files = (struct entry*) tc->dircache; |
550 | 550 | ||
551 | if(!num_files) | 551 | if(!num_files) |
@@ -585,7 +585,7 @@ static int add_directory_to_playlist(struct playlist_info* playlist, | |||
585 | 585 | ||
586 | /* we now need to reload our current directory */ | 586 | /* we now need to reload our current directory */ |
587 | strncpy(tc->currdir, dirname, sizeof(tc->currdir)); | 587 | strncpy(tc->currdir, dirname, sizeof(tc->currdir)); |
588 | num_files = ft_load(tc, NULL); | 588 | num_files = ft_load(tc); |
589 | files = (struct entry*) tc->dircache; | 589 | files = (struct entry*) tc->dircache; |
590 | if (!num_files) | 590 | if (!num_files) |
591 | { | 591 | { |
diff --git a/apps/tree.c b/apps/tree.c index b844060322..2ba4585047 100644 --- a/apps/tree.c +++ b/apps/tree.c | |||
@@ -92,7 +92,9 @@ static struct tree_context tc; | |||
92 | bool boot_changed = false; | 92 | bool boot_changed = false; |
93 | 93 | ||
94 | char lastfile[MAX_PATH]; | 94 | char lastfile[MAX_PATH]; |
95 | char lastdir[MAX_PATH]; | 95 | static char lastdir[MAX_PATH]; |
96 | static int lasttable, lastextra, lastfirstpos; | ||
97 | static int max_files = 0; | ||
96 | 98 | ||
97 | static bool reload_dir = false; | 99 | static bool reload_dir = false; |
98 | 100 | ||
@@ -245,10 +247,9 @@ static int showdir(void) | |||
245 | struct entry *dircache = tc.dircache; | 247 | struct entry *dircache = tc.dircache; |
246 | int i; | 248 | int i; |
247 | int tree_max_on_screen; | 249 | int tree_max_on_screen; |
248 | bool dir_buffer_full = false; | ||
249 | int start = tc.dirstart; | 250 | int start = tc.dirstart; |
250 | bool id3db = global_settings.dirfilter == SHOW_ID3DB; | 251 | bool id3db = global_settings.dirfilter == SHOW_ID3DB; |
251 | 252 | bool newdir = false; | |
252 | #ifdef HAVE_LCD_BITMAP | 253 | #ifdef HAVE_LCD_BITMAP |
253 | const char* icon; | 254 | const char* icon; |
254 | int line_height; | 255 | int line_height; |
@@ -264,17 +265,30 @@ static int showdir(void) | |||
264 | 265 | ||
265 | /* new file dir? load it */ | 266 | /* new file dir? load it */ |
266 | if (id3db) { | 267 | if (id3db) { |
267 | if (db_load(&tc, &dir_buffer_full) < 0) | 268 | if (tc.currtable != lasttable || |
268 | return -1; | 269 | tc.currextra != lastextra || |
270 | tc.firstpos != lastfirstpos) | ||
271 | { | ||
272 | if (db_load(&tc) < 0) | ||
273 | return -1; | ||
274 | lasttable = tc.currtable; | ||
275 | lastextra = tc.currextra; | ||
276 | lastfirstpos = tc.firstpos; | ||
277 | newdir = true; | ||
278 | } | ||
269 | } | 279 | } |
270 | else { | 280 | else { |
271 | if (strncmp(tc.currdir, lastdir, sizeof(lastdir)) || reload_dir) { | 281 | if (strncmp(tc.currdir, lastdir, sizeof(lastdir)) || reload_dir) { |
272 | if (ft_load(&tc, &dir_buffer_full) < 0) | 282 | if (ft_load(&tc) < 0) |
273 | return -1; | 283 | return -1; |
284 | strcpy(lastdir, tc.currdir); | ||
285 | newdir = true; | ||
274 | } | 286 | } |
275 | } | 287 | } |
276 | 288 | ||
277 | if ( dir_buffer_full || tc.filesindir == global_settings.max_files_in_dir ) { | 289 | if (newdir && !id3db && |
290 | (tc.dirfull || tc.filesindir == global_settings.max_files_in_dir) ) | ||
291 | { | ||
278 | #ifdef HAVE_LCD_CHARCELLS | 292 | #ifdef HAVE_LCD_CHARCELLS |
279 | lcd_double_height(false); | 293 | lcd_double_height(false); |
280 | #endif | 294 | #endif |
@@ -383,10 +397,11 @@ static int showdir(void) | |||
383 | } | 397 | } |
384 | 398 | ||
385 | #ifdef HAVE_LCD_BITMAP | 399 | #ifdef HAVE_LCD_BITMAP |
386 | if (global_settings.scrollbar && (tc.filesindir > tree_max_on_screen)) | 400 | if (global_settings.scrollbar && (tc.dirlength > tree_max_on_screen)) |
387 | scrollbar(SCROLLBAR_X, SCROLLBAR_Y, SCROLLBAR_WIDTH - 1, | 401 | scrollbar(SCROLLBAR_X, SCROLLBAR_Y, SCROLLBAR_WIDTH - 1, |
388 | tree_max_on_screen * line_height, tc.filesindir, start, | 402 | tree_max_on_screen * line_height, tc.dirlength, |
389 | start + tree_max_on_screen, VERTICAL); | 403 | start + tc.firstpos, |
404 | start + tc.firstpos + tree_max_on_screen, VERTICAL); | ||
390 | 405 | ||
391 | #if CONFIG_KEYPAD == RECORDER_PAD | 406 | #if CONFIG_KEYPAD == RECORDER_PAD |
392 | if(global_settings.buttonbar) { | 407 | if(global_settings.buttonbar) { |
@@ -483,10 +498,8 @@ static bool ask_resume(bool ask_once) | |||
483 | /* load tracks from specified directory to resume play */ | 498 | /* load tracks from specified directory to resume play */ |
484 | void resume_directory(const char *dir) | 499 | void resume_directory(const char *dir) |
485 | { | 500 | { |
486 | bool buffer_full; | ||
487 | |||
488 | strcpy(tc.currdir, dir); | 501 | strcpy(tc.currdir, dir); |
489 | if (!ft_load(&tc, &buffer_full)) | 502 | if (!ft_load(&tc)) |
490 | return; | 503 | return; |
491 | lastdir[0] = 0; | 504 | lastdir[0] = 0; |
492 | 505 | ||
@@ -586,10 +599,10 @@ static bool check_changed_id3mode(bool currmode) | |||
586 | if (currmode != (global_settings.dirfilter == SHOW_ID3DB)) { | 599 | if (currmode != (global_settings.dirfilter == SHOW_ID3DB)) { |
587 | currmode = global_settings.dirfilter == SHOW_ID3DB; | 600 | currmode = global_settings.dirfilter == SHOW_ID3DB; |
588 | if (currmode) { | 601 | if (currmode) { |
589 | db_load(&tc, NULL); | 602 | db_load(&tc); |
590 | } | 603 | } |
591 | else | 604 | else |
592 | ft_load(&tc, NULL); | 605 | ft_load(&tc); |
593 | } | 606 | } |
594 | return currmode; | 607 | return currmode; |
595 | } | 608 | } |
@@ -624,6 +637,10 @@ static bool dirbrowse(void) | |||
624 | tc.dircursor=0; | 637 | tc.dircursor=0; |
625 | tc.dirstart=0; | 638 | tc.dirstart=0; |
626 | tc.dirlevel=0; | 639 | tc.dirlevel=0; |
640 | tc.firstpos=0; | ||
641 | lasttable = -1; | ||
642 | lastextra = -1; | ||
643 | lastfirstpos = 0; | ||
627 | 644 | ||
628 | if (*tc.dirfilter < NUM_FILTER_MODES) | 645 | if (*tc.dirfilter < NUM_FILTER_MODES) |
629 | start_resume(true); | 646 | start_resume(true); |
@@ -778,39 +795,59 @@ static bool dirbrowse(void) | |||
778 | case TREE_RC_PREV: | 795 | case TREE_RC_PREV: |
779 | case TREE_RC_PREV | BUTTON_REPEAT: | 796 | case TREE_RC_PREV | BUTTON_REPEAT: |
780 | #endif | 797 | #endif |
781 | if(tc.filesindir) { | 798 | if (!tc.filesindir) |
782 | if(tc.dircursor) { | 799 | break; |
783 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false); | 800 | |
784 | tc.dircursor--; | 801 | if (tc.dircursor) { |
785 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); | 802 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false); |
786 | } | 803 | tc.dircursor--; |
787 | else { | 804 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); |
788 | if (tc.dirstart) { | 805 | } |
806 | else { | ||
807 | if (tc.dirstart || tc.firstpos) { | ||
808 | if (tc.dirstart) | ||
789 | tc.dirstart--; | 809 | tc.dirstart--; |
790 | numentries = showdir(); | ||
791 | update_all=true; | ||
792 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); | ||
793 | } | ||
794 | else { | 810 | else { |
795 | if (numentries < tree_max_on_screen) { | 811 | if (tc.firstpos > max_files/2) { |
796 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, | 812 | tc.firstpos -= max_files/2; |
797 | false); | 813 | tc.dirstart += max_files/2; |
798 | tc.dircursor = numentries - 1; | 814 | tc.dirstart--; |
799 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, | ||
800 | true); | ||
801 | } | 815 | } |
802 | else { | 816 | else { |
803 | tc.dirstart = numentries - tree_max_on_screen; | 817 | tc.dirstart = tc.firstpos - 1; |
804 | tc.dircursor = tree_max_on_screen - 1; | 818 | tc.firstpos = 0; |
805 | numentries = showdir(); | ||
806 | update_all = true; | ||
807 | put_cursorxy(CURSOR_X, CURSOR_Y + | ||
808 | tree_max_on_screen - 1, true); | ||
809 | } | 819 | } |
810 | } | 820 | } |
821 | restore = true; | ||
822 | } | ||
823 | else { | ||
824 | if (numentries < tree_max_on_screen) { | ||
825 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, | ||
826 | false); | ||
827 | tc.dircursor = numentries - 1; | ||
828 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, | ||
829 | true); | ||
830 | } | ||
831 | else if (id3db && tc.dirfull) { | ||
832 | /* load last dir segment */ | ||
833 | /* use max_files/2 in case names are longer than | ||
834 | AVERAGE_FILE_LENGTH */ | ||
835 | tc.firstpos = tc.dirlength - max_files/2; | ||
836 | tc.dirstart = tc.firstpos; | ||
837 | tc.dircursor = tree_max_on_screen - 1; | ||
838 | numentries = showdir(); | ||
839 | update_all = true; | ||
840 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, | ||
841 | true); | ||
842 | } | ||
843 | else { | ||
844 | tc.dirstart = numentries - tree_max_on_screen; | ||
845 | tc.dircursor = tree_max_on_screen - 1; | ||
846 | restore = true; | ||
847 | } | ||
811 | } | 848 | } |
812 | need_update = true; | ||
813 | } | 849 | } |
850 | need_update = true; | ||
814 | break; | 851 | break; |
815 | 852 | ||
816 | case TREE_NEXT: | 853 | case TREE_NEXT: |
@@ -819,46 +856,67 @@ static bool dirbrowse(void) | |||
819 | case TREE_RC_NEXT: | 856 | case TREE_RC_NEXT: |
820 | case TREE_RC_NEXT | BUTTON_REPEAT: | 857 | case TREE_RC_NEXT | BUTTON_REPEAT: |
821 | #endif | 858 | #endif |
822 | if(tc.filesindir) | 859 | if (!tc.filesindir) |
823 | { | 860 | break; |
824 | if (tc.dircursor + tc.dirstart + 1 < numentries ) { | 861 | |
825 | if(tc.dircursor+1 < tree_max_on_screen) { | 862 | if (tc.dircursor + tc.dirstart + 1 < numentries ) { |
826 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false); | 863 | if(tc.dircursor+1 < tree_max_on_screen) { |
827 | tc.dircursor++; | 864 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false); |
828 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); | 865 | tc.dircursor++; |
829 | } | 866 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); |
830 | else { | ||
831 | tc.dirstart++; | ||
832 | numentries = showdir(); | ||
833 | update_all = true; | ||
834 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); | ||
835 | } | ||
836 | } | 867 | } |
837 | else { | 868 | else { |
838 | if(numentries < tree_max_on_screen) { | 869 | tc.dirstart++; |
839 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false); | 870 | restore = true; |
840 | tc.dirstart = tc.dircursor = 0; | ||
841 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); | ||
842 | } | ||
843 | else { | ||
844 | tc.dirstart = tc.dircursor = 0; | ||
845 | numentries = showdir(); | ||
846 | update_all=true; | ||
847 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); | ||
848 | } | ||
849 | } | 871 | } |
850 | need_update = true; | ||
851 | } | 872 | } |
873 | else if (id3db && (tc.firstpos || tc.dirfull)) { | ||
874 | if (tc.dircursor + tc.dirstart + tc.firstpos + 1 >= tc.dirlength) { | ||
875 | /* wrap and load first dir segment */ | ||
876 | tc.firstpos = tc.dirstart = tc.dircursor = 0; | ||
877 | } | ||
878 | else { | ||
879 | /* load next dir segment */ | ||
880 | tc.firstpos += tc.dirstart; | ||
881 | tc.dirstart = 0; | ||
882 | } | ||
883 | restore = true; | ||
884 | } | ||
885 | else { | ||
886 | if(numentries < tree_max_on_screen) { | ||
887 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false); | ||
888 | tc.dirstart = tc.dircursor = 0; | ||
889 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); | ||
890 | } | ||
891 | else { | ||
892 | tc.dirstart = tc.dircursor = 0; | ||
893 | numentries = showdir(); | ||
894 | update_all=true; | ||
895 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); | ||
896 | } | ||
897 | } | ||
898 | need_update = true; | ||
852 | break; | 899 | break; |
853 | 900 | ||
854 | #ifdef TREE_PGUP | 901 | #ifdef TREE_PGUP |
855 | case TREE_PGUP: | 902 | case TREE_PGUP: |
856 | case TREE_PGUP | BUTTON_REPEAT: | 903 | case TREE_PGUP | BUTTON_REPEAT: |
857 | if ( tc.dirstart ) { | 904 | if (tc.dirstart) { |
858 | tc.dirstart -= tree_max_on_screen; | 905 | tc.dirstart -= tree_max_on_screen; |
859 | if ( tc.dirstart < 0 ) | 906 | if ( tc.dirstart < 0 ) |
860 | tc.dirstart = 0; | 907 | tc.dirstart = 0; |
861 | } | 908 | } |
909 | else if (tc.firstpos) { | ||
910 | if (tc.firstpos > max_files/2) { | ||
911 | tc.firstpos -= max_files/2; | ||
912 | tc.dirstart += max_files/2; | ||
913 | tc.dirstart -= tree_max_on_screen; | ||
914 | } | ||
915 | else { | ||
916 | tc.dirstart = tc.firstpos - tree_max_on_screen; | ||
917 | tc.firstpos = 0; | ||
918 | } | ||
919 | } | ||
862 | else | 920 | else |
863 | tc.dircursor = 0; | 921 | tc.dircursor = 0; |
864 | restore = true; | 922 | restore = true; |
@@ -868,10 +926,14 @@ static bool dirbrowse(void) | |||
868 | case TREE_PGDN | BUTTON_REPEAT: | 926 | case TREE_PGDN | BUTTON_REPEAT: |
869 | if ( tc.dirstart < numentries - tree_max_on_screen ) { | 927 | if ( tc.dirstart < numentries - tree_max_on_screen ) { |
870 | tc.dirstart += tree_max_on_screen; | 928 | tc.dirstart += tree_max_on_screen; |
871 | if ( tc.dirstart > | 929 | if ( tc.dirstart > numentries - tree_max_on_screen ) |
872 | numentries - tree_max_on_screen ) | ||
873 | tc.dirstart = numentries - tree_max_on_screen; | 930 | tc.dirstart = numentries - tree_max_on_screen; |
874 | } | 931 | } |
932 | else if (id3db && tc.dirfull) { | ||
933 | /* load next dir segment */ | ||
934 | tc.firstpos += tc.dirstart; | ||
935 | tc.dirstart = 0; | ||
936 | } | ||
875 | else | 937 | else |
876 | tc.dircursor = numentries - tc.dirstart - 1; | 938 | tc.dircursor = numentries - tc.dirstart - 1; |
877 | restore = true; | 939 | restore = true; |
@@ -1334,7 +1396,7 @@ void tree_init(void) | |||
1334 | { | 1396 | { |
1335 | /* We copy the settings value in case it is changed by the user. We can't | 1397 | /* We copy the settings value in case it is changed by the user. We can't |
1336 | use it until the next reboot. */ | 1398 | use it until the next reboot. */ |
1337 | int max_files = global_settings.max_files_in_dir; | 1399 | max_files = global_settings.max_files_in_dir; |
1338 | 1400 | ||
1339 | /* initialize tree context struct */ | 1401 | /* initialize tree context struct */ |
1340 | memset(&tc, 0, sizeof(tc)); | 1402 | memset(&tc, 0, sizeof(tc)); |
diff --git a/apps/tree.h b/apps/tree.h index 87e0361e50..87364bfd5a 100644 --- a/apps/tree.h +++ b/apps/tree.h | |||
@@ -121,12 +121,16 @@ struct tree_context { | |||
121 | int dirlevel; | 121 | int dirlevel; |
122 | int dircursor; | 122 | int dircursor; |
123 | int dirstart; | 123 | int dirstart; |
124 | int firstpos; /* which dir entry is on first | ||
125 | position in dir buffer */ | ||
126 | int pos_history[MAX_DIR_LEVELS]; | ||
124 | int dirpos[MAX_DIR_LEVELS]; | 127 | int dirpos[MAX_DIR_LEVELS]; |
125 | int cursorpos[MAX_DIR_LEVELS]; | 128 | int cursorpos[MAX_DIR_LEVELS]; |
126 | char currdir[MAX_PATH]; /* file use */ | 129 | char currdir[MAX_PATH]; /* file use */ |
127 | int *dirfilter; /* file use */ | 130 | int *dirfilter; /* file use */ |
128 | int filesindir; | 131 | int filesindir; |
129 | int dirsindir; /* file use */ | 132 | int dirsindir; /* file use */ |
133 | int dirlength; /* total number of entries in dir, incl. those not loaded */ | ||
130 | int table_history[MAX_DIR_LEVELS]; /* db use */ | 134 | int table_history[MAX_DIR_LEVELS]; /* db use */ |
131 | int extra_history[MAX_DIR_LEVELS]; /* db use */ | 135 | int extra_history[MAX_DIR_LEVELS]; /* db use */ |
132 | int currtable; /* db use */ | 136 | int currtable; /* db use */ |
@@ -137,6 +141,7 @@ struct tree_context { | |||
137 | char* name_buffer; | 141 | char* name_buffer; |
138 | int name_buffer_size; | 142 | int name_buffer_size; |
139 | int dentry_size; | 143 | int dentry_size; |
144 | bool dirfull; | ||
140 | }; | 145 | }; |
141 | 146 | ||
142 | /* using attribute bits not used by FAT (FAT uses lower 7) */ | 147 | /* using attribute bits not used by FAT (FAT uses lower 7) */ |