From 06986d27f06528c8eb9f672a8f4913d3e3e7a307 Mon Sep 17 00:00:00 2001 From: William Wilgus Date: Mon, 23 Sep 2024 03:23:36 -0400 Subject: Generate A-Z menus in the tagtree this adds a new command %byfirstletter %byfirstletter "custom_track" "Track A to Z" "title" ^ command ^menu name ^menu title ^subitem need a better name for subitem btw.. this patch also allows us to tell when we are in the BFL menu by checking customaction == ONPLAY_CUSTOMACTION_FIRSTLETTER we then enable spelling of the letters in the menu it spells Numeric too but that shouldn't matter with the upcoming voice patch Change-Id: I59815f697a4ef84a8cb540783b620d15f6670e00 --- apps/onplay.h | 1 + apps/tagnavi.config | 93 +++------------------------------------------------- apps/tagtree.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++------ apps/tree.c | 4 ++- 4 files changed, 93 insertions(+), 99 deletions(-) diff --git a/apps/onplay.h b/apps/onplay.h index 03861e9cf6..26b1247f7b 100644 --- a/apps/onplay.h +++ b/apps/onplay.h @@ -28,6 +28,7 @@ enum { ONPLAY_NO_CUSTOMACTION, ONPLAY_CUSTOMACTION_SHUFFLE_SONGS, + ONPLAY_CUSTOMACTION_FIRSTLETTER, }; int onplay(char* file, int attr, int from_context, bool hotkey, int customaction); diff --git a/apps/tagnavi.config b/apps/tagnavi.config index b599f9577c..6335610253 100644 --- a/apps/tagnavi.config +++ b/apps/tagnavi.config @@ -30,96 +30,13 @@ # # Define the A to Z Artist sub menu -%menu_start "custom_artist" "Artist A to Z" -"Numeric" -> canonicalartist ? canonicalartist < "A" -> album -> title = "fmt_title" -"A" -> canonicalartist ? canonicalartist ^ "A" -> album -> title = "fmt_title" -"B" -> canonicalartist ? canonicalartist ^ "B" -> album -> title = "fmt_title" -"C" -> canonicalartist ? canonicalartist ^ "C" -> album -> title = "fmt_title" -"D" -> canonicalartist ? canonicalartist ^ "D" -> album -> title = "fmt_title" -"E" -> canonicalartist ? canonicalartist ^ "E" -> album -> title = "fmt_title" -"F" -> canonicalartist ? canonicalartist ^ "F" -> album -> title = "fmt_title" -"G" -> canonicalartist ? canonicalartist ^ "G" -> album -> title = "fmt_title" -"H" -> canonicalartist ? canonicalartist ^ "H" -> album -> title = "fmt_title" -"I" -> canonicalartist ? canonicalartist ^ "I" -> album -> title = "fmt_title" -"J" -> canonicalartist ? canonicalartist ^ "J" -> album -> title = "fmt_title" -"K" -> canonicalartist ? canonicalartist ^ "K" -> album -> title = "fmt_title" -"L" -> canonicalartist ? canonicalartist ^ "L" -> album -> title = "fmt_title" -"M" -> canonicalartist ? canonicalartist ^ "M" -> album -> title = "fmt_title" -"N" -> canonicalartist ? canonicalartist ^ "N" -> album -> title = "fmt_title" -"O" -> canonicalartist ? canonicalartist ^ "O" -> album -> title = "fmt_title" -"P" -> canonicalartist ? canonicalartist ^ "P" -> album -> title = "fmt_title" -"Q" -> canonicalartist ? canonicalartist ^ "Q" -> album -> title = "fmt_title" -"R" -> canonicalartist ? canonicalartist ^ "R" -> album -> title = "fmt_title" -"S" -> canonicalartist ? canonicalartist ^ "S" -> album -> title = "fmt_title" -"T" -> canonicalartist ? canonicalartist ^ "T" -> album -> title = "fmt_title" -"U" -> canonicalartist ? canonicalartist ^ "U" -> album -> title = "fmt_title" -"V" -> canonicalartist ? canonicalartist ^ "V" -> album -> title = "fmt_title" -"W" -> canonicalartist ? canonicalartist ^ "W" -> album -> title = "fmt_title" -"X" -> canonicalartist ? canonicalartist ^ "X" -> album -> title = "fmt_title" -"Y" -> canonicalartist ? canonicalartist ^ "Y" -> album -> title = "fmt_title" -"Z" -> canonicalartist ? canonicalartist ^ "Z" -> album -> title = "fmt_title" - -# ^ An empy line ends the menu - +%byfirstletter "custom_artist" "Artist A to Z" "canonicalartist" # Define the A to Z album sub menu -%menu_start "custom_album" "Album A to Z" -"Numeric" -> album ? album < "A" -> title = "fmt_title" -"A" -> album ? album ^ "A" -> title = "fmt_title" -"B" -> album ? album ^ "B" -> title = "fmt_title" -"C" -> album ? album ^ "C" -> title = "fmt_title" -"D" -> album ? album ^ "D" -> title = "fmt_title" -"E" -> album ? album ^ "E" -> title = "fmt_title" -"F" -> album ? album ^ "F" -> title = "fmt_title" -"G" -> album ? album ^ "G" -> title = "fmt_title" -"H" -> album ? album ^ "H" -> title = "fmt_title" -"I" -> album ? album ^ "I" -> title = "fmt_title" -"J" -> album ? album ^ "J" -> title = "fmt_title" -"K" -> album ? album ^ "K" -> title = "fmt_title" -"L" -> album ? album ^ "L" -> title = "fmt_title" -"M" -> album ? album ^ "M" -> title = "fmt_title" -"N" -> album ? album ^ "N" -> title = "fmt_title" -"O" -> album ? album ^ "O" -> title = "fmt_title" -"P" -> album ? album ^ "P" -> title = "fmt_title" -"Q" -> album ? album ^ "Q" -> title = "fmt_title" -"R" -> album ? album ^ "R" -> title = "fmt_title" -"S" -> album ? album ^ "S" -> title = "fmt_title" -"T" -> album ? album ^ "T" -> title = "fmt_title" -"U" -> album ? album ^ "U" -> title = "fmt_title" -"V" -> album ? album ^ "V" -> title = "fmt_title" -"W" -> album ? album ^ "W" -> title = "fmt_title" -"X" -> album ? album ^ "X" -> title = "fmt_title" -"Y" -> album ? album ^ "Y" -> title = "fmt_title" -"Z" -> album ? album ^ "Z" -> title = "fmt_title" - +%byfirstletter "custom_album" "Album A to Z" "album" # Define the A to Z track sub menu -%menu_start "custom_track" "Track A to Z" -"Numeric" -> title ? title < "A" -> title = "fmt_title" -"A" -> title ? title ^ "A" -> title = "fmt_title" -"B" -> title ? title ^ "B" -> title = "fmt_title" -"C" -> title ? title ^ "C" -> title = "fmt_title" -"D" -> title ? title ^ "D" -> title = "fmt_title" -"E" -> title ? title ^ "E" -> title = "fmt_title" -"F" -> title ? title ^ "F" -> title = "fmt_title" -"G" -> title ? title ^ "G" -> title = "fmt_title" -"H" -> title ? title ^ "H" -> title = "fmt_title" -"I" -> title ? title ^ "I" -> title = "fmt_title" -"J" -> title ? title ^ "J" -> title = "fmt_title" -"K" -> title ? title ^ "K" -> title = "fmt_title" -"L" -> title ? title ^ "L" -> title = "fmt_title" -"M" -> title ? title ^ "M" -> title = "fmt_title" -"N" -> title ? title ^ "N" -> title = "fmt_title" -"O" -> title ? title ^ "O" -> title = "fmt_title" -"P" -> title ? title ^ "P" -> title = "fmt_title" -"Q" -> title ? title ^ "Q" -> title = "fmt_title" -"R" -> title ? title ^ "R" -> title = "fmt_title" -"S" -> title ? title ^ "S" -> title = "fmt_title" -"T" -> title ? title ^ "T" -> title = "fmt_title" -"U" -> title ? title ^ "U" -> title = "fmt_title" -"V" -> title ? title ^ "V" -> title = "fmt_title" -"W" -> title ? title ^ "W" -> title = "fmt_title" -"X" -> title ? title ^ "X" -> title = "fmt_title" -"Y" -> title ? title ^ "Y" -> title = "fmt_title" -"Z" -> title ? title ^ "Z" -> title = "fmt_title" +%byfirstletter "custom_track" "Track A to Z" "title" + +# ^ An empy line ends the menu # Define the A to Z sub menu %menu_start "a2z" "A to Z..." diff --git a/apps/tagtree.c b/apps/tagtree.c index 83bfb4e36d..4983231663 100644 --- a/apps/tagtree.c +++ b/apps/tagtree.c @@ -112,6 +112,7 @@ enum variables { var_include, var_rootmenu, var_format, + menu_byfirstletter, menu_next, menu_load, menu_reload, @@ -173,11 +174,12 @@ struct display_format { static struct display_format *formats[TAGMENU_MAX_FMTS]; static int format_count; +#define MENUENTRY_MAX_NAME 64 struct menu_entry { - char name[64]; + char name[MENUENTRY_MAX_NAME]; int type; struct search_instruction { - char name[64]; + char name[MENUENTRY_MAX_NAME]; int tagorder[MAX_TAGS]; int tagorder_count; struct tagcache_search_clause *clause[MAX_TAGS][TAGCACHE_MAX_CLAUSES]; @@ -381,6 +383,7 @@ static int get_tag(int *tag) TAG_MATCH("comment", tag_comment), TAG_MATCH("discnum", tag_discnumber), TAG_MATCH("%format", var_format), + TAG_MATCH("%byfirstletter", menu_byfirstletter), TAG_MATCH("%reload", menu_reload), TAG_MATCH("filename", tag_filename), @@ -1058,6 +1061,63 @@ int tagtree_import(void) static bool parse_menu(const char *filename); +static bool alloc_menu_item(void) +{ + /* Allocate */ + if (menu->items[menu->itemcount] == NULL) + menu->items[menu->itemcount] = tagtree_alloc0(sizeof(struct menu_entry)); + if (!menu->items[menu->itemcount]) + { + logf("tagtree failed to allocate %s", "menu items"); + return false; + } + return true; +} + +static void firstletter_parse_buf(char *buf) +{ + core_pin(tagtree_handle); + if (parse_search(menu->items[menu->itemcount], buf)) + { + menu->items[menu->itemcount]->type = menu_byfirstletter; + menu->itemcount++; + } + core_unpin(tagtree_handle);; +} + +static void build_firstletter_menu(char *buf, size_t bufsz) +{ + const char *subitem = buf; + size_t l = strlen(buf) + 1; + buf+=l; + bufsz-=l; + + const char *showalbum = ""; + const char * const fmt ="\"%s\" -> %s ? %s %c \"%c\" -> %s title = \"fmt_title\""; + if (!alloc_menu_item()) + return; + + if (strcasestr(subitem, "artist") != NULL) + showalbum = "album ->"; /* album subitem for canonicalartist */ + + /* Numeric ex: "Numeric" -> album ? album < "A" -> title = "fmt_title" */ + snprintf(buf, bufsz, fmt, + str(LANG_DISPLAY_NUMERIC), subitem, subitem,'<', 'A', showalbum); + + firstletter_parse_buf(buf); + + for (int i = 0; i < 26; i++) + { + if (!alloc_menu_item()) + return; + + snprintf(buf, bufsz, fmt, "#", subitem, subitem,'^', 'A' + i, showalbum); + buf[1] = 'A' + i; /* overwrite the placeholder # with the current letter */ + /* ex: "A" -> title ? title ^ "A" -> title = "fmt_title" */ + firstletter_parse_buf(buf); + } +} + static int parse_line(int n, char *buf, void *parameters) { char data[256]; @@ -1127,7 +1187,7 @@ static int parse_line(int n, char *buf, void *parameters) logf("Load menu fail: %s", data); } break; - + case menu_byfirstletter: /* Fallthrough */ case var_menu_start: if (menu_count >= TAGMENU_MAX_MENUS) { @@ -1169,6 +1229,19 @@ static int parse_line(int n, char *buf, void *parameters) return 0; } logf("menu: %s", menu->title); + + if (variable == menu_byfirstletter) + { + if (get_token_str(data, sizeof(data)) < 0) + { + logf("%%firstletter_menu has no subitem"); /*artist,album*/ + return 0; + } + logf("A-Z Menu subitem: %s", data); + read_menu = false; + build_firstletter_menu(data, sizeof(data)); + break; + } read_menu = true; break; @@ -1202,14 +1275,8 @@ static int parse_line(int n, char *buf, void *parameters) return 0; } - /* Allocate */ - if (menu->items[menu->itemcount] == NULL) - menu->items[menu->itemcount] = tagtree_alloc0(sizeof(struct menu_entry)); - if (!menu->items[menu->itemcount]) - { - logf("tagtree failed to allocate %s", "menu items"); + if (!alloc_menu_item()) return -2; - } core_pin(tagtree_handle); if (parse_search(menu->items[menu->itemcount], buf)) menu->itemcount++; @@ -1449,6 +1516,7 @@ static void tcs_get_basename(struct tagcache_search *tcs, bool is_basename) static int retrieve_entries(struct tree_context *c, int offset, bool init) { + logf( "%s", __func__); char tcs_buf[TAGCACHE_BUFSZ]; const long tcs_bufsz = sizeof(tcs_buf); struct tagcache_search tcs; @@ -1818,6 +1886,12 @@ static int load_root(struct tree_context *c) dptr->extraseek = i; dptr->customaction = ONPLAY_CUSTOMACTION_SHUFFLE_SONGS; break; + + case menu_byfirstletter: + dptr->newtable = TABLE_NAVIBROWSE; + dptr->extraseek = i; + dptr->customaction = ONPLAY_CUSTOMACTION_FIRSTLETTER; + break; } dptr++; diff --git a/apps/tree.c b/apps/tree.c index ac82b6c2df..c422100de8 100644 --- a/apps/tree.c +++ b/apps/tree.c @@ -205,6 +205,7 @@ static int tree_voice_cb(int selected_item, void * data) struct tree_context * local_tc=(struct tree_context *)data; char *name; int attr=0; + int customaction = ONPLAY_NO_CUSTOMACTION; #ifdef HAVE_TAGCACHE bool id3db = *(local_tc->dirfilter) == SHOW_ID3DB; char buf[AVERAGE_FILENAME_LENGTH*2]; @@ -213,6 +214,7 @@ static int tree_voice_cb(int selected_item, void * data) { attr = tagtree_get_attr(local_tc); name = tagtree_get_entry_name(local_tc, selected_item, buf, sizeof(buf)); + customaction = tagtree_get_custom_action(local_tc); } else #endif @@ -245,7 +247,7 @@ static int tree_voice_cb(int selected_item, void * data) did_clip = false; } } - bool spell_name = false; + bool spell_name = (customaction == ONPLAY_CUSTOMACTION_FIRSTLETTER); if(!did_clip) { /* say the number or spell if required or as a fallback */ -- cgit v1.2.3