A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2014 Jonathan Gordon
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
15 *
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
18 *
19 ****************************************************************************/
20
21/* mandatory include for all plugins */
22#include "plugin.h"
23
24static struct menu_table *menu_table;
25static int menu_item_count;
26
27#define MAX_ITEM_NAME 64
28#define MAX_ITEMS 16
29struct items
30{
31 unsigned char *name;
32 char string[MAX_ITEM_NAME];
33 bool enabled;
34};
35
36static struct items menu_items[MAX_ITEMS];
37
38
39static const char * menu_get_name(int selected_item, void * data,
40 char * buffer, size_t buffer_len)
41{
42 (void)data;
43 unsigned char *p = menu_items[selected_item].name;
44 int id = P2ID(p);
45
46 rb->snprintf(buffer, buffer_len, "%s: %s", (id != -1) ? rb->str(id) : p,
47 menu_items[selected_item].enabled ?
48 rb->str(LANG_ON) : rb->str(LANG_OFF));
49
50 return buffer;
51}
52
53static enum themable_icons menu_get_icon(int selected_item, void * data)
54{
55 (void)data;
56
57 return menu_items[selected_item].enabled ? Icon_Config : Icon_NOICON;
58}
59
60static unsigned char *item_name(int n)
61{
62 const struct menu_item_ex *item = menu_table[n].item;
63 return (item->flags & MENU_HAS_DESC) ?
64 item->callback_and_desc->desc :
65 (rb->strcmp("wps", menu_table[n].string) ?
66 (unsigned char *)menu_table[n].string :
67 ID2P(LANG_RESUME_PLAYBACK));
68}
69
70void load_from_cfg(void)
71{
72 char config_str[128];
73 char *token, *save;
74 int done = 0;
75 int i = 0;
76 bool found = false;
77
78 config_str[0] = '\0';
79 rb->root_menu_write_to_cfg(NULL, config_str, sizeof(config_str));
80
81 token = rb->strtok_r(config_str, ", ", &save);
82
83 while (token)
84 {
85 for (i = 0, found = false; i < menu_item_count; i++)
86 {
87 found = rb->strcmp(token, menu_table[i].string) == 0;
88 if (found) break;
89 }
90 if (found)
91 {
92 menu_items[done].name = item_name(i);
93 rb->strcpy(menu_items[done].string, token);
94 menu_items[done].enabled = true;
95 done++;
96 }
97 token = rb->strtok_r(NULL, ", ", &save);
98 }
99
100 if (done < menu_item_count)
101 {
102 for (i = 0; i < menu_item_count; i++)
103 {
104 found = false;
105 for (int j = 0; !found && j < done; j++)
106 {
107 found = rb->strcmp(menu_table[i].string, menu_items[j].string) == 0;
108 }
109
110 if (!found)
111 {
112 menu_items[done].name = item_name(i);
113 rb->strcpy(menu_items[done].string, menu_table[i].string);
114 menu_items[done].enabled = false;
115 done++;
116 }
117 }
118 }
119}
120
121static void save_to_cfg(void)
122{
123 char out[128];
124 int i, j = 0;
125
126 out[0] = '\0';
127 for (i = 0; i < menu_item_count; i++)
128 {
129 if (menu_items[i].enabled)
130 {
131 j += rb->snprintf(&out[j],sizeof(out) - j, "%s, ", menu_items[i].string);
132 }
133 }
134
135 rb->root_menu_load_from_cfg(&rb->global_settings->root_menu_customized, out);
136}
137
138static void swap_items(int a, int b)
139{
140 unsigned char *name;
141 char temp[MAX_ITEM_NAME];
142 bool enabled;
143
144 name = menu_items[a].name;
145 rb->strcpy(temp, menu_items[a].string);
146 enabled = menu_items[a].enabled;
147 menu_items[a].name = menu_items[b].name;
148 rb->strcpy(menu_items[a].string,
149 menu_items[b].string);
150 menu_items[a].enabled = menu_items[b].enabled;
151 menu_items[b].name = name;
152 rb->strcpy(menu_items[b].string, temp);
153 menu_items[b].enabled = enabled;
154}
155
156static int menu_speak_item(int selected_item, void *data)
157{
158 (void) data;
159 int id = P2ID(menu_items[selected_item].name);
160
161 if (id != -1)
162 {
163 rb->talk_number(selected_item + 1, false);
164 rb->talk_id(id, true);
165 rb->talk_id(menu_items[selected_item].enabled ? LANG_ON : LANG_OFF, true);
166 }
167
168 return 0;
169}
170
171/* this is the plugin entry point */
172enum plugin_status plugin_start(const void* parameter)
173{
174 (void)parameter;
175 bool show_icons = rb->global_settings->show_icons;
176 rb->global_settings->show_icons = true;
177 struct gui_synclist list;
178 bool done = false;
179 bool changed = false;
180 int action, cur_sel;
181 int ret = PLUGIN_OK;
182
183 menu_table = rb->root_menu_get_options(&menu_item_count);
184 load_from_cfg();
185
186 rb->gui_synclist_init(&list, menu_get_name, NULL, false, 1, NULL);
187 if (rb->global_settings->talk_menu)
188 rb->gui_synclist_set_voice_callback(&list, menu_speak_item);
189 rb->gui_synclist_set_icon_callback(&list, menu_get_icon);
190 rb->gui_synclist_set_nb_items(&list, menu_item_count);
191 rb->gui_synclist_set_title(&list, rb->str(LANG_MAIN_MENU), Icon_Rockbox);
192 rb->gui_synclist_draw(&list);
193 rb->gui_synclist_speak_item(&list);
194
195 while (!done)
196 {
197 cur_sel = rb->gui_synclist_get_sel_pos(&list);
198 action = rb->get_action(CONTEXT_LIST, HZ/10);
199 if (rb->gui_synclist_do_button(&list, &action))
200 continue;
201
202 switch (action)
203 {
204 case ACTION_STD_OK:
205 menu_items[cur_sel].enabled = !menu_items[cur_sel].enabled;
206 rb->gui_synclist_speak_item(&list);
207 changed = true;
208 break;
209 case ACTION_STD_CONTEXT:
210 {
211 MENUITEM_STRINGLIST(menu, ID2P(LANG_MAIN_MENU), NULL,
212 ID2P(LANG_MOVE_ITEM_UP),
213 ID2P(LANG_MOVE_ITEM_DOWN),
214 ID2P(LANG_LOAD_DEFAULT_CONFIGURATION));
215 switch (rb->do_menu(&menu, NULL, NULL, false))
216 {
217 case 0:
218 if (cur_sel == 0)
219 {
220 rb->splash(HZ, ID2P(LANG_FAILED));
221 break;
222 }
223 swap_items(cur_sel, cur_sel - 1);
224 rb->gui_synclist_select_item(&list, cur_sel - 1); /* speaks */
225 changed = true;
226 break;
227 case 1:
228 if (cur_sel + 1 == menu_item_count)
229 {
230 rb->splash(HZ, ID2P(LANG_FAILED));
231 break;
232 }
233 swap_items(cur_sel, cur_sel + 1);
234 rb->gui_synclist_select_item(&list, cur_sel + 1); /* speaks */
235 changed = true;
236 break;
237 case 2:
238 if (rb->yesno_pop_confirm(ID2P(LANG_LOAD_DEFAULT_CONFIGURATION)))
239 {
240 rb->root_menu_set_default(&rb->global_settings->root_menu_customized, NULL);
241 load_from_cfg();
242 }
243 /* fall-through */
244 default:
245 rb->gui_synclist_speak_item(&list);
246 }
247 rb->gui_synclist_set_title(&list, rb->str(LANG_MAIN_MENU), Icon_Rockbox);
248 break;
249 }
250 case ACTION_STD_CANCEL:
251 case ACTION_STD_MENU:
252 done = true;
253 break;
254 default:
255 if (rb->default_event_handler(action) == SYS_USB_CONNECTED)
256 {
257 ret = PLUGIN_USB_CONNECTED;
258 done = true;
259 }
260 continue;
261 }
262
263 if (!done)
264 rb->gui_synclist_draw(&list);
265 }
266
267 if (changed)
268 {
269 save_to_cfg();
270 rb->global_settings->root_menu_customized = true;
271 rb->settings_save();
272 }
273 rb->global_settings->show_icons = show_icons;
274
275 return ret;
276}