A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 625 lines 21 kB view raw
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 );