diff options
author | Björn Stenberg <bjorn@haxx.se> | 2004-01-14 00:13:04 +0000 |
---|---|---|
committer | Björn Stenberg <bjorn@haxx.se> | 2004-01-14 00:13:04 +0000 |
commit | a108ec2ebd237835a688ae5c82c90e07607219ae (patch) | |
tree | 17c0af92368ee76d16cfdc2162aadbb7f103d926 | |
parent | 50b6358272eaf1f255bcb430766e6fc9e26810d3 (diff) | |
download | rockbox-a108ec2ebd237835a688ae5c82c90e07607219ae.tar.gz rockbox-a108ec2ebd237835a688ae5c82c90e07607219ae.zip |
Added Benjamin Metzlers bookmarking feature (patch #669440)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4227 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/bookmark.c | 1105 | ||||
-rw-r--r-- | apps/bookmark.h | 33 | ||||
-rw-r--r-- | apps/lang/english.lang | 122 | ||||
-rw-r--r-- | apps/main_menu.c | 6 | ||||
-rw-r--r-- | apps/playlist.c | 61 | ||||
-rw-r--r-- | apps/playlist.h | 16 | ||||
-rw-r--r-- | apps/playlist_viewer.c | 4 | ||||
-rw-r--r-- | apps/recorder/icons.c | 1 | ||||
-rw-r--r-- | apps/recorder/icons.h | 1 | ||||
-rw-r--r-- | apps/settings.c | 48 | ||||
-rw-r--r-- | apps/settings.h | 16 | ||||
-rw-r--r-- | apps/settings_menu.c | 52 | ||||
-rw-r--r-- | apps/tree.c | 107 | ||||
-rw-r--r-- | apps/tree.h | 1 | ||||
-rw-r--r-- | apps/wps.c | 4 | ||||
-rw-r--r-- | uisimulator/win32/Makefile | 5 | ||||
-rw-r--r-- | uisimulator/x11/Makefile | 5 |
17 files changed, 1545 insertions, 42 deletions
diff --git a/apps/bookmark.c b/apps/bookmark.c new file mode 100644 index 0000000000..b557e88fb2 --- /dev/null +++ b/apps/bookmark.c | |||
@@ -0,0 +1,1105 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2003 by Benjamin Metzler | ||
10 | * | ||
11 | * All files in this archive are subject to the GNU General Public License. | ||
12 | * See the file COPYING in the source tree root for full license agreement. | ||
13 | * | ||
14 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
15 | * KIND, either express or implied. | ||
16 | * | ||
17 | ****************************************************************************/ | ||
18 | |||
19 | |||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | #include <stdbool.h> | ||
24 | |||
25 | #include "applimits.h" | ||
26 | #include "lcd.h" | ||
27 | #include "button.h" | ||
28 | #include "usb.h" | ||
29 | #include "mpeg.h" | ||
30 | #include "wps.h" | ||
31 | #include "settings.h" | ||
32 | #include "bookmark.h" | ||
33 | #include "dir.h" | ||
34 | #include "status.h" | ||
35 | #include "system.h" | ||
36 | #include "errno.h" | ||
37 | #include "icons.h" | ||
38 | #include "atoi.h" | ||
39 | #include "string.h" | ||
40 | #include "menu.h" | ||
41 | #include "lang.h" | ||
42 | #include "screens.h" | ||
43 | #include "status.h" | ||
44 | #include "debug.h" | ||
45 | #include "kernel.h" | ||
46 | |||
47 | #define MAX_BOOKMARK_SIZE 350 | ||
48 | #define RECENT_BOOKMARK_FILE ROCKBOX_DIR "/most-recent.bmark" | ||
49 | |||
50 | static bool add_bookmark(char* bookmark_file_name, char* bookmark); | ||
51 | static bool bookmark_load_menu(void); | ||
52 | static bool check_bookmark(char* bookmark); | ||
53 | static char* create_bookmark(void); | ||
54 | static bool delete_bookmark(char* bookmark_file_name, int bookmark_id); | ||
55 | static void display_bookmark(char* bookmark, | ||
56 | int bookmark_id, | ||
57 | int bookmark_count); | ||
58 | static bool generate_bookmark_file_name(char *in, | ||
59 | char *out, | ||
60 | unsigned int max_length); | ||
61 | static char* get_bookmark(char* bookmark_file, int bookmark_count); | ||
62 | static bool parse_bookmark(char *bookmark, | ||
63 | int *resume_index, | ||
64 | int *resume_offset, | ||
65 | int *resume_seed, | ||
66 | int *resume_first_index, | ||
67 | char* resume_file, | ||
68 | unsigned int resume_file_size, | ||
69 | int* ms, | ||
70 | int * repeat_mode, | ||
71 | bool *shuffle, | ||
72 | char* file_name, | ||
73 | unsigned int max_file_name_size); | ||
74 | static char* select_bookmark(char* bookmark_file_name); | ||
75 | static bool system_check(void); | ||
76 | static bool write_bookmark(bool create_bookmark_file); | ||
77 | static int get_bookmark_count(char* bookmark_file_name); | ||
78 | |||
79 | static char global_temp_buffer[MAX_PATH+1]; | ||
80 | static char global_bookmark_file_name[MAX_PATH]; | ||
81 | static char global_read_buffer[MAX_BOOKMARK_SIZE]; | ||
82 | static char global_bookmark[MAX_BOOKMARK_SIZE]; | ||
83 | |||
84 | /* ----------------------------------------------------------------------- */ | ||
85 | /* Displays the bookmark menu options for the user to decide. This is an */ | ||
86 | /* interface function. */ | ||
87 | /* ----------------------------------------------------------------------- */ | ||
88 | bool bookmark_menu(void) | ||
89 | { | ||
90 | int m; | ||
91 | bool result; | ||
92 | |||
93 | struct menu_items items[] = { | ||
94 | { str(LANG_BOOKMARK_MENU_CREATE), bookmark_create_menu}, | ||
95 | { str(LANG_BOOKMARK_MENU_LIST), bookmark_load_menu}, | ||
96 | { str(LANG_BOOKMARK_MENU_RECENT_BOOKMARKS), bookmark_mrb_load}, | ||
97 | }; | ||
98 | |||
99 | m=menu_init( items, sizeof items / sizeof(struct menu_items) ); | ||
100 | |||
101 | #ifdef HAVE_LCD_CHARCELLS | ||
102 | status_set_param(true); | ||
103 | #endif | ||
104 | result = menu_run(m); | ||
105 | #ifdef HAVE_LCD_CHARCELLS | ||
106 | status_set_param(false); | ||
107 | #endif | ||
108 | menu_exit(m); | ||
109 | |||
110 | settings_save(); | ||
111 | |||
112 | return result; | ||
113 | } | ||
114 | |||
115 | /* ----------------------------------------------------------------------- */ | ||
116 | /* This is the interface function from the main menu. */ | ||
117 | /* ----------------------------------------------------------------------- */ | ||
118 | bool bookmark_create_menu(void) | ||
119 | { | ||
120 | write_bookmark(true); | ||
121 | return false; | ||
122 | } | ||
123 | |||
124 | /* ----------------------------------------------------------------------- */ | ||
125 | /* This function acts as the load interface from the main menu */ | ||
126 | /* This function determines the bookmark file name and then loads that file*/ | ||
127 | /* for the user. The user can then select a bookmark to load. */ | ||
128 | /* If no file/directory is currently playing, the menu item does not work. */ | ||
129 | /* ----------------------------------------------------------------------- */ | ||
130 | static bool bookmark_load_menu(void) | ||
131 | { | ||
132 | bool success = true; | ||
133 | int offset; | ||
134 | int seed; | ||
135 | int index; | ||
136 | char* bookmark; | ||
137 | |||
138 | if(!system_check()) | ||
139 | return false; | ||
140 | else | ||
141 | { | ||
142 | char* name = playlist_get_name(global_temp_buffer, | ||
143 | sizeof(global_temp_buffer)); | ||
144 | if (generate_bookmark_file_name(name, | ||
145 | global_bookmark_file_name, | ||
146 | sizeof(global_bookmark_file_name))) | ||
147 | { | ||
148 | bookmark = select_bookmark(global_bookmark_file_name); | ||
149 | if (!bookmark) | ||
150 | return false; /* User exited without selecting a bookmark */ | ||
151 | |||
152 | success = parse_bookmark(bookmark, | ||
153 | &index, | ||
154 | &offset, | ||
155 | &seed, | ||
156 | NULL, | ||
157 | global_temp_buffer, | ||
158 | sizeof(global_temp_buffer), | ||
159 | NULL, | ||
160 | &global_settings.repeat_mode, | ||
161 | &global_settings.playlist_shuffle, | ||
162 | NULL, 0); | ||
163 | } | ||
164 | else | ||
165 | { | ||
166 | /* something bad happened while creating bookmark name*/ | ||
167 | success = false; | ||
168 | } | ||
169 | |||
170 | if (success) | ||
171 | bookmark_play(global_temp_buffer, index, offset, seed); | ||
172 | } | ||
173 | |||
174 | return success; | ||
175 | } | ||
176 | |||
177 | /* ----------------------------------------------------------------------- */ | ||
178 | /* Gives the user a list of the Most Recent Bookmarks. This is an */ | ||
179 | /* interface function */ | ||
180 | /* ----------------------------------------------------------------------- */ | ||
181 | bool bookmark_mrb_load() | ||
182 | { | ||
183 | bool success = true; | ||
184 | int offset; | ||
185 | int seed; | ||
186 | int index; | ||
187 | char* bookmark; | ||
188 | |||
189 | bookmark = select_bookmark(RECENT_BOOKMARK_FILE); | ||
190 | if (!bookmark) | ||
191 | return false; /* User exited without selecting a bookmark */ | ||
192 | |||
193 | success = parse_bookmark(bookmark, | ||
194 | &index, | ||
195 | &offset, | ||
196 | &seed, | ||
197 | NULL, | ||
198 | global_temp_buffer, | ||
199 | sizeof(global_temp_buffer), | ||
200 | NULL, | ||
201 | &global_settings.repeat_mode, | ||
202 | &global_settings.playlist_shuffle, | ||
203 | NULL, 0); | ||
204 | |||
205 | if (success) | ||
206 | bookmark_play(global_temp_buffer, index, offset, seed); | ||
207 | |||
208 | return success; | ||
209 | } | ||
210 | |||
211 | |||
212 | /* ----------------------------------------------------------------------- */ | ||
213 | /* This function handles an autobookmark creation. This is an interface */ | ||
214 | /* function. */ | ||
215 | /* ----------------------------------------------------------------------- */ | ||
216 | bool bookmark_autobookmark(void) | ||
217 | { | ||
218 | /* prompts the user as to create a bookmark */ | ||
219 | bool done = false; | ||
220 | int key = 0; | ||
221 | |||
222 | if (!system_check()) | ||
223 | return false; | ||
224 | |||
225 | mpeg_pause(); /* first pause playback */ | ||
226 | switch (global_settings.autocreatebookmark) | ||
227 | { | ||
228 | case BOOKMARK_YES: | ||
229 | return write_bookmark(true); | ||
230 | |||
231 | case BOOKMARK_NO: | ||
232 | return false; | ||
233 | |||
234 | case BOOKMARK_RECENT_ONLY_YES: | ||
235 | return write_bookmark(false); | ||
236 | } | ||
237 | |||
238 | /* Prompting user to confirm bookmark creation */ | ||
239 | lcd_clear_display(); | ||
240 | #ifdef HAVE_LCD_BITMAP | ||
241 | lcd_puts(0,0, str(LANG_AUTO_BOOKMARK_QUERY)); | ||
242 | lcd_puts(0,1, str(LANG_CONFIRM_WITH_PLAY_RECORDER)); | ||
243 | lcd_puts(0,2, str(LANG_CANCEL_WITH_ANY_RECORDER)); | ||
244 | #else | ||
245 | status_draw(false); | ||
246 | lcd_puts(0,0, str(LANG_AUTO_BOOKMARK_QUERY)); | ||
247 | lcd_puts(0,1,str(LANG_RESUME_CONFIRM_PLAYER)); | ||
248 | #endif | ||
249 | lcd_update(); | ||
250 | |||
251 | while (!done) | ||
252 | { | ||
253 | /* Wait for a key to be pushed */ | ||
254 | key = button_get(true); | ||
255 | switch (key) | ||
256 | { | ||
257 | case BUTTON_DOWN | BUTTON_REL: | ||
258 | case BUTTON_ON | BUTTON_REL: | ||
259 | #ifdef HAVE_RECORDER_KEYPAD | ||
260 | case BUTTON_OFF | BUTTON_REL: | ||
261 | case BUTTON_RIGHT | BUTTON_REL: | ||
262 | case BUTTON_UP | BUTTON_REL: | ||
263 | #endif | ||
264 | case BUTTON_LEFT | BUTTON_REL: | ||
265 | done = true; | ||
266 | break; | ||
267 | |||
268 | case BUTTON_PLAY | BUTTON_REL: | ||
269 | if (global_settings.autocreatebookmark == | ||
270 | BOOKMARK_RECENT_ONLY_ASK) | ||
271 | write_bookmark(false); | ||
272 | else | ||
273 | write_bookmark(true); | ||
274 | done = true; | ||
275 | break; | ||
276 | |||
277 | case SYS_USB_CONNECTED: | ||
278 | usb_screen(); | ||
279 | #ifdef HAVE_LCD_CHARCELLS | ||
280 | status_set_param(true); | ||
281 | #endif | ||
282 | return false; | ||
283 | } | ||
284 | } | ||
285 | return true; | ||
286 | } | ||
287 | |||
288 | /* ----------------------------------------------------------------------- */ | ||
289 | /* This function takes the current current resume information and writes */ | ||
290 | /* that to the beginning of the bookmark file. */ | ||
291 | /* This file will contain N number of bookmarks in the following format: */ | ||
292 | /* resume_index*resume_offset*resume_seed*resume_first_index* */ | ||
293 | /* resume_file*milliseconds*MP3 Title* */ | ||
294 | /* ------------------------------------------------------------------------*/ | ||
295 | static bool write_bookmark(bool create_bookmark_file) | ||
296 | { | ||
297 | bool success=false; | ||
298 | char* bookmark; | ||
299 | |||
300 | if (!system_check()) | ||
301 | return false; /* something didn't happen correctly, do nothing */ | ||
302 | |||
303 | bookmark = create_bookmark(); | ||
304 | if (!bookmark) | ||
305 | return false; /* something didn't happen correctly, do nothing */ | ||
306 | |||
307 | if (global_settings.usemrb) | ||
308 | success = add_bookmark(RECENT_BOOKMARK_FILE, bookmark); | ||
309 | |||
310 | |||
311 | /* writing the bookmark */ | ||
312 | if (create_bookmark_file) | ||
313 | { | ||
314 | char* name = playlist_get_name(global_temp_buffer, | ||
315 | sizeof(global_temp_buffer)); | ||
316 | if (generate_bookmark_file_name(name, | ||
317 | global_bookmark_file_name, | ||
318 | sizeof(global_bookmark_file_name))) | ||
319 | { | ||
320 | success = add_bookmark(global_bookmark_file_name, bookmark); | ||
321 | } | ||
322 | } | ||
323 | |||
324 | if (success) | ||
325 | splash(HZ, true, str(LANG_BOOKMARK_CREATE_SUCCESS)); | ||
326 | else | ||
327 | splash(HZ, true, str(LANG_BOOKMARK_CREATE_FAILURE)); | ||
328 | |||
329 | return true; | ||
330 | } | ||
331 | |||
332 | /* ----------------------------------------------------------------------- */ | ||
333 | /* This function adds a bookmark to a file. */ | ||
334 | /* ------------------------------------------------------------------------*/ | ||
335 | static bool add_bookmark(char* bookmark_file_name, char* bookmark) | ||
336 | { | ||
337 | int temp_bookmark_file = 0; | ||
338 | int bookmark_file = 0; | ||
339 | int bookmark_count = 0; | ||
340 | char* playlist = NULL; | ||
341 | char* cp; | ||
342 | int len = 0; | ||
343 | bool unique = false; | ||
344 | |||
345 | /* Opening up a temp bookmark file */ | ||
346 | snprintf(global_temp_buffer, sizeof(global_temp_buffer), | ||
347 | "%s.tmp", bookmark_file_name); | ||
348 | temp_bookmark_file = open(global_temp_buffer, | ||
349 | O_WRONLY | O_CREAT | O_TRUNC); | ||
350 | if (temp_bookmark_file < 0) | ||
351 | return false; /* can't open the temp file */ | ||
352 | |||
353 | if (!strcmp(bookmark_file_name,RECENT_BOOKMARK_FILE) && | ||
354 | (global_settings.usemrb == BOOKMARK_UNIQUE_ONLY)) | ||
355 | { | ||
356 | playlist = strchr(bookmark,'/'); | ||
357 | cp = strrchr(bookmark,';'); | ||
358 | len = cp - playlist; | ||
359 | unique = true; | ||
360 | } | ||
361 | |||
362 | /* Writing the new bookmark to the begining of the temp file */ | ||
363 | write(temp_bookmark_file, bookmark, strlen(bookmark)); | ||
364 | write(temp_bookmark_file, "\n", 1); | ||
365 | |||
366 | /* Reading in the previous bookmarks and writing them to the temp file */ | ||
367 | bookmark_file = open(bookmark_file_name, O_RDONLY); | ||
368 | if (bookmark_file >= 0) | ||
369 | { | ||
370 | while (read_line(bookmark_file, global_read_buffer, | ||
371 | sizeof(global_read_buffer))) | ||
372 | { | ||
373 | if (unique) | ||
374 | { | ||
375 | cp=strchr(global_read_buffer,'/'); | ||
376 | if (check_bookmark(global_read_buffer) && | ||
377 | strncmp(playlist,cp,len)) | ||
378 | { | ||
379 | bookmark_count++; | ||
380 | write(temp_bookmark_file, global_read_buffer, | ||
381 | strlen(global_read_buffer)); | ||
382 | write(temp_bookmark_file, "\n", 1); | ||
383 | } | ||
384 | } | ||
385 | else | ||
386 | { | ||
387 | if (check_bookmark(global_read_buffer)) | ||
388 | { | ||
389 | bookmark_count++; | ||
390 | write(temp_bookmark_file, global_read_buffer, | ||
391 | strlen(global_read_buffer)); | ||
392 | write(temp_bookmark_file, "\n", 1); | ||
393 | } | ||
394 | } | ||
395 | } | ||
396 | close(bookmark_file); | ||
397 | } | ||
398 | close(temp_bookmark_file); | ||
399 | |||
400 | remove(bookmark_file_name); | ||
401 | rename(global_temp_buffer, bookmark_file_name); | ||
402 | |||
403 | return true; | ||
404 | } | ||
405 | |||
406 | |||
407 | /* ----------------------------------------------------------------------- */ | ||
408 | /* This function takes the system resume data and formats it into a valid */ | ||
409 | /* bookmark. */ | ||
410 | /* ----------------------------------------------------------------------- */ | ||
411 | static char* create_bookmark() | ||
412 | { | ||
413 | int resume_index = 0; | ||
414 | char *file; | ||
415 | |||
416 | /* grab the currently playing track */ | ||
417 | struct mp3entry *id3 = mpeg_current_track(); | ||
418 | if(!id3) | ||
419 | return NULL; | ||
420 | |||
421 | /* Get some basic resume information */ | ||
422 | /* queue_resume and queue_resume_index are not used and can be ignored.*/ | ||
423 | playlist_get_resume_info(&resume_index); | ||
424 | |||
425 | /* Get the currently playing file minus the path */ | ||
426 | /* This is used when displaying the available bookmarks */ | ||
427 | file = strrchr(id3->path,'/'); | ||
428 | if(NULL == file) | ||
429 | return NULL; | ||
430 | |||
431 | /* create the bookmark */ | ||
432 | snprintf(global_bookmark, sizeof(global_bookmark), | ||
433 | "%d;%d;%d;%d;%d;%d;%d;%s;%s", | ||
434 | resume_index, | ||
435 | id3->offset, | ||
436 | playlist_get_seed(), | ||
437 | 0, | ||
438 | id3->elapsed, | ||
439 | global_settings.repeat_mode, | ||
440 | global_settings.playlist_shuffle, | ||
441 | playlist_get_name(global_temp_buffer,sizeof(global_temp_buffer)), | ||
442 | file+1); | ||
443 | |||
444 | /* checking to see if the bookmark is valid */ | ||
445 | if (check_bookmark(global_bookmark)) | ||
446 | return global_bookmark; | ||
447 | else | ||
448 | return NULL; | ||
449 | } | ||
450 | |||
451 | static bool check_bookmark(char* bookmark) | ||
452 | { | ||
453 | return parse_bookmark(bookmark, | ||
454 | NULL,NULL,NULL, NULL, | ||
455 | NULL,0,NULL,NULL, | ||
456 | NULL, NULL, 0); | ||
457 | } | ||
458 | |||
459 | /* ----------------------------------------------------------------------- */ | ||
460 | /* This function will determine if an autoload is necessary. This is an */ | ||
461 | /* interface function. */ | ||
462 | /* ------------------------------------------------------------------------*/ | ||
463 | bool bookmark_autoload(char* file) | ||
464 | { | ||
465 | int key; | ||
466 | int fd; | ||
467 | bool done = false; | ||
468 | |||
469 | if(global_settings.autoloadbookmark == BOOKMARK_NO) | ||
470 | return false; | ||
471 | |||
472 | /*Checking to see if a bookmark file exists.*/ | ||
473 | if(!generate_bookmark_file_name(file, | ||
474 | global_bookmark_file_name, | ||
475 | sizeof(global_bookmark_file_name))) | ||
476 | { | ||
477 | return false; | ||
478 | } | ||
479 | |||
480 | fd = open(global_bookmark_file_name, O_RDONLY); | ||
481 | if(fd<0) | ||
482 | return false; | ||
483 | if(-1 == lseek(fd, 0, SEEK_END)) | ||
484 | { | ||
485 | close(fd); | ||
486 | return false; | ||
487 | } | ||
488 | close(fd); | ||
489 | |||
490 | if(global_settings.autoloadbookmark == BOOKMARK_YES) | ||
491 | { | ||
492 | return bookmark_load(global_bookmark_file_name, true); | ||
493 | } | ||
494 | else | ||
495 | { | ||
496 | while (button_get(false)); /* clear button queue */ | ||
497 | /* Prompting user to confirm bookmark load */ | ||
498 | lcd_clear_display(); | ||
499 | #ifdef HAVE_LCD_BITMAP | ||
500 | lcd_puts_scroll(0,0, str(LANG_BOOKMARK_AUTOLOAD_QUERY)); | ||
501 | lcd_puts(0,1, str(LANG_CONFIRM_WITH_PLAY_RECORDER)); | ||
502 | lcd_puts(0,2, str(LANG_BOOKMARK_SELECT_LIST_BOOKMARKS)); | ||
503 | lcd_puts(0,3, str(LANG_CANCEL_WITH_ANY_RECORDER)); | ||
504 | #else | ||
505 | status_draw(false); | ||
506 | lcd_puts_scroll(0,0, str(LANG_BOOKMARK_AUTOLOAD_QUERY)); | ||
507 | lcd_puts(0,1,str(LANG_RESUME_CONFIRM_PLAYER)); | ||
508 | #endif | ||
509 | lcd_update(); | ||
510 | |||
511 | sleep(100); | ||
512 | |||
513 | while(!done) | ||
514 | { | ||
515 | /* Wait for a key to be pushed */ | ||
516 | while (button_get(false)); /* clear button queue */ | ||
517 | key = button_get(true); | ||
518 | switch(key) | ||
519 | { | ||
520 | default: | ||
521 | return false; | ||
522 | #ifdef HAVE_LCD_BITMAP | ||
523 | case BUTTON_DOWN: | ||
524 | return bookmark_load(global_bookmark_file_name, false); | ||
525 | #endif | ||
526 | case BUTTON_PLAY: | ||
527 | return bookmark_load(global_bookmark_file_name, true); | ||
528 | case SYS_USB_CONNECTED: | ||
529 | status_set_playmode(STATUS_STOP); | ||
530 | usb_screen(); | ||
531 | #ifdef HAVE_LCD_CHARCELLS | ||
532 | status_set_param(true); | ||
533 | #endif | ||
534 | return true; | ||
535 | } | ||
536 | } | ||
537 | return true; | ||
538 | } | ||
539 | } | ||
540 | |||
541 | /* ----------------------------------------------------------------------- */ | ||
542 | /* This function loads the bookmark information into the resume memory. */ | ||
543 | /* This is an interface function. */ | ||
544 | /* ------------------------------------------------------------------------*/ | ||
545 | bool bookmark_load(char* file, bool autoload) | ||
546 | { | ||
547 | int fd; | ||
548 | bool success = true; | ||
549 | int offset; | ||
550 | int seed; | ||
551 | int index; | ||
552 | char* bookmark = NULL;; | ||
553 | |||
554 | if(autoload) | ||
555 | { | ||
556 | fd = open(file, O_RDONLY); | ||
557 | if(fd >= 0) | ||
558 | { | ||
559 | if(read_line(fd, global_read_buffer, sizeof(global_read_buffer))) | ||
560 | bookmark=global_read_buffer; | ||
561 | close(fd); | ||
562 | } | ||
563 | } | ||
564 | else | ||
565 | { | ||
566 | /* This is not an auto-load, so list the bookmarks */ | ||
567 | bookmark=select_bookmark(file); | ||
568 | if(!bookmark) | ||
569 | return true; /* User exited without selecting a bookmark */ | ||
570 | } | ||
571 | |||
572 | if(bookmark) | ||
573 | { | ||
574 | success = parse_bookmark(bookmark, | ||
575 | &index, | ||
576 | &offset, | ||
577 | &seed, | ||
578 | NULL, | ||
579 | global_temp_buffer, | ||
580 | sizeof(global_temp_buffer), | ||
581 | NULL, | ||
582 | &global_settings.repeat_mode, | ||
583 | &global_settings.playlist_shuffle, | ||
584 | NULL, 0); | ||
585 | |||
586 | } | ||
587 | |||
588 | if(success) | ||
589 | bookmark_play(global_temp_buffer,index,offset,seed); | ||
590 | |||
591 | return success; | ||
592 | } | ||
593 | |||
594 | |||
595 | static int get_bookmark_count(char* bookmark_file_name) | ||
596 | { | ||
597 | int read_count = 0; | ||
598 | int file = open(bookmark_file_name, O_RDONLY); | ||
599 | |||
600 | if(file < 0) | ||
601 | return -1; | ||
602 | |||
603 | /* Get the requested bookmark */ | ||
604 | while(read_line(file, global_read_buffer, sizeof(global_read_buffer))) | ||
605 | { | ||
606 | if(check_bookmark(global_read_buffer)) | ||
607 | read_count++; | ||
608 | } | ||
609 | |||
610 | close(file); | ||
611 | return read_count; | ||
612 | |||
613 | |||
614 | } | ||
615 | |||
616 | |||
617 | /* ----------------------------------------------------------------------- */ | ||
618 | /* This displays a the bookmarks in a file and allows the user to */ | ||
619 | /* select one to play. */ | ||
620 | /* ------------------------------------------------------------------------*/ | ||
621 | static char* select_bookmark(char* bookmark_file_name) | ||
622 | { | ||
623 | int bookmark_id = 0; | ||
624 | bool delete_this_bookmark = true; | ||
625 | int key = 0; | ||
626 | char* bookmark; | ||
627 | int bookmark_count = 0; | ||
628 | |||
629 | while(true) | ||
630 | { | ||
631 | /* Handles the case where the user wants to go below the 0th bookmark */ | ||
632 | if(bookmark_id < 0) | ||
633 | bookmark_id = 0; | ||
634 | |||
635 | if(delete_this_bookmark) | ||
636 | { | ||
637 | bookmark_count = get_bookmark_count(bookmark_file_name); | ||
638 | delete_this_bookmark = false; | ||
639 | } | ||
640 | |||
641 | bookmark = get_bookmark(bookmark_file_name, bookmark_id); | ||
642 | |||
643 | if (!bookmark) | ||
644 | { | ||
645 | /* if there were no bookmarks in the file, delete the file and exit. */ | ||
646 | if(bookmark_id == 0) | ||
647 | { | ||
648 | splash(HZ, true, str(LANG_BOOKMARK_LOAD_EMPTY)); | ||
649 | remove(bookmark_file_name); | ||
650 | while (button_get(false)); /* clear button queue */ | ||
651 | return NULL; | ||
652 | } | ||
653 | else | ||
654 | { | ||
655 | bookmark_id--; | ||
656 | } | ||
657 | } | ||
658 | else | ||
659 | { | ||
660 | display_bookmark(bookmark, bookmark_id, bookmark_count); | ||
661 | } | ||
662 | |||
663 | /* waiting for the user to click a button */ | ||
664 | while (button_get(false)); /* clear button queue */ | ||
665 | key = button_get(true); | ||
666 | switch(key) | ||
667 | { | ||
668 | case BUTTON_PLAY: | ||
669 | /* User wants to use this bookmark */ | ||
670 | return bookmark; | ||
671 | |||
672 | case BUTTON_ON | BUTTON_PLAY: | ||
673 | /* User wants to delete this bookmark */ | ||
674 | delete_this_bookmark = true; | ||
675 | break; | ||
676 | |||
677 | case SYS_USB_CONNECTED: | ||
678 | usb_screen(); | ||
679 | #ifdef HAVE_LCD_CHARCELLS | ||
680 | status_set_param(true); | ||
681 | #endif | ||
682 | return NULL; | ||
683 | #ifdef HAVE_RECORDER_KEYPAD | ||
684 | case BUTTON_UP: | ||
685 | bookmark_id--; | ||
686 | break; | ||
687 | |||
688 | case BUTTON_DOWN: | ||
689 | bookmark_id++; | ||
690 | break; | ||
691 | |||
692 | case BUTTON_LEFT: | ||
693 | case BUTTON_OFF: | ||
694 | return NULL; | ||
695 | #else | ||
696 | case BUTTON_LEFT: | ||
697 | bookmark_id--; | ||
698 | break; | ||
699 | |||
700 | case BUTTON_RIGHT: | ||
701 | bookmark_id++; | ||
702 | break; | ||
703 | |||
704 | case BUTTON_STOP: | ||
705 | return NULL; | ||
706 | #endif | ||
707 | } | ||
708 | |||
709 | if (delete_this_bookmark) | ||
710 | { | ||
711 | delete_bookmark(bookmark_file_name, bookmark_id); | ||
712 | bookmark_id--; | ||
713 | } | ||
714 | } | ||
715 | |||
716 | return NULL; | ||
717 | } | ||
718 | |||
719 | |||
720 | /* ----------------------------------------------------------------------- */ | ||
721 | /* This function takes a location in a bookmark file and deletes that */ | ||
722 | /* bookmark. */ | ||
723 | /* ------------------------------------------------------------------------*/ | ||
724 | static bool delete_bookmark(char* bookmark_file_name, int bookmark_id) | ||
725 | { | ||
726 | int temp_bookmark_file = 0; | ||
727 | int bookmark_file = 0; | ||
728 | int bookmark_count = 0; | ||
729 | |||
730 | /* Opening up a temp bookmark file */ | ||
731 | snprintf(global_temp_buffer, sizeof(global_temp_buffer), | ||
732 | "%s.tmp", bookmark_file_name); | ||
733 | temp_bookmark_file = open(global_temp_buffer, | ||
734 | O_WRONLY | O_CREAT | O_TRUNC); | ||
735 | bookmark_file = open(bookmark_file_name, O_RDONLY); | ||
736 | |||
737 | if (temp_bookmark_file < 0 || bookmark_file < 0) | ||
738 | return false; /* can't open one of the files */ | ||
739 | |||
740 | /* Reading in the previous bookmarks and writing them to the temp file */ | ||
741 | while (read_line(bookmark_file, global_read_buffer, | ||
742 | sizeof(global_read_buffer))) | ||
743 | { | ||
744 | if (check_bookmark(global_read_buffer)) | ||
745 | { | ||
746 | if (bookmark_id != bookmark_count) | ||
747 | { | ||
748 | write(temp_bookmark_file, global_read_buffer, | ||
749 | strlen(global_read_buffer)); | ||
750 | write(temp_bookmark_file, "\n", 1); | ||
751 | } | ||
752 | bookmark_count++; | ||
753 | } | ||
754 | } | ||
755 | |||
756 | close(bookmark_file); | ||
757 | close(temp_bookmark_file); | ||
758 | |||
759 | remove(bookmark_file_name); | ||
760 | rename(global_temp_buffer, bookmark_file_name); | ||
761 | |||
762 | return true; | ||
763 | } | ||
764 | |||
765 | /* ----------------------------------------------------------------------- */ | ||
766 | /* This function parses a bookmark and displays it for the user. */ | ||
767 | /* ------------------------------------------------------------------------*/ | ||
768 | static void display_bookmark(char* bookmark, | ||
769 | int bookmark_id, | ||
770 | int bookmark_count) | ||
771 | { | ||
772 | int resume_index = 0; | ||
773 | int ms = 0; | ||
774 | int repeat_mode = 0; | ||
775 | bool playlist_shuffle = false; | ||
776 | char MP3_file_name[45]; | ||
777 | int len; | ||
778 | char *dot; | ||
779 | |||
780 | /* getting the index and the time into the file */ | ||
781 | parse_bookmark(bookmark, | ||
782 | &resume_index, NULL, NULL, NULL, NULL, 0, | ||
783 | &ms, &repeat_mode, &playlist_shuffle, | ||
784 | MP3_file_name, sizeof(MP3_file_name)); | ||
785 | |||
786 | lcd_clear_display(); | ||
787 | lcd_stop_scroll(); | ||
788 | |||
789 | #ifdef HAVE_LCD_BITMAP | ||
790 | /* bookmark shuffle and repeat states*/ | ||
791 | switch (repeat_mode) | ||
792 | { | ||
793 | case REPEAT_ONE: | ||
794 | statusbar_icon_play_mode(Icon_RepeatOne); | ||
795 | break; | ||
796 | |||
797 | case REPEAT_ALL: | ||
798 | statusbar_icon_play_mode(Icon_Repeat); | ||
799 | break; | ||
800 | } | ||
801 | if(playlist_shuffle) | ||
802 | statusbar_icon_shuffle(); | ||
803 | |||
804 | /* File Name */ | ||
805 | len=strlen(MP3_file_name); | ||
806 | if (len>3) | ||
807 | dot=strrchr(MP3_file_name + len - 4, '.'); | ||
808 | else | ||
809 | dot=NULL; | ||
810 | if (dot) | ||
811 | *dot='\0'; | ||
812 | lcd_puts_scroll(0, 0, MP3_file_name); | ||
813 | if (dot) | ||
814 | *dot='.'; | ||
815 | |||
816 | /* bookmark number */ | ||
817 | snprintf(global_temp_buffer, sizeof(global_temp_buffer), "%s: %2d/%2d", | ||
818 | str(LANG_BOOKMARK_SELECT_BOOKMARK_TEXT), | ||
819 | bookmark_id + 1, bookmark_count); | ||
820 | lcd_puts_scroll(0, 1, global_temp_buffer); | ||
821 | |||
822 | /* bookmark resume index */ | ||
823 | snprintf(global_temp_buffer, sizeof(global_temp_buffer), "%s: %2d", | ||
824 | str(LANG_BOOKMARK_SELECT_INDEX_TEXT), resume_index+1); | ||
825 | lcd_puts_scroll(0, 2, global_temp_buffer); | ||
826 | |||
827 | /* elapsed time*/ | ||
828 | snprintf(global_temp_buffer, sizeof(global_temp_buffer), "%s: %d:%02d", | ||
829 | str(LANG_BOOKMARK_SELECT_TIME_TEXT), | ||
830 | ms / 60000, | ||
831 | ms % 60000 / 1000); | ||
832 | lcd_puts_scroll(0, 3, global_temp_buffer); | ||
833 | |||
834 | /* commands */ | ||
835 | lcd_puts_scroll(0, 4, str(LANG_BOOKMARK_SELECT_PLAY)); | ||
836 | lcd_puts_scroll(0, 5, str(LANG_BOOKMARK_SELECT_EXIT)); | ||
837 | lcd_puts_scroll(0, 6, str(LANG_BOOKMARK_SELECT_DELETE)); | ||
838 | #else | ||
839 | len=strlen(MP3_file_name); | ||
840 | if (len>3) | ||
841 | dot=strrchr(MP3_file_name+len-4,'.'); | ||
842 | else | ||
843 | dot=NULL; | ||
844 | if (dot) | ||
845 | *dot='\0'; | ||
846 | snprintf(global_temp_buffer, sizeof(global_temp_buffer), | ||
847 | "%2d, %d:%02d, %s,", | ||
848 | (bookmark_count+1), | ||
849 | ms / 60000, | ||
850 | ms % 60000 / 1000, | ||
851 | MP3_file_name); | ||
852 | status_draw(false); | ||
853 | lcd_puts_scroll(0,0,global_temp_buffer); | ||
854 | lcd_puts(0,1,str(LANG_RESUME_CONFIRM_PLAYER)); | ||
855 | if (dot) | ||
856 | *dot='.'; | ||
857 | #endif | ||
858 | lcd_update(); | ||
859 | } | ||
860 | |||
861 | /* ----------------------------------------------------------------------- */ | ||
862 | /* This function retrieves a given bookmark from a file. */ | ||
863 | /* If the bookmark requested is beyond the number of bookmarks available */ | ||
864 | /* in the file, it will return the last one. */ | ||
865 | /* It also returns the index number of the bookmark in the file */ | ||
866 | /* ------------------------------------------------------------------------*/ | ||
867 | static char* get_bookmark(char* bookmark_file, int bookmark_count) | ||
868 | { | ||
869 | int read_count = -1; | ||
870 | int result = 0; | ||
871 | int file = open(bookmark_file, O_RDONLY); | ||
872 | |||
873 | if (file < 0) | ||
874 | return NULL; | ||
875 | |||
876 | /* Get the requested bookmark */ | ||
877 | while (read_count < bookmark_count) | ||
878 | { | ||
879 | /*Reading in a single bookmark */ | ||
880 | result = read_line(file, | ||
881 | global_read_buffer, | ||
882 | sizeof(global_read_buffer)); | ||
883 | |||
884 | /* Reading past the last bookmark in the file | ||
885 | causes the loop to stop */ | ||
886 | if (result <= 0) | ||
887 | break; | ||
888 | |||
889 | read_count++; | ||
890 | } | ||
891 | |||
892 | close(file); | ||
893 | if (read_count == bookmark_count) | ||
894 | return global_read_buffer; | ||
895 | else | ||
896 | return NULL; | ||
897 | } | ||
898 | |||
899 | /* ----------------------------------------------------------------------- */ | ||
900 | /* This function takes a bookmark and parses it. This function also */ | ||
901 | /* validates the bookmark. Passing in NULL for an output variable */ | ||
902 | /* indicates that value is not requested. */ | ||
903 | /* ----------------------------------------------------------------------- */ | ||
904 | static bool parse_bookmark(char *bookmark, | ||
905 | int *resume_index, | ||
906 | int *resume_offset, | ||
907 | int *resume_seed, | ||
908 | int *resume_first_index, | ||
909 | char* resume_file, | ||
910 | unsigned int resume_file_size, | ||
911 | int* ms, | ||
912 | int * repeat_mode, bool *shuffle, | ||
913 | char* file_name, | ||
914 | unsigned int max_file_name_size) | ||
915 | { | ||
916 | /* First check to see if a valid line was passed in. */ | ||
917 | int bookmark_len = strlen(bookmark); | ||
918 | int local_resume_index = 0; | ||
919 | int local_resume_offset = 0; | ||
920 | int local_resume_seed = 0; | ||
921 | int local_resume_first_index = 0; | ||
922 | int local_mS = 0; | ||
923 | int local_shuffle = 0; | ||
924 | int local_repeat_mode = 0; | ||
925 | char* local_resume_file = NULL; | ||
926 | char* local_file_name = NULL; | ||
927 | char* field; | ||
928 | char* end; | ||
929 | static char bookmarkcopy[MAX_BOOKMARK_SIZE]; | ||
930 | |||
931 | /* Don't do anything if the bookmark length is 0 */ | ||
932 | if (bookmark_len <= 0) | ||
933 | return false; | ||
934 | |||
935 | /* Making a dup of the bookmark to use with strtok_r */ | ||
936 | strncpy(bookmarkcopy, bookmark, sizeof(bookmarkcopy)); | ||
937 | bookmarkcopy[sizeof(bookmarkcopy) - 1] = 0; | ||
938 | |||
939 | /* resume_index */ | ||
940 | if ((field = strtok_r(bookmarkcopy, ";", &end))) | ||
941 | local_resume_index = atoi(field); | ||
942 | else | ||
943 | return false; | ||
944 | |||
945 | /* resume_offset */ | ||
946 | if ((field = strtok_r(NULL, ";", &end))) | ||
947 | local_resume_offset = atoi(field); | ||
948 | else | ||
949 | return false; | ||
950 | |||
951 | /* resume_seed */ | ||
952 | if ((field = strtok_r(NULL, ";", &end))) | ||
953 | local_resume_seed = atoi(field); | ||
954 | else | ||
955 | return false; | ||
956 | |||
957 | /* resume_first_index */ | ||
958 | if ((field = strtok_r(NULL, ";", &end))) | ||
959 | local_resume_first_index = atoi(field); | ||
960 | else | ||
961 | return false; | ||
962 | |||
963 | /* Milliseconds into MP3. Used for the bookmark select menu */ | ||
964 | if ((field = strtok_r(NULL, ";", &end))) | ||
965 | local_mS = atoi(field); | ||
966 | else | ||
967 | return false; | ||
968 | |||
969 | /* repeat_mode */ | ||
970 | if ((field = strtok_r(NULL, ";", &end))) | ||
971 | local_repeat_mode = atoi(field); | ||
972 | else | ||
973 | return false; | ||
974 | |||
975 | /* shuffle mode */ | ||
976 | if ((field = strtok_r(NULL, ";", &end))) | ||
977 | local_shuffle = atoi(field); | ||
978 | else | ||
979 | return false; | ||
980 | |||
981 | /* resume_file & file_name (for the bookmark select menu)*/ | ||
982 | if (end) | ||
983 | { | ||
984 | local_resume_file = strtok_r(NULL, ";", &end); | ||
985 | if (local_resume_file[strlen(local_resume_file) - 1] == '/') | ||
986 | local_resume_file[strlen(local_resume_file) - 1] = '\0'; | ||
987 | |||
988 | if (end) | ||
989 | local_file_name = strtok_r(NULL, ";", &end); | ||
990 | } | ||
991 | else | ||
992 | return false; | ||
993 | |||
994 | /* Only return the values the calling function wants */ | ||
995 | if (resume_index) | ||
996 | *resume_index = local_resume_index; | ||
997 | |||
998 | if (resume_offset) | ||
999 | *resume_offset = local_resume_offset; | ||
1000 | |||
1001 | if (resume_seed) | ||
1002 | *resume_seed = local_resume_seed; | ||
1003 | |||
1004 | if (resume_first_index) | ||
1005 | *resume_first_index = local_resume_first_index; | ||
1006 | |||
1007 | if (resume_file && local_resume_file) | ||
1008 | { | ||
1009 | strncpy(resume_file, local_resume_file, | ||
1010 | MIN(strlen(local_resume_file), resume_file_size-1)); | ||
1011 | resume_file[MIN(strlen(local_resume_file), resume_file_size-1)]=0; | ||
1012 | } | ||
1013 | |||
1014 | if (ms) | ||
1015 | *ms = local_mS; | ||
1016 | |||
1017 | if (shuffle) | ||
1018 | *shuffle = local_shuffle; | ||
1019 | |||
1020 | if (repeat_mode) | ||
1021 | *repeat_mode = local_repeat_mode; | ||
1022 | |||
1023 | if (file_name && local_file_name) | ||
1024 | { | ||
1025 | strncpy(file_name, local_file_name, | ||
1026 | MIN(strlen(local_file_name),max_file_name_size-1)); | ||
1027 | file_name[MIN(strlen(local_file_name),max_file_name_size-1)]=0; | ||
1028 | } | ||
1029 | |||
1030 | return true; | ||
1031 | } | ||
1032 | |||
1033 | /* ----------------------------------------------------------------------- */ | ||
1034 | /* This function is used by multiple functions and is used to generate a */ | ||
1035 | /* bookmark named based off of the input. */ | ||
1036 | /* Changing this function could result in how the bookmarks are stored. */ | ||
1037 | /* it would be here that the centralized/decentralized bookmark code */ | ||
1038 | /* could be placed. */ | ||
1039 | /* ----------------------------------------------------------------------- */ | ||
1040 | static bool generate_bookmark_file_name(char *in, char *out, | ||
1041 | unsigned int max_length) | ||
1042 | { | ||
1043 | char* cp; | ||
1044 | |||
1045 | if (!in || !out || max_length <= 0) | ||
1046 | return false; | ||
1047 | |||
1048 | if (max_length < strlen(in)+6) | ||
1049 | return false; | ||
1050 | |||
1051 | /* if this is a root dir MP3, rename the boomark file root_dir.bmark */ | ||
1052 | /* otherwise, name it based on the in variable */ | ||
1053 | cp = in; | ||
1054 | |||
1055 | cp = in + strlen(in) - 1; | ||
1056 | if (*cp == '/') | ||
1057 | *cp = 0; | ||
1058 | |||
1059 | cp = in; | ||
1060 | if (*cp == '/') | ||
1061 | cp++; | ||
1062 | |||
1063 | if (strlen(in) > 0) | ||
1064 | snprintf(out, max_length, "/%s.%s", cp, "bmark"); | ||
1065 | else | ||
1066 | snprintf(out, max_length, "/root_dir.%s", "bmark"); | ||
1067 | |||
1068 | return true; | ||
1069 | } | ||
1070 | |||
1071 | /* ----------------------------------------------------------------------- */ | ||
1072 | /* Checks the current state of the system and returns if it is in a */ | ||
1073 | /* bookmarkable state. */ | ||
1074 | /* ----------------------------------------------------------------------- */ | ||
1075 | /* Inputs: */ | ||
1076 | /* ----------------------------------------------------------------------- */ | ||
1077 | /* Outputs: */ | ||
1078 | /* return bool: Indicates if the system was in a bookmarkable state */ | ||
1079 | /* ----------------------------------------------------------------------- */ | ||
1080 | static bool system_check(void) | ||
1081 | { | ||
1082 | int resume_index = 0; | ||
1083 | struct mp3entry *id3 = mpeg_current_track(); | ||
1084 | |||
1085 | if (!id3) | ||
1086 | { | ||
1087 | /* no track playing */ | ||
1088 | return false; | ||
1089 | } | ||
1090 | |||
1091 | /* Checking to see if playing a queued track */ | ||
1092 | if (playlist_get_resume_info(&resume_index) == -1) | ||
1093 | { | ||
1094 | /* something bad happened while getting the queue information */ | ||
1095 | return false; | ||
1096 | } | ||
1097 | else if (playlist_modified()) | ||
1098 | { | ||
1099 | /* can't bookmark while in the queue */ | ||
1100 | return false; | ||
1101 | } | ||
1102 | |||
1103 | return true; | ||
1104 | } | ||
1105 | |||
diff --git a/apps/bookmark.h b/apps/bookmark.h new file mode 100644 index 0000000000..bff58f67a8 --- /dev/null +++ b/apps/bookmark.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2003 by Benjamin Metzler | ||
10 | * | ||
11 | * All files in this archive are subject to the GNU General Public License. | ||
12 | * See the file COPYING in the source tree root for full license agreement. | ||
13 | * | ||
14 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
15 | * KIND, either express or implied. | ||
16 | * | ||
17 | ****************************************************************************/ | ||
18 | |||
19 | #ifndef __BOOKMARK_H__ | ||
20 | #define __BOOKMARK_H__ | ||
21 | |||
22 | #include <stdbool.h> | ||
23 | |||
24 | bool bookmark_menu(void); | ||
25 | bool bookmark_autobookmark(void); | ||
26 | bool bookmark_create_menu(void); | ||
27 | bool bookmark_mrb_load(void); | ||
28 | bool bookmark_autoload(char* file); | ||
29 | bool bookmark_load(char* file, bool autoload); | ||
30 | void bookmark_play(char* resume_file, int index, int offset, int seed); | ||
31 | |||
32 | #endif /* __BOOKMARK_H__ */ | ||
33 | |||
diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 5cad562a7f..24ac940411 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang | |||
@@ -1848,6 +1848,128 @@ desc: in settings_menu, option to turn display+buttos by 180 degreed | |||
1848 | eng: "Upside Down" | 1848 | eng: "Upside Down" |
1849 | new: | 1849 | new: |
1850 | 1850 | ||
1851 | #Auto bookmark prompts | ||
1852 | id: LANG_BOOKMARK_AUTOLOAD_QUERY | ||
1853 | desc: prompt for user to decide to create a bookmark | ||
1854 | eng: "Load Last Bookmark?" | ||
1855 | new: | ||
1856 | |||
1857 | id: LANG_AUTO_BOOKMARK_QUERY | ||
1858 | desc: prompt for user to decide to create an bookmark | ||
1859 | eng: "Create a Bookmark?" | ||
1860 | new: | ||
1861 | |||
1862 | # Bookmark Select Menu Text | ||
1863 | id: LANG_BOOKMARK_SELECT_LIST_BOOKMARKS | ||
1864 | desc: From the auto-load screen, allows user to list all bookmarks | ||
1865 | eng: "Down = List" | ||
1866 | new: | ||
1867 | |||
1868 | id: LANG_BOOKMARK_SELECT_EXIT | ||
1869 | desc: From the bookmark list screen, allows user to exit | ||
1870 | eng: "OFF = Exit" | ||
1871 | new: | ||
1872 | |||
1873 | id: LANG_BOOKMARK_SELECT_BOOKMARK_TEXT | ||
1874 | desc: Used on the bookmark select window to label bookmark number | ||
1875 | eng: "Bookmark" | ||
1876 | new: | ||
1877 | |||
1878 | id: LANG_BOOKMARK_SELECT_INDEX_TEXT | ||
1879 | desc: Used on the bookmark select window to label index number | ||
1880 | eng: "Index" | ||
1881 | new: | ||
1882 | |||
1883 | id: LANG_BOOKMARK_SELECT_TIME_TEXT | ||
1884 | desc: Used on the bookmark select window to label elapsed time | ||
1885 | eng: "Time" | ||
1886 | new: | ||
1887 | |||
1888 | id: LANG_BOOKMARK_SELECT_PLAY | ||
1889 | desc: Used on the bookmark select window to indicated the play option | ||
1890 | eng: "PLAY = Select" | ||
1891 | new: | ||
1892 | |||
1893 | id: LANG_BOOKMARK_SELECT_DELETE | ||
1894 | desc: Used on the bookmark select window to indicated the bookmark delete option | ||
1895 | eng: "ON+Play = Delete" | ||
1896 | new: | ||
1897 | |||
1898 | # Bookmark creation/failure text | ||
1899 | id: LANG_BOOKMARK_CREATE_SUCCESS | ||
1900 | desc: Indicates bookmark was successfully created | ||
1901 | eng: "Bookmark Created" | ||
1902 | new: | ||
1903 | |||
1904 | id: LANG_BOOKMARK_CREATE_FAILURE | ||
1905 | desc: Indicates bookmark was not created | ||
1906 | eng: "Bookmark Failed!" | ||
1907 | new: | ||
1908 | |||
1909 | # Bookmark creation/failure text | ||
1910 | id: LANG_BOOKMARK_LOAD_EMPTY | ||
1911 | desc: Indicates bookmark was empty | ||
1912 | eng: "Bookmark Empty" | ||
1913 | new: | ||
1914 | |||
1915 | # Bookmark Settings Text | ||
1916 | id: LANG_BOOKMARK_SETTINGS | ||
1917 | desc: in general settings | ||
1918 | eng: "Bookmarking" | ||
1919 | new: | ||
1920 | |||
1921 | id: LANG_BOOKMARK_SETTINGS_AUTOLOAD | ||
1922 | desc: prompt for user to decide to create a bookmark | ||
1923 | eng: "Load Last Bookmark" | ||
1924 | new: | ||
1925 | |||
1926 | id: LANG_BOOKMARK_SETTINGS_AUTOCREATE | ||
1927 | desc: prompt for user to decide to create an bookmark | ||
1928 | eng: "Bookmark on Stop" | ||
1929 | new: | ||
1930 | |||
1931 | id: LANG_BOOKMARK_SETTINGS_MAINTAIN_RECENT_BOOKMARKS | ||
1932 | desc: Configuration option to maintain a list of recent bookmarks | ||
1933 | eng: "Maintain a List of Recent Bookmarks?" | ||
1934 | new: | ||
1935 | |||
1936 | id: LANG_BOOKMARK_SETTINGS_RECENT_ONLY_YES | ||
1937 | desc: Save in recent bookmarks only | ||
1938 | eng: "Yes - Recent only" | ||
1939 | new: | ||
1940 | |||
1941 | id: LANG_BOOKMARK_SETTINGS_RECENT_ONLY_ASK | ||
1942 | desc: Save in recent bookmarks only | ||
1943 | eng: "Ask - Recent only" | ||
1944 | new: | ||
1945 | |||
1946 | |||
1947 | id: LANG_BOOKMARK_SETTINGS_UNIQUE_ONLY | ||
1948 | desc: Save only on bookmark for each playlist in recent bookmarks | ||
1949 | eng: "Unique only" | ||
1950 | new: | ||
1951 | |||
1952 | # Main Bookmarks Menu | ||
1953 | id: LANG_BOOKMARK_MENU | ||
1954 | desc: Text on main menu to get to bookmark commands | ||
1955 | eng: "Bookmarks" | ||
1956 | new: | ||
1957 | |||
1958 | id: LANG_BOOKMARK_MENU_CREATE | ||
1959 | desc: Used off of the bookmark menu to create a bookmark | ||
1960 | eng: "Create Bookmark" | ||
1961 | new: | ||
1962 | |||
1963 | id: LANG_BOOKMARK_MENU_LIST | ||
1964 | desc: Used off of the bookmark menu to list available bookmarks for the currently playing directory or M3U | ||
1965 | eng: "List Bookmarks" | ||
1966 | new: | ||
1967 | |||
1968 | id: LANG_BOOKMARK_MENU_RECENT_BOOKMARKS | ||
1969 | desc: Text for the menu text to access the most recent bookmarks list | ||
1970 | eng: "Recent Bookmarks" | ||
1971 | new: | ||
1972 | |||
1851 | id: LANG_RECORD_PRERECORD | 1973 | id: LANG_RECORD_PRERECORD |
1852 | desc: in recording and radio screen | 1974 | desc: in recording and radio screen |
1853 | eng: "Prerecording" | 1975 | eng: "Prerecording" |
diff --git a/apps/main_menu.c b/apps/main_menu.c index b4d676332b..53954d2260 100644 --- a/apps/main_menu.c +++ b/apps/main_menu.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include "status.h" | 40 | #include "status.h" |
41 | #include "fat.h" | 41 | #include "fat.h" |
42 | #include "sleeptimer.h" | 42 | #include "sleeptimer.h" |
43 | #include "bookmark.h" | ||
43 | #include "wps.h" | 44 | #include "wps.h" |
44 | #include "buffer.h" | 45 | #include "buffer.h" |
45 | #include "screens.h" | 46 | #include "screens.h" |
@@ -269,7 +270,10 @@ bool main_menu(void) | |||
269 | int i = 0; | 270 | int i = 0; |
270 | 271 | ||
271 | /* main menu */ | 272 | /* main menu */ |
272 | struct menu_items items[14]; | 273 | struct menu_items items[15]; |
274 | |||
275 | items[i].desc = str(LANG_BOOKMARK_MENU); | ||
276 | items[i++].function = bookmark_menu; | ||
273 | 277 | ||
274 | items[i].desc = str(LANG_SOUND_SETTINGS); | 278 | items[i].desc = str(LANG_SOUND_SETTINGS); |
275 | items[i++].function = sound_menu; | 279 | items[i++].function = sound_menu; |
diff --git a/apps/playlist.c b/apps/playlist.c index 1b6c65245d..13919b2f02 100644 --- a/apps/playlist.c +++ b/apps/playlist.c | |||
@@ -172,6 +172,10 @@ static void empty_playlist(bool resume) | |||
172 | playlist.first_index = 0; | 172 | playlist.first_index = 0; |
173 | playlist.amount = 0; | 173 | playlist.amount = 0; |
174 | playlist.last_insert_pos = -1; | 174 | playlist.last_insert_pos = -1; |
175 | playlist.seed = 0; | ||
176 | playlist.shuffle_modified = false; | ||
177 | playlist.deleted = false; | ||
178 | playlist.num_inserted_tracks = 0; | ||
175 | playlist.shuffle_flush = false; | 179 | playlist.shuffle_flush = false; |
176 | 180 | ||
177 | if (!resume) | 181 | if (!resume) |
@@ -412,6 +416,7 @@ static int add_track_to_playlist(char *filename, int position, bool queue, | |||
412 | playlist.indices[insert_position] = flags | seek_pos; | 416 | playlist.indices[insert_position] = flags | seek_pos; |
413 | 417 | ||
414 | playlist.amount++; | 418 | playlist.amount++; |
419 | playlist.num_inserted_tracks++; | ||
415 | 420 | ||
416 | return insert_position; | 421 | return insert_position; |
417 | } | 422 | } |
@@ -528,16 +533,24 @@ static int add_directory_to_playlist(char *dirname, int *position, bool queue, | |||
528 | static int remove_track_from_playlist(int position, bool write) | 533 | static int remove_track_from_playlist(int position, bool write) |
529 | { | 534 | { |
530 | int i; | 535 | int i; |
536 | bool inserted; | ||
531 | 537 | ||
532 | if (playlist.amount <= 0) | 538 | if (playlist.amount <= 0) |
533 | return -1; | 539 | return -1; |
534 | 540 | ||
541 | inserted = playlist.indices[position] & PLAYLIST_INSERT_TYPE_MASK; | ||
542 | |||
535 | /* shift indices now that track has been removed */ | 543 | /* shift indices now that track has been removed */ |
536 | for (i=position; i<playlist.amount; i++) | 544 | for (i=position; i<playlist.amount; i++) |
537 | playlist.indices[i] = playlist.indices[i+1]; | 545 | playlist.indices[i] = playlist.indices[i+1]; |
538 | 546 | ||
539 | playlist.amount--; | 547 | playlist.amount--; |
540 | 548 | ||
549 | if (inserted) | ||
550 | playlist.num_inserted_tracks--; | ||
551 | else | ||
552 | playlist.deleted = true; | ||
553 | |||
541 | /* update stored indices if needed */ | 554 | /* update stored indices if needed */ |
542 | if (position < playlist.index) | 555 | if (position < playlist.index) |
543 | playlist.index--; | 556 | playlist.index--; |
@@ -622,6 +635,10 @@ static int randomise_playlist(unsigned int seed, bool start_current, bool write) | |||
622 | /* indices have been moved so last insert position is no longer valid */ | 635 | /* indices have been moved so last insert position is no longer valid */ |
623 | playlist.last_insert_pos = -1; | 636 | playlist.last_insert_pos = -1; |
624 | 637 | ||
638 | playlist.seed = seed; | ||
639 | if (playlist.num_inserted_tracks > 0 || playlist.deleted) | ||
640 | playlist.shuffle_modified = true; | ||
641 | |||
625 | if (write) | 642 | if (write) |
626 | { | 643 | { |
627 | /* Don't write to disk immediately. Instead, save in settings and | 644 | /* Don't write to disk immediately. Instead, save in settings and |
@@ -652,6 +669,8 @@ static int sort_playlist(bool start_current, bool write) | |||
652 | /* indices have been moved so last insert position is no longer valid */ | 669 | /* indices have been moved so last insert position is no longer valid */ |
653 | playlist.last_insert_pos = -1; | 670 | playlist.last_insert_pos = -1; |
654 | 671 | ||
672 | if (!playlist.num_inserted_tracks && !playlist.deleted) | ||
673 | playlist.shuffle_modified = false; | ||
655 | if (write && playlist.control_fd >= 0) | 674 | if (write && playlist.control_fd >= 0) |
656 | { | 675 | { |
657 | /* Don't write to disk immediately. Instead, save in settings and | 676 | /* Don't write to disk immediately. Instead, save in settings and |
@@ -1898,9 +1917,26 @@ int playlist_next(int steps) | |||
1898 | return index; | 1917 | return index; |
1899 | } | 1918 | } |
1900 | 1919 | ||
1920 | bool playlist_modified(void) | ||
1921 | { | ||
1922 | if ((mpeg_status() & MPEG_STATUS_PLAY)) | ||
1923 | { | ||
1924 | if (playlist.shuffle_modified || | ||
1925 | playlist.deleted || | ||
1926 | playlist.num_inserted_tracks > 0) | ||
1927 | return true; | ||
1928 | } | ||
1929 | return false; | ||
1930 | } | ||
1931 | |||
1932 | int playlist_get_seed(void) | ||
1933 | { | ||
1934 | return playlist.seed; | ||
1935 | } | ||
1936 | |||
1901 | /* Get resume info for current playing song. If return value is -1 then | 1937 | /* Get resume info for current playing song. If return value is -1 then |
1902 | settings shouldn't be saved. */ | 1938 | settings shouldn't be saved. */ |
1903 | int playlist_get_resume_info(short *resume_index) | 1939 | int playlist_get_resume_info(int *resume_index) |
1904 | { | 1940 | { |
1905 | *resume_index = playlist.index; | 1941 | *resume_index = playlist.index; |
1906 | 1942 | ||
@@ -1924,6 +1960,16 @@ int playlist_get_first_index(void) | |||
1924 | return playlist.first_index; | 1960 | return playlist.first_index; |
1925 | } | 1961 | } |
1926 | 1962 | ||
1963 | char *playlist_get_name(char *buf, int buf_size) | ||
1964 | { | ||
1965 | snprintf(buf, buf_size, "%s", playlist.filename); | ||
1966 | |||
1967 | if (!buf[0]) | ||
1968 | return NULL; | ||
1969 | |||
1970 | return buf; | ||
1971 | } | ||
1972 | |||
1927 | /* returns number of tracks in playlist (includes queued/inserted tracks) */ | 1973 | /* returns number of tracks in playlist (includes queued/inserted tracks) */ |
1928 | int playlist_amount(void) | 1974 | int playlist_amount(void) |
1929 | { | 1975 | { |
@@ -1937,14 +1983,14 @@ char *playlist_name(char *buf, int buf_size) | |||
1937 | 1983 | ||
1938 | snprintf(buf, buf_size, "%s", playlist.filename+playlist.dirlen); | 1984 | snprintf(buf, buf_size, "%s", playlist.filename+playlist.dirlen); |
1939 | 1985 | ||
1940 | if (0 == buf[0]) | 1986 | if (!buf[0]) |
1941 | return NULL; | 1987 | return NULL; |
1942 | 1988 | ||
1943 | /* Remove extension */ | 1989 | /* Remove extension */ |
1944 | sep = strrchr(buf, '.'); | 1990 | sep = strrchr(buf, '.'); |
1945 | if (NULL != sep) | 1991 | if (sep) |
1946 | *sep = 0; | 1992 | *sep = 0; |
1947 | 1993 | ||
1948 | return buf; | 1994 | return buf; |
1949 | } | 1995 | } |
1950 | 1996 | ||
@@ -2001,7 +2047,7 @@ int playlist_save(char *filename) | |||
2001 | 2047 | ||
2002 | /* use current working directory as base for pathname */ | 2048 | /* use current working directory as base for pathname */ |
2003 | if (format_track_path(tmp_buf, filename, sizeof(tmp_buf), | 2049 | if (format_track_path(tmp_buf, filename, sizeof(tmp_buf), |
2004 | strlen(filename)+1, getcwd(NULL, -1)) < 0) | 2050 | strlen(filename)+1, getcwd(NULL, -1)) < 0) |
2005 | return -1; | 2051 | return -1; |
2006 | 2052 | ||
2007 | fd = open(tmp_buf, O_CREAT|O_WRONLY|O_TRUNC); | 2053 | fd = open(tmp_buf, O_CREAT|O_WRONLY|O_TRUNC); |
@@ -2043,15 +2089,14 @@ int playlist_save(char *filename) | |||
2043 | 2089 | ||
2044 | if (fprintf(fd, "%s\n", tmp_buf) < 0) | 2090 | if (fprintf(fd, "%s\n", tmp_buf) < 0) |
2045 | { | 2091 | { |
2046 | splash(HZ*2, true, | 2092 | splash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR)); |
2047 | str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR)); | ||
2048 | result = -1; | 2093 | result = -1; |
2049 | break; | 2094 | break; |
2050 | } | 2095 | } |
2051 | 2096 | ||
2052 | count++; | 2097 | count++; |
2053 | 2098 | ||
2054 | if ((count%PLAYLIST_DISPLAY_COUNT) == 0) | 2099 | if ((count % PLAYLIST_DISPLAY_COUNT) == 0) |
2055 | display_playlist_count(count, str(LANG_PLAYLIST_SAVE_COUNT)); | 2100 | display_playlist_count(count, str(LANG_PLAYLIST_SAVE_COUNT)); |
2056 | 2101 | ||
2057 | yield(); | 2102 | yield(); |
diff --git a/apps/playlist.h b/apps/playlist.h index 82d67bf0bb..020d3332cb 100644 --- a/apps/playlist.h +++ b/apps/playlist.h | |||
@@ -39,11 +39,16 @@ struct playlist_info | |||
39 | char *buffer; /* buffer for in-ram playlists */ | 39 | char *buffer; /* buffer for in-ram playlists */ |
40 | int buffer_size; /* size of buffer */ | 40 | int buffer_size; /* size of buffer */ |
41 | int buffer_end_pos; /* last position where buffer was written */ | 41 | int buffer_end_pos; /* last position where buffer was written */ |
42 | short index; /* index of current playing track */ | 42 | int index; /* index of current playing track */ |
43 | short first_index; /* index of first song in playlist */ | 43 | int first_index; /* index of first song in playlist */ |
44 | int amount; /* number of tracks in the index */ | 44 | int amount; /* number of tracks in the index */ |
45 | int last_insert_pos; /* last position we inserted a track */ | 45 | int last_insert_pos; /* last position we inserted a track */ |
46 | bool shuffle_flush; /* Does shuffle value need to be flushed? */ | 46 | int seed; /* shuffle seed */ |
47 | bool shuffle_modified; /* has playlist been shuffled with | ||
48 | inserted tracks? */ | ||
49 | bool deleted; /* have any tracks been deleted? */ | ||
50 | int num_inserted_tracks; /* number of tracks inserted */ | ||
51 | bool shuffle_flush; /* does shuffle value need to be flushed? */ | ||
47 | struct mutex control_mutex; /* mutex for control file access */ | 52 | struct mutex control_mutex; /* mutex for control file access */ |
48 | }; | 53 | }; |
49 | 54 | ||
@@ -75,13 +80,16 @@ int playlist_start(int start_index, int offset); | |||
75 | bool playlist_check(int steps); | 80 | bool playlist_check(int steps); |
76 | char *playlist_peek(int steps); | 81 | char *playlist_peek(int steps); |
77 | int playlist_next(int steps); | 82 | int playlist_next(int steps); |
78 | int playlist_get_resume_info(short *resume_index); | 83 | int playlist_get_resume_info(int *resume_index); |
79 | int playlist_get_display_index(void); | 84 | int playlist_get_display_index(void); |
80 | int playlist_get_first_index(void); | 85 | int playlist_get_first_index(void); |
81 | int playlist_amount(void); | 86 | int playlist_amount(void); |
82 | char *playlist_name(char *buf, int buf_size); | 87 | char *playlist_name(char *buf, int buf_size); |
83 | int playlist_get_track_info(int index, struct playlist_track_info* info); | 88 | int playlist_get_track_info(int index, struct playlist_track_info* info); |
84 | int playlist_save(char *filename); | 89 | int playlist_save(char *filename); |
90 | int playlist_get_seed(void); | ||
91 | char *playlist_get_name(char *buf, int buf_size); | ||
92 | bool playlist_modified(void); | ||
85 | 93 | ||
86 | enum { | 94 | enum { |
87 | PLAYLIST_PREPEND = -1, | 95 | PLAYLIST_PREPEND = -1, |
diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c index fe792e9bbb..00da973732 100644 --- a/apps/playlist_viewer.c +++ b/apps/playlist_viewer.c | |||
@@ -80,7 +80,7 @@ struct playlist_viewer_info { | |||
80 | int char_width; /* Width (in pixels) of a character */ | 80 | int char_width; /* Width (in pixels) of a character */ |
81 | 81 | ||
82 | int num_tracks; /* Number of tracks in playlist */ | 82 | int num_tracks; /* Number of tracks in playlist */ |
83 | short current_playing_track;/* Index of current playing track */ | 83 | int current_playing_track; /* Index of current playing track */ |
84 | 84 | ||
85 | int num_loaded; /* Number of track entries loaded in viewer */ | 85 | int num_loaded; /* Number of track entries loaded in viewer */ |
86 | int first_index; /* Index of first loaded track */ | 86 | int first_index; /* Index of first loaded track */ |
@@ -643,7 +643,7 @@ bool playlist_viewer(void) | |||
643 | 643 | ||
644 | while (!exit) | 644 | while (!exit) |
645 | { | 645 | { |
646 | short track; | 646 | int track; |
647 | 647 | ||
648 | /* Timeout so we can determine if play status has changed */ | 648 | /* Timeout so we can determine if play status has changed */ |
649 | button = button_get_w_tmo(HZ/2); | 649 | button = button_get_w_tmo(HZ/2); |
diff --git a/apps/recorder/icons.c b/apps/recorder/icons.c index a68167d9ac..88aa943202 100644 --- a/apps/recorder/icons.c +++ b/apps/recorder/icons.c | |||
@@ -68,6 +68,7 @@ unsigned char bitmap_icons_6x8[LastIcon][6] = | |||
68 | { 0x2a, 0x7f, 0x41, 0x41, 0x7f, 0x2a }, /* UCL flash file: chip */ | 68 | { 0x2a, 0x7f, 0x41, 0x41, 0x7f, 0x2a }, /* UCL flash file: chip */ |
69 | { 0x70, 0x70, 0x7f, 0x7f, 0x70, 0x70 }, /* Chip8 game: joystick */ | 69 | { 0x70, 0x70, 0x7f, 0x7f, 0x70, 0x70 }, /* Chip8 game: joystick */ |
70 | { 0x5d, 0x7f, 0x5d, 0x7f, 0x5d, 0x7f }, /* Video file: film strip */ | 70 | { 0x5d, 0x7f, 0x5d, 0x7f, 0x5d, 0x7f }, /* Video file: film strip */ |
71 | { 0xff, 0x81, 0xaf, 0xaa, 0x8c, 0xf8 }, /* Bookmark file */ | ||
71 | }; | 72 | }; |
72 | 73 | ||
73 | unsigned char bitmap_icons_7x8[][7] = | 74 | unsigned char bitmap_icons_7x8[][7] = |
diff --git a/apps/recorder/icons.h b/apps/recorder/icons.h index 7a18cc2473..d362e05fee 100644 --- a/apps/recorder/icons.h +++ b/apps/recorder/icons.h | |||
@@ -30,6 +30,7 @@ enum icons_6x8 { | |||
30 | Selected, Cursor, Wps, Mod_Ajz, | 30 | Selected, Cursor, Wps, Mod_Ajz, |
31 | Font, Language, Text, Config, | 31 | Font, Language, Text, Config, |
32 | Plugin, Flashfile, Chip8, Video, | 32 | Plugin, Flashfile, Chip8, Video, |
33 | Bookmark, | ||
33 | LastIcon | 34 | LastIcon |
34 | }; | 35 | }; |
35 | 36 | ||
diff --git a/apps/settings.c b/apps/settings.c index 1cde6e02e7..a342acc746 100644 --- a/apps/settings.c +++ b/apps/settings.c | |||
@@ -56,6 +56,7 @@ | |||
56 | #include "language.h" | 56 | #include "language.h" |
57 | #include "wps-display.h" | 57 | #include "wps-display.h" |
58 | #include "powermgmt.h" | 58 | #include "powermgmt.h" |
59 | #include "bookmark.h" | ||
59 | #include "sprintf.h" | 60 | #include "sprintf.h" |
60 | #include "keyboard.h" | 61 | #include "keyboard.h" |
61 | #include "version.h" | 62 | #include "version.h" |
@@ -143,7 +144,7 @@ Rest of config block, only saved to disk: | |||
143 | caption backlight (bit 1) | 144 | caption backlight (bit 1) |
144 | car adapter mode (bit 2) | 145 | car adapter mode (bit 2) |
145 | line_in (Player only) (bit 3) | 146 | line_in (Player only) (bit 3) |
146 | 0xAF [available/unused] | 147 | 0xAF <most-recent-bookmarks, auto-bookmark, autoload> |
147 | 0xB0 peak meter clip hold timeout (bit 0-4), peak meter performance (bit 7) | 148 | 0xB0 peak meter clip hold timeout (bit 0-4), peak meter performance (bit 7) |
148 | 0xB1 peak meter release step size, peak_meter_dbfs (bit 7) | 149 | 0xB1 peak meter release step size, peak_meter_dbfs (bit 7) |
149 | 0xB2 peak meter min either in -db or in percent | 150 | 0xB2 peak meter min either in -db or in percent |
@@ -419,6 +420,9 @@ int settings_save( void ) | |||
419 | ((global_settings.caption_backlight & 1) << 1) | | 420 | ((global_settings.caption_backlight & 1) << 1) | |
420 | ((global_settings.car_adapter_mode & 1) << 2) | | 421 | ((global_settings.car_adapter_mode & 1) << 2) | |
421 | ((global_settings.line_in & 1) << 3)); | 422 | ((global_settings.line_in & 1) << 3)); |
423 | config_block[0xaf] = ((global_settings.usemrb << 5) | | ||
424 | (global_settings.autocreatebookmark << 2) | | ||
425 | (global_settings.autoloadbookmark)); | ||
422 | config_block[0xb0] = (unsigned char)global_settings.peak_meter_clip_hold | | 426 | config_block[0xb0] = (unsigned char)global_settings.peak_meter_clip_hold | |
423 | (global_settings.peak_meter_performance ? 0x80 : 0); | 427 | (global_settings.peak_meter_performance ? 0x80 : 0); |
424 | config_block[0xb1] = global_settings.peak_meter_release | | 428 | config_block[0xb1] = global_settings.peak_meter_release | |
@@ -771,6 +775,9 @@ void settings_load(void) | |||
771 | if (config_block[0xa9] != 0xff) | 775 | if (config_block[0xa9] != 0xff) |
772 | global_settings.jump_scroll_delay = config_block[0xa9]; | 776 | global_settings.jump_scroll_delay = config_block[0xa9]; |
773 | #endif | 777 | #endif |
778 | global_settings.usemrb = (config_block[0xaf] >> 5) & 3; | ||
779 | global_settings.autocreatebookmark = (config_block[0xaf] >> 2) & 7; | ||
780 | global_settings.autoloadbookmark = (config_block[0xaf]) & 3; | ||
774 | } | 781 | } |
775 | 782 | ||
776 | settings_apply(); | 783 | settings_apply(); |
@@ -1128,6 +1135,21 @@ bool settings_load_config(char* file) | |||
1128 | set_cfg_option(&global_settings.recursive_dir_insert, value, | 1135 | set_cfg_option(&global_settings.recursive_dir_insert, value, |
1129 | options, 3); | 1136 | options, 3); |
1130 | } | 1137 | } |
1138 | else if (!strcasecmp(name, "autoload bookmarks")) | ||
1139 | { | ||
1140 | static char* options[] = {"off", "on", "ask"}; | ||
1141 | set_cfg_option(&global_settings.autoloadbookmark, value, options, 3); | ||
1142 | } | ||
1143 | else if (!strcasecmp(name, "autocreate bookmarks")) | ||
1144 | { | ||
1145 | static char* options[] = {"off", "on", "ask","recent only - yes","recent only - ask"}; | ||
1146 | set_cfg_option(&global_settings.autocreatebookmark, value, options, 5); | ||
1147 | } | ||
1148 | else if (!strcasecmp(name, "use most-recent-bookmarks")) | ||
1149 | { | ||
1150 | static char* options[] = {"off", "on", "unique only"}; | ||
1151 | set_cfg_option(&global_settings.usemrb, value, options, 3); | ||
1152 | } | ||
1131 | } | 1153 | } |
1132 | 1154 | ||
1133 | close(fd); | 1155 | close(fd); |
@@ -1143,6 +1165,7 @@ bool settings_save_config(void) | |||
1143 | int fd, i, value; | 1165 | int fd, i, value; |
1144 | char filename[MAX_PATH]; | 1166 | char filename[MAX_PATH]; |
1145 | char* boolopt[] = {"off","on"}; | 1167 | char* boolopt[] = {"off","on"}; |
1168 | char* triopt[] = {"off","on","ask"}; | ||
1146 | 1169 | ||
1147 | /* find unused filename */ | 1170 | /* find unused filename */ |
1148 | for (i=0; ; i++) { | 1171 | for (i=0; ; i++) { |
@@ -1431,11 +1454,27 @@ bool settings_save_config(void) | |||
1431 | 1454 | ||
1432 | #endif | 1455 | #endif |
1433 | 1456 | ||
1457 | fprintf(fd, "#\r\n# Bookmarking\r\n#\r\n"); | ||
1458 | { | ||
1459 | fprintf(fd, "autoload bookmarks: %s\r\n", | ||
1460 | triopt[global_settings.autoloadbookmark]); | ||
1461 | } | ||
1462 | |||
1463 | { | ||
1464 | static char* options[] = {"off", "on", "ask","recent only - on", "recent only - ask"}; | ||
1465 | fprintf(fd, "autocreate bookmarks: %s\r\n", | ||
1466 | options[global_settings.autocreatebookmark]); | ||
1467 | } | ||
1468 | |||
1469 | { | ||
1470 | static char* options[] = {"off", "on", "unique only"}; | ||
1471 | fprintf(fd, "UseMRB: %s\r\n", options[global_settings.usemrb]); | ||
1472 | } | ||
1473 | |||
1434 | fprintf(fd, "#\r\n# Playlists\r\n#\r\n"); | 1474 | fprintf(fd, "#\r\n# Playlists\r\n#\r\n"); |
1435 | { | 1475 | { |
1436 | static char* options[] = {"off", "on", "ask"}; | ||
1437 | fprintf(fd, "recursive directory insert: %s\r\n", | 1476 | fprintf(fd, "recursive directory insert: %s\r\n", |
1438 | options[global_settings.recursive_dir_insert]); | 1477 | triopt[global_settings.recursive_dir_insert]); |
1439 | } | 1478 | } |
1440 | 1479 | ||
1441 | close(fd); | 1480 | close(fd); |
@@ -1528,6 +1567,9 @@ void settings_reset(void) { | |||
1528 | global_settings.lang_file[0] = 0; | 1567 | global_settings.lang_file[0] = 0; |
1529 | global_settings.runtime = 0; | 1568 | global_settings.runtime = 0; |
1530 | global_settings.topruntime = 0; | 1569 | global_settings.topruntime = 0; |
1570 | global_settings.autocreatebookmark = BOOKMARK_NO; | ||
1571 | global_settings.autoloadbookmark = BOOKMARK_NO; | ||
1572 | global_settings.usemrb = BOOKMARK_NO; | ||
1531 | global_settings.fade_on_stop = true; | 1573 | global_settings.fade_on_stop = true; |
1532 | global_settings.caption_backlight = false; | 1574 | global_settings.caption_backlight = false; |
1533 | global_settings.car_adapter_mode = false; | 1575 | global_settings.car_adapter_mode = false; |
diff --git a/apps/settings.h b/apps/settings.h index 904bcd6a91..49fa83b359 100644 --- a/apps/settings.h +++ b/apps/settings.h | |||
@@ -38,6 +38,12 @@ | |||
38 | #define RESUME_ASK_ONCE 2 | 38 | #define RESUME_ASK_ONCE 2 |
39 | #define RESUME_ON 3 | 39 | #define RESUME_ON 3 |
40 | 40 | ||
41 | #define BOOKMARK_NO 0 | ||
42 | #define BOOKMARK_YES 1 | ||
43 | #define BOOKMARK_ASK 2 | ||
44 | #define BOOKMARK_UNIQUE_ONLY 2 | ||
45 | #define BOOKMARK_RECENT_ONLY_YES 3 | ||
46 | #define BOOKMARK_RECENT_ONLY_ASK 4 | ||
41 | #define FF_REWIND_1000 0 | 47 | #define FF_REWIND_1000 0 |
42 | #define FF_REWIND_2000 1 | 48 | #define FF_REWIND_2000 1 |
43 | #define FF_REWIND_3000 2 | 49 | #define FF_REWIND_3000 2 |
@@ -109,8 +115,8 @@ struct user_settings | |||
109 | /* resume settings */ | 115 | /* resume settings */ |
110 | 116 | ||
111 | int resume; /* resume option: 0=off, 1=ask, 2=on */ | 117 | int resume; /* resume option: 0=off, 1=ask, 2=on */ |
112 | short resume_index; /* index in playlist (-1 for no active resume) */ | 118 | int resume_index; /* index in playlist (-1 for no active resume) */ |
113 | short resume_first_index; /* index of first track in playlist */ | 119 | int resume_first_index; /* index of first track in playlist */ |
114 | int resume_offset; /* byte offset in mp3 file */ | 120 | int resume_offset; /* byte offset in mp3 file */ |
115 | int resume_seed; /* shuffle seed (-1=no resume shuffle 0=sorted | 121 | int resume_seed; /* shuffle seed (-1=no resume shuffle 0=sorted |
116 | >0=shuffled) */ | 122 | >0=shuffled) */ |
@@ -161,6 +167,11 @@ struct user_settings | |||
161 | int bidir_limit; /* bidir scroll length limit */ | 167 | int bidir_limit; /* bidir scroll length limit */ |
162 | int scroll_delay; /* delay (in 1/10s) before starting scroll */ | 168 | int scroll_delay; /* delay (in 1/10s) before starting scroll */ |
163 | int scroll_step; /* pixels to advance per update */ | 169 | int scroll_step; /* pixels to advance per update */ |
170 | |||
171 | /* auto bookmark settings */ | ||
172 | int autoloadbookmark; /* auto load option: 0=off, 1=ask, 2=on */ | ||
173 | int autocreatebookmark; /* auto create option: 0=off, 1=ask, 2=on */ | ||
174 | int usemrb; /* use MRB list: 0=No, 1=Yes*/ | ||
164 | #ifdef HAVE_LCD_CHARCELLS | 175 | #ifdef HAVE_LCD_CHARCELLS |
165 | int jump_scroll; /* Fast jump when scrolling */ | 176 | int jump_scroll; /* Fast jump when scrolling */ |
166 | int jump_scroll_delay; /* Delay between jump scroll screens */ | 177 | int jump_scroll_delay; /* Delay between jump scroll screens */ |
@@ -205,6 +216,7 @@ bool set_option(char* string, void* variable, enum optiontype type, | |||
205 | bool set_int(char* string, char* unit, int* variable, | 216 | bool set_int(char* string, char* unit, int* variable, |
206 | void (*function)(int), int step, int min, int max ); | 217 | void (*function)(int), int step, int min, int max ); |
207 | bool set_time(char* string, int timedate[]); | 218 | bool set_time(char* string, int timedate[]); |
219 | int read_line(int fd, char* buffer, int buffer_size); | ||
208 | void set_file(char* filename, char* setting, int maxlen); | 220 | void set_file(char* filename, char* setting, int maxlen); |
209 | 221 | ||
210 | #ifdef HAVE_MAS3587F | 222 | #ifdef HAVE_MAS3587F |
diff --git a/apps/settings_menu.c b/apps/settings_menu.c index 65261e348c..a96c88c681 100644 --- a/apps/settings_menu.c +++ b/apps/settings_menu.c | |||
@@ -438,6 +438,40 @@ static bool resume(void) | |||
438 | names, 4, NULL ); | 438 | names, 4, NULL ); |
439 | } | 439 | } |
440 | 440 | ||
441 | static bool autocreatebookmark(void) | ||
442 | { | ||
443 | char* names[] = { str(LANG_SET_BOOL_NO), | ||
444 | str(LANG_SET_BOOL_YES), | ||
445 | str(LANG_RESUME_SETTING_ASK), | ||
446 | str(LANG_BOOKMARK_SETTINGS_RECENT_ONLY_YES), | ||
447 | str(LANG_BOOKMARK_SETTINGS_RECENT_ONLY_ASK) }; | ||
448 | |||
449 | return set_option( str(LANG_BOOKMARK_SETTINGS_AUTOCREATE), | ||
450 | &global_settings.autocreatebookmark, INT, | ||
451 | names, 5, NULL ); | ||
452 | } | ||
453 | |||
454 | static bool autoloadbookmark(void) | ||
455 | { | ||
456 | char* names[] = { str(LANG_SET_BOOL_NO), | ||
457 | str(LANG_SET_BOOL_YES), | ||
458 | str(LANG_RESUME_SETTING_ASK) }; | ||
459 | |||
460 | return set_option( str(LANG_BOOKMARK_SETTINGS_AUTOLOAD), | ||
461 | &global_settings.autoloadbookmark, INT, | ||
462 | names, 3, NULL ); | ||
463 | } | ||
464 | |||
465 | static bool useMRB(void) | ||
466 | { | ||
467 | char* names[] = { str(LANG_SET_BOOL_NO), | ||
468 | str(LANG_SET_BOOL_YES), | ||
469 | str(LANG_BOOKMARK_SETTINGS_UNIQUE_ONLY)}; | ||
470 | |||
471 | return set_option( str(LANG_BOOKMARK_SETTINGS_MAINTAIN_RECENT_BOOKMARKS), | ||
472 | &global_settings.usemrb, INT, | ||
473 | names, 3, NULL ); | ||
474 | } | ||
441 | static bool backlight_on_when_charging(void) | 475 | static bool backlight_on_when_charging(void) |
442 | { | 476 | { |
443 | bool result = set_bool(str(LANG_BACKLIGHT_ON_WHEN_CHARGING), | 477 | bool result = set_bool(str(LANG_BACKLIGHT_ON_WHEN_CHARGING), |
@@ -789,6 +823,23 @@ static bool playback_settings_menu(void) | |||
789 | return result; | 823 | return result; |
790 | } | 824 | } |
791 | 825 | ||
826 | static bool bookmark_settings_menu(void) | ||
827 | { | ||
828 | int m; | ||
829 | bool result; | ||
830 | |||
831 | struct menu_items items[] = { | ||
832 | { str(LANG_BOOKMARK_SETTINGS_AUTOCREATE), autocreatebookmark}, | ||
833 | { str(LANG_BOOKMARK_SETTINGS_AUTOLOAD), autoloadbookmark}, | ||
834 | { str(LANG_BOOKMARK_SETTINGS_MAINTAIN_RECENT_BOOKMARKS), useMRB}, | ||
835 | }; | ||
836 | |||
837 | m=menu_init( items, sizeof items / sizeof(struct menu_items) ); | ||
838 | result = menu_run(m); | ||
839 | menu_exit(m); | ||
840 | |||
841 | return result; | ||
842 | } | ||
792 | static bool reset_settings(void) | 843 | static bool reset_settings(void) |
793 | { | 844 | { |
794 | bool done=false; | 845 | bool done=false; |
@@ -966,6 +1017,7 @@ bool settings_menu(void) | |||
966 | { str(LANG_CUSTOM_FONT), font_browse }, | 1017 | { str(LANG_CUSTOM_FONT), font_browse }, |
967 | #endif | 1018 | #endif |
968 | { str(LANG_SYSTEM), system_settings_menu }, | 1019 | { str(LANG_SYSTEM), system_settings_menu }, |
1020 | { str(LANG_BOOKMARK_SETTINGS),bookmark_settings_menu }, | ||
969 | { str(LANG_SAVE_SETTINGS), settings_save_config }, | 1021 | { str(LANG_SAVE_SETTINGS), settings_save_config }, |
970 | }; | 1022 | }; |
971 | 1023 | ||
diff --git a/apps/tree.c b/apps/tree.c index 3c9827d685..12472fa79b 100644 --- a/apps/tree.c +++ b/apps/tree.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include "language.h" | 49 | #include "language.h" |
50 | #include "screens.h" | 50 | #include "screens.h" |
51 | #include "keyboard.h" | 51 | #include "keyboard.h" |
52 | #include "bookmark.h" | ||
52 | #include "onplay.h" | 53 | #include "onplay.h" |
53 | #include "buffer.h" | 54 | #include "buffer.h" |
54 | #include "plugin.h" | 55 | #include "plugin.h" |
@@ -83,6 +84,9 @@ static struct | |||
83 | { ".fnt", TREE_ATTR_FONT,Font }, | 84 | { ".fnt", TREE_ATTR_FONT,Font }, |
84 | { ".ch8", TREE_ATTR_CH8, Chip8 }, | 85 | { ".ch8", TREE_ATTR_CH8, Chip8 }, |
85 | { ".rvf", TREE_ATTR_RVF, Video }, | 86 | { ".rvf", TREE_ATTR_RVF, Video }, |
87 | { ".bmark",TREE_ATTR_BMARK,Bookmark }, | ||
88 | #else | ||
89 | { ".bmark", TREE_ATTR_BMARK, -1 }, | ||
86 | #endif | 90 | #endif |
87 | #ifndef SIMULATOR | 91 | #ifndef SIMULATOR |
88 | #ifdef HAVE_LCD_BITMAP | 92 | #ifdef HAVE_LCD_BITMAP |
@@ -118,6 +122,7 @@ static int boot_size = 0; | |||
118 | static int boot_cluster; | 122 | static int boot_cluster; |
119 | static bool boot_changed = false; | 123 | static bool boot_changed = false; |
120 | 124 | ||
125 | static bool start_wps = false; | ||
121 | static bool dirbrowse(char *root, int *dirfilter); | 126 | static bool dirbrowse(char *root, int *dirfilter); |
122 | 127 | ||
123 | void browse_root(void) | 128 | void browse_root(void) |
@@ -646,9 +651,7 @@ static void start_resume(bool ask_once) | |||
646 | playlist_start(global_settings.resume_index, | 651 | playlist_start(global_settings.resume_index, |
647 | global_settings.resume_offset); | 652 | global_settings.resume_offset); |
648 | 653 | ||
649 | status_set_playmode(STATUS_PLAY); | 654 | start_wps = true; |
650 | status_draw(true); | ||
651 | wps_show(); | ||
652 | } | 655 | } |
653 | else | 656 | else |
654 | return; | 657 | return; |
@@ -930,6 +933,7 @@ static bool dirbrowse(char *root, int *dirfilter) | |||
930 | 933 | ||
931 | #ifdef HAVE_RECORDER_KEYPAD | 934 | #ifdef HAVE_RECORDER_KEYPAD |
932 | case BUTTON_OFF: | 935 | case BUTTON_OFF: |
936 | bookmark_autobookmark(); | ||
933 | mpeg_stop(); | 937 | mpeg_stop(); |
934 | status_set_playmode(STATUS_STOP); | 938 | status_set_playmode(STATUS_STOP); |
935 | status_draw(false); | 939 | status_draw(false); |
@@ -988,6 +992,12 @@ static bool dirbrowse(char *root, int *dirfilter) | |||
988 | lcd_stop_scroll(); | 992 | lcd_stop_scroll(); |
989 | switch ( file->attr & TREE_ATTR_MASK ) { | 993 | switch ( file->attr & TREE_ATTR_MASK ) { |
990 | case TREE_ATTR_M3U: | 994 | case TREE_ATTR_M3U: |
995 | if (bookmark_autoload(buf)) | ||
996 | { | ||
997 | restore = true; | ||
998 | break; | ||
999 | } | ||
1000 | |||
991 | if (playlist_create(currdir, file->name) != -1) | 1001 | if (playlist_create(currdir, file->name) != -1) |
992 | { | 1002 | { |
993 | if (global_settings.playlist_shuffle) | 1003 | if (global_settings.playlist_shuffle) |
@@ -999,6 +1009,12 @@ static bool dirbrowse(char *root, int *dirfilter) | |||
999 | break; | 1009 | break; |
1000 | 1010 | ||
1001 | case TREE_ATTR_MPA: | 1011 | case TREE_ATTR_MPA: |
1012 | if (bookmark_autoload(currdir)) | ||
1013 | { | ||
1014 | restore = true; | ||
1015 | break; | ||
1016 | } | ||
1017 | |||
1002 | if (playlist_create(currdir, NULL) != -1) | 1018 | if (playlist_create(currdir, NULL) != -1) |
1003 | { | 1019 | { |
1004 | start_index = | 1020 | start_index = |
@@ -1051,6 +1067,12 @@ static bool dirbrowse(char *root, int *dirfilter) | |||
1051 | restore = true; | 1067 | restore = true; |
1052 | break; | 1068 | break; |
1053 | 1069 | ||
1070 | case TREE_ATTR_BMARK: | ||
1071 | bookmark_load(buf, false); | ||
1072 | restore = true; | ||
1073 | reload_dir = true; | ||
1074 | break; | ||
1075 | |||
1054 | case TREE_ATTR_TXT: | 1076 | case TREE_ATTR_TXT: |
1055 | plugin_load("/.rockbox/rocks/viewer.rock",buf); | 1077 | plugin_load("/.rockbox/rocks/viewer.rock",buf); |
1056 | restore = true; | 1078 | restore = true; |
@@ -1122,15 +1144,7 @@ static bool dirbrowse(char *root, int *dirfilter) | |||
1122 | settings_save(); | 1144 | settings_save(); |
1123 | } | 1145 | } |
1124 | 1146 | ||
1125 | status_set_playmode(STATUS_PLAY); | 1147 | start_wps = true; |
1126 | status_draw(false); | ||
1127 | lcd_stop_scroll(); | ||
1128 | if ( wps_show() == SYS_USB_CONNECTED ) { | ||
1129 | reload_root = true; | ||
1130 | } | ||
1131 | #ifdef HAVE_LCD_BITMAP | ||
1132 | tree_max_on_screen = (LCD_HEIGHT - MARGIN_Y) / fh; | ||
1133 | #endif | ||
1134 | } | 1148 | } |
1135 | else if (*dirfilter > NUM_FILTER_MODES) | 1149 | else if (*dirfilter > NUM_FILTER_MODES) |
1136 | exit_func = true; | 1150 | exit_func = true; |
@@ -1238,13 +1252,7 @@ static bool dirbrowse(char *root, int *dirfilter) | |||
1238 | { | 1252 | { |
1239 | if (mpeg_status() & MPEG_STATUS_PLAY) | 1253 | if (mpeg_status() & MPEG_STATUS_PLAY) |
1240 | { | 1254 | { |
1241 | lcd_stop_scroll(); | 1255 | start_wps=true; |
1242 | if (wps_show() == SYS_USB_CONNECTED) | ||
1243 | reload_root = true; | ||
1244 | #ifdef HAVE_LCD_BITMAP | ||
1245 | tree_max_on_screen = (LCD_HEIGHT - MARGIN_Y) / fh; | ||
1246 | #endif | ||
1247 | restore = true; | ||
1248 | } | 1256 | } |
1249 | else | 1257 | else |
1250 | { | 1258 | { |
@@ -1293,6 +1301,18 @@ static bool dirbrowse(char *root, int *dirfilter) | |||
1293 | if ( button ) | 1301 | if ( button ) |
1294 | ata_spin(); | 1302 | ata_spin(); |
1295 | 1303 | ||
1304 | if (start_wps) | ||
1305 | { | ||
1306 | lcd_stop_scroll(); | ||
1307 | if (wps_show() == SYS_USB_CONNECTED) | ||
1308 | reload_root = true; | ||
1309 | #ifdef HAVE_LCD_BITMAP | ||
1310 | tree_max_on_screen = (LCD_HEIGHT - MARGIN_Y) / fh; | ||
1311 | #endif | ||
1312 | restore = true; | ||
1313 | start_wps=false; | ||
1314 | } | ||
1315 | |||
1296 | /* do we need to rescan dir? */ | 1316 | /* do we need to rescan dir? */ |
1297 | if (reload_dir || reload_root || | 1317 | if (reload_dir || reload_root || |
1298 | lastfilter != *dirfilter || | 1318 | lastfilter != *dirfilter || |
@@ -1313,6 +1333,7 @@ static bool dirbrowse(char *root, int *dirfilter) | |||
1313 | lastfilter = *dirfilter; | 1333 | lastfilter = *dirfilter; |
1314 | lastsortcase = global_settings.sort_case; | 1334 | lastsortcase = global_settings.sort_case; |
1315 | restore = true; | 1335 | restore = true; |
1336 | while (button_get(false)); /* clear button queue */ | ||
1316 | } | 1337 | } |
1317 | 1338 | ||
1318 | if (exit_func) | 1339 | if (exit_func) |
@@ -1507,3 +1528,51 @@ void tree_init(void) | |||
1507 | name_buffer = buffer_alloc(name_buffer_size); | 1528 | name_buffer = buffer_alloc(name_buffer_size); |
1508 | dircache = buffer_alloc(max_files_in_dir * sizeof(struct entry)); | 1529 | dircache = buffer_alloc(max_files_in_dir * sizeof(struct entry)); |
1509 | } | 1530 | } |
1531 | |||
1532 | void bookmark_play(char *resume_file, int index, int offset, int seed) | ||
1533 | { | ||
1534 | int len=strlen(resume_file); | ||
1535 | |||
1536 | if (!strcasecmp(&resume_file[len-4], ".m3u")) | ||
1537 | { | ||
1538 | char* slash; | ||
1539 | // check that the file exists | ||
1540 | int fd = open(resume_file, O_RDONLY); | ||
1541 | if(fd<0) | ||
1542 | return; | ||
1543 | close(fd); | ||
1544 | |||
1545 | slash = strrchr(resume_file,'/'); | ||
1546 | if (slash) | ||
1547 | { | ||
1548 | char* cp; | ||
1549 | *slash=0; | ||
1550 | |||
1551 | cp=resume_file; | ||
1552 | if (!cp[0]) | ||
1553 | cp="/"; | ||
1554 | |||
1555 | if (playlist_create(cp, slash+1) != -1) | ||
1556 | { | ||
1557 | if (global_settings.playlist_shuffle) | ||
1558 | playlist_shuffle(seed, -1); | ||
1559 | playlist_start(index,offset); | ||
1560 | } | ||
1561 | *slash='/'; | ||
1562 | } | ||
1563 | } | ||
1564 | else | ||
1565 | { | ||
1566 | lastdir[0]='\0'; | ||
1567 | if (playlist_create(resume_file, NULL) != -1) | ||
1568 | { | ||
1569 | resume_directory(resume_file); | ||
1570 | if (global_settings.playlist_shuffle) | ||
1571 | playlist_shuffle(seed, -1); | ||
1572 | playlist_start(index,offset); | ||
1573 | } | ||
1574 | } | ||
1575 | |||
1576 | status_set_playmode(STATUS_PLAY); | ||
1577 | start_wps=true; | ||
1578 | } | ||
diff --git a/apps/tree.h b/apps/tree.h index 87cd469148..c7b678eb82 100644 --- a/apps/tree.h +++ b/apps/tree.h | |||
@@ -39,6 +39,7 @@ struct entry { | |||
39 | #define TREE_ATTR_UCL 0x0A00 /* rockbox flash image */ | 39 | #define TREE_ATTR_UCL 0x0A00 /* rockbox flash image */ |
40 | #define TREE_ATTR_CH8 0x0B00 /* chip-8 game */ | 40 | #define TREE_ATTR_CH8 0x0B00 /* chip-8 game */ |
41 | #define TREE_ATTR_RVF 0x0C00 /* rockbox video file */ | 41 | #define TREE_ATTR_RVF 0x0C00 /* rockbox video file */ |
42 | #define TREE_ATTR_BMARK 0x0D00 /* book mark file */ | ||
42 | #define TREE_ATTR_MASK 0xFFC0 /* which bits tree.c uses (above) */ | 43 | #define TREE_ATTR_MASK 0xFFC0 /* which bits tree.c uses (above) */ |
43 | 44 | ||
44 | void tree_init(void); | 45 | void tree_init(void); |
diff --git a/apps/wps.c b/apps/wps.c index 777894d535..09eeef4361 100644 --- a/apps/wps.c +++ b/apps/wps.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include "peakmeter.h" | 45 | #include "peakmeter.h" |
46 | #endif | 46 | #endif |
47 | #include "lang.h" | 47 | #include "lang.h" |
48 | #include "bookmark.h" | ||
48 | #define FF_REWIND_MAX_PERCENT 3 /* cap ff/rewind step size at max % of file */ | 49 | #define FF_REWIND_MAX_PERCENT 3 /* cap ff/rewind step size at max % of file */ |
49 | /* 3% of 30min file == 54s step size */ | 50 | /* 3% of 30min file == 54s step size */ |
50 | 51 | ||
@@ -943,7 +944,7 @@ int wps_show(void) | |||
943 | case BUTTON_RC_STOP: | 944 | case BUTTON_RC_STOP: |
944 | #endif | 945 | #endif |
945 | #ifdef BUTTON_OFF | 946 | #ifdef BUTTON_OFF |
946 | case BUTTON_OFF: | 947 | case BUTTON_OFF | BUTTON_REL: |
947 | #else | 948 | #else |
948 | case BUTTON_STOP | BUTTON_REL: | 949 | case BUTTON_STOP | BUTTON_REL: |
949 | if ( lastbutton != BUTTON_STOP ) | 950 | if ( lastbutton != BUTTON_STOP ) |
@@ -985,6 +986,7 @@ int wps_show(void) | |||
985 | fade(0); | 986 | fade(0); |
986 | 987 | ||
987 | lcd_stop_scroll(); | 988 | lcd_stop_scroll(); |
989 | bookmark_autobookmark(); | ||
988 | mpeg_stop(); | 990 | mpeg_stop(); |
989 | status_set_playmode(STATUS_STOP); | 991 | status_set_playmode(STATUS_STOP); |
990 | 992 | ||
diff --git a/uisimulator/win32/Makefile b/uisimulator/win32/Makefile index 69e6e0b734..fe7086391b 100644 --- a/uisimulator/win32/Makefile +++ b/uisimulator/win32/Makefile | |||
@@ -102,7 +102,7 @@ FIRMSRCS = $(LCDSRSC) id3.c mp3data.c usb.c mpeg.c mp3_playback.c \ | |||
102 | APPS = main.c tree.c menu.c credits.c main_menu.c icons.c language.c \ | 102 | APPS = main.c tree.c menu.c credits.c main_menu.c icons.c language.c \ |
103 | playlist.c wps.c wps-display.c settings.c status.c \ | 103 | playlist.c wps.c wps-display.c settings.c status.c \ |
104 | screens.c peakmeter.c sleeptimer.c keyboard.c onplay.c\ | 104 | screens.c peakmeter.c sleeptimer.c keyboard.c onplay.c\ |
105 | misc.c plugin.c playlist_viewer.c | 105 | misc.c plugin.c playlist_viewer.c bookmark.c |
106 | 106 | ||
107 | MENUS = settings_menu.c sound_menu.c playlist_menu.c | 107 | MENUS = settings_menu.c sound_menu.c playlist_menu.c |
108 | 108 | ||
@@ -204,6 +204,9 @@ $(OBJDIR)/playlist.o: $(APPDIR)/playlist.c | |||
204 | $(OBJDIR)/playlist_viewer.o: $(APPDIR)/playlist_viewer.c | 204 | $(OBJDIR)/playlist_viewer.o: $(APPDIR)/playlist_viewer.c |
205 | $(CC) $(APPCFLAGS) -c $< -o $@ | 205 | $(CC) $(APPCFLAGS) -c $< -o $@ |
206 | 206 | ||
207 | $(OBJDIR)/bookmark.o: $(APPDIR)/bookmark.c | ||
208 | $(CC) $(APPCFLAGS) -c $< -o $@ | ||
209 | |||
207 | $(OBJDIR)/plugin.o: $(APPDIR)/plugin.c plugin-win32.h | 210 | $(OBJDIR)/plugin.o: $(APPDIR)/plugin.c plugin-win32.h |
208 | $(CC) $(APPCFLAGS) -c $< -o $@ | 211 | $(CC) $(APPCFLAGS) -c $< -o $@ |
209 | 212 | ||
diff --git a/uisimulator/x11/Makefile b/uisimulator/x11/Makefile index a66d86dfd4..fb609ea2c3 100644 --- a/uisimulator/x11/Makefile +++ b/uisimulator/x11/Makefile | |||
@@ -102,7 +102,7 @@ FIRMSRCS = $(LCDSRSC) id3.c debug.c usb.c mpeg.c mp3_playback.c power.c\ | |||
102 | APPS = main.c tree.c menu.c credits.c main_menu.c language.c\ | 102 | APPS = main.c tree.c menu.c credits.c main_menu.c language.c\ |
103 | playlist.c wps.c wps-display.c settings.c status.c icons.c\ | 103 | playlist.c wps.c wps-display.c settings.c status.c icons.c\ |
104 | screens.c peakmeter.c sleeptimer.c keyboard.c onplay.c\ | 104 | screens.c peakmeter.c sleeptimer.c keyboard.c onplay.c\ |
105 | misc.c plugin.c playlist_viewer.c | 105 | misc.c plugin.c playlist_viewer.c bookmark.c |
106 | 106 | ||
107 | MENUS = settings_menu.c sound_menu.c playlist_menu.c | 107 | MENUS = settings_menu.c sound_menu.c playlist_menu.c |
108 | 108 | ||
@@ -202,6 +202,9 @@ $(OBJDIR)/playlist.o: $(APPDIR)/playlist.c | |||
202 | $(OBJDIR)/playlist_viewer.o: $(APPDIR)/playlist_viewer.c | 202 | $(OBJDIR)/playlist_viewer.o: $(APPDIR)/playlist_viewer.c |
203 | $(CC) $(APPCFLAGS) -c $< -o $@ | 203 | $(CC) $(APPCFLAGS) -c $< -o $@ |
204 | 204 | ||
205 | $(OBJDIR)/bookmark.o: $(APPDIR)/bookmark.c | ||
206 | $(CC) $(APPCFLAGS) -c $< -o $@ | ||
207 | |||
205 | $(OBJDIR)/build.lang: $(APPDIR)/lang/$(LANGUAGE).lang | 208 | $(OBJDIR)/build.lang: $(APPDIR)/lang/$(LANGUAGE).lang |
206 | perl $(TOOLSDIR)/uplang $(APPDIR)/lang/english.lang $< > $@ | 209 | perl $(TOOLSDIR)/uplang $(APPDIR)/lang/english.lang $< > $@ |
207 | 210 | ||