diff options
author | William Wilgus <wilgus.william@gmail.com> | 2024-09-23 03:23:36 -0400 |
---|---|---|
committer | William Wilgus <wilgus.william@gmail.com> | 2024-11-02 17:27:22 -0400 |
commit | 06986d27f06528c8eb9f672a8f4913d3e3e7a307 (patch) | |
tree | eba4e37fbc0685621702b7ab04ad69f6616253b0 | |
parent | 67ad6589fbcd65281364dba51aabefdc55990b2d (diff) | |
download | rockbox-06986d27f06528c8eb9f672a8f4913d3e3e7a307.tar.gz rockbox-06986d27f06528c8eb9f672a8f4913d3e3e7a307.zip |
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
-rw-r--r-- | apps/onplay.h | 1 | ||||
-rw-r--r-- | apps/tagnavi.config | 93 | ||||
-rw-r--r-- | apps/tagtree.c | 94 | ||||
-rw-r--r-- | 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 @@ | |||
28 | enum { | 28 | enum { |
29 | ONPLAY_NO_CUSTOMACTION, | 29 | ONPLAY_NO_CUSTOMACTION, |
30 | ONPLAY_CUSTOMACTION_SHUFFLE_SONGS, | 30 | ONPLAY_CUSTOMACTION_SHUFFLE_SONGS, |
31 | ONPLAY_CUSTOMACTION_FIRSTLETTER, | ||
31 | }; | 32 | }; |
32 | 33 | ||
33 | int onplay(char* file, int attr, int from_context, bool hotkey, int customaction); | 34 | 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 @@ | |||
30 | # | 30 | # |
31 | 31 | ||
32 | # Define the A to Z Artist sub menu | 32 | # Define the A to Z Artist sub menu |
33 | %menu_start "custom_artist" "Artist A to Z" | 33 | %byfirstletter "custom_artist" "Artist A to Z" "canonicalartist" |
34 | "Numeric" -> canonicalartist ? canonicalartist < "A" -> album -> title = "fmt_title" | ||
35 | "A" -> canonicalartist ? canonicalartist ^ "A" -> album -> title = "fmt_title" | ||
36 | "B" -> canonicalartist ? canonicalartist ^ "B" -> album -> title = "fmt_title" | ||
37 | "C" -> canonicalartist ? canonicalartist ^ "C" -> album -> title = "fmt_title" | ||
38 | "D" -> canonicalartist ? canonicalartist ^ "D" -> album -> title = "fmt_title" | ||
39 | "E" -> canonicalartist ? canonicalartist ^ "E" -> album -> title = "fmt_title" | ||
40 | "F" -> canonicalartist ? canonicalartist ^ "F" -> album -> title = "fmt_title" | ||
41 | "G" -> canonicalartist ? canonicalartist ^ "G" -> album -> title = "fmt_title" | ||
42 | "H" -> canonicalartist ? canonicalartist ^ "H" -> album -> title = "fmt_title" | ||
43 | "I" -> canonicalartist ? canonicalartist ^ "I" -> album -> title = "fmt_title" | ||
44 | "J" -> canonicalartist ? canonicalartist ^ "J" -> album -> title = "fmt_title" | ||
45 | "K" -> canonicalartist ? canonicalartist ^ "K" -> album -> title = "fmt_title" | ||
46 | "L" -> canonicalartist ? canonicalartist ^ "L" -> album -> title = "fmt_title" | ||
47 | "M" -> canonicalartist ? canonicalartist ^ "M" -> album -> title = "fmt_title" | ||
48 | "N" -> canonicalartist ? canonicalartist ^ "N" -> album -> title = "fmt_title" | ||
49 | "O" -> canonicalartist ? canonicalartist ^ "O" -> album -> title = "fmt_title" | ||
50 | "P" -> canonicalartist ? canonicalartist ^ "P" -> album -> title = "fmt_title" | ||
51 | "Q" -> canonicalartist ? canonicalartist ^ "Q" -> album -> title = "fmt_title" | ||
52 | "R" -> canonicalartist ? canonicalartist ^ "R" -> album -> title = "fmt_title" | ||
53 | "S" -> canonicalartist ? canonicalartist ^ "S" -> album -> title = "fmt_title" | ||
54 | "T" -> canonicalartist ? canonicalartist ^ "T" -> album -> title = "fmt_title" | ||
55 | "U" -> canonicalartist ? canonicalartist ^ "U" -> album -> title = "fmt_title" | ||
56 | "V" -> canonicalartist ? canonicalartist ^ "V" -> album -> title = "fmt_title" | ||
57 | "W" -> canonicalartist ? canonicalartist ^ "W" -> album -> title = "fmt_title" | ||
58 | "X" -> canonicalartist ? canonicalartist ^ "X" -> album -> title = "fmt_title" | ||
59 | "Y" -> canonicalartist ? canonicalartist ^ "Y" -> album -> title = "fmt_title" | ||
60 | "Z" -> canonicalartist ? canonicalartist ^ "Z" -> album -> title = "fmt_title" | ||
61 | |||
62 | # ^ An empy line ends the menu | ||
63 | |||
64 | # Define the A to Z album sub menu | 34 | # Define the A to Z album sub menu |
65 | %menu_start "custom_album" "Album A to Z" | 35 | %byfirstletter "custom_album" "Album A to Z" "album" |
66 | "Numeric" -> album ? album < "A" -> title = "fmt_title" | ||
67 | "A" -> album ? album ^ "A" -> title = "fmt_title" | ||
68 | "B" -> album ? album ^ "B" -> title = "fmt_title" | ||
69 | "C" -> album ? album ^ "C" -> title = "fmt_title" | ||
70 | "D" -> album ? album ^ "D" -> title = "fmt_title" | ||
71 | "E" -> album ? album ^ "E" -> title = "fmt_title" | ||
72 | "F" -> album ? album ^ "F" -> title = "fmt_title" | ||
73 | "G" -> album ? album ^ "G" -> title = "fmt_title" | ||
74 | "H" -> album ? album ^ "H" -> title = "fmt_title" | ||
75 | "I" -> album ? album ^ "I" -> title = "fmt_title" | ||
76 | "J" -> album ? album ^ "J" -> title = "fmt_title" | ||
77 | "K" -> album ? album ^ "K" -> title = "fmt_title" | ||
78 | "L" -> album ? album ^ "L" -> title = "fmt_title" | ||
79 | "M" -> album ? album ^ "M" -> title = "fmt_title" | ||
80 | "N" -> album ? album ^ "N" -> title = "fmt_title" | ||
81 | "O" -> album ? album ^ "O" -> title = "fmt_title" | ||
82 | "P" -> album ? album ^ "P" -> title = "fmt_title" | ||
83 | "Q" -> album ? album ^ "Q" -> title = "fmt_title" | ||
84 | "R" -> album ? album ^ "R" -> title = "fmt_title" | ||
85 | "S" -> album ? album ^ "S" -> title = "fmt_title" | ||
86 | "T" -> album ? album ^ "T" -> title = "fmt_title" | ||
87 | "U" -> album ? album ^ "U" -> title = "fmt_title" | ||
88 | "V" -> album ? album ^ "V" -> title = "fmt_title" | ||
89 | "W" -> album ? album ^ "W" -> title = "fmt_title" | ||
90 | "X" -> album ? album ^ "X" -> title = "fmt_title" | ||
91 | "Y" -> album ? album ^ "Y" -> title = "fmt_title" | ||
92 | "Z" -> album ? album ^ "Z" -> title = "fmt_title" | ||
93 | |||
94 | # Define the A to Z track sub menu | 36 | # Define the A to Z track sub menu |
95 | %menu_start "custom_track" "Track A to Z" | 37 | %byfirstletter "custom_track" "Track A to Z" "title" |
96 | "Numeric" -> title ? title < "A" -> title = "fmt_title" | 38 | |
97 | "A" -> title ? title ^ "A" -> title = "fmt_title" | 39 | # ^ An empy line ends the menu |
98 | "B" -> title ? title ^ "B" -> title = "fmt_title" | ||
99 | "C" -> title ? title ^ "C" -> title = "fmt_title" | ||
100 | "D" -> title ? title ^ "D" -> title = "fmt_title" | ||
101 | "E" -> title ? title ^ "E" -> title = "fmt_title" | ||
102 | "F" -> title ? title ^ "F" -> title = "fmt_title" | ||
103 | "G" -> title ? title ^ "G" -> title = "fmt_title" | ||
104 | "H" -> title ? title ^ "H" -> title = "fmt_title" | ||
105 | "I" -> title ? title ^ "I" -> title = "fmt_title" | ||
106 | "J" -> title ? title ^ "J" -> title = "fmt_title" | ||
107 | "K" -> title ? title ^ "K" -> title = "fmt_title" | ||
108 | "L" -> title ? title ^ "L" -> title = "fmt_title" | ||
109 | "M" -> title ? title ^ "M" -> title = "fmt_title" | ||
110 | "N" -> title ? title ^ "N" -> title = "fmt_title" | ||
111 | "O" -> title ? title ^ "O" -> title = "fmt_title" | ||
112 | "P" -> title ? title ^ "P" -> title = "fmt_title" | ||
113 | "Q" -> title ? title ^ "Q" -> title = "fmt_title" | ||
114 | "R" -> title ? title ^ "R" -> title = "fmt_title" | ||
115 | "S" -> title ? title ^ "S" -> title = "fmt_title" | ||
116 | "T" -> title ? title ^ "T" -> title = "fmt_title" | ||
117 | "U" -> title ? title ^ "U" -> title = "fmt_title" | ||
118 | "V" -> title ? title ^ "V" -> title = "fmt_title" | ||
119 | "W" -> title ? title ^ "W" -> title = "fmt_title" | ||
120 | "X" -> title ? title ^ "X" -> title = "fmt_title" | ||
121 | "Y" -> title ? title ^ "Y" -> title = "fmt_title" | ||
122 | "Z" -> title ? title ^ "Z" -> title = "fmt_title" | ||
123 | 40 | ||
124 | # Define the A to Z sub menu | 41 | # Define the A to Z sub menu |
125 | %menu_start "a2z" "A to Z..." | 42 | %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 { | |||
112 | var_include, | 112 | var_include, |
113 | var_rootmenu, | 113 | var_rootmenu, |
114 | var_format, | 114 | var_format, |
115 | menu_byfirstletter, | ||
115 | menu_next, | 116 | menu_next, |
116 | menu_load, | 117 | menu_load, |
117 | menu_reload, | 118 | menu_reload, |
@@ -173,11 +174,12 @@ struct display_format { | |||
173 | static struct display_format *formats[TAGMENU_MAX_FMTS]; | 174 | static struct display_format *formats[TAGMENU_MAX_FMTS]; |
174 | static int format_count; | 175 | static int format_count; |
175 | 176 | ||
177 | #define MENUENTRY_MAX_NAME 64 | ||
176 | struct menu_entry { | 178 | struct menu_entry { |
177 | char name[64]; | 179 | char name[MENUENTRY_MAX_NAME]; |
178 | int type; | 180 | int type; |
179 | struct search_instruction { | 181 | struct search_instruction { |
180 | char name[64]; | 182 | char name[MENUENTRY_MAX_NAME]; |
181 | int tagorder[MAX_TAGS]; | 183 | int tagorder[MAX_TAGS]; |
182 | int tagorder_count; | 184 | int tagorder_count; |
183 | struct tagcache_search_clause *clause[MAX_TAGS][TAGCACHE_MAX_CLAUSES]; | 185 | struct tagcache_search_clause *clause[MAX_TAGS][TAGCACHE_MAX_CLAUSES]; |
@@ -381,6 +383,7 @@ static int get_tag(int *tag) | |||
381 | TAG_MATCH("comment", tag_comment), | 383 | TAG_MATCH("comment", tag_comment), |
382 | TAG_MATCH("discnum", tag_discnumber), | 384 | TAG_MATCH("discnum", tag_discnumber), |
383 | TAG_MATCH("%format", var_format), | 385 | TAG_MATCH("%format", var_format), |
386 | TAG_MATCH("%byfirstletter", menu_byfirstletter), | ||
384 | TAG_MATCH("%reload", menu_reload), | 387 | TAG_MATCH("%reload", menu_reload), |
385 | 388 | ||
386 | TAG_MATCH("filename", tag_filename), | 389 | TAG_MATCH("filename", tag_filename), |
@@ -1058,6 +1061,63 @@ int tagtree_import(void) | |||
1058 | 1061 | ||
1059 | static bool parse_menu(const char *filename); | 1062 | static bool parse_menu(const char *filename); |
1060 | 1063 | ||
1064 | static bool alloc_menu_item(void) | ||
1065 | { | ||
1066 | /* Allocate */ | ||
1067 | if (menu->items[menu->itemcount] == NULL) | ||
1068 | menu->items[menu->itemcount] = tagtree_alloc0(sizeof(struct menu_entry)); | ||
1069 | if (!menu->items[menu->itemcount]) | ||
1070 | { | ||
1071 | logf("tagtree failed to allocate %s", "menu items"); | ||
1072 | return false; | ||
1073 | } | ||
1074 | return true; | ||
1075 | } | ||
1076 | |||
1077 | static void firstletter_parse_buf(char *buf) | ||
1078 | { | ||
1079 | core_pin(tagtree_handle); | ||
1080 | if (parse_search(menu->items[menu->itemcount], buf)) | ||
1081 | { | ||
1082 | menu->items[menu->itemcount]->type = menu_byfirstletter; | ||
1083 | menu->itemcount++; | ||
1084 | } | ||
1085 | core_unpin(tagtree_handle);; | ||
1086 | } | ||
1087 | |||
1088 | static void build_firstletter_menu(char *buf, size_t bufsz) | ||
1089 | { | ||
1090 | const char *subitem = buf; | ||
1091 | size_t l = strlen(buf) + 1; | ||
1092 | buf+=l; | ||
1093 | bufsz-=l; | ||
1094 | |||
1095 | const char *showalbum = ""; | ||
1096 | const char * const fmt ="\"%s\" -> %s ? %s %c \"%c\" -> %s title = \"fmt_title\""; | ||
1097 | if (!alloc_menu_item()) | ||
1098 | return; | ||
1099 | |||
1100 | if (strcasestr(subitem, "artist") != NULL) | ||
1101 | showalbum = "album ->"; /* album subitem for canonicalartist */ | ||
1102 | |||
1103 | /* Numeric ex: "Numeric" -> album ? album < "A" -> title = "fmt_title" */ | ||
1104 | snprintf(buf, bufsz, fmt, | ||
1105 | str(LANG_DISPLAY_NUMERIC), subitem, subitem,'<', 'A', showalbum); | ||
1106 | |||
1107 | firstletter_parse_buf(buf); | ||
1108 | |||
1109 | for (int i = 0; i < 26; i++) | ||
1110 | { | ||
1111 | if (!alloc_menu_item()) | ||
1112 | return; | ||
1113 | |||
1114 | snprintf(buf, bufsz, fmt, "#", subitem, subitem,'^', 'A' + i, showalbum); | ||
1115 | buf[1] = 'A' + i; /* overwrite the placeholder # with the current letter */ | ||
1116 | /* ex: "A" -> title ? title ^ "A" -> title = "fmt_title" */ | ||
1117 | firstletter_parse_buf(buf); | ||
1118 | } | ||
1119 | } | ||
1120 | |||
1061 | static int parse_line(int n, char *buf, void *parameters) | 1121 | static int parse_line(int n, char *buf, void *parameters) |
1062 | { | 1122 | { |
1063 | char data[256]; | 1123 | char data[256]; |
@@ -1127,7 +1187,7 @@ static int parse_line(int n, char *buf, void *parameters) | |||
1127 | logf("Load menu fail: %s", data); | 1187 | logf("Load menu fail: %s", data); |
1128 | } | 1188 | } |
1129 | break; | 1189 | break; |
1130 | 1190 | case menu_byfirstletter: /* Fallthrough */ | |
1131 | case var_menu_start: | 1191 | case var_menu_start: |
1132 | if (menu_count >= TAGMENU_MAX_MENUS) | 1192 | if (menu_count >= TAGMENU_MAX_MENUS) |
1133 | { | 1193 | { |
@@ -1169,6 +1229,19 @@ static int parse_line(int n, char *buf, void *parameters) | |||
1169 | return 0; | 1229 | return 0; |
1170 | } | 1230 | } |
1171 | logf("menu: %s", menu->title); | 1231 | logf("menu: %s", menu->title); |
1232 | |||
1233 | if (variable == menu_byfirstletter) | ||
1234 | { | ||
1235 | if (get_token_str(data, sizeof(data)) < 0) | ||
1236 | { | ||
1237 | logf("%%firstletter_menu has no subitem"); /*artist,album*/ | ||
1238 | return 0; | ||
1239 | } | ||
1240 | logf("A-Z Menu subitem: %s", data); | ||
1241 | read_menu = false; | ||
1242 | build_firstletter_menu(data, sizeof(data)); | ||
1243 | break; | ||
1244 | } | ||
1172 | read_menu = true; | 1245 | read_menu = true; |
1173 | break; | 1246 | break; |
1174 | 1247 | ||
@@ -1202,14 +1275,8 @@ static int parse_line(int n, char *buf, void *parameters) | |||
1202 | return 0; | 1275 | return 0; |
1203 | } | 1276 | } |
1204 | 1277 | ||
1205 | /* Allocate */ | 1278 | if (!alloc_menu_item()) |
1206 | if (menu->items[menu->itemcount] == NULL) | ||
1207 | menu->items[menu->itemcount] = tagtree_alloc0(sizeof(struct menu_entry)); | ||
1208 | if (!menu->items[menu->itemcount]) | ||
1209 | { | ||
1210 | logf("tagtree failed to allocate %s", "menu items"); | ||
1211 | return -2; | 1279 | return -2; |
1212 | } | ||
1213 | core_pin(tagtree_handle); | 1280 | core_pin(tagtree_handle); |
1214 | if (parse_search(menu->items[menu->itemcount], buf)) | 1281 | if (parse_search(menu->items[menu->itemcount], buf)) |
1215 | menu->itemcount++; | 1282 | menu->itemcount++; |
@@ -1449,6 +1516,7 @@ static void tcs_get_basename(struct tagcache_search *tcs, bool is_basename) | |||
1449 | 1516 | ||
1450 | static int retrieve_entries(struct tree_context *c, int offset, bool init) | 1517 | static int retrieve_entries(struct tree_context *c, int offset, bool init) |
1451 | { | 1518 | { |
1519 | logf( "%s", __func__); | ||
1452 | char tcs_buf[TAGCACHE_BUFSZ]; | 1520 | char tcs_buf[TAGCACHE_BUFSZ]; |
1453 | const long tcs_bufsz = sizeof(tcs_buf); | 1521 | const long tcs_bufsz = sizeof(tcs_buf); |
1454 | struct tagcache_search tcs; | 1522 | struct tagcache_search tcs; |
@@ -1818,6 +1886,12 @@ static int load_root(struct tree_context *c) | |||
1818 | dptr->extraseek = i; | 1886 | dptr->extraseek = i; |
1819 | dptr->customaction = ONPLAY_CUSTOMACTION_SHUFFLE_SONGS; | 1887 | dptr->customaction = ONPLAY_CUSTOMACTION_SHUFFLE_SONGS; |
1820 | break; | 1888 | break; |
1889 | |||
1890 | case menu_byfirstletter: | ||
1891 | dptr->newtable = TABLE_NAVIBROWSE; | ||
1892 | dptr->extraseek = i; | ||
1893 | dptr->customaction = ONPLAY_CUSTOMACTION_FIRSTLETTER; | ||
1894 | break; | ||
1821 | } | 1895 | } |
1822 | 1896 | ||
1823 | dptr++; | 1897 | 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) | |||
205 | struct tree_context * local_tc=(struct tree_context *)data; | 205 | struct tree_context * local_tc=(struct tree_context *)data; |
206 | char *name; | 206 | char *name; |
207 | int attr=0; | 207 | int attr=0; |
208 | int customaction = ONPLAY_NO_CUSTOMACTION; | ||
208 | #ifdef HAVE_TAGCACHE | 209 | #ifdef HAVE_TAGCACHE |
209 | bool id3db = *(local_tc->dirfilter) == SHOW_ID3DB; | 210 | bool id3db = *(local_tc->dirfilter) == SHOW_ID3DB; |
210 | char buf[AVERAGE_FILENAME_LENGTH*2]; | 211 | char buf[AVERAGE_FILENAME_LENGTH*2]; |
@@ -213,6 +214,7 @@ static int tree_voice_cb(int selected_item, void * data) | |||
213 | { | 214 | { |
214 | attr = tagtree_get_attr(local_tc); | 215 | attr = tagtree_get_attr(local_tc); |
215 | name = tagtree_get_entry_name(local_tc, selected_item, buf, sizeof(buf)); | 216 | name = tagtree_get_entry_name(local_tc, selected_item, buf, sizeof(buf)); |
217 | customaction = tagtree_get_custom_action(local_tc); | ||
216 | } | 218 | } |
217 | else | 219 | else |
218 | #endif | 220 | #endif |
@@ -245,7 +247,7 @@ static int tree_voice_cb(int selected_item, void * data) | |||
245 | did_clip = false; | 247 | did_clip = false; |
246 | } | 248 | } |
247 | } | 249 | } |
248 | bool spell_name = false; | 250 | bool spell_name = (customaction == ONPLAY_CUSTOMACTION_FIRSTLETTER); |
249 | if(!did_clip) | 251 | if(!did_clip) |
250 | { | 252 | { |
251 | /* say the number or spell if required or as a fallback */ | 253 | /* say the number or spell if required or as a fallback */ |