Rockbox open source high quality audio player as a Music Player Daemon
mpris rockbox mpd libadwaita audio rust zig deno
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

[Feature] Set values of settings from shortcuts

Adds 'Add Current to Shortcuts' for settings alowing you to save
the current value and restore it with a shortcut

Change-Id: I0d5c5da9553248a70fd46d5553486ebf7865a20a

+318 -213
+15
apps/lang/english.lang
··· 6952 6952 </voice> 6953 6953 </phrase> 6954 6954 <phrase> 6955 + id: LANG_ADD_CURRENT_TO_FAVES 6956 + desc: 6957 + user: core 6958 + <source> 6959 + *: "Add Current to Shortcuts" 6960 + </source> 6961 + <dest> 6962 + *: "Add Current to Shortcuts" 6963 + </dest> 6964 + <voice> 6965 + *: "Add Current to Shortcuts" 6966 + </voice> 6967 + </phrase> 6968 + 6969 + <phrase> 6955 6970 id: LANG_PITCH 6956 6971 desc: "pitch" in the pitch screen 6957 6972 user: core
+27 -14
apps/menu.c
··· 513 513 514 514 if (type == MT_SETTING_W_TEXT || type == MT_SETTING) 515 515 { 516 - #ifdef HAVE_QUICKSCREEN 517 - MENUITEM_STRINGLIST(quickscreen_able_option, 516 + const struct menu_item_ex *context_menu; 517 + const struct settings_list *setting = 518 + find_setting(temp->variable); 519 + 520 + MENUITEM_STRINGLIST(settings_op_menu, 518 521 ID2P(LANG_ONPLAY_MENU_TITLE), NULL, 519 522 ID2P(LANG_RESET_SETTING), 523 + #ifndef HAVE_QUICKSCREEN 524 + }; 525 + context_menu = &settings_op_menu; 526 + #else 520 527 ID2P(LANG_TOP_QS_ITEM), 521 528 ID2P(LANG_LEFT_QS_ITEM), 522 529 ID2P(LANG_BOTTOM_QS_ITEM), 523 530 ID2P(LANG_RIGHT_QS_ITEM), 531 + ID2P(LANG_ADD_CURRENT_TO_FAVES), 524 532 ID2P(LANG_ADD_TO_FAVES)); 525 - #endif 526 - MENUITEM_STRINGLIST(notquickscreen_able_option, 527 - ID2P(LANG_ONPLAY_MENU_TITLE), NULL, 528 - ID2P(LANG_RESET_SETTING)); 529 - const struct menu_item_ex *context_menu; 530 - const struct settings_list *setting = 531 - find_setting(temp->variable); 532 - #ifdef HAVE_QUICKSCREEN 533 + 534 + /* re-use the strings and desc from the settings_op_menu */ 535 + static const struct menu_item_ex non_quickscreen_op_menu = 536 + {MT_RETURN_ID|MENU_HAS_DESC|MENU_ITEM_COUNT(1), 537 + { .strings = settings_op_menu_}, 538 + {.callback_and_desc = &settings_op_menu__}}; 539 + 533 540 if (is_setting_quickscreenable(setting)) 534 - context_menu = &quickscreen_able_option; 541 + context_menu = &settings_op_menu; 535 542 else 543 + { 544 + context_menu = &non_quickscreen_op_menu; 545 + } 536 546 #endif 537 - context_menu = &notquickscreen_able_option; 538 - 539 547 int msel = do_menu(context_menu, NULL, NULL, false); 540 548 541 549 switch (msel) ··· 560 568 case 4: /* set as right QS item */ 561 569 global_settings.qs_items[QUICKSCREEN_RIGHT] = setting; 562 570 break; 563 - case 5: /* Add to faves. Same limitation on which can be 571 + case 5: /* Add current value of setting to faves. 572 + Same limitation on which can be 573 + added to the shortcuts menu as the quickscreen */ 574 + shortcuts_add(SHORTCUT_SETTING_APPLY, (void*)setting); 575 + break; 576 + case 6: /* Add to faves. Same limitation on which can be 564 577 added to the shortcuts menu as the quickscreen */ 565 578 shortcuts_add(SHORTCUT_SETTING, (void*)setting); 566 579 break;
+96 -92
apps/settings.c
··· 258 258 return true; 259 259 } 260 260 261 - bool settings_load_config(const char* file, bool apply) 261 + void string_to_cfg(const char *name, char* value, bool *theme_changed) 262 262 { 263 - logf("%s()\r\n", __func__); 264 - const struct settings_list *setting; 265 - int fd; 266 - char line[128]; 267 - char* name; 268 - char* value; 269 - bool theme_changed = false; 263 + const struct settings_list *setting = find_setting_by_cfgname(name); 264 + if (!setting) 265 + return; 270 266 271 - fd = open_utf8(file, O_RDONLY); 272 - if (fd < 0) 273 - return false; 267 + uint32_t flags = setting->flags; 274 268 275 - while (read_line(fd, line, sizeof line) > 0) 269 + if (flags & F_THEMESETTING) 270 + *theme_changed = true; 271 + 272 + switch (flags & F_T_MASK) 276 273 { 277 - if (!settings_parseline(line, &name, &value)) 278 - continue; 279 - 280 - setting = find_setting_by_cfgname(name); 281 - if (!setting) 282 - continue; 283 - 284 - if (setting->flags & F_THEMESETTING) 285 - theme_changed = true; 286 - 287 - switch (setting->flags & F_T_MASK) 288 - { 289 - case F_T_CUSTOM: 290 - setting->custom_setting->load_from_cfg(setting->setting, value); 291 - logf("Val: %s\r\n",value); 292 - break; 293 - case F_T_INT: 294 - case F_T_UINT: 274 + case F_T_CUSTOM: 275 + setting->custom_setting->load_from_cfg(setting->setting, value); 276 + logf("Val: %s\r\n",value); 277 + break; 278 + case F_T_INT: 279 + case F_T_UINT: 295 280 #ifdef HAVE_LCD_COLOR 296 - if (setting->flags & F_RGB) 281 + if (flags & F_RGB) 282 + { 283 + hex_to_rgb(value, (int*)setting->setting); 284 + logf("Val: %s\r\n", value); 285 + } 286 + else 287 + #endif 288 + if (setting_get_cfgvals(setting) == NULL) 297 289 { 298 - hex_to_rgb(value, (int*)setting->setting); 299 - logf("Val: %s\r\n", value); 290 + *(int*)setting->setting = atoi(value); 291 + logf("Val: %s\r\n",value); 300 292 } 301 293 else 302 - #endif 303 - if (setting_get_cfgvals(setting) == NULL) 294 + { 295 + int temp, *v = (int*)setting->setting; 296 + bool found = cfg_string_to_int(setting, &temp, value); 297 + if (found) 298 + { 299 + if (flags & F_TABLE_SETTING) 300 + *v = setting->table_setting->values[temp]; 301 + else 302 + *v = temp; 303 + logf("Val: %d\r\n", *v); 304 + } 305 + else if (flags & F_ALLOW_ARBITRARY_VALS) 304 306 { 305 - *(int*)setting->setting = atoi(value); 306 - logf("Val: %s\r\n",value); 307 + *v = atoi(value); 308 + logf("Val: %s = %d\r\n", value, *v); 307 309 } 308 - else 310 + else if (flags & F_TABLE_SETTING) 309 311 { 310 - int temp, *v = (int*)setting->setting; 311 - bool found = cfg_string_to_int(setting, &temp, value); 312 - if (found) 313 - { 314 - if (setting->flags & F_TABLE_SETTING) 315 - *v = setting->table_setting->values[temp]; 316 - else 317 - *v = temp; 318 - logf("Val: %d\r\n", *v); 319 - } 320 - else if (setting->flags & F_ALLOW_ARBITRARY_VALS) 321 - { 322 - *v = atoi(value); 323 - logf("Val: %s = %d\r\n", value, *v); 324 - } 325 - else if (setting->flags & F_TABLE_SETTING) 312 + const struct table_setting *info = setting->table_setting; 313 + temp = atoi(value); 314 + *v = setting->default_val.int_; 315 + if (info->values) 326 316 { 327 - const struct table_setting *info = setting->table_setting; 328 - temp = atoi(value); 329 - *v = setting->default_val.int_; 330 - if (info->values) 317 + for(int i = 0; i < info->count; i++) 331 318 { 332 - for(int i = 0; i < info->count; i++) 319 + if (info->values[i] == temp) 333 320 { 334 - if (info->values[i] == temp) 335 - { 336 - *v = temp; 337 - break; 338 - } 321 + *v = temp; 322 + break; 339 323 } 340 324 } 341 - logf("Val: %s", *v == temp ? "Found":"Error Not Found"); 342 - logf("Val: %s = %d\r\n", value, *v); 343 325 } 326 + logf("Val: %s", *v == temp ? "Found":"Error Not Found"); 327 + logf("Val: %s = %d\r\n", value, *v); 328 + } 344 329 345 - else 346 - { 347 - logf("Error: %s: Not Found! [%s]\r\n", 348 - setting->cfg_name, value); 349 - } 330 + else 331 + { 332 + logf("Error: %s: Not Found! [%s]\r\n", 333 + setting->cfg_name, value); 350 334 } 351 - break; 352 - case F_T_BOOL: 353 - { 354 - int temp; 355 - if (cfg_string_to_int(setting, &temp, value)) 356 - { 357 - *(bool*)setting->setting = !!temp; 358 - logf("Val: %s\r\n", value); 359 335 } 360 - if (setting->bool_setting->option_callback) 361 - { 362 - setting->bool_setting->option_callback(!!temp); 363 - } 364 - break; 365 - } 366 - /* these can be plain text, filenames, or dirnames */ 367 - case F_T_CHARPTR: 368 - case F_T_UCHARPTR: 336 + break; 337 + case F_T_BOOL: 338 + { 339 + int temp; 340 + if (cfg_string_to_int(setting, &temp, value)) 369 341 { 370 - const struct filename_setting *fs = setting->filename_setting; 371 - copy_filename_setting((char*)setting->setting, 372 - fs->max_len, value, fs); 342 + *(bool*)setting->setting = !!temp; 373 343 logf("Val: %s\r\n", value); 374 - break; 375 344 } 345 + if (setting->bool_setting->option_callback) 346 + { 347 + setting->bool_setting->option_callback(!!temp); 376 348 } 349 + break; 350 + } 351 + /* these can be plain text, filenames, or dirnames */ 352 + case F_T_CHARPTR: 353 + case F_T_UCHARPTR: 354 + { 355 + const struct filename_setting *fs = setting->filename_setting; 356 + copy_filename_setting((char*)setting->setting, 357 + fs->max_len, value, fs); 358 + logf("Val: %s\r\n", value); 359 + break; 360 + } 361 + } 362 + } 363 + 364 + bool settings_load_config(const char* file, bool apply) 365 + { 366 + logf("%s()\r\n", __func__); 367 + int fd; 368 + char line[128]; 369 + bool theme_changed = false; 370 + 371 + fd = open_utf8(file, O_RDONLY); 372 + if (fd < 0) 373 + return false; 374 + 375 + while (read_line(fd, line, sizeof line) > 0) 376 + { 377 + char *name, *value; 378 + if (!settings_parseline(line, &name, &value)) 379 + continue; 380 + string_to_cfg(name, value, &theme_changed); 377 381 } /* while(...) */ 378 382 379 383 close(fd);
+2
apps/settings.h
··· 288 288 bool cfg_int_to_string(const struct settings_list *setting, int val, char* buf, int buf_len); 289 289 bool cfg_string_to_int(const struct settings_list *setting, int* out, const char* str); 290 290 void cfg_to_string(const struct settings_list *setting, char* buf, int buf_len); 291 + void string_to_cfg(const char *name, char* value, bool *theme_changed); 292 + 291 293 bool copy_filename_setting(char *buf, size_t buflen, const char *input, 292 294 const struct filename_setting *fs); 293 295 bool set_bool_options(const char* string, const bool* variable,
+172 -107
apps/shortcuts.c
··· 52 52 #endif 53 53 54 54 #define MAX_SHORTCUT_NAME 64 55 + #define SHORTCUTS_HDR "[shortcut]" 55 56 #define SHORTCUTS_FILENAME ROCKBOX_DIR "/shortcuts.txt" 56 57 static const char * const type_strings[SHORTCUT_TYPE_COUNT] = { 57 58 [SHORTCUT_SETTING] = "setting", 58 - [SHORTCUT_FILE] = "file", 59 + [SHORTCUT_SETTING_APPLY] = "apply", 59 60 [SHORTCUT_DEBUGITEM] = "debug", 60 61 [SHORTCUT_BROWSER] = "browse", 61 62 [SHORTCUT_PLAYLISTMENU] = "playlist menu", ··· 63 64 [SHORTCUT_SHUTDOWN] = "shutdown", 64 65 [SHORTCUT_REBOOT] = "reboot", 65 66 [SHORTCUT_TIME] = "time", 67 + [SHORTCUT_FILE] = "file", 66 68 }; 67 69 68 70 struct shortcut { 69 71 enum shortcut_type type; 72 + int8_t icon; 70 73 char name[MAX_SHORTCUT_NAME]; 71 74 char talk_clip[MAX_PATH]; 72 - int icon; 75 + const struct settings_list *setting; 73 76 union { 74 77 char path[MAX_PATH]; 75 - const struct settings_list *setting; 76 78 struct { 77 79 #if CONFIG_RTC 78 80 bool talktime; ··· 81 83 } timedata; 82 84 } u; 83 85 }; 86 + 84 87 #define SHORTCUTS_PER_HANDLE 4 85 88 struct shortcut_handle { 86 89 struct shortcut shortcuts[SHORTCUTS_PER_HANDLE]; ··· 121 124 shortcut_count = 0; 122 125 } 123 126 124 - static struct shortcut* get_shortcut(int index) 127 + static struct shortcut_handle * alloc_first_sc_handle(void) 128 + { 129 + struct shortcut_handle *h = NULL; 130 + #if 0 /* all paths are guarded, compiler doesn't recognize INIT_ATTR callers */ 131 + if (first_handle != 0) 132 + return h; /* No re-init allowed */ 133 + #endif 134 + first_handle = core_alloc_ex(sizeof(struct shortcut_handle), &shortcut_ops); 135 + if (first_handle > 0) 136 + { 137 + h = core_get_data(first_handle); 138 + h->next_handle = 0; 139 + } 140 + 141 + return h; 142 + } 143 + 144 + static struct shortcut* get_shortcut(int index, struct shortcut *fail) 125 145 { 126 146 int handle_count, handle_index; 127 147 int current_handle = first_handle; 128 - struct shortcut_handle *h = NULL; 148 + struct shortcut_handle *h; 129 149 130 150 if (first_handle == 0) 131 151 { 132 - first_handle = core_alloc_ex(sizeof(struct shortcut_handle), &shortcut_ops); 133 - if (first_handle <= 0) 134 - return NULL; 135 - h = core_get_data(first_handle); 136 - h->next_handle = 0; 152 + h = alloc_first_sc_handle(); 153 + if (!h) 154 + return fail; 137 155 current_handle = first_handle; 138 156 } 139 157 ··· 143 161 h = core_get_data(current_handle); 144 162 current_handle = h->next_handle; 145 163 handle_count--; 146 - } while (handle_count > 0 && current_handle > 0); 147 - if (handle_count > 0 && handle_index == 0) 164 + if(handle_count <= 0) 165 + return &h->shortcuts[handle_index]; 166 + } while (current_handle > 0); 167 + 168 + if (handle_index == 0) 148 169 { 149 170 /* prevent invalidation of 'h' during compaction */ 150 171 ++buflib_move_lock; 151 172 h->next_handle = core_alloc_ex(sizeof(struct shortcut_handle), &shortcut_ops); 152 173 --buflib_move_lock; 153 174 if (h->next_handle <= 0) 154 - return NULL; 175 + return fail; 155 176 h = core_get_data(h->next_handle); 156 177 h->next_handle = 0; 157 178 } ··· 161 182 static void remove_shortcut(int index) 162 183 { 163 184 int this = index, next = index + 1; 164 - struct shortcut *prev = get_shortcut(this); 185 + struct shortcut *prev = get_shortcut(this, NULL); 165 186 166 187 while (next <= shortcut_count) 167 188 { 168 - struct shortcut *sc = get_shortcut(next); 189 + struct shortcut *sc = get_shortcut(next, NULL); 169 190 memcpy(prev, sc, sizeof(struct shortcut)); 170 191 next++; 171 192 prev = sc; ··· 183 204 case SHORTCUT_FILE: 184 205 case SHORTCUT_PLAYLISTMENU: 185 206 return sc->u.path[0] != '\0'; 207 + case SHORTCUT_SETTING_APPLY: 186 208 case SHORTCUT_SETTING: 187 - return sc->u.setting != NULL; 209 + return sc->setting != NULL; 188 210 case SHORTCUT_TIME: 189 211 #if CONFIG_RTC 190 212 if (sc->u.timedata.talktime) ··· 203 225 204 226 static void init_shortcut(struct shortcut* sc) 205 227 { 228 + memset(sc, 0, sizeof(*sc)); 206 229 sc->type = SHORTCUT_UNDEFINED; 207 - sc->name[0] = '\0'; 208 - sc->u.path[0] = '\0'; 209 - sc->talk_clip[0] = '\0'; 210 230 sc->icon = Icon_NOICON; 211 231 } 212 232 ··· 215 235 static void shortcuts_ata_idle_callback(void) 216 236 { 217 237 int fd; 218 - char buf[MAX_PATH]; 238 + 219 239 int current_idx = first_idx_to_writeback; 220 240 int append = overwrite_shortcuts ? O_TRUNC : O_APPEND; 221 241 ··· 231 251 232 252 while (current_idx < shortcut_count) 233 253 { 234 - struct shortcut* sc = get_shortcut(current_idx++); 254 + struct shortcut* sc = get_shortcut(current_idx++, NULL); 235 255 const char *type; 236 - int len; 256 + 237 257 if (!sc) 238 258 break; 239 259 type = type_strings[sc->type]; 240 - len = snprintf(buf, MAX_PATH, "[shortcut]\ntype: %s\ndata: ", type); 241 - write(fd, buf, len); 242 - if (sc->type == SHORTCUT_SETTING) 243 - write(fd, sc->u.setting->cfg_name, strlen(sc->u.setting->cfg_name)); 244 - else if (sc->type == SHORTCUT_TIME) 260 + 261 + fdprintf(fd, SHORTCUTS_HDR "\ntype: %s\ndata: ", type); 262 + 263 + if (sc->type == SHORTCUT_TIME) 245 264 { 246 265 #if CONFIG_RTC 247 266 if (sc->u.timedata.talktime) ··· 249 268 else 250 269 #endif 251 270 { 252 - write(fd, "sleep ", 6); 253 - if (sc->u.timedata.sleep_timeout >= 0) 254 - { 255 - len = snprintf(buf, MAX_PATH, "%d", sc->u.timedata.sleep_timeout); 256 - write(fd, buf, len); 257 - } 271 + write(fd, "sleep", 5); 272 + if(sc->u.timedata.sleep_timeout >= 0) 273 + fdprintf(fd, " %d", sc->u.timedata.sleep_timeout); 258 274 } 259 275 } 276 + else if (sc->type == SHORTCUT_SETTING_APPLY) 277 + { 278 + fdprintf(fd, "%s: %s", sc->setting->cfg_name, sc->u.path); 279 + } 280 + else if (sc->type == SHORTCUT_SETTING) 281 + { 282 + write(fd, sc->setting->cfg_name, strlen(sc->setting->cfg_name)); 283 + } 260 284 else 261 285 write(fd, sc->u.path, strlen(sc->u.path)); 262 286 263 287 /* write name:, icon:, talkclip: */ 264 - len = snprintf(buf, MAX_PATH, "\nname: %s\nicon: %d\ntalkclip: ", 265 - sc->name, sc->icon); 266 - write(fd, buf, len); 267 - write(fd, sc->talk_clip, strlen(sc->talk_clip)); 268 - write(fd, "\n\n", 2); 288 + fdprintf(fd, "\nname: %s\nicon: %d\ntalkclip: %s\n\n", 289 + sc->name, sc->icon, sc->talk_clip); 269 290 } 270 291 close(fd); 271 292 if (first_idx_to_writeback == 0) ··· 282 303 283 304 void shortcuts_add(enum shortcut_type type, const char* value) 284 305 { 285 - struct shortcut* sc = get_shortcut(shortcut_count++); 306 + struct shortcut* sc = get_shortcut(shortcut_count++, NULL); 286 307 if (!sc) 287 308 return; 288 309 init_shortcut(sc); 289 310 sc->type = type; 290 - if (type == SHORTCUT_SETTING) 291 - sc->u.setting = (void*)value; 311 + if (type == SHORTCUT_SETTING || type == SHORTCUT_SETTING_APPLY) 312 + { 313 + sc->setting = (void*)value; 314 + /* write the current value, will be ignored for SHORTCUT_SETTING */ 315 + cfg_to_string(sc->setting, sc->u.path, sizeof(sc->u.path)); 316 + } 292 317 else 293 318 strmemccpy(sc->u.path, value, MAX_PATH); 294 319 ··· 306 331 struct shortcut* sc = *param; 307 332 char *name, *value; 308 333 309 - if (!strcasecmp(skip_whitespace(buf), "[shortcut]")) 334 + buf = skip_whitespace(buf); 335 + 336 + if (!strcasecmp(buf, SHORTCUTS_HDR)) 310 337 { 311 338 if (sc && verify_shortcut(sc)) 312 339 shortcut_count++; 313 - sc = get_shortcut(shortcut_count); 340 + sc = get_shortcut(shortcut_count, NULL); 314 341 if (!sc) 315 342 return 1; 316 343 init_shortcut(sc); ··· 319 346 else if (sc && settings_parseline(buf, &name, &value)) 320 347 { 321 348 static const char * const nm_options[] = {"type", "name", "data", 322 - "icon", "talkclip", NULL}; 349 + "icon", "talkclip", NULL}; 323 350 int nm_op = string_option(name, nm_options, false); 324 351 325 352 if (nm_op == 0) /*type*/ ··· 347 374 case SHORTCUT_PLAYLISTMENU: 348 375 strmemccpy(sc->u.path, value, MAX_PATH); 349 376 break; 377 + case SHORTCUT_SETTING_APPLY: 350 378 case SHORTCUT_SETTING: 351 - sc->u.setting = find_setting_by_cfgname(value); 379 + /* can handle 'name: value' pair for either type */ 380 + if (settings_parseline(value, &name, &value)) 381 + { 382 + sc->setting = find_setting_by_cfgname(name); 383 + strmemccpy(sc->u.path, value, MAX_PATH); 384 + } 385 + else /* force SHORTCUT_SETTING, no 'name: value' pair */ 386 + { 387 + sc->type = SHORTCUT_SETTING; 388 + sc->setting = find_setting_by_cfgname(value); 389 + } 352 390 break; 353 391 case SHORTCUT_TIME: 354 392 #if CONFIG_RTC ··· 357 395 sc->u.timedata.talktime = true; 358 396 else 359 397 #endif 360 - if (!strncasecmp(value, "sleep", strlen("sleep"))) 398 + if (!strncasecmp(value, "sleep", sizeof("sleep")-1)) 361 399 { 362 400 /* 'sleep' may appear alone or followed by number after a space */ 363 - sc->u.timedata.sleep_timeout = strlen(&value[5]) > 1 ? 364 - atoi(&value[strlen("sleep ")]) : -1; 401 + if (strlen(value) > sizeof("sleep")) /* sizeof 1 larger (+space chr..) */ 402 + sc->u.timedata.sleep_timeout = atoi(&value[sizeof("sleep")-1]); 403 + else 404 + sc->u.timedata.sleep_timeout = -1; 365 405 } 366 406 else 367 407 sc->type = SHORTCUT_UNDEFINED; /* error */ ··· 374 414 } 375 415 else if (nm_op == 3) /*icon*/ 376 416 { 377 - if (!strcmp(value, "filetype") && sc->type != SHORTCUT_SETTING && sc->u.path[0]) 417 + if (!strcmp(value, "filetype") && sc->type != SHORTCUT_SETTING 418 + && sc->type != SHORTCUT_SETTING_APPLY && sc->u.path[0]) 378 419 { 379 420 sc->icon = filetype_get_icon(filetype_get_attr(sc->u.path)); 380 421 } ··· 401 442 fd = open_utf8(SHORTCUTS_FILENAME, O_RDONLY); 402 443 if (fd < 0) 403 444 return; 404 - first_handle = core_alloc_ex(sizeof(struct shortcut_handle), &shortcut_ops); 405 - if (first_handle <= 0) { 445 + h = alloc_first_sc_handle(); 446 + if (!h) { 406 447 close(fd); 407 448 return; 408 449 } 409 450 410 - h = core_get_data(first_handle); 411 - h->next_handle = 0; 412 - 413 451 /* we enter readline_cb() multiple times with a buffer 414 - obtained when we encounter a "[shortcut]" section. 452 + obtained when we encounter a SHORTCUTS_HDR ("[shortcut]") section. 415 453 fast_readline() might yield() -> protect buffer */ 416 454 ++buflib_move_lock; 417 455 ··· 429 467 char * buffer, size_t buffer_len) 430 468 { 431 469 (void)data; 432 - struct shortcut *sc = get_shortcut(selected_item); 470 + struct shortcut *sc = get_shortcut(selected_item, NULL); 433 471 if (!sc) 434 472 return ""; 435 - if (sc->type == SHORTCUT_SETTING) 436 - return sc->name[0] ? sc->name : P2STR(ID2P(sc->u.setting->lang_id)); 473 + const char *ret = sc->u.path; 474 + 475 + if (sc->type == SHORTCUT_SETTING && sc->name[0] == '\0') 476 + return P2STR(ID2P(sc->setting->lang_id)); 477 + else if (sc->type == SHORTCUT_SETTING_APPLY && sc->name[0] == '\0') 478 + { 479 + snprintf(buffer, buffer_len, "%s (%s)", 480 + P2STR(ID2P(sc->setting->lang_id)), sc->u.path); 481 + return buffer; 482 + } 437 483 else if (sc->type == SHORTCUT_SEPARATOR) 438 484 return sc->name; 439 485 else if (sc->type == SHORTCUT_TIME) ··· 463 509 } 464 510 } 465 511 466 - return sc->name[0] ? sc->name : sc->u.path; 512 + return sc->name[0] ? sc->name : ret; 467 513 } 468 514 469 515 static int shortcut_menu_speak_item(int selected_item, void * data) 470 516 { 471 517 (void)data; 472 - struct shortcut *sc = get_shortcut(selected_item); 518 + struct shortcut *sc = get_shortcut(selected_item, NULL); 473 519 if (sc) 474 520 { 475 521 if (sc->talk_clip[0]) ··· 523 569 case SHORTCUT_PLAYLISTMENU: 524 570 talk_file_or_spell(NULL, sc->u.path, NULL, false); 525 571 break; 572 + case SHORTCUT_SETTING_APPLY: 526 573 case SHORTCUT_SETTING: 527 - talk_id(sc->u.setting->lang_id, false); 574 + talk_id(sc->setting->lang_id, false); 575 + if (sc->type == SHORTCUT_SETTING_APPLY) 576 + talk_spell(sc->u.path, true); 528 577 break; 578 + 529 579 case SHORTCUT_TIME: 530 580 #if CONFIG_RTC 531 581 if (sc->u.timedata.talktime) ··· 557 607 static int shortcut_menu_get_action(int action, struct gui_synclist *lists) 558 608 { 559 609 (void)lists; 560 - if (action == ACTION_STD_OK || action == ACTION_STD_MENU) 561 - return ACTION_STD_CANCEL; 562 - else if (action == ACTION_STD_QUICKSCREEN && action != ACTION_STD_CONTEXT) 563 - return ACTION_STD_CANCEL; 564 - else if (action == ACTION_STD_CONTEXT) 610 + if (action == ACTION_STD_CONTEXT) 565 611 { 566 612 int selection = gui_synclist_get_sel_pos(lists); 567 613 ··· 580 626 first_idx_to_writeback = 0; 581 627 overwrite_shortcuts = true; 582 628 shortcuts_ata_idle_callback(); 583 - if (shortcut_count == 0) 584 - return ACTION_STD_CANCEL; 629 + 630 + if (shortcut_count > 0) 631 + { 632 + shortcut_menu_speak_item(gui_synclist_get_sel_pos(lists), NULL); 633 + return ACTION_REDRAW; 634 + } 635 + 636 + return ACTION_STD_CANCEL; 637 + } 585 638 586 - shortcut_menu_speak_item(gui_synclist_get_sel_pos(lists), NULL); 587 - return ACTION_REDRAW; 639 + if (action == ACTION_STD_OK 640 + || action == ACTION_STD_MENU 641 + || action == ACTION_STD_QUICKSCREEN) 642 + { 643 + return ACTION_STD_CANCEL; 588 644 } 645 + 589 646 return action; 590 647 } 591 648 592 649 static enum themable_icons shortcut_menu_get_icon(int selected_item, void * data) 593 650 { 651 + static const int8_t type_icons[SHORTCUT_TYPE_COUNT] = { 652 + [SHORTCUT_SETTING] = Icon_Menu_setting, 653 + [SHORTCUT_SETTING_APPLY] = Icon_Queued, 654 + [SHORTCUT_DEBUGITEM] = Icon_Menu_functioncall, 655 + [SHORTCUT_BROWSER] = Icon_Folder, 656 + [SHORTCUT_PLAYLISTMENU] = Icon_Playlist, 657 + [SHORTCUT_SEPARATOR] = Icon_NOICON, 658 + [SHORTCUT_SHUTDOWN] = Icon_System_menu, 659 + [SHORTCUT_REBOOT] = Icon_System_menu, 660 + [SHORTCUT_TIME] = Icon_Menu_functioncall, 661 + [SHORTCUT_FILE] = Icon_NOICON, 662 + }; 663 + 594 664 (void)data; 595 665 int icon; 596 - struct shortcut *sc = get_shortcut(selected_item); 666 + struct shortcut *sc = get_shortcut(selected_item, NULL); 597 667 if (!sc) 598 668 return Icon_NOICON; 599 669 if (sc->icon == Icon_NOICON) 600 670 { 601 - 602 - switch (sc->type) 671 + if (sc->type == SHORTCUT_BROWSER || sc->type == SHORTCUT_FILE) 603 672 { 604 - case SHORTCUT_FILE: 605 - return filetype_get_icon(filetype_get_attr(sc->u.path)); 606 - case SHORTCUT_BROWSER: 607 - icon = filetype_get_icon(filetype_get_attr(sc->u.path)); 608 - if (icon <= 0) 609 - icon = Icon_Folder; 673 + icon = filetype_get_icon(filetype_get_attr(sc->u.path)); 674 + if (icon > 0) 610 675 return icon; 611 - case SHORTCUT_SETTING: 612 - return Icon_Menu_setting; 613 - case SHORTCUT_DEBUGITEM: 614 - return Icon_Menu_functioncall; 615 - case SHORTCUT_PLAYLISTMENU: 616 - return Icon_Playlist; 617 - case SHORTCUT_SHUTDOWN: 618 - case SHORTCUT_REBOOT: 619 - return Icon_System_menu; 620 - case SHORTCUT_TIME: 621 - return Icon_Menu_functioncall; 622 - default: 623 - break; 624 676 } 677 + /* excluding SHORTCUT_UNDEFINED (-1) */ 678 + if (sc->type >= 0 && sc->type < SHORTCUT_TYPE_COUNT) 679 + return type_icons[sc->type]; 625 680 } 626 681 return sc->icon; 627 682 } 628 683 684 + static void apply_new_setting(const struct settings_list *setting) 685 + { 686 + settings_apply(false); 687 + if (setting->flags & F_THEMESETTING) 688 + { 689 + settings_apply_skins(); 690 + } 691 + if (setting->setting == &global_settings.sleeptimer_duration && get_sleep_timer()) 692 + { 693 + set_sleeptimer_duration(global_settings.sleeptimer_duration); 694 + } 695 + } 696 + 629 697 int do_shortcut_menu(void *ignored) 630 698 { 631 699 (void)ignored; ··· 665 733 break; 666 734 else 667 735 { 668 - sc = get_shortcut(list.selection); 736 + sc = get_shortcut(list.selection, NULL); 669 737 670 738 if (!sc) 671 739 continue; ··· 711 779 712 780 } 713 781 break; 782 + case SHORTCUT_SETTING_APPLY: 783 + { 784 + bool theme_changed; 785 + string_to_cfg(sc->setting->cfg_name, sc->u.path, &theme_changed); 786 + settings_save(); 787 + apply_new_setting(sc->setting); 788 + break; 789 + } 714 790 case SHORTCUT_SETTING: 715 791 { 716 - int old_sleeptimer_duration = global_settings.sleeptimer_duration; 717 - #ifdef HAVE_ALBUMART 718 - int old_album_art = global_settings.album_art; 719 - #endif 720 - do_setting_screen(sc->u.setting, 721 - sc->name[0] ? sc->name : P2STR(ID2P(sc->u.setting->lang_id)),NULL); 722 - 723 - #ifdef HAVE_ALBUMART 724 - if (old_album_art != global_settings.album_art) 725 - set_albumart_mode(global_settings.album_art); 726 - #endif 727 - if (old_sleeptimer_duration != global_settings.sleeptimer_duration && 728 - get_sleep_timer()) 729 - set_sleeptimer_duration(global_settings.sleeptimer_duration); 792 + do_setting_screen(sc->setting, 793 + sc->name[0] ? sc->name : P2STR(ID2P(sc->setting->lang_id)),NULL); 794 + apply_new_setting(sc->setting); 730 795 break; 731 796 } 732 797 case SHORTCUT_DEBUGITEM:
+1
apps/shortcuts.h
··· 30 30 SHORTCUT_FILE, 31 31 SHORTCUT_DEBUGITEM, 32 32 SHORTCUT_BROWSER, 33 + SHORTCUT_SETTING_APPLY, 33 34 SHORTCUT_PLAYLISTMENU, 34 35 SHORTCUT_SEPARATOR, 35 36 SHORTCUT_SHUTDOWN,
+5
manual/main_menu/main.tex
··· 286 286 a specified file or folder 287 287 \item A file's or folder's ``Playing Next...'' context menu item can 288 288 be displayed 289 + \item A settings current value (any which can be added to the 290 + \setting{Quick Screen}) 289 291 \item A setting can be configured (any which can be added to the 290 292 \setting{Quick Screen}) 291 293 \item A debug menu item can be displayed (useful for developers mostly) ··· 320 322 \item[playlist menu] \config{data} is the file or the folder to open the 321 323 ``Playing Next...'' context menu item on (see \reference{ref:playingnext_submenu}) 322 324 \item[setting] \config{data} is the config name of the setting you want to change 325 + (see \reference{ref:config_file_options} for the list of the possible settings) 326 + \item[apply] \config{data} is the config name of the setting followed by ':' 327 + and the value you want applied. ex. 'data: volume: 20' would set the volume to 20 when selected 323 328 (see \reference{ref:config_file_options} for the list of the possible settings) 324 329 \item[debug] \config{data} is the name of the debug menu item to display 325 330 \item[separator] \config{data} is ignored; \config{name} can be used to display text,