summaryrefslogtreecommitdiff
path: root/apps/plugins/rb_info.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/rb_info.c')
-rw-r--r--apps/plugins/rb_info.c494
1 files changed, 494 insertions, 0 deletions
diff --git a/apps/plugins/rb_info.c b/apps/plugins/rb_info.c
new file mode 100644
index 0000000000..f82c80c0cf
--- /dev/null
+++ b/apps/plugins/rb_info.c
@@ -0,0 +1,494 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// __ \_/ ___\| |/ /| __ \ / __ \ \/ /
5 * Jukebox | | ( (__) ) \___| ( | \_\ ( (__) ) (
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2020 William Wilgus
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22/* WIP rb_info common info that you wonder about when rockboxing?
23 */
24
25#include "plugin.h"
26#include "lang_enum.h"
27#include "../open_plugin.h"
28#include "logf.h"
29#include "lib/action_helper.h"
30#include "lib/button_helper.h"
31#include "lib/pluginlib_actions.h"
32
33#define MENU_ID(x) (((void*)&"RPBUTACNGX\0" + x))
34enum {
35 M_ROOT = 0,
36 M_PATHS,
37 M_BUFFERS,
38 M_BUTTONS,
39 M_BTNTEST,
40 M_ACTIONS,
41 M_CONTEXTS,
42 M_ACTTEST,
43 M_PLUGINS,
44 M_EXIT,
45 M_LAST_ITEM //ITEM COUNT
46};
47
48#define MENU_ID_PLUGINS_ITEMS 5
49
50/*Action test and Button test*/
51static struct menu_test_t {
52 int count;
53 int context;
54 int last_btn_or_act;
55} m_test;
56
57struct menu_buffer_t { const char *name; size_t size;};
58static const struct menu_buffer_t m_buffer[] =
59{
60#ifndef MAX_LOGF_SIZE
61#define MAX_LOGF_SIZE (0)
62#endif
63#ifndef CACHE_SIZE
64#define CACHE_SIZE (0)
65#endif
66 {"thread stack", DEFAULT_STACK_SIZE},
67 {"plugin buffer", PLUGIN_BUFFER_SIZE},
68 {"frame_buffer", FRAMEBUFFER_SIZE},
69 {"codec_buffer", CODEC_SIZE},
70 {"logf_buffer", MAX_LOGF_SIZE},
71 {"cache", CACHE_SIZE},
72};
73
74/* stringify the macro value */
75#define MACROVAL(x) MACROSTR(x)
76#define MACROSTR(x) #x
77static int main_last_sel = 0;
78static struct gui_synclist lists;
79static void synclist_set(char*, int, int, int);
80
81struct paths { const char *name; const char *path; };
82static const struct paths paths[] = {
83 {"Home", ""HOME_DIR},
84 {"Rockbox", ""ROCKBOX_DIR},
85 {"Plugins", ""PLUGIN_DIR},
86 {"Codecs", ""CODECS_DIR},
87 {"WPS", ""WPS_DIR},
88 {"SBS", ""SBS_DIR},
89 {"Theme", ""THEME_DIR},
90 {"Font", ""FONT_DIR},
91 {"Icon", ""ICON_DIR},
92 {"Backdrop", ""BACKDROP_DIR},
93 {"Eq", ""EQS_DIR},
94 {"Rec Presets", ""RECPRESETS_DIR},
95 {"Recordings", ""REC_BASE_DIR,},
96 {"Fm Presets", ""FMPRESET_PATH},
97 {"MAX_PATH", ""MACROVAL(MAX_PATH)" bytes"},
98};
99
100struct mainmenu { const char *name; void *menuid; int items;};
101static struct mainmenu mainmenu[M_LAST_ITEM] = {
102#define MENU_ITEM(ID, NAME, COUNT) [ID]{NAME, MENU_ID(ID), (int)COUNT}
103MENU_ITEM(M_ROOT, "Rockbox Info Plugin", M_LAST_ITEM),
104MENU_ITEM(M_PATHS, ID2P(LANG_SHOW_PATH), ARRAYLEN(paths)),
105MENU_ITEM(M_BUFFERS, ID2P(LANG_BUFFER_STAT), ARRAYLEN(m_buffer)),
106MENU_ITEM(M_BUTTONS, "Buttons", -1), /* Set at runtime in plugin_start: */
107MENU_ITEM(M_BTNTEST, "Button test", 2),
108MENU_ITEM(M_ACTIONS, "Actions", LAST_ACTION_PLACEHOLDER),
109MENU_ITEM(M_CONTEXTS, "Contexts", LAST_CONTEXT_PLACEHOLDER ),
110MENU_ITEM(M_ACTTEST, "Action test", 3),
111MENU_ITEM(M_PLUGINS, ID2P(LANG_PLUGINS), MENU_ID_PLUGINS_ITEMS),
112MENU_ITEM(M_EXIT, ID2P(LANG_MENU_QUIT), 0),
113#undef MENU_ITEM
114};
115
116static const struct mainmenu *mainitem(int selected_item)
117{
118 static const struct mainmenu empty = {0};
119 if (selected_item >= 0 && selected_item < (int) ARRAYLEN(mainmenu))
120 return &mainmenu[selected_item];
121 else
122 return &empty;
123}
124
125static void cleanup(void *parameter)
126{
127 (void)parameter;
128
129}
130
131static const char *menu_plugin_name_cb(int selected_item, void* data,
132 char* buf, size_t buf_len)
133{
134 (void)data;
135 buf[0] = '\0';
136 switch(selected_item)
137 {
138 case 0:
139 rb->snprintf(buf, buf_len, "%s: [%d bytes] ", "plugin_api", (int)sizeof(struct plugin_api));
140 break;
141 case 1:
142 rb->snprintf(buf, buf_len, "%s: [%d bytes] ", "plugin buffer", PLUGIN_BUFFER_SIZE);
143 break;
144 case 2:
145 rb->snprintf(buf, buf_len, "%s: [%d bytes] ", "frame_buffer", (int)FRAMEBUFFER_SIZE);
146 break;
147 case 3:
148 rb->snprintf(buf, buf_len, "%s: [W: %d H:%d] ", "LCD", LCD_WIDTH, LCD_HEIGHT);
149 break;
150 case 4:
151 rb->snprintf(buf, buf_len, "%s: [%d bits] ", "fb_data", (int)(sizeof(fb_data) * CHAR_BIT));
152 break;
153 case 5:
154 break;
155 }
156 return buf;
157}
158
159static const char *menu_button_test_name_cb(int selected_item, void* data,
160 char* buf, size_t buf_len)
161{
162 (void)data;
163 int curbtn = BUTTON_NONE;
164 buf[0] = '\0';
165 switch(selected_item)
166 {
167 case 0:
168 rb->snprintf(buf, buf_len, "%s: [%s] ", "Button test",
169 m_test.count > 0 ? "true":"false");
170 break;
171 case 1:
172 if (m_test.count > 0)
173 {
174 if (m_test.count <= 2)
175 curbtn = rb->button_get_w_tmo(HZ * 2);
176 else
177 m_test.last_btn_or_act = BUTTON_NONE;
178 if (curbtn == BUTTON_NONE)
179 {
180 m_test.count--;
181 }
182 else
183 m_test.last_btn_or_act = curbtn;
184 }
185 get_button_names(buf, buf_len, m_test.last_btn_or_act);
186
187 break;
188 }
189 return buf;
190}
191
192static const char *menu_action_test_name_cb(int selected_item, void* data,
193 char* buf, size_t buf_len)
194{
195 (void)data;
196 const char *fmtstr;
197 int curact = ACTION_NONE;
198 buf[0] = '\0';
199 switch(selected_item)
200 {
201 case 0:
202 rb->snprintf(buf, buf_len, "%s: [%s] ", "Action test",
203 m_test.count > 0 ? "true":"false");
204 break;
205 case 1:
206 if (m_test.count <= 0)
207 {
208 if (m_test.context <= 0)
209 fmtstr = "%s > ";
210 else if (m_test.context >= LAST_CONTEXT_PLACEHOLDER - 1)
211 fmtstr = "< %s ";
212 else
213 fmtstr = "< %s > ";
214 }
215 else
216 fmtstr = "%s";
217
218 rb->snprintf(buf, buf_len, fmtstr, context_name(m_test.context));
219 break;
220 case 2:
221 if (m_test.count > 0)
222 {
223 if (m_test.count <= 2)
224 curact = rb->get_action(m_test.context, HZ * 2);
225 else
226 m_test.last_btn_or_act = ACTION_NONE;
227 if (curact == ACTION_NONE && rb->button_get(false) == BUTTON_NONE)
228 {
229 m_test.count--;
230 }
231 else
232 {
233 m_test.last_btn_or_act = curact;
234 m_test.count = 2;
235 }
236 }
237 return action_name(m_test.last_btn_or_act);
238
239 break;
240 }
241 return buf;
242}
243
244static const char* list_get_name_cb(int selected_item, void* data,
245 char* buf, size_t buf_len)
246{
247 buf[0] = '\0';
248 if (data == MENU_ID(M_ROOT))
249 return mainitem(selected_item)->name;
250 else if (selected_item == 0) /*header text*/
251 return mainitem(main_last_sel)->name;
252 else if (selected_item >= mainitem(main_last_sel)->items - 1)
253 return ID2P(LANG_BACK);
254
255 if (data == MENU_ID(M_PATHS))
256 {
257 selected_item--;
258 if (selected_item >= 0 && selected_item < mainitem(M_PATHS)->items)
259 {
260 const struct paths *cur = &paths[selected_item];
261 rb->snprintf(buf, buf_len, "%s: [%s] ", cur->name, cur->path);
262 return buf;
263 }
264 }
265 else if (data == MENU_ID(M_BUTTONS))
266 {
267 const struct available_button *btn = &available_buttons[selected_item - 1];
268 rb->snprintf(buf, buf_len, "%s: [0x%X] ", btn->name, (unsigned int) btn->value);
269 return buf;
270 }
271 else if (data == MENU_ID(M_BTNTEST))
272 return menu_button_test_name_cb(selected_item - 1, data, buf, buf_len);
273 else if (data == MENU_ID(M_ACTIONS))
274 return action_name(selected_item - 1);
275 else if (data == MENU_ID(M_CONTEXTS))
276 return context_name(selected_item - 1);
277 else if (data == MENU_ID(M_ACTTEST))
278 return menu_action_test_name_cb(selected_item - 1, data, buf, buf_len);
279 else if (data == MENU_ID(M_BUFFERS))
280 {
281 const struct menu_buffer_t *bufm = &m_buffer[selected_item - 1];
282 rb->snprintf(buf, buf_len, "%s: [%ld bytes] ", bufm->name, (long)bufm->size);
283 return buf;
284 }
285 else if (data == MENU_ID(M_PLUGINS))
286 {
287 return menu_plugin_name_cb(selected_item - 1, data, buf, buf_len);
288 }
289 return buf;
290}
291
292static int list_voice_cb(int list_index, void* data)
293{
294 if (!rb->global_settings->talk_menu)
295 return -1;
296
297 if (data == MENU_ID(M_ROOT))
298 {
299 const char * name = mainitem(list_index)->name;
300 long id = P2ID((const unsigned char *)name);
301 if(id>=0)
302 rb->talk_id(id, true);
303 else
304 rb->talk_spell(name, true);
305 }
306 else if (data == MENU_ID(M_BUFFERS) || data == MENU_ID(M_PLUGINS))
307 {
308 char buf[64];
309 const char* name = list_get_name_cb(list_index, data, buf, sizeof(buf));
310 long id = P2ID((const unsigned char *)name);
311 if(id>=0)
312 rb->talk_id(id, true);
313 else
314 {
315 char* bytstr = rb->strcasestr(name, "bytes");
316 if (bytstr != NULL)
317 *bytstr = '\0';
318 rb->talk_spell(name, true);
319 }
320 }
321 else
322 {
323 char buf[64];
324 const char* name = list_get_name_cb(list_index, data, buf, sizeof(buf));
325 long id = P2ID((const unsigned char *)name);
326 if(id>=0)
327 rb->talk_id(id, true);
328 else
329 rb->talk_spell(name, true);
330 }
331 return 0;
332}
333
334int menu_action_cb(int action, int selected_item, bool* exit, struct gui_synclist *lists)
335{
336 if (lists->data == MENU_ID(M_ACTTEST))
337 {
338 if (selected_item == 2) /* context */
339 {
340 int ctx = m_test.context;
341 if (action == ACTION_STD_OK)
342 m_test.context++;
343 else if (action == ACTION_STD_CANCEL)
344 m_test.context--;
345
346 if (m_test.context < 0)
347 m_test.context = 0;
348 else if (m_test.context >= LAST_CONTEXT_PLACEHOLDER)
349 m_test.context = LAST_CONTEXT_PLACEHOLDER - 1;
350
351 if (ctx != m_test.context)
352 rb->gui_synclist_speak_item(lists);
353
354 goto default_handler;
355 }
356 if (action == ACTION_STD_OK)
357 {
358 if (selected_item == 1 || selected_item == 3)
359 {
360 m_test.count = 3;
361 rb->gui_synclist_select_item(lists, 3);
362 }
363 }
364 }
365 else if (lists->data == MENU_ID(M_BTNTEST))
366 {
367 if (action == ACTION_STD_OK)
368 {
369 if (selected_item == 1 || selected_item == 2)
370 {
371 m_test.count = 3;
372 rb->gui_synclist_select_item(lists, 2);
373 }
374 }
375 }
376 if (action == ACTION_STD_OK)
377 {
378 if (lists->data == MENU_ID(M_ROOT))
379 {
380 rb->memset(&m_test, 0, sizeof(struct menu_test_t));
381 const struct mainmenu *cur = mainitem(selected_item);
382 if (cur->menuid == NULL || cur->menuid == MENU_ID(M_EXIT))
383 *exit = true;
384 else
385 {
386 main_last_sel = selected_item;
387 synclist_set(cur->menuid, 1, cur->items, 1);
388 rb->gui_synclist_draw(lists);
389 }
390 }
391 else if (selected_item <= 0) /* title */
392 {
393 rb->gui_synclist_select_item(lists, 1);
394 }
395 else if (selected_item >= (mainitem(main_last_sel)->items) - 1)/*back*/
396 {
397 action = ACTION_STD_CANCEL;
398 }
399 else if (lists->data == MENU_ID(M_ACTIONS) ||
400 lists->data == MENU_ID(M_CONTEXTS))
401 {
402 char buf[MAX_PATH];
403 const char *name = list_get_name_cb(selected_item, lists->data, buf, sizeof(buf));
404 /* splash long enough to get fingers off button then wait for new button press */
405 rb->splashf(HZ / 2, "%s %d (0x%X)", name, selected_item -1, selected_item -1);
406 rb->button_get(true);
407 }
408 }
409 if (action == ACTION_STD_CANCEL)
410 {
411 if (lists->data != MENU_ID(M_ROOT))
412 {
413 const struct mainmenu *mainm = &mainmenu[0];
414 synclist_set(mainm->menuid, main_last_sel, mainm->items, 1);
415 rb->gui_synclist_draw(lists);
416 }
417 else
418 *exit = true;
419 }
420default_handler:
421 if (rb->default_event_handler_ex(action, cleanup, NULL) == SYS_USB_CONNECTED)
422 {
423 *exit = true;
424 return PLUGIN_USB_CONNECTED;
425 }
426 return PLUGIN_OK;
427}
428
429static void synclist_set(char* menu_id, int selected_item, int items, int sel_size)
430{
431 if (items <= 0)
432 return;
433 if (selected_item < 0)
434 selected_item = 0;
435
436 list_voice_cb(0, menu_id);
437 rb->gui_synclist_init(&lists,list_get_name_cb,
438 menu_id, false, sel_size, NULL);
439
440 rb->gui_synclist_set_icon_callback(&lists,NULL);
441 rb->gui_synclist_set_voice_callback(&lists, list_voice_cb);
442 rb->gui_synclist_set_nb_items(&lists,items);
443 rb->gui_synclist_limit_scroll(&lists,true);
444 rb->gui_synclist_select_item(&lists, selected_item);
445
446}
447
448enum plugin_status plugin_start(const void* parameter)
449{
450 int ret = PLUGIN_OK;
451 int selected_item = -1;
452 int action;
453 bool redraw = true;
454 bool exit = false;
455 if (parameter)
456 {
457 //
458 }
459 mainmenu[M_BUTTONS].items = available_button_count;
460 /* add header and back item to each submenu */
461 for (int i = 1; i < M_LAST_ITEM; i++)
462 mainmenu[i].items += 2;
463
464 if (!exit)
465 {
466 const struct mainmenu *mainm = &mainmenu[0];
467 synclist_set(mainm->menuid, main_last_sel, mainm->items, 1);
468 rb->gui_synclist_draw(&lists);
469
470 while (!exit)
471 {
472 action = rb->get_action(CONTEXT_LIST, HZ / 10);
473 if (m_test.count > 0)
474 action = ACTION_REDRAW;
475
476 if (action == ACTION_NONE)
477 {
478 if (redraw)
479 {
480 action = ACTION_REDRAW;
481 redraw = false;
482 }
483 }
484 else
485 redraw = true;
486 if (rb->gui_synclist_do_button(&lists,&action,LIST_WRAP_UNLESS_HELD))
487 continue;
488 selected_item = rb->gui_synclist_get_sel_pos(&lists);
489 ret = menu_action_cb(action, selected_item, &exit, &lists);
490 }
491 }
492
493 return ret;
494}