1 /*  RetroArch - A frontend for libretro.
2  *  Copyright (C) 2011-2017 - Daniel De Matteis
3  *
4  *  RetroArch is free software: you can redistribute it and/or modify it under the terms
5  *  of the GNU General Public License as published by the Free Software Found-
6  *  ation, either version 3 of the License, or (at your option) any later version.
7  *
8  *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9  *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10  *  PURPOSE.  See the GNU General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License along with RetroArch.
13  *  If not, see <http://www.gnu.org/licenses/>.
14  */
15 
16 #include <compat/strl.h>
17 #include <file/file_path.h>
18 #include <string/stdstring.h>
19 #include <lists/string_list.h>
20 
21 #ifdef HAVE_CONFIG_H
22 #include "../../config.h"
23 #endif
24 
25 #include "../menu_driver.h"
26 #include "../menu_entries.h"
27 #include "../menu_cbs.h"
28 #include "../menu_input.h"
29 #include "../menu_setting.h"
30 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
31 #include "../menu_shader.h"
32 #endif
33 
34 #include "../../configuration.h"
35 #include "../../core.h"
36 #include "../../core_info.h"
37 #ifdef HAVE_CHEATS
38 #include "../../cheat_manager.h"
39 #endif
40 #include "../../file_path_special.h"
41 #include "../../driver.h"
42 #include "../../retroarch.h"
43 #include "../../network/netplay/netplay.h"
44 #include "../../playlist.h"
45 #include "../../manual_content_scan.h"
46 #include "../misc/cpufreq/cpufreq.h"
47 
48 #ifndef BIND_ACTION_LEFT
49 #define BIND_ACTION_LEFT(cbs, name) (cbs)->action_left = (name)
50 #endif
51 
52 /* Forward declarations */
53 int action_ok_core_lock(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx);
54 
55 extern struct key_desc key_descriptors[RARCH_MAX_KEYS];
56 
57 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
generic_shader_action_parameter_left(struct video_shader_parameter * param,unsigned type,const char * label,bool wraparound)58 static int generic_shader_action_parameter_left(
59       struct video_shader_parameter *param,
60       unsigned type, const char *label, bool wraparound)
61 {
62    param->current -= param->step;
63    param->current  = MIN(MAX(param->minimum, param->current),
64          param->maximum);
65    return 0;
66 }
67 
shader_action_parameter_left_internal(unsigned type,const char * label,bool wraparound,unsigned offset)68 static int shader_action_parameter_left_internal(unsigned type, const char *label, bool wraparound,
69       unsigned offset)
70 {
71    video_shader_ctx_t shader_info;
72    struct video_shader *shader          = menu_shader_get();
73    struct video_shader_parameter *param_menu = NULL;
74    struct video_shader_parameter *param_prev = NULL;
75 
76    int ret = 0;
77 
78    video_shader_driver_get_current_shader(&shader_info);
79 
80    param_prev = &shader_info.data->parameters[type - offset];
81    param_menu = shader ? &shader->parameters [type - offset] : NULL;
82 
83    if (!param_prev || !param_menu)
84       return menu_cbs_exit();
85    ret = generic_shader_action_parameter_left(param_prev, type, label, wraparound);
86 
87    param_menu->current = param_prev->current;
88 
89    shader->modified    = true;
90 
91    return ret;
92 }
93 
shader_action_parameter_left(unsigned type,const char * label,bool wraparound)94 static int shader_action_parameter_left(unsigned type, const char *label, bool wraparound)
95 {
96    return shader_action_parameter_left_internal(type, label, wraparound, MENU_SETTINGS_SHADER_PARAMETER_0);
97 }
98 
shader_action_preset_parameter_left(unsigned type,const char * label,bool wraparound)99 static int shader_action_preset_parameter_left(unsigned type, const char *label, bool wraparound)
100 {
101    return shader_action_parameter_left_internal(type, label, wraparound, MENU_SETTINGS_SHADER_PRESET_PARAMETER_0);
102 }
103 #endif
104 
105 #ifdef HAVE_AUDIOMIXER
audio_mixer_stream_volume_left(unsigned type,const char * label,bool wraparound)106 static int audio_mixer_stream_volume_left(unsigned type, const char *label,
107       bool wraparound)
108 {
109    unsigned         offset      = (type - MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_VOLUME_BEGIN);
110    float orig_volume            = 0.0f;
111 
112    if (offset >= AUDIO_MIXER_MAX_STREAMS)
113       return 0;
114 
115    orig_volume                  = audio_driver_mixer_get_stream_volume(offset);
116    orig_volume                  = orig_volume - 1.00f;
117 
118    audio_driver_mixer_set_stream_volume(offset, orig_volume);
119 
120    return 0;
121 }
122 #endif
123 
124 #ifdef HAVE_CHEATS
action_left_cheat(unsigned type,const char * label,bool wraparound)125 static int action_left_cheat(unsigned type, const char *label,
126       bool wraparound)
127 {
128    size_t idx             = type - MENU_SETTINGS_CHEAT_BEGIN;
129    return generic_action_cheat_toggle(idx, type, label,
130          wraparound);
131 }
132 #endif
133 
action_left_input_desc(unsigned type,const char * label,bool wraparound)134 static int action_left_input_desc(unsigned type, const char *label,
135    bool wraparound)
136 {
137    rarch_system_info_t *system           = runloop_get_system_info();
138    settings_t *settings                  = config_get_ptr();
139    unsigned btn_idx;
140    unsigned user_idx;
141    unsigned remap_idx;
142    unsigned bind_idx;
143    unsigned mapped_port;
144 
145    if (!settings || !system)
146       return 0;
147 
148    user_idx    = (type - MENU_SETTINGS_INPUT_DESC_BEGIN) / (RARCH_FIRST_CUSTOM_BIND + 8);
149    btn_idx     = (type - MENU_SETTINGS_INPUT_DESC_BEGIN) - (RARCH_FIRST_CUSTOM_BIND + 8) * user_idx;
150    mapped_port = settings->uints.input_remap_ports[user_idx];
151 
152    if (settings->uints.input_remap_ids[user_idx][btn_idx] == RARCH_UNMAPPED)
153       settings->uints.input_remap_ids[user_idx][btn_idx] = RARCH_CUSTOM_BIND_LIST_END - 1;
154 
155    remap_idx = settings->uints.input_remap_ids[user_idx][btn_idx];
156    for (bind_idx = 0; bind_idx < RARCH_ANALOG_BIND_LIST_END; bind_idx++)
157    {
158       if (input_config_bind_order[bind_idx] == remap_idx)
159          break;
160    }
161 
162    if (bind_idx > 0)
163    {
164       if (bind_idx > RARCH_ANALOG_BIND_LIST_END)
165          settings->uints.input_remap_ids[user_idx][btn_idx]--;
166       else
167       {
168          bind_idx--;
169          bind_idx = input_config_bind_order[bind_idx];
170          settings->uints.input_remap_ids[user_idx][btn_idx] = bind_idx;
171       }
172    }
173    else if (bind_idx == 0)
174       settings->uints.input_remap_ids[user_idx][btn_idx] = RARCH_UNMAPPED;
175    else
176       settings->uints.input_remap_ids[user_idx][btn_idx] = RARCH_CUSTOM_BIND_LIST_END - 1;
177 
178    remap_idx = settings->uints.input_remap_ids[user_idx][btn_idx];
179 
180    /* skip the not used buttons (unless they are at the end by calling the right desc function recursively
181       also skip all the axes until analog remapping is implemented */
182    if (remap_idx != RARCH_UNMAPPED)
183    {
184       if ((string_is_empty(system->input_desc_btn[mapped_port][remap_idx]) && remap_idx < RARCH_CUSTOM_BIND_LIST_END) /*||
185           (remap_idx >= RARCH_FIRST_CUSTOM_BIND && remap_idx < RARCH_CUSTOM_BIND_LIST_END)*/)
186          action_left_input_desc(type, label, wraparound);
187    }
188 
189    return 0;
190 }
191 
action_left_input_desc_kbd(unsigned type,const char * label,bool wraparound)192 static int action_left_input_desc_kbd(unsigned type, const char *label,
193    bool wraparound)
194 {
195    unsigned remap_id;
196    unsigned key_id, user_idx, btn_idx;
197    settings_t *settings = config_get_ptr();
198 
199    if (!settings)
200       return 0;
201 
202    user_idx = (type - MENU_SETTINGS_INPUT_DESC_KBD_BEGIN) / RARCH_ANALOG_BIND_LIST_END;
203    btn_idx  = (type - MENU_SETTINGS_INPUT_DESC_KBD_BEGIN) - RARCH_ANALOG_BIND_LIST_END * user_idx;
204 
205    remap_id =
206       settings->uints.input_keymapper_ids[user_idx][btn_idx];
207 
208    for (key_id = 0; key_id < RARCH_MAX_KEYS; key_id++)
209    {
210       if (remap_id == key_descriptors[key_id].key)
211          break;
212    }
213 
214    if (key_id > 0)
215       key_id--;
216    else
217       key_id = RARCH_MAX_KEYS - 1;
218 
219    settings->uints.input_keymapper_ids[user_idx][btn_idx] = key_descriptors[key_id].key;
220 
221    return 0;
222 }
223 
action_left_scroll(unsigned type,const char * label,bool wraparound)224 static int action_left_scroll(unsigned type, const char *label,
225       bool wraparound)
226 {
227    size_t scroll_accel   = 0;
228    unsigned scroll_speed = 0, fast_scroll_speed = 0;
229    size_t selection      = menu_navigation_get_selection();
230 
231    if (!menu_driver_ctl(MENU_NAVIGATION_CTL_GET_SCROLL_ACCEL, &scroll_accel))
232       return false;
233 
234    scroll_speed          = (unsigned)((MAX(scroll_accel, 2) - 2) / 4 + 1);
235    fast_scroll_speed     = 4 + 4 * scroll_speed;
236 
237    if (selection > fast_scroll_speed)
238    {
239       size_t idx  = selection - fast_scroll_speed;
240       menu_navigation_set_selection(idx);
241       menu_driver_navigation_set(true);
242    }
243    else
244    {
245       bool pending_push = false;
246       menu_driver_ctl(MENU_NAVIGATION_CTL_CLEAR, &pending_push);
247    }
248 
249    return 0;
250 }
251 
action_left_goto_tab(void)252 static int action_left_goto_tab(void)
253 {
254    menu_ctx_list_t list_info;
255    file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0);
256 
257    list_info.type             = MENU_LIST_HORIZONTAL;
258    list_info.action           = MENU_ACTION_LEFT;
259 
260    menu_driver_list_cache(&list_info);
261 
262    return menu_driver_deferred_push_content_list(selection_buf);
263 }
264 
action_left_mainmenu(unsigned type,const char * label,bool wraparound)265 static int action_left_mainmenu(unsigned type, const char *label,
266       bool wraparound)
267 {
268    menu_ctx_list_t list_info;
269    settings_t            *settings = config_get_ptr();
270    bool menu_nav_wraparound_enable = settings->bools.menu_navigation_wraparound_enable;
271    const char *menu_ident          = menu_driver_ident();
272 
273    menu_driver_list_get_selection(&list_info);
274 
275    list_info.type = MENU_LIST_PLAIN;
276 
277    menu_driver_list_get_size(&list_info);
278 
279    /* Tab switching functionality only applies
280     * to XMB */
281    if ((list_info.size == 1) &&
282        string_is_equal(menu_ident, "xmb"))
283    {
284       if ((list_info.selection != 0) || menu_nav_wraparound_enable)
285          return action_left_goto_tab();
286    }
287    else
288       action_left_scroll(0, "", false);
289 
290    return 0;
291 }
292 
293 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
action_left_shader_scale_pass(unsigned type,const char * label,bool wraparound)294 static int action_left_shader_scale_pass(unsigned type, const char *label,
295       bool wraparound)
296 {
297    unsigned current_scale, delta;
298    unsigned pass                         = type -
299       MENU_SETTINGS_SHADER_PASS_SCALE_0;
300    struct video_shader *shader           = menu_shader_get();
301    struct video_shader_pass *shader_pass = shader ? &shader->pass[pass] : NULL;
302 
303    if (!shader_pass)
304       return menu_cbs_exit();
305 
306    current_scale            = shader_pass->fbo.scale_x;
307    delta                    = 5;
308    current_scale            = (current_scale + delta) % 6;
309 
310    shader_pass->fbo.valid   = current_scale;
311    shader_pass->fbo.scale_x = current_scale;
312    shader_pass->fbo.scale_y = current_scale;
313 
314    shader->modified         = true;
315 
316    return 0;
317 }
318 
action_left_shader_filter_pass(unsigned type,const char * label,bool wraparound)319 static int action_left_shader_filter_pass(unsigned type, const char *label,
320       bool wraparound)
321 {
322    unsigned delta = 2;
323    unsigned pass                         = type - MENU_SETTINGS_SHADER_PASS_FILTER_0;
324    struct video_shader *shader           = menu_shader_get();
325    struct video_shader_pass *shader_pass = shader ? &shader->pass[pass] : NULL;
326 
327    if (!shader_pass)
328       return menu_cbs_exit();
329 
330    shader_pass->filter                   = ((shader_pass->filter + delta) % 3);
331    shader->modified                      = true;
332 
333    return 0;
334 }
335 
action_left_shader_filter_default(unsigned type,const char * label,bool wraparound)336 static int action_left_shader_filter_default(unsigned type, const char *label,
337       bool wraparound)
338 {
339    rarch_setting_t *setting = menu_setting_find_enum(
340          MENU_ENUM_LABEL_VIDEO_SMOOTH);
341    if (!setting)
342       return menu_cbs_exit();
343    return menu_action_handle_setting(setting,
344          setting->type, MENU_ACTION_LEFT, wraparound);
345 }
346 #endif
347 
348 #ifdef HAVE_CHEATS
action_left_cheat_num_passes(unsigned type,const char * label,bool wraparound)349 static int action_left_cheat_num_passes(unsigned type, const char *label,
350       bool wraparound)
351 {
352    bool refresh      = false;
353    unsigned new_size = 0;
354 
355    if (cheat_manager_get_size())
356       new_size = cheat_manager_get_size() - 1;
357    menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
358    menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
359    cheat_manager_realloc(new_size, CHEAT_HANDLER_TYPE_EMU);
360 
361    return 0;
362 }
363 #endif
364 
365 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
action_left_shader_num_passes(unsigned type,const char * label,bool wraparound)366 static int action_left_shader_num_passes(unsigned type, const char *label,
367       bool wraparound)
368 {
369    bool refresh      = false;
370    struct video_shader *shader = menu_shader_get();
371    unsigned pass_count         = shader ? shader->passes : 0;
372 
373    if (!shader)
374       return menu_cbs_exit();
375 
376    if (pass_count > 0)
377       shader->passes--;
378 
379    menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
380    menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
381    video_shader_resolve_parameters(shader);
382 
383    shader->modified                      = true;
384 
385    return 0;
386 }
387 #endif
388 
action_left_video_resolution(unsigned type,const char * label,bool wraparound)389 static int action_left_video_resolution(unsigned type, const char *label,
390       bool wraparound)
391 {
392    video_driver_get_prev_video_out();
393    return 0;
394 }
395 
playlist_association_left(unsigned type,const char * label,bool wraparound)396 static int playlist_association_left(unsigned type, const char *label,
397       bool wraparound)
398 {
399    char core_filename[PATH_MAX_LENGTH];
400    size_t i, current                = 0;
401    size_t next                      = 0;
402    playlist_t *playlist             = playlist_get_cached();
403    const char *default_core_path    = playlist_get_default_core_path(playlist);
404    bool default_core_set            = false;
405    core_info_list_t *core_info_list = NULL;
406    core_info_t *core_info           = NULL;
407 
408    core_filename[0] = '\0';
409 
410    if (!playlist)
411       return -1;
412 
413    core_info_get_list(&core_info_list);
414    if (!core_info_list)
415       return menu_cbs_exit();
416 
417    /* Get current core path association */
418    if (!string_is_empty(default_core_path) &&
419        !string_is_equal(default_core_path, "DETECT"))
420    {
421       const char *default_core_filename = path_basename(default_core_path);
422       if (!string_is_empty(default_core_filename))
423       {
424          strlcpy(core_filename, default_core_filename, sizeof(core_filename));
425          default_core_set = true;
426       }
427    }
428 
429    /* Sort cores alphabetically */
430    core_info_qsort(core_info_list, CORE_INFO_LIST_SORT_DISPLAY_NAME);
431 
432    /* If a core is currently associated... */
433    if (default_core_set)
434    {
435       /* ...get its index */
436       for (i = 0; i < core_info_list->count; i++)
437       {
438          core_info = NULL;
439          core_info = core_info_get(core_info_list, i);
440          if (!core_info)
441             continue;
442          if (string_starts_with(core_filename, core_info->core_file_id.str))
443             current = i;
444       }
445 
446       /* ...then decrement it */
447       if (current == 0)
448          /* Unset core association (DETECT) */
449          default_core_set = false;
450       else
451          next = current - 1;
452    }
453    /* If a core is *not* currently associated and
454     * wraparound is enabled, select last core in
455     * the list */
456    else if (wraparound && (core_info_list->count > 1))
457    {
458       next             = core_info_list->count - 1;
459       default_core_set = true;
460    }
461 
462    /* If a core is now associated, get new core info */
463    core_info = NULL;
464    if (default_core_set)
465       core_info = core_info_get(core_info_list, next);
466 
467    /* Update playlist */
468    playlist_set_default_core_path(playlist, core_info ? core_info->path         : "DETECT");
469    playlist_set_default_core_name(playlist, core_info ? core_info->display_name : "DETECT");
470    playlist_write_file(playlist);
471 
472    return 0;
473 }
474 
playlist_label_display_mode_left(unsigned type,const char * label,bool wraparound)475 static int playlist_label_display_mode_left(unsigned type, const char *label,
476       bool wraparound)
477 {
478    enum playlist_label_display_mode label_display_mode;
479    playlist_t *playlist = playlist_get_cached();
480 
481    if (!playlist)
482       return -1;
483 
484    label_display_mode = playlist_get_label_display_mode(playlist);
485 
486    if (label_display_mode != LABEL_DISPLAY_MODE_DEFAULT)
487       label_display_mode = (enum playlist_label_display_mode)((int)label_display_mode - 1);
488    else if (wraparound)
489       label_display_mode = LABEL_DISPLAY_MODE_KEEP_REGION_AND_DISC_INDEX;
490 
491    playlist_set_label_display_mode(playlist, label_display_mode);
492    playlist_write_file(playlist);
493 
494    return 0;
495 }
496 
playlist_thumbnail_mode_left(playlist_t * playlist,enum playlist_thumbnail_id thumbnail_id,bool wraparound)497 static void playlist_thumbnail_mode_left(playlist_t *playlist, enum playlist_thumbnail_id thumbnail_id,
498       bool wraparound)
499 {
500    enum playlist_thumbnail_mode thumbnail_mode =
501          playlist_get_thumbnail_mode(playlist, thumbnail_id);
502 
503    if (thumbnail_mode > PLAYLIST_THUMBNAIL_MODE_DEFAULT)
504       thumbnail_mode = (enum playlist_thumbnail_mode)((unsigned)thumbnail_mode - 1);
505    else if (wraparound)
506       thumbnail_mode = PLAYLIST_THUMBNAIL_MODE_BOXARTS;
507 
508    playlist_set_thumbnail_mode(playlist, thumbnail_id, thumbnail_mode);
509    playlist_write_file(playlist);
510 }
511 
playlist_right_thumbnail_mode_left(unsigned type,const char * label,bool wraparound)512 static int playlist_right_thumbnail_mode_left(unsigned type, const char *label,
513       bool wraparound)
514 {
515    playlist_t *playlist = playlist_get_cached();
516 
517    if (!playlist)
518       return -1;
519 
520    playlist_thumbnail_mode_left(playlist, PLAYLIST_THUMBNAIL_RIGHT, wraparound);
521 
522    return 0;
523 }
524 
playlist_left_thumbnail_mode_left(unsigned type,const char * label,bool wraparound)525 static int playlist_left_thumbnail_mode_left(unsigned type, const char *label,
526       bool wraparound)
527 {
528    playlist_t *playlist = playlist_get_cached();
529 
530    if (!playlist)
531       return -1;
532 
533    playlist_thumbnail_mode_left(playlist, PLAYLIST_THUMBNAIL_LEFT, wraparound);
534 
535    return 0;
536 }
537 
playlist_sort_mode_left(unsigned type,const char * label,bool wraparound)538 static int playlist_sort_mode_left(unsigned type, const char *label,
539       bool wraparound)
540 {
541    enum playlist_sort_mode sort_mode;
542    playlist_t *playlist = playlist_get_cached();
543 
544    if (!playlist)
545       return -1;
546 
547    sort_mode = playlist_get_sort_mode(playlist);
548 
549    if (sort_mode > PLAYLIST_SORT_MODE_DEFAULT)
550       sort_mode = (enum playlist_sort_mode)((int)sort_mode - 1);
551    else if (wraparound)
552       sort_mode = PLAYLIST_SORT_MODE_OFF;
553 
554    playlist_set_sort_mode(playlist, sort_mode);
555    playlist_write_file(playlist);
556 
557    return 0;
558 }
559 
manual_content_scan_system_name_left(unsigned type,const char * label,bool wraparound)560 static int manual_content_scan_system_name_left(
561       unsigned type, const char *label,
562       bool wraparound)
563 {
564    settings_t *settings              = config_get_ptr();
565    bool show_hidden_files            = settings->bools.show_hidden_files;
566 #ifdef HAVE_LIBRETRODB
567    const char *path_content_database = settings->paths.path_content_database;
568    struct string_list *system_name_list                            =
569       manual_content_scan_get_menu_system_name_list(path_content_database, show_hidden_files);
570 #else
571    struct string_list *system_name_list                            =
572       manual_content_scan_get_menu_system_name_list(NULL, show_hidden_files);
573 #endif
574    const char *current_system_name                                 = NULL;
575    enum manual_content_scan_system_name_type next_system_name_type =
576          MANUAL_CONTENT_SCAN_SYSTEM_NAME_DATABASE;
577    const char *next_system_name                                    = NULL;
578    unsigned current_index                                          = 0;
579    unsigned next_index                                             = 0;
580    unsigned i;
581 
582    if (!system_name_list)
583       return -1;
584 
585    /* Get currently selected system name */
586    if (manual_content_scan_get_menu_system_name(&current_system_name))
587    {
588       /* Get index of currently selected system name */
589       for (i = 0; i < system_name_list->size; i++)
590       {
591          const char *system_name = system_name_list->elems[i].data;
592 
593          if (string_is_equal(current_system_name, system_name))
594          {
595             current_index = i;
596             break;
597          }
598       }
599 
600       /* Decrement index */
601       if (current_index > 0)
602          next_index = current_index - 1;
603       else if (wraparound && (system_name_list->size > 1))
604          next_index = (unsigned)(system_name_list->size - 1);
605    }
606 
607    /* Get new system name parameters */
608    if (next_index == (unsigned)MANUAL_CONTENT_SCAN_SYSTEM_NAME_CONTENT_DIR)
609       next_system_name_type = MANUAL_CONTENT_SCAN_SYSTEM_NAME_CONTENT_DIR;
610    else if (next_index == (unsigned)MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM)
611       next_system_name_type = MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM;
612 
613    next_system_name = system_name_list->elems[next_index].data;
614 
615    /* Set system name */
616    manual_content_scan_set_menu_system_name(
617          next_system_name_type, next_system_name);
618 
619    /* Clean up */
620    string_list_free(system_name_list);
621 
622    return 0;
623 }
624 
manual_content_scan_core_name_left(unsigned type,const char * label,bool wraparound)625 static int manual_content_scan_core_name_left(unsigned type, const char *label,
626       bool wraparound)
627 {
628    struct string_list *core_name_list                =
629          manual_content_scan_get_menu_core_name_list();
630    const char *current_core_name                     = NULL;
631    enum manual_content_scan_core_type next_core_type =
632          MANUAL_CONTENT_SCAN_CORE_SET;
633    const char *next_core_name                        = NULL;
634    unsigned current_index                            = 0;
635    unsigned next_index                               = 0;
636    unsigned i;
637 
638    if (!core_name_list)
639       return -1;
640 
641    /* Get currently selected core name */
642    if (manual_content_scan_get_menu_core_name(&current_core_name))
643    {
644       /* Get index of currently selected core name */
645       for (i = 0; i < core_name_list->size; i++)
646       {
647          const char *core_name = core_name_list->elems[i].data;
648 
649          if (string_is_equal(current_core_name, core_name))
650          {
651             current_index = i;
652             break;
653          }
654       }
655 
656       /* Decrement index */
657       if (current_index > 0)
658          next_index = current_index - 1;
659       else if (wraparound && (core_name_list->size > 1))
660          next_index = (unsigned)(core_name_list->size - 1);
661    }
662 
663    /* Get new core name parameters */
664    if (next_index == (unsigned)MANUAL_CONTENT_SCAN_CORE_DETECT)
665       next_core_type = MANUAL_CONTENT_SCAN_CORE_DETECT;
666 
667    next_core_name = core_name_list->elems[next_index].data;
668 
669    /* Set core name */
670    manual_content_scan_set_menu_core_name(
671          next_core_type, next_core_name);
672 
673    /* Clean up */
674    string_list_free(core_name_list);
675 
676    return 0;
677 }
678 
679 #ifdef HAVE_LAKKA
cpu_policy_mode_change(unsigned type,const char * label,bool wraparound)680 static int cpu_policy_mode_change(unsigned type, const char *label,
681       bool wraparound)
682 {
683    bool refresh = false;
684    enum cpu_scaling_mode mode = get_cpu_scaling_mode(NULL);
685    if (mode != CPUSCALING_MANAGED_PERFORMANCE)
686       mode--;
687    set_cpu_scaling_mode(mode, NULL);
688    menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
689    return 0;
690 }
691 
cpu_policy_freq_managed_tweak(unsigned type,const char * label,bool wraparound)692 static int cpu_policy_freq_managed_tweak(unsigned type, const char *label,
693       bool wraparound)
694 {
695    bool refresh = false;
696    cpu_scaling_opts_t opts;
697    enum cpu_scaling_mode mode = get_cpu_scaling_mode(&opts);
698 
699    switch (type) {
700    case MENU_SETTINGS_CPU_MANAGED_SET_MINFREQ:
701       opts.min_freq = get_cpu_scaling_next_frequency_limit(
702          opts.min_freq, -1);
703       set_cpu_scaling_mode(mode, &opts);
704       break;
705    case MENU_SETTINGS_CPU_MANAGED_SET_MAXFREQ:
706       opts.max_freq = get_cpu_scaling_next_frequency_limit(
707          opts.max_freq, -1);
708       set_cpu_scaling_mode(mode, &opts);
709       break;
710    };
711 
712    return 0;
713 }
714 
cpu_policy_freq_managed_gov(unsigned type,const char * label,bool wraparound)715 static int cpu_policy_freq_managed_gov(unsigned type, const char *label,
716       bool wraparound)
717 {
718    int pidx;
719    bool refresh = false;
720    cpu_scaling_opts_t opts;
721    enum cpu_scaling_mode mode = get_cpu_scaling_mode(&opts);
722    cpu_scaling_driver_t **drivers = get_cpu_scaling_drivers(false);
723 
724    /* Using drivers[0] governors, should be improved */
725    if (!drivers || !drivers[0])
726       return -1;
727 
728    switch (atoi(label)) {
729    case 0:
730       pidx = string_list_find_elem(drivers[0]->available_governors,
731          opts.main_policy);
732       if (pidx > 1)
733       {
734          strlcpy(opts.main_policy,
735             drivers[0]->available_governors->elems[pidx-2].data,
736             sizeof(opts.main_policy));
737          set_cpu_scaling_mode(mode, &opts);
738       }
739       break;
740    case 1:
741       pidx = string_list_find_elem(drivers[0]->available_governors,
742          opts.menu_policy);
743       if (pidx > 1)
744       {
745          strlcpy(opts.menu_policy,
746             drivers[0]->available_governors->elems[pidx-2].data,
747             sizeof(opts.menu_policy));
748          set_cpu_scaling_mode(mode, &opts);
749       }
750       break;
751    };
752 
753    return 0;
754 }
755 
cpu_policy_freq_tweak(unsigned type,const char * label,bool wraparound)756 static int cpu_policy_freq_tweak(unsigned type, const char *label,
757       bool wraparound)
758 {
759    bool refresh = false;
760    cpu_scaling_driver_t **drivers = get_cpu_scaling_drivers(false);
761    unsigned policyid = atoi(label);
762    uint32_t next_freq;
763    if (!drivers)
764      return 0;
765 
766    switch (type) {
767    case MENU_SETTINGS_CPU_POLICY_SET_MINFREQ:
768       next_freq = get_cpu_scaling_next_frequency(drivers[policyid],
769          drivers[policyid]->min_policy_freq, -1);
770       set_cpu_scaling_min_frequency(drivers[policyid], next_freq);
771       break;
772    case MENU_SETTINGS_CPU_POLICY_SET_MAXFREQ:
773       next_freq = get_cpu_scaling_next_frequency(drivers[policyid],
774          drivers[policyid]->max_policy_freq, -1);
775       set_cpu_scaling_max_frequency(drivers[policyid], next_freq);
776       break;
777    case MENU_SETTINGS_CPU_POLICY_SET_GOVERNOR:
778    {
779       int pidx = string_list_find_elem(drivers[policyid]->available_governors,
780          drivers[policyid]->scaling_governor);
781       if (pidx > 1)
782       {
783          set_cpu_scaling_governor(drivers[policyid],
784             drivers[policyid]->available_governors->elems[pidx-2].data);
785       }
786       break;
787    }
788    };
789 
790    return 0;
791 }
792 #endif
793 
core_setting_left(unsigned type,const char * label,bool wraparound)794 static int core_setting_left(unsigned type, const char *label,
795       bool wraparound)
796 {
797    unsigned idx     = type - MENU_SETTINGS_CORE_OPTION_START;
798 
799    rarch_ctl(RARCH_CTL_CORE_OPTION_PREV, &idx);
800 
801    return 0;
802 }
803 
action_left_core_lock(unsigned type,const char * label,bool wraparound)804 static int action_left_core_lock(unsigned type, const char *label,
805       bool wraparound)
806 {
807    return action_ok_core_lock(label, label, type, 0, 0);
808 }
809 
disk_options_disk_idx_left(unsigned type,const char * label,bool wraparound)810 static int disk_options_disk_idx_left(unsigned type, const char *label,
811       bool wraparound)
812 {
813    /* Note: Menu itself provides visual feedback - no
814     * need to print info message to screen */
815    bool print_log = false;
816 
817    command_event(CMD_EVENT_DISK_PREV, &print_log);
818 
819    return 0;
820 }
821 
action_left_video_gpu_index(unsigned type,const char * label,bool wraparound)822 static int action_left_video_gpu_index(unsigned type, const char *label,
823       bool wraparound)
824 {
825    enum gfx_ctx_api api = video_context_driver_get_api();
826 
827    switch (api)
828    {
829 #ifdef HAVE_VULKAN
830       case GFX_CTX_VULKAN_API:
831       {
832          struct string_list *list = video_driver_get_gpu_api_devices(api);
833 
834          if (list)
835          {
836             settings_t *settings = config_get_ptr();
837             int vulkan_gpu_index = settings->ints.vulkan_gpu_index;
838 
839             if (vulkan_gpu_index > 0)
840             {
841                configuration_set_int(settings,
842                      settings->ints.vulkan_gpu_index,
843                      vulkan_gpu_index - 1);
844             }
845             else
846             {
847                configuration_set_int(settings,
848                      settings->ints.vulkan_gpu_index,
849                      list->size - 1);
850             }
851          }
852 
853          break;
854       }
855 #endif
856 #ifdef HAVE_D3D10
857       case GFX_CTX_DIRECT3D10_API:
858       {
859          struct string_list *list = video_driver_get_gpu_api_devices(api);
860 
861          if (list)
862          {
863             settings_t *settings = config_get_ptr();
864             int d3d10_gpu_index  = settings->ints.d3d10_gpu_index;
865             if (d3d10_gpu_index > 0)
866             {
867                configuration_set_int(settings,
868                      settings->ints.d3d10_gpu_index,
869                      settings->ints.d3d10_gpu_index - 1);
870             }
871             else
872             {
873                configuration_set_int(settings,
874                      settings->ints.d3d10_gpu_index,
875                      list->size - 1);
876             }
877          }
878 
879          break;
880       }
881 #endif
882 #ifdef HAVE_D3D11
883       case GFX_CTX_DIRECT3D11_API:
884       {
885          struct string_list *list = video_driver_get_gpu_api_devices(api);
886 
887          if (list)
888          {
889             settings_t *settings = config_get_ptr();
890             int d3d11_gpu_index  = settings->ints.d3d11_gpu_index;
891             if (d3d11_gpu_index > 0)
892             {
893                configuration_set_int(settings,
894                      settings->ints.d3d11_gpu_index,
895                      settings->ints.d3d11_gpu_index - 1);
896             }
897             else
898             {
899                configuration_set_int(settings,
900                      settings->ints.d3d11_gpu_index,
901                      list->size - 1);
902             }
903          }
904 
905          break;
906       }
907 #endif
908 #ifdef HAVE_D3D12
909       case GFX_CTX_DIRECT3D12_API:
910       {
911          struct string_list *list = video_driver_get_gpu_api_devices(api);
912 
913          if (list)
914          {
915             settings_t *settings = config_get_ptr();
916             int d3d12_gpu_index  = settings->ints.d3d12_gpu_index;
917             if (d3d12_gpu_index > 0)
918             {
919                configuration_set_int(settings,
920                      settings->ints.d3d12_gpu_index,
921                      settings->ints.d3d12_gpu_index - 1);
922             }
923             else
924             {
925                configuration_set_int(settings,
926                      settings->ints.d3d12_gpu_index,
927                      list->size - 1);
928             }
929          }
930 
931          break;
932       }
933 #endif
934       default:
935          break;
936    }
937 
938    return 0;
939 }
940 
bind_left_generic(unsigned type,const char * label,bool wraparound)941 static int bind_left_generic(unsigned type, const char *label,
942       bool wraparound)
943 {
944    return menu_setting_set(type, MENU_ACTION_LEFT, wraparound);
945 }
946 
menu_cbs_init_bind_left_compare_label(menu_file_list_cbs_t * cbs,const char * label,const char * menu_label)947 static int menu_cbs_init_bind_left_compare_label(menu_file_list_cbs_t *cbs,
948       const char *label, const char *menu_label)
949 {
950 
951    if (cbs->setting)
952    {
953       const char *parent_group   = cbs->setting->parent_group;
954 
955       if (string_is_equal(parent_group,
956                msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU))
957                && (cbs->setting->type == ST_GROUP))
958       {
959          BIND_ACTION_LEFT(cbs, action_left_mainmenu);
960          return 0;
961       }
962    }
963 
964    if (  string_starts_with_size(label, "input_player", STRLEN_CONST("input_player")) &&
965          string_ends_with_size(label, "_joypad_index", strlen(label),
966             STRLEN_CONST("_joypad_index")))
967    {
968       unsigned i;
969       for (i = 0; i < MAX_USERS; i++)
970       {
971          char label_setting[128];
972          label_setting[0] = '\0';
973 
974          snprintf(label_setting,
975                sizeof(label_setting), "input_player%d_joypad_index", i + 1);
976 
977          if (!string_is_equal(label, label_setting))
978             continue;
979 
980          BIND_ACTION_LEFT(cbs, bind_left_generic);
981          return 0;
982       }
983    }
984 
985    if (string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB)))
986    {
987       BIND_ACTION_LEFT(cbs, action_left_mainmenu);
988       return 0;
989    }
990 
991    if (strstr(label, "rdb_entry") || string_starts_with_size(label, "content_info", STRLEN_CONST("content_info")))
992    {
993       BIND_ACTION_LEFT(cbs, action_left_scroll);
994    }
995    else
996    {
997       if (cbs->enum_idx != MSG_UNKNOWN)
998       {
999          switch (cbs->enum_idx)
1000          {
1001             case MENU_ENUM_LABEL_SUBSYSTEM_ADD:
1002             case MENU_ENUM_LABEL_SUBSYSTEM_LOAD:
1003             case MENU_ENUM_LABEL_CONNECT_NETPLAY_ROOM:
1004             case MENU_ENUM_LABEL_EXPLORE_ITEM:
1005             case MENU_ENUM_LABEL_NO_SETTINGS_FOUND:
1006                BIND_ACTION_LEFT(cbs, action_left_mainmenu);
1007                break;
1008             case MENU_ENUM_LABEL_VIDEO_SHADER_SCALE_PASS:
1009 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
1010                BIND_ACTION_LEFT(cbs, action_left_shader_scale_pass);
1011 #endif
1012                break;
1013             case MENU_ENUM_LABEL_VIDEO_SHADER_FILTER_PASS:
1014 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
1015                BIND_ACTION_LEFT(cbs, action_left_shader_filter_pass);
1016 #endif
1017                break;
1018             case MENU_ENUM_LABEL_VIDEO_SHADER_DEFAULT_FILTER:
1019 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
1020                BIND_ACTION_LEFT(cbs, action_left_shader_filter_default);
1021 #endif
1022                break;
1023             case MENU_ENUM_LABEL_VIDEO_SHADER_NUM_PASSES:
1024 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
1025                BIND_ACTION_LEFT(cbs, action_left_shader_num_passes);
1026 #endif
1027                break;
1028             case MENU_ENUM_LABEL_CHEAT_NUM_PASSES:
1029 #ifdef HAVE_CHEATS
1030                BIND_ACTION_LEFT(cbs, action_left_cheat_num_passes);
1031 #endif
1032                break;
1033             case MENU_ENUM_LABEL_SCREEN_RESOLUTION:
1034                BIND_ACTION_LEFT(cbs, action_left_video_resolution);
1035                break;
1036             case MENU_ENUM_LABEL_OPEN_ARCHIVE_DETECT_CORE:
1037             case MENU_ENUM_LABEL_LOAD_ARCHIVE_DETECT_CORE:
1038                BIND_ACTION_LEFT(cbs, action_left_scroll);
1039                break;
1040             case MENU_ENUM_LABEL_NO_ITEMS:
1041             case MENU_ENUM_LABEL_NO_PLAYLIST_ENTRIES_AVAILABLE:
1042                if (
1043                         string_ends_with_size(menu_label, "_tab",
1044                            strlen(menu_label),
1045                            STRLEN_CONST("_tab")
1046                            )
1047                      || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU))
1048                      || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_HORIZONTAL_MENU))
1049                   )
1050                {
1051                   BIND_ACTION_LEFT(cbs, action_left_mainmenu);
1052                }
1053                else
1054                {
1055                   BIND_ACTION_LEFT(cbs, action_left_scroll);
1056                }
1057                break;
1058             case MENU_ENUM_LABEL_START_VIDEO_PROCESSOR:
1059             case MENU_ENUM_LABEL_TAKE_SCREENSHOT:
1060                if (
1061                         string_ends_with_size(menu_label, "_tab",
1062                            strlen(menu_label),
1063                            STRLEN_CONST("_tab"))
1064                      || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_HORIZONTAL_MENU))
1065                   )
1066                {
1067                   BIND_ACTION_LEFT(cbs, action_left_mainmenu);
1068                   break;
1069                }
1070             case MENU_ENUM_LABEL_VIDEO_GPU_INDEX:
1071                BIND_ACTION_LEFT(cbs, action_left_video_gpu_index);
1072                break;
1073             case MENU_ENUM_LABEL_PLAYLIST_MANAGER_DEFAULT_CORE:
1074                BIND_ACTION_LEFT(cbs, playlist_association_left);
1075                break;
1076             case MENU_ENUM_LABEL_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE:
1077                BIND_ACTION_LEFT(cbs, playlist_label_display_mode_left);
1078                break;
1079             case MENU_ENUM_LABEL_PLAYLIST_MANAGER_RIGHT_THUMBNAIL_MODE:
1080                BIND_ACTION_LEFT(cbs, playlist_right_thumbnail_mode_left);
1081                break;
1082             case MENU_ENUM_LABEL_PLAYLIST_MANAGER_LEFT_THUMBNAIL_MODE:
1083                BIND_ACTION_LEFT(cbs, playlist_left_thumbnail_mode_left);
1084                break;
1085             case MENU_ENUM_LABEL_PLAYLIST_MANAGER_SORT_MODE:
1086                BIND_ACTION_LEFT(cbs, playlist_sort_mode_left);
1087                break;
1088             case MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_SYSTEM_NAME:
1089                BIND_ACTION_LEFT(cbs, manual_content_scan_system_name_left);
1090                break;
1091             case MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_CORE_NAME:
1092                BIND_ACTION_LEFT(cbs, manual_content_scan_core_name_left);
1093                break;
1094             #ifndef HAVE_LAKKA_SWITCH
1095             #ifdef HAVE_LAKKA
1096             case MENU_ENUM_LABEL_CPU_PERF_MODE:
1097                BIND_ACTION_LEFT(cbs, cpu_policy_mode_change);
1098                break;
1099             case MENU_ENUM_LABEL_CPU_POLICY_MAX_FREQ:
1100             case MENU_ENUM_LABEL_CPU_POLICY_MIN_FREQ:
1101             case MENU_ENUM_LABEL_CPU_POLICY_GOVERNOR:
1102                BIND_ACTION_LEFT(cbs, cpu_policy_freq_tweak);
1103                break;
1104             case MENU_ENUM_LABEL_CPU_MANAGED_MIN_FREQ:
1105             case MENU_ENUM_LABEL_CPU_MANAGED_MAX_FREQ:
1106                BIND_ACTION_LEFT(cbs, cpu_policy_freq_managed_tweak);
1107                break;
1108             case MENU_ENUM_LABEL_CPU_POLICY_CORE_GOVERNOR:
1109             case MENU_ENUM_LABEL_CPU_POLICY_MENU_GOVERNOR:
1110                BIND_ACTION_LEFT(cbs, cpu_policy_freq_managed_gov);
1111                break;
1112             #endif
1113             #endif
1114             default:
1115                return -1;
1116          }
1117       }
1118       else
1119       {
1120          return -1;
1121       }
1122    }
1123 
1124    return 0;
1125 }
1126 
menu_cbs_init_bind_left_compare_type(menu_file_list_cbs_t * cbs,unsigned type,const char * menu_label)1127 static int menu_cbs_init_bind_left_compare_type(menu_file_list_cbs_t *cbs,
1128       unsigned type, const char *menu_label)
1129 {
1130 #ifdef HAVE_CHEATS
1131    if (type >= MENU_SETTINGS_CHEAT_BEGIN
1132          && type <= MENU_SETTINGS_CHEAT_END)
1133    {
1134       BIND_ACTION_LEFT(cbs, action_left_cheat);
1135    } else
1136 #endif
1137 #ifdef HAVE_AUDIOMIXER
1138    if (type >= MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_VOLUME_BEGIN
1139          && type <= MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_VOLUME_END)
1140    {
1141       BIND_ACTION_LEFT(cbs, audio_mixer_stream_volume_left);
1142    } else
1143 #endif
1144 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
1145    if (type >= MENU_SETTINGS_SHADER_PARAMETER_0
1146          && type <= MENU_SETTINGS_SHADER_PARAMETER_LAST)
1147    {
1148       BIND_ACTION_LEFT(cbs, shader_action_parameter_left);
1149    }
1150    else if (type >= MENU_SETTINGS_SHADER_PRESET_PARAMETER_0
1151          && type <= MENU_SETTINGS_SHADER_PRESET_PARAMETER_LAST)
1152    {
1153       BIND_ACTION_LEFT(cbs, shader_action_preset_parameter_left);
1154    } else
1155 #endif
1156    if (type >= MENU_SETTINGS_INPUT_DESC_BEGIN
1157          && type <= MENU_SETTINGS_INPUT_DESC_END)
1158    {
1159       BIND_ACTION_LEFT(cbs, action_left_input_desc);
1160    }
1161    else if (type >= MENU_SETTINGS_INPUT_DESC_KBD_BEGIN
1162       && type <= MENU_SETTINGS_INPUT_DESC_KBD_END)
1163    {
1164       BIND_ACTION_LEFT(cbs, action_left_input_desc_kbd);
1165    }
1166    else if ((type >= MENU_SETTINGS_CORE_OPTION_START) &&
1167             (type < MENU_SETTINGS_CHEEVOS_START))
1168    {
1169       BIND_ACTION_LEFT(cbs, core_setting_left);
1170    }
1171    else
1172    {
1173       switch (type)
1174       {
1175          case MENU_SETTINGS_CORE_DISK_OPTIONS_DISK_INDEX:
1176             BIND_ACTION_LEFT(cbs, disk_options_disk_idx_left);
1177             break;
1178          case FILE_TYPE_PLAIN:
1179          case FILE_TYPE_DIRECTORY:
1180          case FILE_TYPE_CARCHIVE:
1181          case FILE_TYPE_IN_CARCHIVE:
1182          case FILE_TYPE_CORE:
1183          case FILE_TYPE_RDB:
1184          case FILE_TYPE_RDB_ENTRY:
1185          case FILE_TYPE_RPL_ENTRY:
1186          case FILE_TYPE_CURSOR:
1187          case FILE_TYPE_SHADER:
1188          case FILE_TYPE_SHADER_PRESET:
1189          case FILE_TYPE_IMAGE:
1190          case FILE_TYPE_OVERLAY:
1191 #ifdef HAVE_VIDEO_LAYOUT
1192          case FILE_TYPE_VIDEO_LAYOUT:
1193 #endif
1194          case FILE_TYPE_VIDEOFILTER:
1195          case FILE_TYPE_AUDIOFILTER:
1196          case FILE_TYPE_CONFIG:
1197          case FILE_TYPE_USE_DIRECTORY:
1198          case FILE_TYPE_PLAYLIST_ENTRY:
1199          case MENU_INFO_MESSAGE:
1200          case FILE_TYPE_DOWNLOAD_CORE:
1201          case FILE_TYPE_CHEAT:
1202          case FILE_TYPE_REMAP:
1203          case FILE_TYPE_MOVIE:
1204          case FILE_TYPE_MUSIC:
1205          case FILE_TYPE_IMAGEVIEWER:
1206          case FILE_TYPE_PLAYLIST_COLLECTION:
1207          case FILE_TYPE_DOWNLOAD_CORE_CONTENT:
1208          case FILE_TYPE_DOWNLOAD_THUMBNAIL_CONTENT:
1209          case FILE_TYPE_DOWNLOAD_URL:
1210          case FILE_TYPE_SCAN_DIRECTORY:
1211          case FILE_TYPE_MANUAL_SCAN_DIRECTORY:
1212          case FILE_TYPE_FONT:
1213          case FILE_TYPE_VIDEO_FONT:
1214          case MENU_SETTING_GROUP:
1215          case MENU_SETTINGS_CORE_INFO_NONE:
1216          case MENU_SETTING_ACTION_FAVORITES_DIR:
1217          case MENU_SETTING_ACTION_CORE_MANAGER_OPTIONS:
1218             if (
1219                   string_ends_with_size(menu_label, "_tab",
1220                      strlen(menu_label), STRLEN_CONST("_tab"))
1221                   || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_HORIZONTAL_MENU))
1222                )
1223             {
1224                BIND_ACTION_LEFT(cbs, action_left_mainmenu);
1225                break;
1226             }
1227             BIND_ACTION_LEFT(cbs, action_left_scroll);
1228             break;
1229          case MENU_SETTING_ACTION:
1230          case FILE_TYPE_CONTENTLIST_ENTRY:
1231             BIND_ACTION_LEFT(cbs, action_left_mainmenu);
1232             break;
1233          case MENU_SETTING_ACTION_CORE_LOCK:
1234             BIND_ACTION_LEFT(cbs, action_left_core_lock);
1235             break;
1236          case MENU_SETTING_DROPDOWN_ITEM_INPUT_DESCRIPTION:
1237          case MENU_SETTING_DROPDOWN_ITEM_INPUT_DESCRIPTION_KBD:
1238             BIND_ACTION_LEFT(cbs, action_left_scroll);
1239             break;
1240          default:
1241             return -1;
1242       }
1243    }
1244 
1245    return 0;
1246 }
1247 
menu_cbs_init_bind_left(menu_file_list_cbs_t * cbs,const char * path,const char * label,unsigned type,size_t idx,const char * menu_label)1248 int menu_cbs_init_bind_left(menu_file_list_cbs_t *cbs,
1249       const char *path, const char *label, unsigned type, size_t idx,
1250       const char *menu_label)
1251 {
1252    if (!cbs)
1253       return -1;
1254 
1255    BIND_ACTION_LEFT(cbs, bind_left_generic);
1256 
1257    if (type == MENU_SETTING_NO_ITEM)
1258    {
1259       if (
1260                string_ends_with_size(menu_label, "_tab",
1261                   strlen(menu_label), STRLEN_CONST("_tab"))
1262             || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU))
1263             || string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_HORIZONTAL_MENU))
1264          )
1265       {
1266             BIND_ACTION_LEFT(cbs, action_left_mainmenu);
1267             return 0;
1268       }
1269    }
1270 
1271    if (menu_cbs_init_bind_left_compare_label(cbs, label, menu_label) == 0)
1272       return 0;
1273 
1274    if (menu_cbs_init_bind_left_compare_type(cbs, type, menu_label) == 0)
1275       return 0;
1276 
1277    return -1;
1278 }
1279