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 * $Id$
9 *
10 * Copyright (C) 2007 Jonathan Gordon
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#include <stdbool.h>
23#include <stddef.h>
24#include <limits.h>
25#include "config.h"
26#include "appevents.h"
27#include "lang.h"
28#include "action.h"
29#include "settings.h"
30#include "menu.h"
31#include "tree.h"
32#include "list.h"
33#include "peakmeter.h"
34#include "talk.h"
35#include "lcd.h"
36#ifdef HAVE_REMOTE_LCD
37#include "lcd-remote.h"
38#endif
39#ifdef HAVE_BACKLIGHT
40#include "mask_select.h"
41#include "splash.h"
42#endif
43#ifdef HAVE_TOUCHSCREEN
44#include "screens.h"
45#endif
46#include "viewport.h"
47#include "statusbar.h" /* statusbar_vals enum*/
48#include "rbunicode.h"
49
50#ifdef HAVE_BACKLIGHT
51static int selectivebacklight_callback(int action,
52 const struct menu_item_ex *this_item,
53 struct gui_synclist *this_list)
54{
55 (void)this_item;
56 (void)this_list;
57 switch (action)
58 {
59 case ACTION_EXIT_MENUITEM:
60 case ACTION_STD_MENU:
61 case ACTION_STD_CANCEL:
62 set_selective_backlight_actions(
63 global_settings.bl_selective_actions,
64 global_settings.bl_selective_actions_mask,
65 global_settings.bl_filter_first_keypress);
66 break;
67 }
68
69 return action;
70}
71
72static int filterfirstkeypress_callback(int action,
73 const struct menu_item_ex *this_item,
74 struct gui_synclist *this_list)
75{
76 /*(void)this_item;REMOVED*/
77 switch (action)
78 {
79 case ACTION_EXIT_MENUITEM:
80 set_backlight_filter_keypress(global_settings.bl_filter_first_keypress);
81#ifdef HAVE_REMOTE_LCD
82 set_remote_backlight_filter_keypress(
83 global_settings.remote_bl_filter_first_keypress);
84#endif /* HAVE_REMOTE_LCD */
85 selectivebacklight_callback(action,this_item, this_list);/*uses Filter First KP*/
86 break;
87 }
88
89 return action;
90}
91
92static int selectivebacklight_set_mask(void* param)
93{
94 (void)param;
95 int mask = global_settings.bl_selective_actions_mask;
96 struct s_mask_items maskitems[]={
97 {ID2P(LANG_ACTION_VOLUME) , SEL_ACTION_VOL},
98 {ID2P(LANG_ACTION_PLAY), SEL_ACTION_PLAY},
99 {ID2P(LANG_ACTION_SEEK), SEL_ACTION_SEEK},
100 {ID2P(LANG_ACTION_SKIP), SEL_ACTION_SKIP},
101 {ID2P(LANG_ACTION_DISABLE_UNMAPPED), SEL_ACTION_NOUNMAPPED}
102#if CONFIG_CHARGING
103 ,{ID2P(LANG_ACTION_DISABLE_EXT_POWER), SEL_ACTION_NOEXT}
104#endif
105 };
106
107 mask = mask_select(mask, ID2P(LANG_BACKLIGHT_SELECTIVE)
108 , maskitems, ARRAYLEN(maskitems));
109
110 if (mask == SEL_ACTION_NONE || mask == SEL_ACTION_NOEXT)
111 global_settings.bl_selective_actions = false;
112 else if (global_settings.bl_selective_actions_mask != mask)
113 global_settings.bl_selective_actions = true;
114
115 global_settings.bl_selective_actions_mask = mask;
116
117 return true;
118}
119
120#endif /* HAVE_BACKLIGHT */
121#ifdef HAVE_LCD_FLIP
122static int flipdisplay_callback(int action,
123 const struct menu_item_ex *this_item,
124 struct gui_synclist *this_list)
125{
126 (void)this_item;
127 (void)this_list;
128 switch (action)
129 {
130 case ACTION_EXIT_MENUITEM:
131 button_set_flip(global_settings.flip_display);
132 lcd_set_flip(global_settings.flip_display);
133 lcd_update();
134#ifdef HAVE_REMOTE_LCD
135 lcd_remote_set_flip(global_settings.remote_flip_display);
136 lcd_remote_update();
137#endif
138 break;
139 }
140 return action;
141}
142#endif
143
144/***********************************/
145/* LCD MENU */
146#ifdef HAVE_BACKLIGHT
147MENUITEM_SETTING(backlight_timeout, &global_settings.backlight_timeout, NULL);
148#if CONFIG_CHARGING
149MENUITEM_SETTING(backlight_timeout_plugged,
150 &global_settings.backlight_timeout_plugged, NULL);
151#endif
152
153MENUITEM_SETTING(backlight_on_button_hold,
154 &global_settings.backlight_on_button_hold, NULL);
155
156MENUITEM_SETTING(caption_backlight, &global_settings.caption_backlight, NULL);
157#if defined(HAVE_BACKLIGHT_FADING_INT_SETTING) \
158 || defined(HAVE_BACKLIGHT_FADING_BOOL_SETTING)
159MENUITEM_SETTING(backlight_fade_in, &global_settings.backlight_fade_in, NULL);
160MENUITEM_SETTING(backlight_fade_out, &global_settings.backlight_fade_out, NULL);
161#endif
162MENUITEM_SETTING(bl_filter_first_keypress,
163 &global_settings.bl_filter_first_keypress,
164 filterfirstkeypress_callback);
165
166MENUITEM_SETTING(bl_selective_actions,
167 &global_settings.bl_selective_actions,
168 selectivebacklight_callback);
169
170MENUITEM_FUNCTION(sel_backlight_mask, 0, ID2P(LANG_SETTINGS),
171 selectivebacklight_set_mask, selectivebacklight_callback,
172 Icon_Menu_setting);
173
174MAKE_MENU(sel_backlight, ID2P(LANG_BACKLIGHT_SELECTIVE),
175 NULL, Icon_Menu_setting, &bl_selective_actions, &sel_backlight_mask);
176
177#ifdef HAVE_LCD_SLEEP_SETTING
178MENUITEM_SETTING(lcd_sleep_after_backlight_off,
179 &global_settings.lcd_sleep_after_backlight_off, NULL);
180#endif
181#ifdef HAVE_BACKLIGHT_BRIGHTNESS
182MENUITEM_SETTING(brightness_item, &global_settings.brightness, NULL);
183#endif
184#endif /* HAVE_BACKLIGHT */
185#ifdef HAVE_LCD_CONTRAST
186MENUITEM_SETTING(contrast, &global_settings.contrast, NULL);
187#endif
188#ifdef HAVE_LCD_INVERT
189MENUITEM_SETTING(invert, &global_settings.invert, NULL);
190#endif
191#ifdef HAVE_LCD_FLIP
192MENUITEM_SETTING(flip_display, &global_settings.flip_display, flipdisplay_callback);
193#endif
194
195/* now the actual menu */
196MAKE_MENU(lcd_settings,ID2P(LANG_LCD_MENU),
197 NULL, Icon_Display_menu
198#ifdef HAVE_BACKLIGHT
199 ,&backlight_timeout
200# if CONFIG_CHARGING
201 ,&backlight_timeout_plugged
202# endif
203 ,&backlight_on_button_hold
204 ,&caption_backlight
205#if defined(HAVE_BACKLIGHT_FADING_INT_SETTING) \
206 || defined(HAVE_BACKLIGHT_FADING_BOOL_SETTING)
207 ,&backlight_fade_in, &backlight_fade_out
208#endif
209 ,&bl_filter_first_keypress
210 ,&sel_backlight
211# ifdef HAVE_LCD_SLEEP_SETTING
212 ,&lcd_sleep_after_backlight_off
213# endif
214# ifdef HAVE_BACKLIGHT_BRIGHTNESS
215 ,&brightness_item
216# endif
217#endif /* HAVE_BACKLIGHT */
218#ifdef HAVE_LCD_CONTRAST
219 ,&contrast
220#endif
221# ifdef HAVE_LCD_INVERT
222 ,&invert
223# endif
224# ifdef HAVE_LCD_FLIP
225 ,&flip_display
226# endif
227 );
228/* LCD MENU */
229/***********************************/
230
231
232/********************************/
233/* Remote LCD settings menu */
234#ifdef HAVE_REMOTE_LCD
235MENUITEM_SETTING(remote_backlight_timeout,
236 &global_settings.remote_backlight_timeout, NULL);
237
238#if CONFIG_CHARGING
239MENUITEM_SETTING(remote_backlight_timeout_plugged,
240 &global_settings.remote_backlight_timeout_plugged, NULL);
241#endif
242
243#ifdef HAS_REMOTE_BUTTON_HOLD
244MENUITEM_SETTING(remote_backlight_on_button_hold,
245 &global_settings.remote_backlight_on_button_hold, NULL);
246#endif
247
248MENUITEM_SETTING(remote_caption_backlight,
249 &global_settings.remote_caption_backlight, NULL);
250MENUITEM_SETTING(remote_bl_filter_first_keypress,
251 &global_settings.remote_bl_filter_first_keypress,
252 filterfirstkeypress_callback);
253MENUITEM_SETTING(remote_contrast,
254 &global_settings.remote_contrast, NULL);
255MENUITEM_SETTING(remote_invert,
256 &global_settings.remote_invert, NULL);
257
258#ifdef HAVE_LCD_FLIP
259MENUITEM_SETTING(remote_flip_display,
260 &global_settings.remote_flip_display, flipdisplay_callback);
261#endif
262
263#ifdef HAVE_REMOTE_LCD_TICKING
264static int ticking_callback(int action,
265 const struct menu_item_ex *this_item,
266 struct gui_synclist *this_list)
267{
268 (void)this_item;
269 (void)this_list;
270 switch (action)
271 {
272 case ACTION_EXIT_MENUITEM:
273 lcd_remote_emireduce(global_settings.remote_reduce_ticking);
274 break;
275 }
276 return action;
277}
278MENUITEM_SETTING(remote_reduce_ticking,
279 &global_settings.remote_reduce_ticking, ticking_callback);
280#endif
281
282MAKE_MENU(lcd_remote_settings, ID2P(LANG_LCD_REMOTE_MENU),
283 NULL, Icon_Remote_Display_menu,
284 &remote_backlight_timeout,
285#if CONFIG_CHARGING
286 &remote_backlight_timeout_plugged,
287#endif
288#ifdef HAS_REMOTE_BUTTON_HOLD
289 &remote_backlight_on_button_hold,
290#endif
291 &remote_caption_backlight, &remote_bl_filter_first_keypress,
292 &remote_contrast, &remote_invert
293
294#ifdef HAVE_LCD_FLIP
295 ,&remote_flip_display
296#endif
297#ifdef HAVE_REMOTE_LCD_TICKING
298 ,&remote_reduce_ticking
299#endif
300 );
301
302#endif /* HAVE_REMOTE_LCD */
303/* Remote LCD settings menu */
304/********************************/
305
306/***********************************/
307/* SCROLL MENU */
308MENUITEM_SETTING_W_TEXT(scroll_speed, &global_settings.scroll_speed,
309 ID2P(LANG_SCROLL), NULL);
310MENUITEM_SETTING(scroll_delay, &global_settings.scroll_delay, NULL);
311MENUITEM_SETTING_W_TEXT(scroll_step, &global_settings.scroll_step,
312 ID2P(LANG_SCROLL_STEP_EXAMPLE), NULL);
313MENUITEM_SETTING(bidir_limit, &global_settings.bidir_limit, NULL);
314#ifdef HAVE_REMOTE_LCD
315MENUITEM_SETTING_W_TEXT(remote_scroll_speed, &global_settings.remote_scroll_speed,
316 ID2P(LANG_SCROLL), NULL);
317MENUITEM_SETTING(remote_scroll_delay, &global_settings.remote_scroll_delay, NULL);
318MENUITEM_SETTING_W_TEXT(remote_scroll_step, &global_settings.remote_scroll_step,
319 ID2P(LANG_SCROLL_STEP_EXAMPLE), NULL);
320MENUITEM_SETTING(remote_bidir_limit, &global_settings.remote_bidir_limit, NULL);
321
322MAKE_MENU(remote_scroll_sets, ID2P(LANG_REMOTE_SCROLL_SETS), 0, Icon_NOICON,
323 &remote_scroll_speed, &remote_scroll_delay,
324 &remote_scroll_step, &remote_bidir_limit);
325#endif /* HAVE_REMOTE_LCD */
326
327/* list acceleration */
328#ifndef HAVE_WHEEL_ACCELERATION
329MENUITEM_SETTING(list_accel_start_delay,
330 &global_settings.list_accel_start_delay, NULL);
331MENUITEM_SETTING(list_accel_wait, &global_settings.list_accel_wait, NULL);
332#endif /* HAVE_WHEEL_ACCELERATION */
333MENUITEM_SETTING(offset_out_of_view, &global_settings.offset_out_of_view, NULL);
334MENUITEM_SETTING(disable_mainmenu_scrolling, &global_settings.disable_mainmenu_scrolling, NULL);
335MENUITEM_SETTING(screen_scroll_step, &global_settings.screen_scroll_step, NULL);
336MENUITEM_SETTING(scroll_paginated, &global_settings.scroll_paginated, NULL);
337MENUITEM_SETTING(list_wraparound, &global_settings.list_wraparound, NULL);
338MENUITEM_SETTING(list_order, &global_settings.list_order, NULL);
339
340MAKE_MENU(scroll_settings_menu, ID2P(LANG_SCROLL_MENU), 0, Icon_NOICON,
341 &scroll_speed, &scroll_delay,
342 &scroll_step,
343 &bidir_limit,
344#ifdef HAVE_REMOTE_LCD
345 &remote_scroll_sets,
346#endif
347 &offset_out_of_view,
348 &disable_mainmenu_scrolling,
349 &screen_scroll_step,
350 &scroll_paginated,
351 &list_wraparound,
352 &list_order,
353#ifndef HAVE_WHEEL_ACCELERATION
354 &list_accel_start_delay, &list_accel_wait
355#endif
356 );
357/* SCROLL MENU */
358/***********************************/
359
360/***********************************/
361/* PEAK METER MENU */
362
363static int peakmeter_callback(int action,
364 const struct menu_item_ex *this_item,
365 struct gui_synclist *this_list)
366{
367 (void)this_item;
368 (void)this_list;
369 switch (action)
370 {
371 case ACTION_EXIT_MENUITEM:
372 peak_meter_init_times(global_settings.peak_meter_release,
373 global_settings.peak_meter_hold,
374 global_settings.peak_meter_clip_hold);
375 break;
376 }
377 return action;
378}
379MENUITEM_SETTING(peak_meter_hold,
380 &global_settings.peak_meter_hold, peakmeter_callback);
381MENUITEM_SETTING(peak_meter_clip_hold,
382 &global_settings.peak_meter_clip_hold, peakmeter_callback);
383#ifdef HAVE_RECORDING
384MENUITEM_SETTING(peak_meter_clipcounter,
385 &global_settings.peak_meter_clipcounter, NULL);
386#endif
387MENUITEM_SETTING(peak_meter_release,
388 &global_settings.peak_meter_release, peakmeter_callback);
389/**
390 * Menu to select wether the scale of the meter
391 * displays dBfs of linear values.
392 */
393static int peak_meter_scale(void) {
394 bool retval = false;
395 bool use_dbfs = global_settings.peak_meter_dbfs;
396 retval = set_bool_options(str(LANG_PM_SCALE),
397 &use_dbfs,
398 STR(LANG_PM_DBFS), STR(LANG_PM_LINEAR),
399 NULL);
400
401 /* has the user really changed the scale? */
402 if (use_dbfs != global_settings.peak_meter_dbfs) {
403
404 /* store the change */
405 global_settings.peak_meter_dbfs = use_dbfs;
406 peak_meter_set_use_dbfs(use_dbfs);
407
408 /* If the user changed the scale mode the meaning of
409 peak_meter_min (peak_meter_max) has changed. Thus we have
410 to convert the values stored in global_settings. */
411 if (use_dbfs) {
412
413 /* we only store -dBfs */
414 global_settings.peak_meter_min = -peak_meter_get_min() / 100;
415 global_settings.peak_meter_max = -peak_meter_get_max() / 100;
416
417 /* limit the returned value to the allowed range */
418 if(global_settings.peak_meter_min > 89)
419 global_settings.peak_meter_min = 89;
420 } else {
421 int max;
422
423 /* linear percent */
424 global_settings.peak_meter_min = peak_meter_get_min();
425
426 /* converting dBfs -> percent results in a precision loss.
427 I assume that the user doesn't bother that conversion
428 dBfs <-> percent isn't symmetrical for odd values but that
429 he wants 0 dBfs == 100%. Thus I 'correct' the percent value
430 resulting from dBfs -> percent manually here */
431 max = peak_meter_get_max();
432 global_settings.peak_meter_max = max < 99 ? max : 100;
433 }
434 settings_apply_pm_range();
435 }
436 return retval;
437}
438
439/**
440 * Adjust the min value of the value range that
441 * the peak meter shall visualize.
442 */
443static int peak_meter_min(void) {
444 bool retval = false;
445 if (global_settings.peak_meter_dbfs) {
446
447 /* for dBfs scale */
448 int range_max = -global_settings.peak_meter_max;
449 int min = -global_settings.peak_meter_min;
450
451 retval = set_int(str(LANG_PM_MIN), str(LANG_PM_DBFS), UNIT_DB,
452 &min, NULL, 1, -89, range_max, NULL);
453
454 global_settings.peak_meter_min = - min;
455 }
456
457 /* for linear scale */
458 else {
459 int min = global_settings.peak_meter_min;
460
461 retval = set_int(str(LANG_PM_MIN), "%", UNIT_PERCENT,
462 &min, NULL,
463 1, 0, global_settings.peak_meter_max - 1, NULL);
464
465 global_settings.peak_meter_min = (unsigned char)min;
466 }
467
468 settings_apply_pm_range();
469 return retval;
470}
471
472
473/**
474 * Adjust the max value of the value range that
475 * the peak meter shall visualize.
476 */
477static int peak_meter_max(void) {
478 bool retval = false;
479 if (global_settings.peak_meter_dbfs) {
480
481 /* for dBfs scale */
482 int range_min = -global_settings.peak_meter_min;
483 int max = -global_settings.peak_meter_max;
484
485 retval = set_int(str(LANG_PM_MAX), str(LANG_PM_DBFS), UNIT_DB,
486 &max, NULL, 1, range_min, 0, NULL);
487
488 global_settings.peak_meter_max = - max;
489
490 }
491
492 /* for linear scale */
493 else {
494 int max = global_settings.peak_meter_max;
495
496 retval = set_int(str(LANG_PM_MAX), "%", UNIT_PERCENT,
497 &max, NULL,
498 1, global_settings.peak_meter_min + 1, 100, NULL);
499
500 global_settings.peak_meter_max = (unsigned char)max;
501 }
502
503 settings_apply_pm_range();
504 return retval;
505}
506
507#if defined(HAVE_HISTOGRAM)
508static bool history_interval(void)
509{
510 static const struct opt_items names[] = {
511 { "0s", TALK_ID(0, UNIT_SEC) },
512 { "1s", TALK_ID(1, UNIT_SEC) },
513 { "2s", TALK_ID(2, UNIT_SEC) },
514 { "4s", TALK_ID(4, UNIT_SEC) }
515 };
516
517 /* reconfigure histogram settings here */
518
519 return set_option(str(LANG_HISTOGRAM_INTERVAL),
520 &global_settings.histogram_interval,
521 RB_INT, names, 4, NULL );
522}
523
524MENUITEM_FUNCTION(histogram, 0, ID2P(LANG_HISTOGRAM_INTERVAL),
525 history_interval, NULL, Icon_Menu_setting);
526
527#endif
528
529MENUITEM_FUNCTION(peak_meter_scale_item, 0, ID2P(LANG_PM_SCALE),
530 peak_meter_scale, NULL, Icon_NOICON);
531MENUITEM_FUNCTION(peak_meter_min_item, 0, ID2P(LANG_PM_MIN),
532 peak_meter_min, NULL, Icon_NOICON);
533MENUITEM_FUNCTION(peak_meter_max_item, 0, ID2P(LANG_PM_MAX),
534 peak_meter_max, NULL, Icon_NOICON);
535MAKE_MENU(peak_meter_menu, ID2P(LANG_PM_MENU), NULL, Icon_NOICON,
536 &peak_meter_release, &peak_meter_hold,
537 &peak_meter_clip_hold,
538#ifdef HAVE_RECORDING
539 &peak_meter_clipcounter,
540#endif
541#ifdef HAVE_HISTOGRAM
542 &histogram,
543#endif
544 &peak_meter_scale_item, &peak_meter_min_item, &peak_meter_max_item);
545/* PEAK METER MENU */
546/***********************************/
547
548
549#ifdef HAVE_TOUCHSCREEN
550static int touch_mode_callback(int action,
551 const struct menu_item_ex *this_item,
552 struct gui_synclist *this_list)
553{
554 (void)this_item;
555 (void)this_list;
556 switch (action)
557 {
558 case ACTION_EXIT_MENUITEM: /* on exit */
559 touchscreen_set_mode(global_settings.touch_mode);
560 break;
561 }
562 return action;
563}
564
565static int line_padding_callback(int action,
566 const struct menu_item_ex *this_item,
567 struct gui_synclist *this_list)
568{
569 (void)this_item;
570 (void)this_list;
571 if (action == ACTION_EXIT_MENUITEM)
572 viewportmanager_theme_changed(THEME_LISTS);
573 return action;
574}
575
576MENUITEM_SETTING(touch_mode, &global_settings.touch_mode, touch_mode_callback);
577
578MENUITEM_FUNCTION(touchscreen_menu_calibrate, 0,
579 ID2P(LANG_TOUCHSCREEN_CALIBRATE), calibrate, NULL, Icon_NOICON);
580MENUITEM_FUNCTION(touchscreen_menu_reset_calibration, 0,
581 ID2P(LANG_TOUCHSCREEN_RESET_CALIBRATION),
582 reset_mapping, NULL, Icon_NOICON);
583MENUITEM_SETTING(list_line_padding, &global_settings.list_line_padding, line_padding_callback);
584
585MAKE_MENU(touchscreen_menu, ID2P(LANG_TOUCHSCREEN_SETTINGS), NULL, Icon_NOICON, &list_line_padding, &touch_mode,
586 &touchscreen_menu_calibrate, &touchscreen_menu_reset_calibration);
587#endif
588
589static int codepage_callback(int action,
590 const struct menu_item_ex *this_item,
591 struct gui_synclist *this_list)
592{
593 (void)this_item;
594 (void)this_list;
595 static int old_codepage;
596 int new_codepage = global_settings.default_codepage;
597 switch (action)
598 {
599 case ACTION_ENTER_MENUITEM:
600 old_codepage = new_codepage;
601 break;
602 case ACTION_EXIT_MENUITEM:
603 if (new_codepage != old_codepage)
604 set_codepage(new_codepage);
605 break;
606 }
607 return action;
608}
609
610MENUITEM_SETTING(codepage_setting, &global_settings.default_codepage, codepage_callback);
611
612
613MAKE_MENU(display_menu, ID2P(LANG_DISPLAY),
614 NULL, Icon_Display_menu,
615 &lcd_settings,
616#ifdef HAVE_REMOTE_LCD
617 &lcd_remote_settings,
618#endif
619 &scroll_settings_menu,
620 &peak_meter_menu,
621 &codepage_setting,
622#ifdef HAVE_TOUCHSCREEN
623 &touchscreen_menu,
624#endif
625 );