Improved tag browser configuration file syntax with submenus and

includes (custom user menu, without overwriting by default menu).


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11000 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Miika Pekkarinen 2006-09-19 11:54:33 +00:00
parent 1d5b248f7b
commit ba34c37967
3 changed files with 271 additions and 55 deletions

View file

@ -1,15 +1,46 @@
"Artist" artist : album : title = "%02d. %s" tracknum title
"Album" album : title = "%02d. %s" tracknum title
"Genre" genre : artist : album : title = "%02d. %s" tracknum title
"Composer" composer : album : title = "%02d. %s" tracknum title
"Track" title
"Year" year ? year > "1000" & year < "2008" : artist : album : title = "%02d. %s" tracknum title
"Search by artist" artist ? artist ~ "" : album : title = "%02d. %s" tracknum title
"Search by album" album ? album ~ "" : title = "%02d. %s" tracknum title
"Search by title" title ? title ~ ""
"Search by filename" filename ? filename ~ ""
"Search by score" title = "(%3d) %s" autoscore title ? autoscore > ""
"Most played tracks" title = "(%3d) %s" playcount title %sort = "inverse" %limit = "100" ? playcount > "0"
"Never played tracks" artist ? playcount == "0" : album : title = "%02d. %s" tracknum title
"Best tracks" artist ? playcount > "1" & autoscore > "85" : album : title = "%02d. %s (%3d)" tracknum title autoscore
"List played tracks" title = "(%3d/%d) %s" autoscore playcount title ? playcount > "0"
#! rockbox/tagbrowser/2.0
# ^ Version header must be the first line of every file
# Tag Browser configuration file, do not edit as changes will be lost!
# Instead, you can modify "/.rockbox/tagnavi_custom.config" which will never
# get overwritten automatically.
# Include our custom menu
%include "/.rockbox/tagnavi_custom.config"
#
# === Begin of "Search by..." sub menu
#
# Define the search sub menu
%menu_start "search" "Search by..."
"Artist" -> artist ? artist ~ "" -> album -> title = "%02d. %s" tracknum title
"Artist -> (score > 85)" artist ? artist ~ "" & autoscore >= "85" -> album -> title = "%02d. %s" tracknum title
"Album" -> album ? album ~ "" -> title = "%02d. %s" tracknum title
"Title" -> title ? title ~ ""
"Filename" -> filename ? filename ~ ""
"Score" -> title = "(%3d) %s" autoscore title ? autoscore > ""
# ^ An empy line ends the menu
#
# === Begin of main menu
#
# Define the title of the main menu
%menu_start "main" "Browse by..."
"Artist" -> artist -> album -> title = "%02d. %s" tracknum title
"Album" -> album -> title = "%02d. %s" tracknum title
"Genre" -> genre -> artist -> album -> title = "%02d. %s" tracknum title
"Composer" -> composer -> album -> title = "%02d. %s" tracknum title
"Track" -> title
"Year" -> year ? year > "1000" & year < "2008" -> artist -> album -> title = "%02d. %s" tracknum title
"Search..." ==> "search"
"Most played tracks" -> title = "(%3d) %s" playcount title %sort = "inverse" %limit = "100" ? playcount > "0"
"Never played tracks" -> artist ? playcount == "0" -> album -> title = "%02d. %s" tracknum title
"Best tracks" -> artist ? playcount > "1" & autoscore > "85" -> album -> title = "%02d. %s (%3d)" tracknum title autoscore
"List played tracks" -> title = "(%3d/%d) %s" autoscore playcount title ? playcount > "0"
"Custom view..." ==> "custom"
# And finally set main menu as our root menu
%root_menu "main"

View file

@ -51,7 +51,12 @@ static char searchstring[32];
enum variables {
var_sorttype = 100,
var_limit
var_limit,
var_menu_start,
var_include,
var_rootmenu,
menu_next,
menu_load,
};
/* Capacity 10 000 entries (for example 10k different artists) */
@ -95,9 +100,30 @@ struct search_instruction {
int result_seek[MAX_TAGS];
};
static struct search_instruction *si, *csi;
static int si_count = 0;
struct menu_entry {
char name[64];
int type;
struct search_instruction *si;
int link;
};
#define TAGNAVI_VERSION "#! rockbox/tagbrowser/2.0"
#define TAGMENU_MAX_ITEMS 32
#define TAGMENU_MAX_MENUS 8
struct root_menu {
char title[64];
char id[32];
int itemcount;
struct root_menu *parent;
struct menu_entry *items[TAGMENU_MAX_ITEMS];
};
static struct root_menu menus[TAGMENU_MAX_MENUS];
static struct root_menu *menu;
static struct search_instruction *csi;
static const char *strp;
static int menu_count;
static int root_menu;
static int current_offset;
static int current_entry_count;
@ -138,10 +164,10 @@ static int get_tag(int *tag)
int i;
/* Find the start. */
while (*strp == ' ' && *strp != '\0')
while ((*strp == ' ' || *strp == '>') && *strp != '\0')
strp++;
if (*strp == '\0' || *strp == '?' || *strp == ':')
if (*strp == '\0' || *strp == '?')
return 0;
for (i = 0; i < (int)sizeof(buf)-1; i++)
@ -167,6 +193,11 @@ static int get_tag(int *tag)
MATCH(tag, buf, "autoscore", tag_virt_autoscore);
MATCH(tag, buf, "%sort", var_sorttype);
MATCH(tag, buf, "%limit", var_limit);
MATCH(tag, buf, "%menu_start", var_menu_start);
MATCH(tag, buf, "%include", var_include);
MATCH(tag, buf, "%root_menu", var_rootmenu);
MATCH(tag, buf, "->", menu_next);
MATCH(tag, buf, "==>", menu_load);
logf("NO MATCH: %s\n", buf);
if (buf[0] == '?')
@ -337,8 +368,7 @@ static int get_condition(struct search_instruction *inst)
case '&':
strp++;
return 1;
case ':':
strp++;
case '-':
case '\0':
return 0;
}
@ -366,25 +396,56 @@ static int get_condition(struct search_instruction *inst)
* $ ends with
*/
static bool parse_search(struct search_instruction *inst, const char *str)
static bool parse_search(struct menu_entry *entry, const char *str)
{
int ret;
int type;
struct search_instruction *inst = entry->si;
char buf[MAX_PATH];
int i;
memset(inst, 0, sizeof(struct search_instruction));
strp = str;
if (get_token_str(inst->name, sizeof inst->name) < 0)
/* Parse entry name */
if (get_token_str(entry->name, sizeof entry->name) < 0)
{
logf("No name found.");
return false;
}
/* Parse entry type */
if (get_tag(&entry->type) <= 0)
return false;
if (entry->type == menu_load)
{
if (get_token_str(buf, sizeof buf) < 0)
return false;
/* Find the matching root menu or "create" it */
for (i = 0; i < menu_count; i++)
{
if (!strcasecmp(menus[i].id, buf))
{
entry->link = i;
menus[i].parent = menu;
return true;
}
}
return false;
}
if (entry->type != menu_next)
return false;
while (inst->tagorder_count < MAX_TAGS)
{
ret = get_tag(&inst->tagorder[inst->tagorder_count]);
if (ret < 0)
{
logf("Parse error #1");
logf("%s", strp);
return false;
}
@ -396,6 +457,9 @@ static bool parse_search(struct search_instruction *inst, const char *str)
while (get_condition(inst) > 0) ;
inst->tagorder_count++;
if (get_tag(&type) <= 0 || type != menu_next)
break;
}
return true;
@ -520,46 +584,142 @@ bool tagtree_import(void)
return false;
}
void tagtree_init(void)
static bool parse_menu(const char *filename)
{
int fd;
char buf[256];
char data[256];
int variable;
int rc;
int line_count;
bool first = true;
bool read_menu = false;
int i;
if (menu_count >= TAGMENU_MAX_MENUS)
return false;
fd = open(FILE_SEARCH_INSTRUCTIONS, O_RDONLY);
fd = open(filename, O_RDONLY);
if (fd < 0)
{
logf("Search instruction file not found.");
return ;
return false;
}
/* Pre-pass search instructions file to count how many entries */
line_count = 0;
while ( 1 )
{
rc = read_line(fd, buf, sizeof(buf)-1);
if (rc <= 0)
break;
line_count++;
}
/* Allocate memory for searches */
si = (struct search_instruction *) buffer_alloc(sizeof(struct search_instruction) * line_count + 4);
/* Now read file for real, parsing into si */
lseek(fd, 0L, SEEK_SET);
while ( 1 )
{
rc = read_line(fd, buf, sizeof(buf)-1);
if (rc <= 0)
break;
if (!parse_search(si + si_count, buf))
break;
si_count++;
if (first)
{
if (strcasecmp(TAGNAVI_VERSION, buf))
{
logf("Version mismatch");
break;
}
first = false;
}
if (buf[0] == '#')
continue;
if (buf[0] == '\0')
{
if (read_menu)
{
/* End the menu */
menu_count++;
menu = &menus[menu_count];
read_menu = false;
}
continue;
}
if (!read_menu)
{
strp = buf;
if (get_tag(&variable) <= 0)
continue;
switch (variable)
{
case var_include:
if (get_token_str(data, sizeof(data)) < 0)
{
logf("%include empty");
return false;
}
if (!parse_menu(data))
{
logf("Load menu fail: %s", data);
}
break;
case var_menu_start:
if (get_token_str(menu->id, sizeof(menu->id)) < 0)
{
logf("%menu_start id empty");
return false;
}
if (get_token_str(menu->title, sizeof(menu->title)) < 0)
{
logf("%menu_start title empty");
return false;
}
menu->itemcount = 0;
read_menu = true;
break;
case var_rootmenu:
if (get_token_str(data, sizeof(data)) < 0)
{
logf("%root_menu empty");
return false;
}
for (i = 0; i < menu_count; i++)
{
if (!strcasecmp(menus[i].id, data))
{
root_menu = i;
}
}
break;
}
continue;
}
/* Allocate */
if (menu->items[menu->itemcount] == NULL)
{
menu->items[menu->itemcount] = buffer_alloc(sizeof(struct menu_entry));
memset(menu->items[menu->itemcount], 0, sizeof(struct menu_entry));
menu->items[menu->itemcount]->si = buffer_alloc(sizeof(struct search_instruction));
memset(menu->items[menu->itemcount]->si, 0, sizeof(struct search_instruction));
}
if (!parse_search(menu->items[menu->itemcount], buf))
continue;
menu->itemcount++;
}
close(fd);
return true;
}
void tagtree_init(void)
{
memset(menus, 0, sizeof menus);
menu_count = 0;
menu = &menus[0];
root_menu = 0;
parse_menu(FILE_SEARCH_INSTRUCTIONS);
uniqbuf = buffer_alloc(UNIQBUF_SIZE);
audio_set_track_buffer_event(tagtree_buffer_event);
audio_set_track_unbuffer_event(tagtree_unbuffer_event);
@ -858,11 +1018,27 @@ static int load_root(struct tree_context *c)
tc = c;
c->currtable = root;
for (i = 0; i < si_count; i++)
if (c->dirlevel == 0)
c->currextra = root_menu;
menu = &menus[c->currextra];
for (i = 0; i < menu->itemcount; i++)
{
dptr->name = (si+i)->name;
dptr->newtable = navibrowse;
dptr->extraseek = i;
dptr->name = menu->items[i]->name;
switch (menu->items[i]->type)
{
case menu_next:
dptr->newtable = navibrowse;
dptr->extraseek = i;
break;
case menu_load:
dptr->newtable = root;
dptr->extraseek = menu->items[i]->link;
break;
}
dptr++;
}
@ -884,13 +1060,13 @@ int tagtree_load(struct tree_context* c)
c->dirfull = false;
table = root;
c->currtable = table;
c->currextra = root_menu;
}
switch (table)
{
case root:
count = load_root(c);
c->dirlevel = 0;
break;
case allsubentries:
@ -945,11 +1121,17 @@ int tagtree_enter(struct tree_context* c)
case root:
c->currextra = newextra;
if (newextra == navibrowse)
if (newextra == root)
{
menu = &menus[seek];
c->currextra = seek;
}
else if (newextra == navibrowse)
{
int i, j;
csi = si+seek;
csi = menu->items[seek]->si;
c->currextra = 0;
/* Read input as necessary. */
@ -963,7 +1145,7 @@ int tagtree_enter(struct tree_context* c)
rc = kbd_input(searchstring, sizeof(searchstring));
if (rc == -1 || !searchstring[0])
{
c->dirlevel--;
tagtree_exit(c);
return 0;
}
@ -1024,7 +1206,8 @@ int tagtree_enter(struct tree_context* c)
void tagtree_exit(struct tree_context* c)
{
c->dirfull = false;
c->dirlevel--;
if (c->dirlevel > 0)
c->dirlevel--;
c->selected_item=c->selected_item_history[c->dirlevel];
gui_synclist_select_item(&tree_lists, c->selected_item);
c->currtable = c->table_history[c->dirlevel];

View file

@ -532,10 +532,12 @@ static bool check_changed_id3mode(bool currmode)
currmode = global_settings.dirfilter == SHOW_ID3DB;
if (currmode) {
curr_context=CONTEXT_ID3DB;
tc.dirlevel = 0;
tagtree_load(&tc);
}
else
{
tc.dirlevel = 0;
curr_context=CONTEXT_TREE;
ft_load(&tc, NULL);
reload_dir = true;