1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006 Jonathan Gordon
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
29 static int dirs_count
;
31 #define RFA_FILE ROCKBOX_DIR "/folder_advance_list.dat"
32 #define RFADIR_FILE ROCKBOX_DIR "/folder_advance_dir.txt"
33 #define RFA_FILE_TEXT ROCKBOX_DIR "/folder_advance_list.txt"
34 #define MAX_REMOVED_DIRS 10
38 int num_replaced_dirs
= 0;
39 char removed_dirs
[MAX_REMOVED_DIRS
][MAX_PATH
];
42 char folder
[][MAX_PATH
];
44 struct file_format
*list
= NULL
;
46 static void update_screen(bool clear
)
50 rb
->snprintf(buf
,sizeof(buf
),"Folders: %d",dirs_count
);
54 rb
->screens
[i
]->clear_display();
55 rb
->screens
[i
]->putsxy(0,0,buf
);
56 rb
->screens
[i
]->update();
60 static void traversedir(char* location
, char* name
)
64 char fullpath
[MAX_PATH
], path
[MAX_PATH
];
68 /* behave differently if we're at root to avoid
69 duplication of the initial slash later on */
70 if (location
[0] == '\0' && name
[0] == '\0') {
71 rb
->strcpy(fullpath
, "");
72 dir
= rb
->opendir("/");
74 rb
->snprintf(fullpath
, sizeof(fullpath
), "%s/%s", location
, name
);
75 dir
= rb
->opendir(fullpath
);
78 entry
= rb
->readdir(dir
);
83 if (entry
->d_name
[0] == '.')
85 if ( !rb
->strcmp(entry
->d_name
,".")
86 || !rb
->strcmp(entry
->d_name
,"..")
87 || !rb
->strcmp(entry
->d_name
,".rockbox"))
93 /* check if path is removed directory, if so dont enter it */
94 rb
->snprintf(path
, MAX_PATH
, "%s/%s", fullpath
, entry
->d_name
);
96 rb
->strlcpy(path
, path
+ 1, sizeof(path
));
97 for(i
= 0; i
< num_replaced_dirs
; i
++)
99 if(!rb
->strcmp(path
, removed_dirs
[i
]))
108 struct dirinfo info
= rb
->dir_get_info(dir
, entry
);
109 if (info
.attribute
& ATTR_DIRECTORY
) {
112 rb
->snprintf(path
,MAX_PATH
,"%s/%s",fullpath
,entry
->d_name
);
113 start
= &path
[rb
->strlen(path
)];
114 rb
->memset(start
,0,&path
[MAX_PATH
-1]-start
);
115 rb
->write(fd
,path
,MAX_PATH
);
116 traversedir(fullpath
, entry
->d_name
);
119 if (*rb
->current_tick
- lasttick
> (HZ
/2)) {
120 update_screen(false);
121 lasttick
= *rb
->current_tick
;
122 if (rb
->action_userabort(TIMEOUT_NOBLOCK
))
129 entry
= rb
->readdir(dir
);
135 static bool custom_dir(void)
138 char *starts
, line
[MAX_PATH
], formatted_line
[MAX_PATH
];
143 /* populate removed dirs array */
144 if((fd2
= rb
->open(RFADIR_FILE
,O_RDONLY
)) >= 0)
146 while ((rb
->read_line(fd2
, line
, MAX_PATH
- 1)) > 0)
148 if ((line
[0] == '-') && (line
[1] == '/') &&
149 (num_replaced_dirs
< MAX_REMOVED_DIRS
))
151 num_replaced_dirs
++;
152 rb
->strlcpy(removed_dirs
[num_replaced_dirs
- 1], line
+ 2,
159 if((fd2
= rb
->open(RFADIR_FILE
,O_RDONLY
)) >= 0)
161 while ((rb
->read_line(fd2
, line
, MAX_PATH
- 1)) > 0)
163 /* blank lines and removed dirs ignored */
164 if (rb
->strlen(line
) && ((line
[0] != '-') || (line
[1] != '/')))
166 /* remove preceeding '/'s from the line */
167 while(line
[0] == '/')
168 rb
->strlcpy(line
, line
+ 1, sizeof(line
));
170 rb
->snprintf(formatted_line
, MAX_PATH
, "/%s", line
);
172 dir_check
= rb
->opendir(formatted_line
);
176 rb
->closedir(dir_check
);
177 starts
= &formatted_line
[rb
->strlen(formatted_line
)];
178 rb
->memset(starts
, 0, &formatted_line
[MAX_PATH
-1]-starts
);
179 bool write_line
= true;
181 for(i
= 0; i
< num_replaced_dirs
; i
++)
183 if(!rb
->strcmp(line
, removed_dirs
[i
]))
193 rb
->write(fd
, formatted_line
, MAX_PATH
);
196 traversedir("", line
);
201 rb
->snprintf(buf
,sizeof(buf
),"Not found:");
204 rb
->screens
[i
]->puts(0,0,buf
);
205 rb
->screens
[i
]->puts(0, errors
, line
);
207 update_screen(false);
213 /* Press button to continue */
214 rb
->get_action(CONTEXT_STD
, TIMEOUT_BLOCK
);
221 static void generate(void)
225 fd
= rb
->open(RFA_FILE
,O_CREAT
|O_WRONLY
, 0666);
226 rb
->write(fd
,&dirs_count
,sizeof(int));
229 rb
->splashf(HZ
, "Couldnt open %s", RFA_FILE
);
232 #ifndef HAVE_LCD_CHARCELLS
235 lasttick
= *rb
->current_tick
;
240 rb
->lseek(fd
,0,SEEK_SET
);
241 rb
->write(fd
,&dirs_count
,sizeof(int));
243 rb
->splash(HZ
, "Done");
246 static const char* list_get_name_cb(int selected_item
, void* data
,
247 char* buf
, size_t buf_len
)
250 rb
->strlcpy(buf
, list
->folder
[selected_item
], buf_len
);
254 static int load_list(void)
256 int myfd
= rb
->open(RFA_FILE
,O_RDONLY
);
259 buffer
= rb
->plugin_get_audio_buffer(&buffer_size
);
265 rb
->read(myfd
,buffer
,buffer_size
);
267 list
= (struct file_format
*)buffer
;
272 static int save_list(void)
274 int myfd
= rb
->creat(RFA_FILE
, 0666);
277 rb
->splash(HZ
, "Could Not Open " RFA_FILE
);
280 int dirs_count
= 0, i
= 0;
281 rb
->write(myfd
,&dirs_count
,sizeof(int));
282 for ( ;i
<list
->count
;i
++)
284 if (list
->folder
[i
][0] != ' ')
287 rb
->write(myfd
,list
->folder
[i
],MAX_PATH
);
290 rb
->lseek(myfd
,0,SEEK_SET
);
291 rb
->write(myfd
,&dirs_count
,sizeof(int));
297 static int edit_list(void)
299 struct gui_synclist lists
;
302 int selection
, ret
= 0;
304 /* load the dat file if not already done */
305 if ((list
== NULL
|| list
->count
== 0) && (i
= load_list()) != 0)
307 rb
->splashf(HZ
*2, "Could not load %s, rv = %d", RFA_FILE
, i
);
311 dirs_count
= list
->count
;
313 rb
->gui_synclist_init(&lists
,list_get_name_cb
,0, false, 1, NULL
);
314 rb
->gui_synclist_set_icon_callback(&lists
,NULL
);
315 rb
->gui_synclist_set_nb_items(&lists
,list
->count
);
316 rb
->gui_synclist_limit_scroll(&lists
,true);
317 rb
->gui_synclist_select_item(&lists
, 0);
321 rb
->gui_synclist_draw(&lists
);
322 button
= rb
->get_action(CONTEXT_LIST
,TIMEOUT_BLOCK
);
323 if (rb
->gui_synclist_do_button(&lists
,&button
,LIST_WRAP_UNLESS_HELD
))
325 selection
= rb
->gui_synclist_get_sel_pos(&lists
);
329 list
->folder
[selection
][0] = ' ';
330 list
->folder
[selection
][1] = '\0';
332 case ACTION_STD_CONTEXT
:
335 MENUITEM_STRINGLIST(menu
, "Remove Menu", NULL
,
336 "Remove Folder", "Remove Folder Tree");
338 switch (rb
->do_menu(&menu
, NULL
, NULL
, false))
341 list
->folder
[selection
][0] = ' ';
342 list
->folder
[selection
][1] = '\0';
347 rb
->strcpy(temp
,list
->folder
[selection
]);
348 len
= rb
->strlen(temp
);
349 for (i
=0;i
<list
->count
;i
++)
351 if (!rb
->strncmp(list
->folder
[i
],temp
,len
))
353 list
->folder
[i
][0] = ' ';
354 list
->folder
[i
][1] = '\0';
362 case ACTION_STD_CANCEL
:
364 MENUITEM_STRINGLIST(menu
, "Exit Menu", NULL
,
365 "Save and Exit", "Ignore Changes and Exit");
367 switch (rb
->do_menu(&menu
, NULL
, NULL
, false))
382 static int export_list_to_file_text(void)
385 /* load the dat file if not already done */
386 if ((list
== NULL
|| list
->count
== 0) && (i
= load_list()) != 0)
388 rb
->splashf(HZ
*2, "Could not load %s, rv = %d", RFA_FILE
, i
);
392 if (list
->count
<= 0)
394 rb
->splashf(HZ
*2, "no dirs in list file: %s", RFA_FILE
);
398 /* create and open the file */
399 int myfd
= rb
->creat(RFA_FILE_TEXT
, 0666);
402 rb
->splashf(HZ
*4, "failed to open: fd = %d, file = %s",
403 myfd
, RFA_FILE_TEXT
);
407 /* write each directory to file */
408 for (i
= 0; i
< list
->count
; i
++)
410 if (list
->folder
[i
][0] != ' ')
412 rb
->fdprintf(myfd
, "%s\n", list
->folder
[i
]);
417 rb
->splash(HZ
, "Done");
421 static int import_list_from_file_text(void)
425 buffer
= rb
->plugin_get_audio_buffer(&buffer_size
);
428 rb
->splash(HZ
*2, "failed to get audio buffer");
432 int myfd
= rb
->open(RFA_FILE_TEXT
, O_RDONLY
);
435 rb
->splashf(HZ
*2, "failed to open: %s", RFA_FILE_TEXT
);
439 /* set the list structure, and initialize count */
440 list
= (struct file_format
*)buffer
;
443 while ((rb
->read_line(myfd
, line
, MAX_PATH
- 1)) > 0)
445 /* copy the dir name, and skip the newline */
446 int len
= rb
->strlen(line
);
450 if (line
[len
-1] == 0x0A || line
[len
-1] == 0x0D)
453 (line
[len
-2] == 0x0A || line
[len
-2] == 0x0D))
457 rb
->strcpy(list
->folder
[list
->count
++], line
);
462 if (list
->count
== 0)
470 rb
->splash(HZ
, "Done");
474 static int start_shuffled_play(void)
477 size_t max_shuffle_size
;
480 /* get memory for shuffling */
481 order
=rb
->plugin_get_buffer(&max_shuffle_size
);
482 max_shuffle_size
/=sizeof(int);
483 if (order
==NULL
|| max_shuffle_size
==0)
485 rb
->splashf(HZ
*2, "Not enough memory for shuffling");
489 /* load the dat file if not already done */
490 if ((list
== NULL
|| list
->count
== 0) && (i
= load_list()) != 0)
492 rb
->splashf(HZ
*2, "Could not load %s, rv = %d", RFA_FILE
, i
);
496 if (list
->count
<= 0)
498 rb
->splashf(HZ
*2, "no dirs in list file: %s", RFA_FILE
);
502 /* shuffle the thing */
503 rb
->srand(*rb
->current_tick
);
504 if(list
->count
>(int)max_shuffle_size
)
506 rb
->splashf(HZ
*2, "Too many folders: %d (room for %d)", list
->count
,(int)max_shuffle_size
);
509 for(i
=0;i
<list
->count
;i
++)
512 for(i
= list
->count
- 1; i
>= 0; i
--)
514 /* the rand is from 0 to RAND_MAX, so adjust to our value range */
515 int candidate
= rb
->rand() % (i
+ 1);
517 /* now swap the values at the 'i' and 'candidate' positions */
518 int store
= order
[candidate
];
519 order
[candidate
] = order
[i
];
523 /* We don't want whatever is playing */
524 if (!(rb
->playlist_remove_all_tracks(NULL
) == 0
525 && rb
->playlist_create(NULL
, NULL
) == 0))
527 rb
->splashf(HZ
*2, "Could not clear playlist");
531 /* add the lot to the playlist */
532 for (i
= 0; i
< list
->count
; i
++)
534 if (list
->folder
[order
[i
]][0] != ' ')
536 rb
->playlist_insert_directory(NULL
,list
->folder
[order
[i
]],PLAYLIST_INSERT_LAST
,false,false);
538 if (rb
->action_userabort(TIMEOUT_NOBLOCK
))
543 rb
->splash(HZ
, "Done");
544 rb
->playlist_start(0,0);
548 static enum plugin_status
main_menu(void)
551 MENUITEM_STRINGLIST(menu
, "Main Menu", NULL
,
552 "Generate Folder List",
554 "Export List To Textfile",
555 "Import List From Textfile",
561 switch (rb
->do_menu(&menu
, NULL
, NULL
, false))
563 case 0: /* generate */
564 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
568 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
569 rb
->cpu_boost(false);
571 #ifdef HAVE_REMOTE_LCD
572 rb
->remote_backlight_on();
577 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
582 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
583 rb
->cpu_boost(false);
585 #ifdef HAVE_REMOTE_LCD
586 rb
->remote_backlight_on();
590 case 2: /* export to textfile */
591 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
594 export_list_to_file_text();
595 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
596 rb
->cpu_boost(false);
598 #ifdef HAVE_REMOTE_LCD
599 rb
->remote_backlight_on();
603 case 3: /* import from textfile */
604 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
607 import_list_from_file_text();
608 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
609 rb
->cpu_boost(false);
611 #ifdef HAVE_REMOTE_LCD
612 rb
->remote_backlight_on();
617 if (!start_shuffled_play())
620 return PLUGIN_GOTO_WPS
;
628 enum plugin_status
plugin_start(const void* parameter
)
631 #ifdef HAVE_TOUCHSCREEN
632 rb
->touchscreen_set_mode(rb
->global_settings
->touch_mode
);