From 0db409d5b53f8802cec00483836fbec11a395de5 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Tue, 31 Aug 2021 00:43:04 +0200 Subject: [PATCH] Move lots of menu code over to menu/menu_driver.c - moved at least 44Kb of code over --- Makefile.common | 1 + gfx/gfx_widgets.c | 3 +- griffin/griffin.c | 1 + menu/menu_driver.c | 1375 ++++++++++++++++++++++++++++++++++++++++ menu/menu_driver.h | 238 ++++++- retroarch.c | 1398 +---------------------------------------- retroarch_data.h | 130 ---- retroarch_fwd_decls.h | 6 +- 8 files changed, 1646 insertions(+), 1506 deletions(-) create mode 100644 menu/menu_driver.c diff --git a/Makefile.common b/Makefile.common index 7103b379cb..a48f3d7399 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1048,6 +1048,7 @@ endif ifeq ($(HAVE_MENU_COMMON), 1) OBJ += menu/menu_setting.o \ + menu/menu_driver.o \ menu/cbs/menu_cbs_ok.o \ menu/cbs/menu_cbs_cancel.o \ menu/cbs/menu_cbs_select.o \ diff --git a/gfx/gfx_widgets.c b/gfx/gfx_widgets.c index c9c147b587..457c6ed495 100644 --- a/gfx/gfx_widgets.c +++ b/gfx/gfx_widgets.c @@ -159,6 +159,7 @@ static float gfx_display_get_widget_dpi_scale( return adjusted_scale; } +#if defined(HAVE_MENU) && defined(HAVE_XMB) static float gfx_display_get_widget_pixel_scale( gfx_display_t *p_disp, settings_t *settings, @@ -237,7 +238,7 @@ static float gfx_display_get_widget_pixel_scale( return adjusted_scale; } - +#endif static void msg_widget_msg_transition_animation_done(void *userdata) { diff --git a/griffin/griffin.c b/griffin/griffin.c index 22154db23b..bc90340ce9 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -1369,6 +1369,7 @@ MENU #endif #ifdef HAVE_MENU +#include "../menu/menu_driver.c" #include "../menu/menu_setting.c" #if defined(HAVE_MATERIALUI) || defined(HAVE_XMB) || defined(HAVE_OZONE) #include "../menu/menu_screensaver.c" diff --git a/menu/menu_driver.c b/menu/menu_driver.c new file mode 100644 index 0000000000..496d7dc44a --- /dev/null +++ b/menu/menu_driver.c @@ -0,0 +1,1375 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2021 - Daniel De Matteis + * Copyright (C) 2014-2017 - Jean-André Santoni + * Copyright (C) 2016-2019 - Andrés Suárez + * Copyright (C) 2016-2019 - Brad Parker + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#if defined(HAVE_CONFIG_H) +#include "../config.h" +#endif + +#include +#include "menu_driver.h" + +#ifdef HAVE_LANGEXTRA +/* This file has a UTF8 BOM, we assume HAVE_LANGEXTRA + * is only enabled for compilers that can support this. */ +#include "../input/input_osk_utf8_pages.h" +#endif + +#ifdef HAVE_CHEEVOS +#include "../cheevos/cheevos_menu.h" +#endif + +#include "../input/input_driver.h" +#include "../input/input_remapping.h" +#include "../performance_counters.h" + +static bool menu_should_pop_stack(const char *label) +{ + /* > Info box */ + if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_INFO_SCREEN))) + return true; + /* > Help box */ + if (string_starts_with_size(label, "help", STRLEN_CONST("help"))) + if ( + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP)) + || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_CONTROLS)) + || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_WHAT_IS_A_CORE)) + || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_LOADING_CONTENT)) + || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_SCANNING_CONTENT)) + || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_CHANGE_VIRTUAL_GAMEPAD)) + || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_AUDIO_VIDEO_TROUBLESHOOTING)) + || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_SEND_DEBUG_INFO)) + || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CHEEVOS_DESCRIPTION))) + return true; + if ( + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CHEEVOS_DESCRIPTION))) + return true; + return false; +} + +/* Used to close an active message box (help or info) + * TODO/FIXME: The way that message boxes are handled + * is complete garbage. generic_menu_iterate() and + * message boxes in general need a total rewrite. + * I consider this current 'close_messagebox' a hack, + * but at least it prevents undefined/dangerous + * behaviour... */ +void menu_input_pointer_close_messagebox(struct menu_state *menu_st) +{ + const char *label = NULL; + + /* Determine whether this is a help or info + * message box */ + file_list_get_last(MENU_LIST_GET(menu_st->entries.list, 0), + NULL, &label, NULL, NULL); + + /* Pop stack, if required */ + if (menu_should_pop_stack(label)) + { + size_t selection = menu_st->selection_ptr; + size_t new_selection = selection; + + menu_entries_pop_stack(&new_selection, 0, 0); + menu_st->selection_ptr = selection; + } +} + + +float menu_input_get_dpi( + menu_handle_t *menu, + gfx_display_t *p_disp, + unsigned video_width, + unsigned video_height) +{ + static unsigned last_video_width = 0; + static unsigned last_video_height = 0; + static float dpi = 0.0f; + static bool dpi_cached = false; + + /* Regardless of menu driver, need 'actual' screen DPI + * Note: DPI is a fixed hardware property. To minimise performance + * overheads we therefore only call video_context_driver_get_metrics() + * on first run, or when the current video resolution changes */ + if (!dpi_cached || + (video_width != last_video_width) || + (video_height != last_video_height)) + { + gfx_ctx_metrics_t mets; + /* Note: If video_context_driver_get_metrics() fails, + * we don't know what happened to dpi - so ensure it + * is reset to a sane value */ + + mets.type = DISPLAY_METRIC_DPI; + mets.value = &dpi; + if (!video_context_driver_get_metrics(&mets)) + dpi = 0.0f; + + dpi_cached = true; + last_video_width = video_width; + last_video_height = video_height; + } + + /* RGUI uses a framebuffer texture, which means we + * operate in menu space, not screen space. + * DPI in a traditional sense is therefore meaningless, + * so generate a substitute value based upon framebuffer + * dimensions */ + if (dpi > 0.0f) + { + bool menu_has_fb = + menu->driver_ctx + && menu->driver_ctx->set_texture; + + /* Read framebuffer info? */ + if (menu_has_fb) + { + unsigned fb_height = p_disp->framebuf_height; + /* Rationale for current 'DPI' determination method: + * - Divide screen height by DPI, to get number of vertical + * '1 inch' squares + * - Divide RGUI framebuffer height by number of vertical + * '1 inch' squares to get number of menu space pixels + * per inch + * This is crude, but should be sufficient... */ + return ((float)fb_height / (float)video_height) * dpi; + } + } + + return dpi; +} + +bool input_event_osk_show_symbol_pages( + menu_handle_t *menu) +{ +#if defined(HAVE_LANGEXTRA) +#if defined(HAVE_RGUI) + bool menu_has_fb = (menu && + menu->driver_ctx && + menu->driver_ctx->set_texture); + unsigned language = *msg_hash_get_uint(MSG_HASH_USER_LANGUAGE); + return !menu_has_fb || + ((language == RETRO_LANGUAGE_JAPANESE) || + (language == RETRO_LANGUAGE_KOREAN) || + (language == RETRO_LANGUAGE_CHINESE_SIMPLIFIED) || + (language == RETRO_LANGUAGE_CHINESE_TRADITIONAL)); +#else /* HAVE_RGUI */ + return true; +#endif /* HAVE_RGUI */ +#else /* HAVE_LANGEXTRA */ + return false; +#endif /* HAVE_LANGEXTRA */ +} + +static void menu_driver_list_free( + const menu_ctx_driver_t *menu_driver_ctx, + menu_ctx_list_t *list) +{ + if (menu_driver_ctx) + if (menu_driver_ctx->list_free) + menu_driver_ctx->list_free( + list->list, list->idx, list->list_size); + + if (list->list) + { + file_list_free_userdata (list->list, list->idx); + file_list_free_actiondata(list->list, list->idx); + } +} + +static void menu_list_free_list( + const menu_ctx_driver_t *menu_driver_ctx, + file_list_t *list) +{ + unsigned i; + + for (i = 0; i < list->size; i++) + { + menu_ctx_list_t list_info; + + list_info.list = list; + list_info.idx = i; + list_info.list_size = list->size; + + menu_driver_list_free(menu_driver_ctx, &list_info); + } + + file_list_free(list); +} + +bool menu_list_pop_stack( + const menu_ctx_driver_t *menu_driver_ctx, + void *menu_userdata, + menu_list_t *list, + size_t idx, + size_t *directory_ptr) +{ + file_list_t *menu_list = MENU_LIST_GET(list, (unsigned)idx); + + if (!menu_list) + return false; + + if (menu_list->size != 0) + { + menu_ctx_list_t list_info; + + list_info.list = menu_list; + list_info.idx = menu_list->size - 1; + list_info.list_size = menu_list->size - 1; + + menu_driver_list_free(menu_driver_ctx, &list_info); + } + + file_list_pop(menu_list, directory_ptr); + if ( menu_driver_ctx && + menu_driver_ctx->list_set_selection) + menu_driver_ctx->list_set_selection(menu_userdata, + menu_list); + + return true; +} + +static int menu_list_flush_stack_type(const char *needle, const char *label, + unsigned type, unsigned final_type) +{ + return needle ? !string_is_equal(needle, label) : (type != final_type); +} + +void menu_list_flush_stack( + const menu_ctx_driver_t *menu_driver_ctx, + void *menu_userdata, + struct menu_state *menu_st, + menu_list_t *list, + size_t idx, const char *needle, unsigned final_type) +{ + bool refresh = false; + const char *path = NULL; + const char *label = NULL; + unsigned type = 0; + size_t entry_idx = 0; + file_list_t *menu_list = MENU_LIST_GET(list, (unsigned)idx); + + menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); + + if (menu_list && menu_list->size) + file_list_get_at_offset(menu_list, menu_list->size - 1, &path, &label, &type, &entry_idx); + + while (menu_list_flush_stack_type( + needle, label, type, final_type) != 0) + { + bool refresh = false; + size_t new_selection_ptr = menu_st->selection_ptr; + bool wont_pop_stack = (MENU_LIST_GET_STACK_SIZE(list, idx) <= 1); + if (wont_pop_stack) + break; + + if (menu_driver_ctx->list_cache) + menu_driver_ctx->list_cache(menu_userdata, + MENU_LIST_PLAIN, 0); + + menu_list_pop_stack(menu_driver_ctx, + menu_userdata, + list, idx, &new_selection_ptr); + + menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); + + menu_st->selection_ptr = new_selection_ptr; + menu_list = MENU_LIST_GET(list, (unsigned)idx); + + if (menu_list && menu_list->size) + file_list_get_at_offset(menu_list, menu_list->size - 1, &path, &label, &type, &entry_idx); + } +} + +static void menu_list_free( + const menu_ctx_driver_t *menu_driver_ctx, + menu_list_t *menu_list) +{ + if (!menu_list) + return; + + if (menu_list->menu_stack) + { + unsigned i; + + for (i = 0; i < menu_list->menu_stack_size; i++) + { + if (!menu_list->menu_stack[i]) + continue; + + menu_list_free_list(menu_driver_ctx, + menu_list->menu_stack[i]); + menu_list->menu_stack[i] = NULL; + } + + free(menu_list->menu_stack); + } + + if (menu_list->selection_buf) + { + unsigned i; + + for (i = 0; i < menu_list->selection_buf_size; i++) + { + if (!menu_list->selection_buf[i]) + continue; + + menu_list_free_list(menu_driver_ctx, + menu_list->selection_buf[i]); + menu_list->selection_buf[i] = NULL; + } + + free(menu_list->selection_buf); + } + + free(menu_list); +} + +static menu_list_t *menu_list_new(const menu_ctx_driver_t *menu_driver_ctx) +{ + unsigned i; + menu_list_t *list = (menu_list_t*)malloc(sizeof(*list)); + + if (!list) + return NULL; + + list->menu_stack_size = 1; + list->selection_buf_size = 1; + list->selection_buf = NULL; + list->menu_stack = (file_list_t**) + calloc(list->menu_stack_size, sizeof(*list->menu_stack)); + + if (!list->menu_stack) + goto error; + + list->selection_buf = (file_list_t**) + calloc(list->selection_buf_size, sizeof(*list->selection_buf)); + + if (!list->selection_buf) + goto error; + + for (i = 0; i < list->menu_stack_size; i++) + { + list->menu_stack[i] = (file_list_t*) + malloc(sizeof(*list->menu_stack[i])); + list->menu_stack[i]->list = NULL; + list->menu_stack[i]->capacity = 0; + list->menu_stack[i]->size = 0; + } + + for (i = 0; i < list->selection_buf_size; i++) + { + list->selection_buf[i] = (file_list_t*) + malloc(sizeof(*list->selection_buf[i])); + list->selection_buf[i]->list = NULL; + list->selection_buf[i]->capacity = 0; + list->selection_buf[i]->size = 0; + } + + return list; + +error: + menu_list_free(menu_driver_ctx, list); + return NULL; +} + + +int menu_input_key_bind_set_mode_common( + struct menu_state *menu_st, + struct menu_bind_state *binds, + enum menu_input_binds_ctl_state state, + rarch_setting_t *setting, + settings_t *settings) +{ + menu_displaylist_info_t info; + unsigned bind_type = 0; + struct retro_keybind *keybind = NULL; + unsigned index_offset = setting->index_offset; + menu_list_t *menu_list = menu_st->entries.list; + file_list_t *menu_stack = menu_list ? MENU_LIST_GET(menu_list, (unsigned)0) : NULL; + size_t selection = menu_st->selection_ptr; + + menu_displaylist_info_init(&info); + + switch (state) + { + case MENU_INPUT_BINDS_CTL_BIND_SINGLE: + keybind = (struct retro_keybind*)setting->value.target.keybind; + + if (!keybind) + return -1; + + bind_type = setting_get_bind_type(setting); + + binds->begin = bind_type; + binds->last = bind_type; + binds->output = keybind; + binds->buffer = *(binds->output); + binds->user = index_offset; + + info.list = menu_stack; + info.type = MENU_SETTINGS_CUSTOM_BIND_KEYBOARD; + info.directory_ptr = selection; + info.enum_idx = MENU_ENUM_LABEL_CUSTOM_BIND; + info.label = strdup( + msg_hash_to_str(MENU_ENUM_LABEL_CUSTOM_BIND)); + break; + case MENU_INPUT_BINDS_CTL_BIND_ALL: + binds->output = &input_config_binds[index_offset][0]; + binds->buffer = *(binds->output); + binds->begin = MENU_SETTINGS_BIND_BEGIN; + binds->last = MENU_SETTINGS_BIND_LAST; + + info.list = menu_stack; + info.type = MENU_SETTINGS_CUSTOM_BIND_KEYBOARD; + info.directory_ptr = selection; + info.enum_idx = MENU_ENUM_LABEL_CUSTOM_BIND_ALL; + info.label = strdup( + msg_hash_to_str(MENU_ENUM_LABEL_CUSTOM_BIND_ALL)); + break; + default: + case MENU_INPUT_BINDS_CTL_BIND_NONE: + return 0; + } + + if (menu_displaylist_ctl(DISPLAYLIST_INFO, &info, settings)) + menu_displaylist_process(&info); + menu_displaylist_info_free(&info); + + return 0; +} + +#ifdef ANDROID +bool menu_input_key_bind_poll_find_hold_pad( + struct menu_bind_state *new_state, + struct retro_keybind * output, + unsigned p) +{ + unsigned a, b, h; + const struct menu_bind_state_port *n = + (const struct menu_bind_state_port*) + &new_state->state[p]; + + for (b = 0; b < MENU_MAX_MBUTTONS; b++) + { + bool iterate = n->mouse_buttons[b]; + + if (!iterate) + continue; + + switch (b) + { + case RETRO_DEVICE_ID_MOUSE_LEFT: + case RETRO_DEVICE_ID_MOUSE_RIGHT: + case RETRO_DEVICE_ID_MOUSE_MIDDLE: + case RETRO_DEVICE_ID_MOUSE_BUTTON_4: + case RETRO_DEVICE_ID_MOUSE_BUTTON_5: + case RETRO_DEVICE_ID_MOUSE_WHEELUP: + case RETRO_DEVICE_ID_MOUSE_WHEELDOWN: + case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP: + case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN: + output->mbutton = b; + return true; + } + } + + for (b = 0; b < MENU_MAX_BUTTONS; b++) + { + bool iterate = n->buttons[b]; + + if (!iterate) + continue; + + output->joykey = b; + output->joyaxis = AXIS_NONE; + return true; + } + + /* Axes are a bit tricky ... */ + for (a = 0; a < MENU_MAX_AXES; a++) + { + if (abs(n->axes[a]) >= 20000) + { + /* Take care of case where axis rests on +/- 0x7fff + * (e.g. 360 controller on Linux) */ + output->joyaxis = n->axes[a] > 0 + ? AXIS_POS(a) : AXIS_NEG(a); + output->joykey = NO_BTN; + + return true; + } + } + + for (h = 0; h < MENU_MAX_HATS; h++) + { + uint16_t trigged = n->hats[h]; + uint16_t sane_trigger = 0; + + if (trigged & HAT_UP_MASK) + sane_trigger = HAT_UP_MASK; + else if (trigged & HAT_DOWN_MASK) + sane_trigger = HAT_DOWN_MASK; + else if (trigged & HAT_LEFT_MASK) + sane_trigger = HAT_LEFT_MASK; + else if (trigged & HAT_RIGHT_MASK) + sane_trigger = HAT_RIGHT_MASK; + + if (sane_trigger) + { + output->joykey = HAT_MAP(h, sane_trigger); + output->joyaxis = AXIS_NONE; + return true; + } + } + + return false; +} + +static bool menu_input_key_bind_poll_find_hold( + unsigned max_users, + struct menu_bind_state *new_state, + struct retro_keybind * output) +{ + if (new_state) + { + unsigned i; + + for (i = 0; i < max_users; i++) + { + if (menu_input_key_bind_poll_find_hold_pad(new_state, output, i)) + return true; + } + } + + return false; +} +#endif + +bool menu_input_key_bind_poll_find_trigger_pad( + struct menu_bind_state *state, + struct menu_bind_state *new_state, + struct retro_keybind * output, + unsigned p) +{ + unsigned a, b, h; + const struct menu_bind_state_port *n = (const struct menu_bind_state_port*) + &new_state->state[p]; + const struct menu_bind_state_port *o = (const struct menu_bind_state_port*) + &state->state[p]; + + for (b = 0; b < MENU_MAX_MBUTTONS; b++) + { + bool iterate = n->mouse_buttons[b] && !o->mouse_buttons[b]; + + if (!iterate) + continue; + + switch (b) + { + case RETRO_DEVICE_ID_MOUSE_LEFT: + case RETRO_DEVICE_ID_MOUSE_RIGHT: + case RETRO_DEVICE_ID_MOUSE_MIDDLE: + case RETRO_DEVICE_ID_MOUSE_BUTTON_4: + case RETRO_DEVICE_ID_MOUSE_BUTTON_5: + case RETRO_DEVICE_ID_MOUSE_WHEELUP: + case RETRO_DEVICE_ID_MOUSE_WHEELDOWN: + case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP: + case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN: + output->mbutton = b; + return true; + } + } + + for (b = 0; b < MENU_MAX_BUTTONS; b++) + { + bool iterate = n->buttons[b] && !o->buttons[b]; + + if (!iterate) + continue; + + output->joykey = b; + output->joyaxis = AXIS_NONE; + return true; + } + + /* Axes are a bit tricky ... */ + for (a = 0; a < MENU_MAX_AXES; a++) + { + int locked_distance = abs(n->axes[a] - + new_state->axis_state[p].locked_axes[a]); + int rested_distance = abs(n->axes[a] - + new_state->axis_state[p].rested_axes[a]); + + if (abs(n->axes[a]) >= 20000 && + locked_distance >= 20000 && + rested_distance >= 20000) + { + /* Take care of case where axis rests on +/- 0x7fff + * (e.g. 360 controller on Linux) */ + output->joyaxis = n->axes[a] > 0 + ? AXIS_POS(a) : AXIS_NEG(a); + output->joykey = NO_BTN; + + /* Lock the current axis */ + new_state->axis_state[p].locked_axes[a] = + n->axes[a] > 0 ? + 0x7fff : -0x7fff; + return true; + } + + if (locked_distance >= 20000) /* Unlock the axis. */ + new_state->axis_state[p].locked_axes[a] = 0; + } + + for (h = 0; h < MENU_MAX_HATS; h++) + { + uint16_t trigged = n->hats[h] & (~o->hats[h]); + uint16_t sane_trigger = 0; + + if (trigged & HAT_UP_MASK) + sane_trigger = HAT_UP_MASK; + else if (trigged & HAT_DOWN_MASK) + sane_trigger = HAT_DOWN_MASK; + else if (trigged & HAT_LEFT_MASK) + sane_trigger = HAT_LEFT_MASK; + else if (trigged & HAT_RIGHT_MASK) + sane_trigger = HAT_RIGHT_MASK; + + if (sane_trigger) + { + output->joykey = HAT_MAP(h, sane_trigger); + output->joyaxis = AXIS_NONE; + return true; + } + } + + return false; +} + +bool menu_input_key_bind_poll_find_trigger( + unsigned max_users, + struct menu_bind_state *state, + struct menu_bind_state *new_state, + struct retro_keybind * output) +{ + if (state && new_state) + { + unsigned i; + + for (i = 0; i < max_users; i++) + { + if (menu_input_key_bind_poll_find_trigger_pad( + state, new_state, output, i)) + return true; + } + } + + return false; +} + + +void menu_input_key_bind_poll_bind_get_rested_axes( + const input_device_driver_t *joypad, + const input_device_driver_t *sec_joypad, + struct menu_bind_state *state) +{ + unsigned a; + unsigned port = state->port; + + if (joypad) + { + /* poll only the relevant port */ + for (a = 0; a < MENU_MAX_AXES; a++) + { + if (AXIS_POS(a) != AXIS_NONE) + state->axis_state[port].rested_axes[a] = + joypad->axis(port, AXIS_POS(a)); + if (AXIS_NEG(a) != AXIS_NONE) + state->axis_state[port].rested_axes[a] += + joypad->axis(port, AXIS_NEG(a)); + } + } + + if (sec_joypad) + { + /* poll only the relevant port */ + for (a = 0; a < MENU_MAX_AXES; a++) + { + if (AXIS_POS(a) != AXIS_NONE) + state->axis_state[port].rested_axes[a] = sec_joypad->axis(port, AXIS_POS(a)); + + if (AXIS_NEG(a) != AXIS_NONE) + state->axis_state[port].rested_axes[a] += sec_joypad->axis(port, AXIS_NEG(a)); + } + } +} + +void input_event_osk_iterate( + void *osk_grid, + enum osk_type osk_idx) +{ +#ifndef HAVE_LANGEXTRA + /* If HAVE_LANGEXTRA is not defined, define some ASCII-friendly pages. */ + static const char *uppercase_grid[] = { + "1","2","3","4","5","6","7","8","9","0","Bksp", + "Q","W","E","R","T","Y","U","I","O","P","Enter", + "A","S","D","F","G","H","J","K","L","+","Lower", + "Z","X","C","V","B","N","M"," ","_","/","Next"}; + static const char *lowercase_grid[] = { + "1","2","3","4","5","6","7","8","9","0","Bksp", + "q","w","e","r","t","y","u","i","o","p","Enter", + "a","s","d","f","g","h","j","k","l","@","Upper", + "z","x","c","v","b","n","m"," ","-",".","Next"}; + static const char *symbols_page1_grid[] = { + "1","2","3","4","5","6","7","8","9","0","Bksp", + "!","\"","#","$","%","&","'","*","(",")","Enter", + "+",",","-","~","/",":",";","=","<",">","Lower", + "?","@","[","\\","]","^","_","|","{","}","Next"}; +#endif + switch (osk_idx) + { +#ifdef HAVE_LANGEXTRA + case OSK_HIRAGANA_PAGE1: + memcpy(osk_grid, + hiragana_page1_grid, + sizeof(hiragana_page1_grid)); + break; + case OSK_HIRAGANA_PAGE2: + memcpy(osk_grid, + hiragana_page2_grid, + sizeof(hiragana_page2_grid)); + break; + case OSK_KATAKANA_PAGE1: + memcpy(osk_grid, + katakana_page1_grid, + sizeof(katakana_page1_grid)); + break; + case OSK_KATAKANA_PAGE2: + memcpy(osk_grid, + katakana_page2_grid, + sizeof(katakana_page2_grid)); + break; +#endif + case OSK_SYMBOLS_PAGE1: + memcpy(osk_grid, + symbols_page1_grid, + sizeof(uppercase_grid)); + break; + case OSK_UPPERCASE_LATIN: + memcpy(osk_grid, + uppercase_grid, + sizeof(uppercase_grid)); + break; + case OSK_LOWERCASE_LATIN: + default: + memcpy(osk_grid, + lowercase_grid, + sizeof(lowercase_grid)); + break; + } +} + +void menu_input_get_mouse_hw_state( + gfx_display_t *p_disp, + menu_handle_t *menu, + input_driver_state_t *input_driver_st, + input_driver_t *current_input, + const input_device_driver_t *joypad, + const input_device_driver_t *sec_joypad, + bool keyboard_mapping_blocked, + bool menu_mouse_enable, + bool input_overlay_enable, + bool overlay_active, + menu_input_pointer_hw_state_t *hw_state) +{ + rarch_joypad_info_t joypad_info; + static int16_t last_x = 0; + static int16_t last_y = 0; + static bool last_select_pressed = false; + static bool last_cancel_pressed = false; + bool menu_has_fb = + (menu && + menu->driver_ctx && + menu->driver_ctx->set_texture); + bool state_inited = current_input && + current_input->input_state; +#ifdef HAVE_OVERLAY + /* Menu pointer controls are ignored when overlays are enabled. */ + if (overlay_active) + menu_mouse_enable = false; +#endif + + /* Easiest to set inactive by default, and toggle + * when input is detected */ + hw_state->active = false; + hw_state->x = 0; + hw_state->y = 0; + hw_state->select_pressed = false; + hw_state->cancel_pressed = false; + hw_state->up_pressed = false; + hw_state->down_pressed = false; + hw_state->left_pressed = false; + hw_state->right_pressed = false; + + if (!menu_mouse_enable) + return; + + joypad_info.joy_idx = 0; + joypad_info.auto_binds = NULL; + joypad_info.axis_threshold = 0.0f; + + /* X/Y position */ + if (state_inited) + { + if ((hw_state->x = current_input->input_state( + input_driver_st->current_data, + joypad, + sec_joypad, + &joypad_info, + NULL, + keyboard_mapping_blocked, + 0, + RARCH_DEVICE_MOUSE_SCREEN, + 0, + RETRO_DEVICE_ID_MOUSE_X)) != last_x) + hw_state->active = true; + if ((hw_state->y = current_input->input_state( + input_driver_st->current_data, + joypad, + sec_joypad, + &joypad_info, + NULL, + keyboard_mapping_blocked, + 0, + RARCH_DEVICE_MOUSE_SCREEN, + 0, + RETRO_DEVICE_ID_MOUSE_Y)) != last_y) + hw_state->active = true; + } + + last_x = hw_state->x; + last_y = hw_state->y; + + /* > X/Y position adjustment */ + if (menu_has_fb) + { + /* RGUI uses a framebuffer texture + custom viewports, + * which means we have to convert from screen space to + * menu space... */ + struct video_viewport vp = {0}; + /* Read display/framebuffer info */ + unsigned fb_width = p_disp->framebuf_width; + unsigned fb_height = p_disp->framebuf_height; + + video_driver_get_viewport_info(&vp); + + /* Adjust X position */ + hw_state->x = (int16_t)(((float)(hw_state->x - vp.x) / (float)vp.width) * (float)fb_width); + hw_state->x = (hw_state->x < 0) ? (0 ) : hw_state->x; + hw_state->x = (hw_state->x >= fb_width) ? (fb_width -1) : hw_state->x; + + /* Adjust Y position */ + hw_state->y = (int16_t)(((float)(hw_state->y - vp.y) / (float)vp.height) * (float)fb_height); + hw_state->y = (hw_state->y < 0) ? (0 ) : hw_state->y; + hw_state->y = (hw_state->y >= fb_height) ? (fb_height-1) : hw_state->y; + } + + if (state_inited) + { + /* Select (LMB) + * Note that releasing select also counts as activity */ + hw_state->select_pressed = (bool) + current_input->input_state( + input_driver_st->current_data, + joypad, + sec_joypad, + &joypad_info, + NULL, + keyboard_mapping_blocked, + 0, + RETRO_DEVICE_MOUSE, + 0, + RETRO_DEVICE_ID_MOUSE_LEFT); + /* Cancel (RMB) + * Note that releasing cancel also counts as activity */ + hw_state->cancel_pressed = (bool) + current_input->input_state( + input_driver_st->current_data, + joypad, + sec_joypad, + &joypad_info, + NULL, + keyboard_mapping_blocked, + 0, + RETRO_DEVICE_MOUSE, + 0, + RETRO_DEVICE_ID_MOUSE_RIGHT); + /* Up (mouse wheel up) */ + if ((hw_state->up_pressed = (bool) + current_input->input_state( + input_driver_st->current_data, + joypad, + sec_joypad, + &joypad_info, + NULL, + keyboard_mapping_blocked, + 0, + RETRO_DEVICE_MOUSE, + 0, + RETRO_DEVICE_ID_MOUSE_WHEELUP))) + hw_state->active = true; + /* Down (mouse wheel down) */ + if ((hw_state->down_pressed = (bool) + current_input->input_state( + input_driver_st->current_data, + joypad, + sec_joypad, + &joypad_info, + NULL, + keyboard_mapping_blocked, + 0, + RETRO_DEVICE_MOUSE, + 0, + RETRO_DEVICE_ID_MOUSE_WHEELDOWN))) + hw_state->active = true; + /* Left (mouse wheel horizontal left) */ + if ((hw_state->left_pressed = (bool) + current_input->input_state( + input_driver_st->current_data, + joypad, + sec_joypad, + &joypad_info, + NULL, + keyboard_mapping_blocked, + 0, + RETRO_DEVICE_MOUSE, + 0, + RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN))) + hw_state->active = true; + /* Right (mouse wheel horizontal right) */ + if ((hw_state->right_pressed = (bool) + current_input->input_state( + input_driver_st->current_data, + joypad, + sec_joypad, + &joypad_info, + NULL, + keyboard_mapping_blocked, + 0, + RETRO_DEVICE_MOUSE, + 0, + RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP))) + hw_state->active = true; + } + + if (hw_state->select_pressed || (hw_state->select_pressed != last_select_pressed)) + hw_state->active = true; + if (hw_state->cancel_pressed || (hw_state->cancel_pressed != last_cancel_pressed)) + hw_state->active = true; + last_select_pressed = hw_state->select_pressed; + last_cancel_pressed = hw_state->cancel_pressed; +} + +void menu_input_get_touchscreen_hw_state( + gfx_display_t *p_disp, + menu_handle_t *menu, + input_driver_state_t *input_driver_st, + input_driver_t *current_input, + const input_device_driver_t *joypad, + const input_device_driver_t *sec_joypad, + bool keyboard_mapping_blocked, + bool overlay_active, + bool pointer_enabled, + unsigned input_touch_scale, + menu_input_pointer_hw_state_t *hw_state) +{ + rarch_joypad_info_t joypad_info; + unsigned fb_width, fb_height; + int pointer_x = 0; + int pointer_y = 0; + const struct retro_keybind *binds[MAX_USERS] = {NULL}; + /* Is a background texture set for the current menu driver? + * Checks if the menu framebuffer is set. + * This would usually only return true + * for framebuffer-based menu drivers, like RGUI. */ + int pointer_device = + (menu && menu->driver_ctx && menu->driver_ctx->set_texture) ? + RETRO_DEVICE_POINTER : RARCH_DEVICE_POINTER_SCREEN; + static int16_t last_x = 0; + static int16_t last_y = 0; + static bool last_select_pressed = false; + static bool last_cancel_pressed = false; + + /* Easiest to set inactive by default, and toggle + * when input is detected */ + hw_state->active = false; + + /* Touch screens don't have mouse wheels, so these + * are always disabled */ + hw_state->up_pressed = false; + hw_state->down_pressed = false; + hw_state->left_pressed = false; + hw_state->right_pressed = false; + +#ifdef HAVE_OVERLAY + /* Menu pointer controls are ignored when overlays are enabled. */ + if (overlay_active) + pointer_enabled = false; +#endif + + /* If touchscreen is disabled, ignore all input */ + if (!pointer_enabled) + { + hw_state->x = 0; + hw_state->y = 0; + hw_state->select_pressed = false; + hw_state->cancel_pressed = false; + return; + } + + /* TODO/FIXME - this should only be used for framebuffer-based + * menu drivers like RGUI. Touchscreen input as a whole should + * NOT be dependent on this + */ + fb_width = p_disp->framebuf_width; + fb_height = p_disp->framebuf_height; + + joypad_info.joy_idx = 0; + joypad_info.auto_binds = NULL; + joypad_info.axis_threshold = 0.0f; + + /* X pos */ + if (current_input->input_state) + pointer_x = current_input->input_state( + input_driver_st->current_data, + joypad, + sec_joypad, + &joypad_info, binds, + keyboard_mapping_blocked, + 0, pointer_device, + 0, RETRO_DEVICE_ID_POINTER_X); + hw_state->x = ((pointer_x + 0x7fff) * (int)fb_width) / 0xFFFF; + hw_state->x *= input_touch_scale; + + /* > An annoyance - we get different starting positions + * depending upon whether pointer_device is + * RETRO_DEVICE_POINTER or RARCH_DEVICE_POINTER_SCREEN, + * so different 'activity' checks are required to prevent + * false positives on first run */ + if (pointer_device == RARCH_DEVICE_POINTER_SCREEN) + { + if (hw_state->x != last_x) + hw_state->active = true; + last_x = hw_state->x; + } + else + { + if (pointer_x != last_x) + hw_state->active = true; + last_x = pointer_x; + } + + /* Y pos */ + if (current_input->input_state) + pointer_y = current_input->input_state( + input_driver_st->current_data, + joypad, + sec_joypad, + &joypad_info, binds, + keyboard_mapping_blocked, + 0, pointer_device, + 0, RETRO_DEVICE_ID_POINTER_Y); + hw_state->y = ((pointer_y + 0x7fff) * (int)fb_height) / 0xFFFF; + hw_state->y *= input_touch_scale; + + if (pointer_device == RARCH_DEVICE_POINTER_SCREEN) + { + if (hw_state->y != last_y) + hw_state->active = true; + last_y = hw_state->y; + } + else + { + if (pointer_y != last_y) + hw_state->active = true; + last_y = pointer_y; + } + + /* Select (touch screen contact) + * Note that releasing select also counts as activity */ + if (current_input->input_state) + hw_state->select_pressed = (bool)current_input->input_state( + input_driver_st->current_data, + joypad, + sec_joypad, + &joypad_info, binds, + keyboard_mapping_blocked, + 0, pointer_device, + 0, RETRO_DEVICE_ID_POINTER_PRESSED); + if (hw_state->select_pressed || (hw_state->select_pressed != last_select_pressed)) + hw_state->active = true; + last_select_pressed = hw_state->select_pressed; + + /* Cancel (touch screen 'back' - don't know what is this, but whatever...) + * Note that releasing cancel also counts as activity */ + if (current_input->input_state) + hw_state->cancel_pressed = (bool)current_input->input_state( + input_driver_st->current_data, + joypad, + sec_joypad, + &joypad_info, binds, + keyboard_mapping_blocked, + 0, pointer_device, + 0, RARCH_DEVICE_ID_POINTER_BACK); + if (hw_state->cancel_pressed || (hw_state->cancel_pressed != last_cancel_pressed)) + hw_state->active = true; + last_cancel_pressed = hw_state->cancel_pressed; +} + +void menu_entries_settings_deinit(struct menu_state *menu_st) +{ + menu_setting_free(menu_st->entries.list_settings); + if (menu_st->entries.list_settings) + free(menu_st->entries.list_settings); + menu_st->entries.list_settings = NULL; +} + +int menu_dialog_iterate( + menu_dialog_t *p_dialog, + settings_t *settings, + char *s, size_t len, + retro_time_t current_time +) +{ + switch (p_dialog->current_type) + { + case MENU_DIALOG_WELCOME: + { + static rarch_timer_t timer; + + if (!timer.timer_begin) + { + timer.timeout_us = 3 * 1000000; + timer.current = cpu_features_get_time_usec(); + timer.timeout_end = timer.current + timer.timeout_us; + timer.timer_begin = true; + timer.timer_end = false; + } + + timer.current = current_time; + timer.timeout_us = (timer.timeout_end = timer.current); + + msg_hash_get_help_enum( + MENU_ENUM_LABEL_WELCOME_TO_RETROARCH, + s, len); + + if (!timer.timer_end && (timer.timeout_us <= 0)) + { + timer.timer_end = true; + timer.timer_begin = false; + timer.timeout_end = 0; + p_dialog->current_type = MENU_DIALOG_NONE; + return 1; + } + } + break; + case MENU_DIALOG_HELP_CONTROLS: + { + unsigned i; + char s2[PATH_MAX_LENGTH]; + const unsigned binds[] = { + RETRO_DEVICE_ID_JOYPAD_UP, + RETRO_DEVICE_ID_JOYPAD_DOWN, + RETRO_DEVICE_ID_JOYPAD_A, + RETRO_DEVICE_ID_JOYPAD_B, + RETRO_DEVICE_ID_JOYPAD_SELECT, + RETRO_DEVICE_ID_JOYPAD_START, + RARCH_MENU_TOGGLE, + RARCH_QUIT_KEY, + RETRO_DEVICE_ID_JOYPAD_X, + RETRO_DEVICE_ID_JOYPAD_Y, + }; + char desc[ARRAY_SIZE(binds)][64]; + + for (i = 0; i < ARRAY_SIZE(binds); i++) + desc[i][0] = '\0'; + + for (i = 0; i < ARRAY_SIZE(binds); i++) + { + const struct retro_keybind *keybind = &input_config_binds[0][binds[i]]; + const struct retro_keybind *auto_bind = + (const struct retro_keybind*) + input_config_get_bind_auto(0, binds[i]); + + input_config_get_bind_string(desc[i], + keybind, auto_bind, sizeof(desc[i])); + } + + s2[0] = '\0'; + + msg_hash_get_help_enum( + MENU_ENUM_LABEL_VALUE_MENU_ENUM_CONTROLS_PROLOG, + s2, sizeof(s2)); + + snprintf(s, len, + "%s" + "[%s]: " + "%-20s\n" + "[%s]: " + "%-20s\n" + "[%s]: " + "%-20s\n" + "[%s]: " + "%-20s\n" + "[%s]: " + "%-20s\n" + "[%s]: " + "%-20s\n" + "[%s]: " + "%-20s\n" + "[%s]: " + "%-20s\n" + "[%s]: " + "%-20s\n", + + s2, + + msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_UP), + desc[0], + + msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_DOWN), + desc[1], + + msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_CONFIRM), + desc[2], + + msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK), + desc[3], + + msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_INFO), + desc[4], + + msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_START), + desc[5], + + msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU), + desc[6], + + msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_QUIT), + desc[7], + + msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_KEYBOARD), + desc[8] + + ); + } + break; + +#ifdef HAVE_CHEEVOS + case MENU_DIALOG_HELP_CHEEVOS_DESCRIPTION: + if (!rcheevos_menu_get_sublabel(p_dialog->current_id, s, len)) + return 1; + break; +#endif + + case MENU_DIALOG_HELP_WHAT_IS_A_CORE: + msg_hash_get_help_enum(MENU_ENUM_LABEL_VALUE_WHAT_IS_A_CORE_DESC, + s, len); + break; + case MENU_DIALOG_HELP_LOADING_CONTENT: + msg_hash_get_help_enum(MENU_ENUM_LABEL_LOAD_CONTENT_LIST, + s, len); + break; + case MENU_DIALOG_HELP_CHANGE_VIRTUAL_GAMEPAD: + msg_hash_get_help_enum( + MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD_DESC, + s, len); + break; + case MENU_DIALOG_HELP_AUDIO_VIDEO_TROUBLESHOOTING: + msg_hash_get_help_enum( + MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING_DESC, + s, len); + break; + case MENU_DIALOG_HELP_SEND_DEBUG_INFO: + msg_hash_get_help_enum( + MENU_ENUM_LABEL_VALUE_HELP_SEND_DEBUG_INFO_DESC, + s, len); + break; + case MENU_DIALOG_HELP_SCANNING_CONTENT: + msg_hash_get_help_enum(MENU_ENUM_LABEL_VALUE_HELP_SCANNING_CONTENT_DESC, + s, len); + break; + case MENU_DIALOG_HELP_EXTRACT: + { + bool bundle_finished = settings->bools.bundle_finished; + + msg_hash_get_help_enum( + MENU_ENUM_LABEL_VALUE_EXTRACTING_PLEASE_WAIT, + s, len); + + if (bundle_finished) + { + configuration_set_bool(settings, + settings->bools.bundle_finished, false); + p_dialog->current_type = MENU_DIALOG_NONE; + return 1; + } + } + break; + case MENU_DIALOG_QUIT_CONFIRM: + case MENU_DIALOG_INFORMATION: + case MENU_DIALOG_QUESTION: + case MENU_DIALOG_WARNING: + case MENU_DIALOG_ERROR: + msg_hash_get_help_enum(MSG_UNKNOWN, + s, len); + break; + case MENU_DIALOG_NONE: + default: + break; + } + + return 0; +} + +void menu_entries_list_deinit( + const menu_ctx_driver_t *menu_driver_ctx, + struct menu_state *menu_st) +{ + if (menu_st->entries.list) + menu_list_free(menu_driver_ctx, menu_st->entries.list); + menu_st->entries.list = NULL; +} + +bool menu_entries_init( + struct menu_state *menu_st, + const menu_ctx_driver_t *menu_driver_ctx) +{ + if (!(menu_st->entries.list = (menu_list_t*)menu_list_new(menu_driver_ctx))) + return false; + if (!(menu_st->entries.list_settings = menu_setting_new())) + return false; + return true; +} diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 007baffc5b..0ef6ca69db 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -29,17 +29,22 @@ #include #include +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + #include "menu_defines.h" +#include "menu_dialog.h" #include "menu_input.h" +#include "../input/input_osk.h" +#include "menu_input_bind_dialog.h" #include "menu_entries.h" #include "menu_shader.h" #include "../gfx/gfx_display.h" #include "../gfx/font_driver.h" +#include "../performance_counters.h" -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif RETRO_BEGIN_DECLS @@ -51,6 +56,25 @@ RETRO_BEGIN_DECLS #define MAX_CHEAT_COUNTERS 6000 #endif +#define SCROLL_INDEX_SIZE (2 * (26 + 2) + 1) + +#define POWERSTATE_CHECK_INTERVAL (30 * 1000000) +#define DATETIME_CHECK_INTERVAL 1000000 + +#define MENU_MAX_BUTTONS 219 +#define MENU_MAX_AXES 32 +#define MENU_MAX_HATS 4 +#define MENU_MAX_MBUTTONS 32 /* Enough to cover largest libretro constant*/ + +#define MENU_LIST_GET(list, idx) ((list) ? ((list)->menu_stack[(idx)]) : NULL) + +#define MENU_LIST_GET_SELECTION(list, idx) ((list) ? ((list)->selection_buf[(idx)]) : NULL) + +#define MENU_LIST_GET_STACK_SIZE(list, idx) ((list)->menu_stack[(idx)]->size) + +#define MENU_ENTRIES_GET_SELECTION_BUF_PTR_INTERNAL(menu_st, idx) ((menu_st->entries.list) ? MENU_LIST_GET_SELECTION(menu_st->entries.list, (unsigned)idx) : NULL) +#define MENU_ENTRIES_NEEDS_REFRESH(menu_st) (!(menu_st->entries_nonblocking_refresh || !menu_st->entries_need_refresh)) + #define MENU_SETTINGS_CORE_INFO_NONE 0xffff #define MENU_SETTINGS_CORE_OPTION_NONE 0xffff #define MENU_SETTINGS_CHEEVOS_NONE 0xffff @@ -249,6 +273,112 @@ enum menu_settings_type MENU_SETTINGS_LAST }; +struct menu_list +{ + file_list_t **menu_stack; + size_t menu_stack_size; + file_list_t **selection_buf; + size_t selection_buf_size; +}; + +typedef struct menu_list menu_list_t; + +struct menu_state +{ + /* Timers */ + retro_time_t current_time_us; + retro_time_t powerstate_last_time_us; + retro_time_t datetime_last_time_us; + retro_time_t input_last_time_us; + + struct + { + rarch_setting_t *list_settings; + menu_list_t *list; + size_t begin; + } entries; + size_t selection_ptr; + + /* Quick jumping indices with L/R. + * Rebuilt when parsing directory. */ + struct + { + size_t index_list[SCROLL_INDEX_SIZE]; + unsigned index_size; + unsigned acceleration; + } scroll; + + /* Storage container for current menu datetime + * representation string */ + char datetime_cache[255]; + + /* When generating a menu list in menu_displaylist_build_list(), + * the entry with a label matching 'pending_selection' will + * be selected automatically */ + char pending_selection[PATH_MAX_LENGTH]; + + /* when enabled, on next iteration the 'Quick Menu' list will + * be pushed onto the stack */ + bool pending_quick_menu; + bool prevent_populate; + /* The menu driver owns the userdata */ + bool data_own; + /* Flagged when menu entries need to be refreshed */ + bool entries_need_refresh; + bool entries_nonblocking_refresh; + /* 'Close Content'-hotkey menu resetting */ + bool pending_close_content; + /* Screensaver status + * - Does menu driver support screensaver functionality? + * - Is screensaver currently active? */ + bool screensaver_supported; + bool screensaver_active; +}; + +typedef struct menu_ctx_load_image +{ + void *data; + enum menu_image_type type; +} menu_ctx_load_image_t; + + + +struct menu_bind_state_port +{ + int16_t axes[MENU_MAX_AXES]; + uint16_t hats[MENU_MAX_HATS]; + bool mouse_buttons[MENU_MAX_MBUTTONS]; + bool buttons[MENU_MAX_BUTTONS]; +}; + +struct menu_bind_axis_state +{ + /* Default axis state. */ + int16_t rested_axes[MENU_MAX_AXES]; + /* Locked axis state. If we configured an axis, + * avoid having the same axis state trigger something again right away. */ + int16_t locked_axes[MENU_MAX_AXES]; +}; + +struct menu_bind_state +{ + rarch_timer_t timer_timeout; + rarch_timer_t timer_hold; + + struct retro_keybind *output; + struct retro_keybind buffer; + + struct menu_bind_state_port state[MAX_USERS]; + struct menu_bind_axis_state axis_state[MAX_USERS]; + + unsigned begin; + unsigned last; + unsigned user; + unsigned port; + + bool skip; +}; + typedef struct menu_ctx_driver { /* Set a framebuffer texture. This is used for instance by RGUI. */ @@ -537,6 +667,108 @@ enum action_iterate_type ITERATE_TYPE_BIND }; +int menu_dialog_iterate( + menu_dialog_t *p_dialog, + settings_t *settings, + char *s, size_t len, + retro_time_t current_time); + +void menu_entries_settings_deinit(struct menu_state *menu_st); + +int menu_input_key_bind_set_mode_common( + struct menu_state *menu_st, + struct menu_bind_state *binds, + enum menu_input_binds_ctl_state state, + rarch_setting_t *setting, + settings_t *settings); + +void menu_input_key_bind_poll_bind_get_rested_axes( + const input_device_driver_t *joypad, + const input_device_driver_t *sec_joypad, + struct menu_bind_state *state); + +#ifdef ANDROID +bool menu_input_key_bind_poll_find_hold_pad( + struct menu_bind_state *new_state, + struct retro_keybind * output, + unsigned p); +#endif + +bool menu_input_key_bind_poll_find_trigger_pad( + struct menu_bind_state *state, + struct menu_bind_state *new_state, + struct retro_keybind * output, + unsigned p); + +bool menu_input_key_bind_poll_find_trigger( + unsigned max_users, + struct menu_bind_state *state, + struct menu_bind_state *new_state, + struct retro_keybind * output); + +void input_event_osk_iterate( + void *osk_grid, + enum osk_type osk_idx); + +void menu_input_get_mouse_hw_state( + gfx_display_t *p_disp, + menu_handle_t *menu, + input_driver_state_t *input_driver_st, + input_driver_t *current_input, + const input_device_driver_t *joypad, + const input_device_driver_t *sec_joypad, + bool keyboard_mapping_blocked, + bool menu_mouse_enable, + bool input_overlay_enable, + bool overlay_active, + menu_input_pointer_hw_state_t *hw_state); + +void menu_input_get_touchscreen_hw_state( + gfx_display_t *p_disp, + menu_handle_t *menu, + input_driver_state_t *input_driver_st, + input_driver_t *current_input, + const input_device_driver_t *joypad, + const input_device_driver_t *sec_joypad, + bool keyboard_mapping_blocked, + bool overlay_active, + bool pointer_enabled, + unsigned input_touch_scale, + menu_input_pointer_hw_state_t *hw_state); + +bool menu_entries_init( + struct menu_state *menu_st, + const menu_ctx_driver_t *menu_driver_ctx); + +void menu_entries_list_deinit( + const menu_ctx_driver_t *menu_driver_ctx, + struct menu_state *menu_st); + +void menu_list_flush_stack( + const menu_ctx_driver_t *menu_driver_ctx, + void *menu_userdata, + struct menu_state *menu_st, + menu_list_t *list, + size_t idx, const char *needle, unsigned final_type); + +bool menu_list_pop_stack( + const menu_ctx_driver_t *menu_driver_ctx, + void *menu_userdata, + menu_list_t *list, + size_t idx, + size_t *directory_ptr); + +bool input_event_osk_show_symbol_pages( + menu_handle_t *menu); + +float menu_input_get_dpi( + menu_handle_t *menu, + gfx_display_t *p_disp, + unsigned video_width, + unsigned video_height); + +void menu_input_pointer_close_messagebox(struct menu_state *menu_st); + int generic_menu_entry_action(void *userdata, menu_entry_t *entry, size_t i, enum menu_action action); extern menu_ctx_driver_t menu_ctx_ozone; diff --git a/retroarch.c b/retroarch.c index e3746583f9..1a09cdd4bb 100644 --- a/retroarch.c +++ b/retroarch.c @@ -269,12 +269,6 @@ #include "audio/audio_thread_wrapper.h" #endif -#ifdef HAVE_LANGEXTRA -/* This file has a UTF8 BOM, we assume HAVE_LANGEXTRA - * is only enabled for compilers that can support this. */ -#include "input/input_osk_utf8_pages.h" -#endif - #if defined(HAVE_SDL) || defined(HAVE_SDL2) || defined(HAVE_SDL_DINGUX) #include "SDL.h" #endif @@ -661,210 +655,6 @@ void input_keyboard_mapping_bits(unsigned mode, unsigned key) #ifdef HAVE_MENU -static int menu_dialog_iterate( - menu_dialog_t *p_dialog, - char *s, size_t len, - retro_time_t current_time) -{ - switch (p_dialog->current_type) - { - case MENU_DIALOG_WELCOME: - { - static rarch_timer_t timer; - - if (!timer.timer_begin) - { - RARCH_TIMER_BEGIN_NEW_TIME_USEC(timer, - cpu_features_get_time_usec(), - 3 * 1000000); - timer.timer_begin = true; - timer.timer_end = false; - } - - RARCH_TIMER_TICK(timer, current_time); - - msg_hash_get_help_enum( - MENU_ENUM_LABEL_WELCOME_TO_RETROARCH, - s, len); - - if (!timer.timer_end && RARCH_TIMER_HAS_EXPIRED(timer)) - { - RARCH_TIMER_END(timer); - p_dialog->current_type = MENU_DIALOG_NONE; - return 1; - } - } - break; - case MENU_DIALOG_HELP_CONTROLS: - { - unsigned i; - char s2[PATH_MAX_LENGTH]; - const unsigned binds[] = { - RETRO_DEVICE_ID_JOYPAD_UP, - RETRO_DEVICE_ID_JOYPAD_DOWN, - RETRO_DEVICE_ID_JOYPAD_A, - RETRO_DEVICE_ID_JOYPAD_B, - RETRO_DEVICE_ID_JOYPAD_SELECT, - RETRO_DEVICE_ID_JOYPAD_START, - RARCH_MENU_TOGGLE, - RARCH_QUIT_KEY, - RETRO_DEVICE_ID_JOYPAD_X, - RETRO_DEVICE_ID_JOYPAD_Y, - }; - char desc[ARRAY_SIZE(binds)][64]; - - for (i = 0; i < ARRAY_SIZE(binds); i++) - desc[i][0] = '\0'; - - for (i = 0; i < ARRAY_SIZE(binds); i++) - { - const struct retro_keybind *keybind = &input_config_binds[0][binds[i]]; - const struct retro_keybind *auto_bind = - (const struct retro_keybind*) - input_config_get_bind_auto(0, binds[i]); - - input_config_get_bind_string(desc[i], - keybind, auto_bind, sizeof(desc[i])); - } - - s2[0] = '\0'; - - msg_hash_get_help_enum( - MENU_ENUM_LABEL_VALUE_MENU_ENUM_CONTROLS_PROLOG, - s2, sizeof(s2)); - - snprintf(s, len, - "%s" - "[%s]: " - "%-20s\n" - "[%s]: " - "%-20s\n" - "[%s]: " - "%-20s\n" - "[%s]: " - "%-20s\n" - "[%s]: " - "%-20s\n" - "[%s]: " - "%-20s\n" - "[%s]: " - "%-20s\n" - "[%s]: " - "%-20s\n" - "[%s]: " - "%-20s\n", - - s2, - - msg_hash_to_str( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_UP), - desc[0], - - msg_hash_to_str( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_DOWN), - desc[1], - - msg_hash_to_str( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_CONFIRM), - desc[2], - - msg_hash_to_str( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK), - desc[3], - - msg_hash_to_str( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_INFO), - desc[4], - - msg_hash_to_str( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_START), - desc[5], - - msg_hash_to_str( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU), - desc[6], - - msg_hash_to_str( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_QUIT), - desc[7], - - msg_hash_to_str( - MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_KEYBOARD), - desc[8] - - ); - } - break; - -#ifdef HAVE_CHEEVOS - case MENU_DIALOG_HELP_CHEEVOS_DESCRIPTION: - if (!rcheevos_menu_get_sublabel(p_dialog->current_id, s, len)) - return 1; - break; -#endif - - case MENU_DIALOG_HELP_WHAT_IS_A_CORE: - msg_hash_get_help_enum(MENU_ENUM_LABEL_VALUE_WHAT_IS_A_CORE_DESC, - s, len); - break; - case MENU_DIALOG_HELP_LOADING_CONTENT: - msg_hash_get_help_enum(MENU_ENUM_LABEL_LOAD_CONTENT_LIST, - s, len); - break; - case MENU_DIALOG_HELP_CHANGE_VIRTUAL_GAMEPAD: - msg_hash_get_help_enum( - MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD_DESC, - s, len); - break; - case MENU_DIALOG_HELP_AUDIO_VIDEO_TROUBLESHOOTING: - msg_hash_get_help_enum( - MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING_DESC, - s, len); - break; - case MENU_DIALOG_HELP_SEND_DEBUG_INFO: - msg_hash_get_help_enum( - MENU_ENUM_LABEL_VALUE_HELP_SEND_DEBUG_INFO_DESC, - s, len); - break; - case MENU_DIALOG_HELP_SCANNING_CONTENT: - msg_hash_get_help_enum(MENU_ENUM_LABEL_VALUE_HELP_SCANNING_CONTENT_DESC, - s, len); - break; - case MENU_DIALOG_HELP_EXTRACT: - { - struct rarch_state *p_rarch = &rarch_st; - settings_t *settings = p_rarch->configuration_settings; - bool bundle_finished = settings->bools.bundle_finished; - - msg_hash_get_help_enum( - MENU_ENUM_LABEL_VALUE_EXTRACTING_PLEASE_WAIT, - s, len); - - if (bundle_finished) - { - configuration_set_bool(settings, - settings->bools.bundle_finished, false); - p_dialog->current_type = MENU_DIALOG_NONE; - return 1; - } - } - break; - case MENU_DIALOG_QUIT_CONFIRM: - case MENU_DIALOG_INFORMATION: - case MENU_DIALOG_QUESTION: - case MENU_DIALOG_WARNING: - case MENU_DIALOG_ERROR: - msg_hash_get_help_enum(MSG_UNKNOWN, - s, len); - break; - case MENU_DIALOG_NONE: - default: - break; - } - - return 0; -} - void menu_dialog_unset_pending_push(void) { struct rarch_state *p_rarch = &rarch_st; @@ -929,107 +719,6 @@ static bool menu_input_key_bind_custom_bind_keyboard_cb( return (binds->begin <= binds->last); } -static int menu_input_key_bind_set_mode_common( - struct menu_state *menu_st, - struct menu_bind_state *binds, - enum menu_input_binds_ctl_state state, - rarch_setting_t *setting, - settings_t *settings) -{ - menu_displaylist_info_t info; - unsigned bind_type = 0; - struct retro_keybind *keybind = NULL; - unsigned index_offset = setting->index_offset; - menu_list_t *menu_list = menu_st->entries.list; - file_list_t *menu_stack = menu_list ? MENU_LIST_GET(menu_list, (unsigned)0) : NULL; - size_t selection = menu_st->selection_ptr; - - menu_displaylist_info_init(&info); - - switch (state) - { - case MENU_INPUT_BINDS_CTL_BIND_SINGLE: - keybind = (struct retro_keybind*)setting->value.target.keybind; - - if (!keybind) - return -1; - - bind_type = setting_get_bind_type(setting); - - binds->begin = bind_type; - binds->last = bind_type; - binds->output = keybind; - binds->buffer = *(binds->output); - binds->user = index_offset; - - info.list = menu_stack; - info.type = MENU_SETTINGS_CUSTOM_BIND_KEYBOARD; - info.directory_ptr = selection; - info.enum_idx = MENU_ENUM_LABEL_CUSTOM_BIND; - info.label = strdup( - msg_hash_to_str(MENU_ENUM_LABEL_CUSTOM_BIND)); - break; - case MENU_INPUT_BINDS_CTL_BIND_ALL: - binds->output = &input_config_binds[index_offset][0]; - binds->buffer = *(binds->output); - binds->begin = MENU_SETTINGS_BIND_BEGIN; - binds->last = MENU_SETTINGS_BIND_LAST; - - info.list = menu_stack; - info.type = MENU_SETTINGS_CUSTOM_BIND_KEYBOARD; - info.directory_ptr = selection; - info.enum_idx = MENU_ENUM_LABEL_CUSTOM_BIND_ALL; - info.label = strdup( - msg_hash_to_str(MENU_ENUM_LABEL_CUSTOM_BIND_ALL)); - break; - default: - case MENU_INPUT_BINDS_CTL_BIND_NONE: - return 0; - } - - if (menu_displaylist_ctl(DISPLAYLIST_INFO, &info, settings)) - menu_displaylist_process(&info); - menu_displaylist_info_free(&info); - - return 0; -} - -static void menu_input_key_bind_poll_bind_get_rested_axes( - const input_device_driver_t *joypad, - const input_device_driver_t *sec_joypad, - struct menu_bind_state *state) -{ - unsigned a; - unsigned port = state->port; - - if (joypad) - { - /* poll only the relevant port */ - for (a = 0; a < MENU_MAX_AXES; a++) - { - if (AXIS_POS(a) != AXIS_NONE) - state->axis_state[port].rested_axes[a] = - joypad->axis(port, AXIS_POS(a)); - if (AXIS_NEG(a) != AXIS_NONE) - state->axis_state[port].rested_axes[a] += - joypad->axis(port, AXIS_NEG(a)); - } - } - - if (sec_joypad) - { - /* poll only the relevant port */ - for (a = 0; a < MENU_MAX_AXES; a++) - { - if (AXIS_POS(a) != AXIS_NONE) - state->axis_state[port].rested_axes[a] = sec_joypad->axis(port, AXIS_POS(a)); - - if (AXIS_NEG(a) != AXIS_NONE) - state->axis_state[port].rested_axes[a] += sec_joypad->axis(port, AXIS_NEG(a)); - } - } -} - static void menu_input_key_bind_poll_bind_state_internal( const input_device_driver_t *joypad, struct menu_bind_state *state, @@ -1151,236 +840,6 @@ static void menu_input_key_bind_poll_bind_state( } } -static bool menu_input_key_bind_poll_find_trigger_pad( - struct menu_bind_state *state, - struct menu_bind_state *new_state, - struct retro_keybind * output, - unsigned p) -{ - unsigned a, b, h; - const struct menu_bind_state_port *n = (const struct menu_bind_state_port*) - &new_state->state[p]; - const struct menu_bind_state_port *o = (const struct menu_bind_state_port*) - &state->state[p]; - - for (b = 0; b < MENU_MAX_MBUTTONS; b++) - { - bool iterate = n->mouse_buttons[b] && !o->mouse_buttons[b]; - - if (!iterate) - continue; - - switch (b) - { - case RETRO_DEVICE_ID_MOUSE_LEFT: - case RETRO_DEVICE_ID_MOUSE_RIGHT: - case RETRO_DEVICE_ID_MOUSE_MIDDLE: - case RETRO_DEVICE_ID_MOUSE_BUTTON_4: - case RETRO_DEVICE_ID_MOUSE_BUTTON_5: - case RETRO_DEVICE_ID_MOUSE_WHEELUP: - case RETRO_DEVICE_ID_MOUSE_WHEELDOWN: - case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP: - case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN: - output->mbutton = b; - return true; - } - } - - for (b = 0; b < MENU_MAX_BUTTONS; b++) - { - bool iterate = n->buttons[b] && !o->buttons[b]; - - if (!iterate) - continue; - - output->joykey = b; - output->joyaxis = AXIS_NONE; - return true; - } - - /* Axes are a bit tricky ... */ - for (a = 0; a < MENU_MAX_AXES; a++) - { - int locked_distance = abs(n->axes[a] - - new_state->axis_state[p].locked_axes[a]); - int rested_distance = abs(n->axes[a] - - new_state->axis_state[p].rested_axes[a]); - - if (abs(n->axes[a]) >= 20000 && - locked_distance >= 20000 && - rested_distance >= 20000) - { - /* Take care of case where axis rests on +/- 0x7fff - * (e.g. 360 controller on Linux) */ - output->joyaxis = n->axes[a] > 0 - ? AXIS_POS(a) : AXIS_NEG(a); - output->joykey = NO_BTN; - - /* Lock the current axis */ - new_state->axis_state[p].locked_axes[a] = - n->axes[a] > 0 ? - 0x7fff : -0x7fff; - return true; - } - - if (locked_distance >= 20000) /* Unlock the axis. */ - new_state->axis_state[p].locked_axes[a] = 0; - } - - for (h = 0; h < MENU_MAX_HATS; h++) - { - uint16_t trigged = n->hats[h] & (~o->hats[h]); - uint16_t sane_trigger = 0; - - if (trigged & HAT_UP_MASK) - sane_trigger = HAT_UP_MASK; - else if (trigged & HAT_DOWN_MASK) - sane_trigger = HAT_DOWN_MASK; - else if (trigged & HAT_LEFT_MASK) - sane_trigger = HAT_LEFT_MASK; - else if (trigged & HAT_RIGHT_MASK) - sane_trigger = HAT_RIGHT_MASK; - - if (sane_trigger) - { - output->joykey = HAT_MAP(h, sane_trigger); - output->joyaxis = AXIS_NONE; - return true; - } - } - - return false; -} - -#ifdef ANDROID -static bool menu_input_key_bind_poll_find_hold_pad( - struct menu_bind_state *new_state, - struct retro_keybind * output, - unsigned p) -{ - unsigned a, b, h; - const struct menu_bind_state_port *n = - (const struct menu_bind_state_port*) - &new_state->state[p]; - - for (b = 0; b < MENU_MAX_MBUTTONS; b++) - { - bool iterate = n->mouse_buttons[b]; - - if (!iterate) - continue; - - switch (b) - { - case RETRO_DEVICE_ID_MOUSE_LEFT: - case RETRO_DEVICE_ID_MOUSE_RIGHT: - case RETRO_DEVICE_ID_MOUSE_MIDDLE: - case RETRO_DEVICE_ID_MOUSE_BUTTON_4: - case RETRO_DEVICE_ID_MOUSE_BUTTON_5: - case RETRO_DEVICE_ID_MOUSE_WHEELUP: - case RETRO_DEVICE_ID_MOUSE_WHEELDOWN: - case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP: - case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN: - output->mbutton = b; - return true; - } - } - - for (b = 0; b < MENU_MAX_BUTTONS; b++) - { - bool iterate = n->buttons[b]; - - if (!iterate) - continue; - - output->joykey = b; - output->joyaxis = AXIS_NONE; - return true; - } - - /* Axes are a bit tricky ... */ - for (a = 0; a < MENU_MAX_AXES; a++) - { - if (abs(n->axes[a]) >= 20000) - { - /* Take care of case where axis rests on +/- 0x7fff - * (e.g. 360 controller on Linux) */ - output->joyaxis = n->axes[a] > 0 - ? AXIS_POS(a) : AXIS_NEG(a); - output->joykey = NO_BTN; - - return true; - } - } - - for (h = 0; h < MENU_MAX_HATS; h++) - { - uint16_t trigged = n->hats[h]; - uint16_t sane_trigger = 0; - - if (trigged & HAT_UP_MASK) - sane_trigger = HAT_UP_MASK; - else if (trigged & HAT_DOWN_MASK) - sane_trigger = HAT_DOWN_MASK; - else if (trigged & HAT_LEFT_MASK) - sane_trigger = HAT_LEFT_MASK; - else if (trigged & HAT_RIGHT_MASK) - sane_trigger = HAT_RIGHT_MASK; - - if (sane_trigger) - { - output->joykey = HAT_MAP(h, sane_trigger); - output->joyaxis = AXIS_NONE; - return true; - } - } - - return false; -} -#endif - -static bool menu_input_key_bind_poll_find_trigger( - unsigned max_users, - struct menu_bind_state *state, - struct menu_bind_state *new_state, - struct retro_keybind * output) -{ - if (state && new_state) - { - unsigned i; - - for (i = 0; i < max_users; i++) - { - if (menu_input_key_bind_poll_find_trigger_pad( - state, new_state, output, i)) - return true; - } - } - - return false; -} - -#ifdef ANDROID -static bool menu_input_key_bind_poll_find_hold( - unsigned max_users, - struct menu_bind_state *new_state, - struct retro_keybind * output) -{ - if (new_state) - { - unsigned i; - - for (i = 0; i < max_users; i++) - { - if (menu_input_key_bind_poll_find_hold_pad(new_state, output, i)) - return true; - } - } - - return false; -} -#endif - bool menu_input_key_bind_set_mode( enum menu_input_binds_ctl_state state, void *data) { @@ -1930,7 +1389,7 @@ static int generic_menu_iterate( { case ITERATE_TYPE_HELP: ret = menu_dialog_iterate( - &p_rarch->dialog_st, + &p_rarch->dialog_st, settings, menu->menu_state_msg, sizeof(menu->menu_state_msg), current_time); @@ -2893,202 +2352,6 @@ int menu_entry_action( return -1; } -static void menu_list_free_list( - const menu_ctx_driver_t *menu_driver_ctx, - file_list_t *list) -{ - unsigned i; - - for (i = 0; i < list->size; i++) - { - menu_ctx_list_t list_info; - - list_info.list = list; - list_info.idx = i; - list_info.list_size = list->size; - - menu_driver_list_free(menu_driver_ctx, &list_info); - } - - file_list_free(list); -} - -static void menu_list_free( - const menu_ctx_driver_t *menu_driver_ctx, - menu_list_t *menu_list) -{ - if (!menu_list) - return; - - if (menu_list->menu_stack) - { - unsigned i; - - for (i = 0; i < menu_list->menu_stack_size; i++) - { - if (!menu_list->menu_stack[i]) - continue; - - menu_list_free_list(menu_driver_ctx, - menu_list->menu_stack[i]); - menu_list->menu_stack[i] = NULL; - } - - free(menu_list->menu_stack); - } - - if (menu_list->selection_buf) - { - unsigned i; - - for (i = 0; i < menu_list->selection_buf_size; i++) - { - if (!menu_list->selection_buf[i]) - continue; - - menu_list_free_list(menu_driver_ctx, - menu_list->selection_buf[i]); - menu_list->selection_buf[i] = NULL; - } - - free(menu_list->selection_buf); - } - - free(menu_list); -} - -static menu_list_t *menu_list_new(const menu_ctx_driver_t *menu_driver_ctx) -{ - unsigned i; - menu_list_t *list = (menu_list_t*)malloc(sizeof(*list)); - - if (!list) - return NULL; - - list->menu_stack_size = 1; - list->selection_buf_size = 1; - list->selection_buf = NULL; - list->menu_stack = (file_list_t**) - calloc(list->menu_stack_size, sizeof(*list->menu_stack)); - - if (!list->menu_stack) - goto error; - - list->selection_buf = (file_list_t**) - calloc(list->selection_buf_size, sizeof(*list->selection_buf)); - - if (!list->selection_buf) - goto error; - - for (i = 0; i < list->menu_stack_size; i++) - { - list->menu_stack[i] = (file_list_t*) - malloc(sizeof(*list->menu_stack[i])); - list->menu_stack[i]->list = NULL; - list->menu_stack[i]->capacity = 0; - list->menu_stack[i]->size = 0; - } - - for (i = 0; i < list->selection_buf_size; i++) - { - list->selection_buf[i] = (file_list_t*) - malloc(sizeof(*list->selection_buf[i])); - list->selection_buf[i]->list = NULL; - list->selection_buf[i]->capacity = 0; - list->selection_buf[i]->size = 0; - } - - return list; - -error: - menu_list_free(menu_driver_ctx, list); - return NULL; -} - -static int menu_list_flush_stack_type(const char *needle, const char *label, - unsigned type, unsigned final_type) -{ - return needle ? !string_is_equal(needle, label) : (type != final_type); -} - -static bool menu_list_pop_stack( - const menu_ctx_driver_t *menu_driver_ctx, - void *menu_userdata, - menu_list_t *list, - size_t idx, - size_t *directory_ptr) -{ - file_list_t *menu_list = MENU_LIST_GET(list, (unsigned)idx); - - if (!menu_list) - return false; - - if (menu_list->size != 0) - { - menu_ctx_list_t list_info; - - list_info.list = menu_list; - list_info.idx = menu_list->size - 1; - list_info.list_size = menu_list->size - 1; - - menu_driver_list_free(menu_driver_ctx, &list_info); - } - - file_list_pop(menu_list, directory_ptr); - if ( menu_driver_ctx && - menu_driver_ctx->list_set_selection) - menu_driver_ctx->list_set_selection(menu_userdata, - menu_list); - - return true; -} - -static void menu_list_flush_stack( - const menu_ctx_driver_t *menu_driver_ctx, - void *menu_userdata, - struct menu_state *menu_st, - menu_list_t *list, - size_t idx, const char *needle, unsigned final_type) -{ - bool refresh = false; - const char *path = NULL; - const char *label = NULL; - unsigned type = 0; - size_t entry_idx = 0; - file_list_t *menu_list = MENU_LIST_GET(list, (unsigned)idx); - - menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); - - if (menu_list && menu_list->size) - file_list_get_at_offset(menu_list, menu_list->size - 1, &path, &label, &type, &entry_idx); - - while (menu_list_flush_stack_type( - needle, label, type, final_type) != 0) - { - bool refresh = false; - size_t new_selection_ptr = menu_st->selection_ptr; - bool wont_pop_stack = (MENU_LIST_GET_STACK_SIZE(list, idx) <= 1); - if (wont_pop_stack) - break; - - if (menu_driver_ctx->list_cache) - menu_driver_ctx->list_cache(menu_userdata, - MENU_LIST_PLAIN, 0); - - menu_list_pop_stack(menu_driver_ctx, - menu_userdata, - list, idx, &new_selection_ptr); - - menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); - - menu_st->selection_ptr = new_selection_ptr; - menu_list = MENU_LIST_GET(list, (unsigned)idx); - - if (menu_list && menu_list->size) - file_list_get_at_offset(menu_list, menu_list->size - 1, &path, &label, &type, &entry_idx); - } -} - /** * menu_entries_elem_get_first_char: * @list : File list handle. @@ -3291,36 +2554,6 @@ file_list_t *menu_entries_get_selection_buf_ptr(size_t idx) return MENU_LIST_GET_SELECTION(menu_list, (unsigned)idx); } -static void menu_entries_list_deinit( - const menu_ctx_driver_t *menu_driver_ctx, - struct menu_state *menu_st) -{ - if (menu_st->entries.list) - menu_list_free(menu_driver_ctx, menu_st->entries.list); - menu_st->entries.list = NULL; -} - -static void menu_entries_settings_deinit(struct menu_state *menu_st) -{ - menu_setting_free(menu_st->entries.list_settings); - if (menu_st->entries.list_settings) - free(menu_st->entries.list_settings); - menu_st->entries.list_settings = NULL; -} - - -static bool menu_entries_init( - struct menu_state *menu_st, - const menu_ctx_driver_t *menu_driver_ctx - ) -{ - if (!(menu_st->entries.list = (menu_list_t*)menu_list_new(menu_driver_ctx))) - return false; - if (!(menu_st->entries.list_settings = menu_setting_new())) - return false; - return true; -} - void menu_entries_append( file_list_t *list, const char *path, @@ -4999,22 +4232,6 @@ retro_time_t menu_driver_get_current_time(void) return menu_st->current_time_us; } -static void menu_driver_list_free( - const menu_ctx_driver_t *menu_driver_ctx, - menu_ctx_list_t *list) -{ - if (menu_driver_ctx) - if (menu_driver_ctx->list_free) - menu_driver_ctx->list_free( - list->list, list->idx, list->list_size); - - if (list->list) - { - file_list_free_userdata (list->list, list->idx); - file_list_free_actiondata(list->list, list->idx); - } -} - /* Returns true if search filter is enabled * for the specified menu list */ bool menu_driver_search_filter_enabled(const char *label, unsigned type) @@ -16543,10 +15760,10 @@ static bool rarch_environment_cb(unsigned cmd, void *data) RARCH_LOG("[Environ]: SET_VARIABLES.\n"); if (runloop_state.core_options) - retroarch_deinit_core_options(p_rarch, + retroarch_deinit_core_options( path_get(RARCH_PATH_CORE_OPTIONS)); - retroarch_init_core_variables(p_rarch, + retroarch_init_core_variables(settings, (const struct retro_variable *)data); break; @@ -16562,13 +15779,13 @@ static bool rarch_environment_cb(unsigned cmd, void *data) (const struct retro_core_option_definition*)data); if (runloop_state.core_options) - retroarch_deinit_core_options(p_rarch, + retroarch_deinit_core_options( path_get(RARCH_PATH_CORE_OPTIONS)); if (options_v2) { /* Initialise core options */ - rarch_init_core_options(p_rarch, options_v2); + rarch_init_core_options(settings, options_v2); /* Clean up */ core_option_manager_free_converted(options_v2); @@ -16587,13 +15804,13 @@ static bool rarch_environment_cb(unsigned cmd, void *data) (const struct retro_core_options_intl*)data); if (runloop_state.core_options) - retroarch_deinit_core_options(p_rarch, + retroarch_deinit_core_options( path_get(RARCH_PATH_CORE_OPTIONS)); if (options_v2) { /* Initialise core options */ - rarch_init_core_options(p_rarch, options_v2); + rarch_init_core_options(settings, options_v2); /* Clean up */ core_option_manager_free_converted(options_v2); @@ -16611,11 +15828,11 @@ static bool rarch_environment_cb(unsigned cmd, void *data) settings->bools.core_option_category_enable; if (runloop_state.core_options) - retroarch_deinit_core_options(p_rarch, + retroarch_deinit_core_options( path_get(RARCH_PATH_CORE_OPTIONS)); if (options_v2) - rarch_init_core_options(p_rarch, options_v2); + rarch_init_core_options(settings, options_v2); /* Return value does not indicate success. * Callback returns 'true' if core option @@ -16638,13 +15855,13 @@ static bool rarch_environment_cb(unsigned cmd, void *data) settings->bools.core_option_category_enable; if (runloop_state.core_options) - retroarch_deinit_core_options(p_rarch, + retroarch_deinit_core_options( path_get(RARCH_PATH_CORE_OPTIONS)); if (options_v2) { /* Initialise core options */ - rarch_init_core_options(p_rarch, options_v2); + rarch_init_core_options(settings, options_v2); /* Clean up */ core_option_manager_free_converted(options_v2); @@ -18429,7 +17646,7 @@ static void uninit_libretro_symbols( p_rarch->core_set_shared_context = false; if (runloop_state.core_options) - retroarch_deinit_core_options(p_rarch, + retroarch_deinit_core_options( path_get(RARCH_PATH_CORE_OPTIONS)); retroarch_system_info_free(p_rarch); retroarch_frame_time_free(p_rarch); @@ -23013,385 +22230,6 @@ static int16_t input_joypad_axis( /* MENU INPUT */ #ifdef HAVE_MENU -static void menu_input_get_mouse_hw_state( - gfx_display_t *p_disp, - menu_handle_t *menu, - input_driver_state_t *input_driver_st, - input_driver_t *current_input, - const input_device_driver_t *joypad, - const input_device_driver_t *sec_joypad, - bool keyboard_mapping_blocked, - bool menu_mouse_enable, - bool input_overlay_enable, - bool overlay_active, - menu_input_pointer_hw_state_t *hw_state) -{ - rarch_joypad_info_t joypad_info; - static int16_t last_x = 0; - static int16_t last_y = 0; - static bool last_select_pressed = false; - static bool last_cancel_pressed = false; - bool menu_has_fb = - (menu && - menu->driver_ctx && - menu->driver_ctx->set_texture); - bool state_inited = current_input && - current_input->input_state; -#ifdef HAVE_OVERLAY - /* Menu pointer controls are ignored when overlays are enabled. */ - if (overlay_active) - menu_mouse_enable = false; -#endif - - /* Easiest to set inactive by default, and toggle - * when input is detected */ - hw_state->active = false; - hw_state->x = 0; - hw_state->y = 0; - hw_state->select_pressed = false; - hw_state->cancel_pressed = false; - hw_state->up_pressed = false; - hw_state->down_pressed = false; - hw_state->left_pressed = false; - hw_state->right_pressed = false; - - if (!menu_mouse_enable) - return; - - joypad_info.joy_idx = 0; - joypad_info.auto_binds = NULL; - joypad_info.axis_threshold = 0.0f; - - /* X/Y position */ - if (state_inited) - { - if ((hw_state->x = current_input->input_state( - input_driver_st->current_data, - joypad, - sec_joypad, - &joypad_info, - NULL, - keyboard_mapping_blocked, - 0, - RARCH_DEVICE_MOUSE_SCREEN, - 0, - RETRO_DEVICE_ID_MOUSE_X)) != last_x) - hw_state->active = true; - if ((hw_state->y = current_input->input_state( - input_driver_st->current_data, - joypad, - sec_joypad, - &joypad_info, - NULL, - keyboard_mapping_blocked, - 0, - RARCH_DEVICE_MOUSE_SCREEN, - 0, - RETRO_DEVICE_ID_MOUSE_Y)) != last_y) - hw_state->active = true; - } - - last_x = hw_state->x; - last_y = hw_state->y; - - /* > X/Y position adjustment */ - if (menu_has_fb) - { - /* RGUI uses a framebuffer texture + custom viewports, - * which means we have to convert from screen space to - * menu space... */ - struct video_viewport vp = {0}; - /* Read display/framebuffer info */ - unsigned fb_width = p_disp->framebuf_width; - unsigned fb_height = p_disp->framebuf_height; - - video_driver_get_viewport_info(&vp); - - /* Adjust X position */ - hw_state->x = (int16_t)(((float)(hw_state->x - vp.x) / (float)vp.width) * (float)fb_width); - hw_state->x = (hw_state->x < 0) ? (0 ) : hw_state->x; - hw_state->x = (hw_state->x >= fb_width) ? (fb_width -1) : hw_state->x; - - /* Adjust Y position */ - hw_state->y = (int16_t)(((float)(hw_state->y - vp.y) / (float)vp.height) * (float)fb_height); - hw_state->y = (hw_state->y < 0) ? (0 ) : hw_state->y; - hw_state->y = (hw_state->y >= fb_height) ? (fb_height-1) : hw_state->y; - } - - if (state_inited) - { - /* Select (LMB) - * Note that releasing select also counts as activity */ - hw_state->select_pressed = (bool) - current_input->input_state( - input_driver_st->current_data, - joypad, - sec_joypad, - &joypad_info, - NULL, - keyboard_mapping_blocked, - 0, - RETRO_DEVICE_MOUSE, - 0, - RETRO_DEVICE_ID_MOUSE_LEFT); - /* Cancel (RMB) - * Note that releasing cancel also counts as activity */ - hw_state->cancel_pressed = (bool) - current_input->input_state( - input_driver_st->current_data, - joypad, - sec_joypad, - &joypad_info, - NULL, - keyboard_mapping_blocked, - 0, - RETRO_DEVICE_MOUSE, - 0, - RETRO_DEVICE_ID_MOUSE_RIGHT); - /* Up (mouse wheel up) */ - if ((hw_state->up_pressed = (bool) - current_input->input_state( - input_driver_st->current_data, - joypad, - sec_joypad, - &joypad_info, - NULL, - keyboard_mapping_blocked, - 0, - RETRO_DEVICE_MOUSE, - 0, - RETRO_DEVICE_ID_MOUSE_WHEELUP))) - hw_state->active = true; - /* Down (mouse wheel down) */ - if ((hw_state->down_pressed = (bool) - current_input->input_state( - input_driver_st->current_data, - joypad, - sec_joypad, - &joypad_info, - NULL, - keyboard_mapping_blocked, - 0, - RETRO_DEVICE_MOUSE, - 0, - RETRO_DEVICE_ID_MOUSE_WHEELDOWN))) - hw_state->active = true; - /* Left (mouse wheel horizontal left) */ - if ((hw_state->left_pressed = (bool) - current_input->input_state( - input_driver_st->current_data, - joypad, - sec_joypad, - &joypad_info, - NULL, - keyboard_mapping_blocked, - 0, - RETRO_DEVICE_MOUSE, - 0, - RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN))) - hw_state->active = true; - /* Right (mouse wheel horizontal right) */ - if ((hw_state->right_pressed = (bool) - current_input->input_state( - input_driver_st->current_data, - joypad, - sec_joypad, - &joypad_info, - NULL, - keyboard_mapping_blocked, - 0, - RETRO_DEVICE_MOUSE, - 0, - RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP))) - hw_state->active = true; - } - - if (hw_state->select_pressed || (hw_state->select_pressed != last_select_pressed)) - hw_state->active = true; - if (hw_state->cancel_pressed || (hw_state->cancel_pressed != last_cancel_pressed)) - hw_state->active = true; - last_select_pressed = hw_state->select_pressed; - last_cancel_pressed = hw_state->cancel_pressed; -} - -static void menu_input_get_touchscreen_hw_state( - gfx_display_t *p_disp, - menu_handle_t *menu, - input_driver_state_t *input_driver_st, - input_driver_t *current_input, - const input_device_driver_t *joypad, - const input_device_driver_t *sec_joypad, - bool keyboard_mapping_blocked, - bool overlay_active, - bool pointer_enabled, - unsigned input_touch_scale, - menu_input_pointer_hw_state_t *hw_state) -{ - rarch_joypad_info_t joypad_info; - unsigned fb_width, fb_height; - int pointer_x = 0; - int pointer_y = 0; - const struct retro_keybind *binds[MAX_USERS] = {NULL}; - /* Is a background texture set for the current menu driver? - * Checks if the menu framebuffer is set. - * This would usually only return true - * for framebuffer-based menu drivers, like RGUI. */ - int pointer_device = - (menu && menu->driver_ctx && menu->driver_ctx->set_texture) ? - RETRO_DEVICE_POINTER : RARCH_DEVICE_POINTER_SCREEN; - static int16_t last_x = 0; - static int16_t last_y = 0; - static bool last_select_pressed = false; - static bool last_cancel_pressed = false; - - /* Easiest to set inactive by default, and toggle - * when input is detected */ - hw_state->active = false; - - /* Touch screens don't have mouse wheels, so these - * are always disabled */ - hw_state->up_pressed = false; - hw_state->down_pressed = false; - hw_state->left_pressed = false; - hw_state->right_pressed = false; - -#ifdef HAVE_OVERLAY - /* Menu pointer controls are ignored when overlays are enabled. */ - if (overlay_active) - pointer_enabled = false; -#endif - - /* If touchscreen is disabled, ignore all input */ - if (!pointer_enabled) - { - hw_state->x = 0; - hw_state->y = 0; - hw_state->select_pressed = false; - hw_state->cancel_pressed = false; - return; - } - - /* TODO/FIXME - this should only be used for framebuffer-based - * menu drivers like RGUI. Touchscreen input as a whole should - * NOT be dependent on this - */ - fb_width = p_disp->framebuf_width; - fb_height = p_disp->framebuf_height; - - joypad_info.joy_idx = 0; - joypad_info.auto_binds = NULL; - joypad_info.axis_threshold = 0.0f; - - /* X pos */ - if (current_input->input_state) - pointer_x = current_input->input_state( - input_driver_st->current_data, - joypad, - sec_joypad, - &joypad_info, binds, - keyboard_mapping_blocked, - 0, pointer_device, - 0, RETRO_DEVICE_ID_POINTER_X); - hw_state->x = ((pointer_x + 0x7fff) * (int)fb_width) / 0xFFFF; - hw_state->x *= input_touch_scale; - - /* > An annoyance - we get different starting positions - * depending upon whether pointer_device is - * RETRO_DEVICE_POINTER or RARCH_DEVICE_POINTER_SCREEN, - * so different 'activity' checks are required to prevent - * false positives on first run */ - if (pointer_device == RARCH_DEVICE_POINTER_SCREEN) - { - if (hw_state->x != last_x) - hw_state->active = true; - last_x = hw_state->x; - } - else - { - if (pointer_x != last_x) - hw_state->active = true; - last_x = pointer_x; - } - - /* Y pos */ - if (current_input->input_state) - pointer_y = current_input->input_state( - input_driver_st->current_data, - joypad, - sec_joypad, - &joypad_info, binds, - keyboard_mapping_blocked, - 0, pointer_device, - 0, RETRO_DEVICE_ID_POINTER_Y); - hw_state->y = ((pointer_y + 0x7fff) * (int)fb_height) / 0xFFFF; - hw_state->y *= input_touch_scale; - - if (pointer_device == RARCH_DEVICE_POINTER_SCREEN) - { - if (hw_state->y != last_y) - hw_state->active = true; - last_y = hw_state->y; - } - else - { - if (pointer_y != last_y) - hw_state->active = true; - last_y = pointer_y; - } - - /* Select (touch screen contact) - * Note that releasing select also counts as activity */ - if (current_input->input_state) - hw_state->select_pressed = (bool)current_input->input_state( - input_driver_st->current_data, - joypad, - sec_joypad, - &joypad_info, binds, - keyboard_mapping_blocked, - 0, pointer_device, - 0, RETRO_DEVICE_ID_POINTER_PRESSED); - if (hw_state->select_pressed || (hw_state->select_pressed != last_select_pressed)) - hw_state->active = true; - last_select_pressed = hw_state->select_pressed; - - /* Cancel (touch screen 'back' - don't know what is this, but whatever...) - * Note that releasing cancel also counts as activity */ - if (current_input->input_state) - hw_state->cancel_pressed = (bool)current_input->input_state( - input_driver_st->current_data, - joypad, - sec_joypad, - &joypad_info, binds, - keyboard_mapping_blocked, - 0, pointer_device, - 0, RARCH_DEVICE_ID_POINTER_BACK); - if (hw_state->cancel_pressed || (hw_state->cancel_pressed != last_cancel_pressed)) - hw_state->active = true; - last_cancel_pressed = hw_state->cancel_pressed; -} - -static INLINE bool input_event_osk_show_symbol_pages( - menu_handle_t *menu) -{ -#if defined(HAVE_LANGEXTRA) -#if defined(HAVE_RGUI) - bool menu_has_fb = (menu && - menu->driver_ctx && - menu->driver_ctx->set_texture); - unsigned language = *msg_hash_get_uint(MSG_HASH_USER_LANGUAGE); - return !menu_has_fb || - ((language == RETRO_LANGUAGE_JAPANESE) || - (language == RETRO_LANGUAGE_KOREAN) || - (language == RETRO_LANGUAGE_CHINESE_SIMPLIFIED) || - (language == RETRO_LANGUAGE_CHINESE_TRADITIONAL)); -#else /* HAVE_RGUI */ - return true; -#endif /* HAVE_RGUI */ -#else /* HAVE_LANGEXTRA */ - return false; -#endif /* HAVE_LANGEXTRA */ -} - static void input_event_osk_append( struct rarch_state *p_rarch, enum osk_type *osk_idx, int ptr, @@ -23441,71 +22279,6 @@ static void input_event_osk_append( } } -static void input_event_osk_iterate( - void *osk_grid, - enum osk_type osk_idx) -{ -#ifndef HAVE_LANGEXTRA - /* If HAVE_LANGEXTRA is not defined, define some ASCII-friendly pages. */ - static const char *uppercase_grid[] = { - "1","2","3","4","5","6","7","8","9","0","Bksp", - "Q","W","E","R","T","Y","U","I","O","P","Enter", - "A","S","D","F","G","H","J","K","L","+","Lower", - "Z","X","C","V","B","N","M"," ","_","/","Next"}; - static const char *lowercase_grid[] = { - "1","2","3","4","5","6","7","8","9","0","Bksp", - "q","w","e","r","t","y","u","i","o","p","Enter", - "a","s","d","f","g","h","j","k","l","@","Upper", - "z","x","c","v","b","n","m"," ","-",".","Next"}; - static const char *symbols_page1_grid[] = { - "1","2","3","4","5","6","7","8","9","0","Bksp", - "!","\"","#","$","%","&","'","*","(",")","Enter", - "+",",","-","~","/",":",";","=","<",">","Lower", - "?","@","[","\\","]","^","_","|","{","}","Next"}; -#endif - switch (osk_idx) - { -#ifdef HAVE_LANGEXTRA - case OSK_HIRAGANA_PAGE1: - memcpy(osk_grid, - hiragana_page1_grid, - sizeof(hiragana_page1_grid)); - break; - case OSK_HIRAGANA_PAGE2: - memcpy(osk_grid, - hiragana_page2_grid, - sizeof(hiragana_page2_grid)); - break; - case OSK_KATAKANA_PAGE1: - memcpy(osk_grid, - katakana_page1_grid, - sizeof(katakana_page1_grid)); - break; - case OSK_KATAKANA_PAGE2: - memcpy(osk_grid, - katakana_page2_grid, - sizeof(katakana_page2_grid)); - break; -#endif - case OSK_SYMBOLS_PAGE1: - memcpy(osk_grid, - symbols_page1_grid, - sizeof(uppercase_grid)); - break; - case OSK_UPPERCASE_LATIN: - memcpy(osk_grid, - uppercase_grid, - sizeof(uppercase_grid)); - break; - case OSK_LOWERCASE_LATIN: - default: - memcpy(osk_grid, - lowercase_grid, - sizeof(lowercase_grid)); - break; - } -} - /* * This function gets called in order to process all input events * for the current frame. @@ -23934,118 +22707,6 @@ void menu_input_set_pointer_y_accel(float y_accel) menu_input->pointer.y_accel = y_accel; } -static float menu_input_get_dpi(struct rarch_state *p_rarch, - menu_handle_t *menu, - gfx_display_t *p_disp) -{ - static unsigned last_video_width = 0; - static unsigned last_video_height = 0; - static float dpi = 0.0f; - static bool dpi_cached = false; - - /* Regardless of menu driver, need 'actual' screen DPI - * Note: DPI is a fixed hardware property. To minimise performance - * overheads we therefore only call video_context_driver_get_metrics() - * on first run, or when the current video resolution changes */ - if (!dpi_cached || - (p_rarch->video_driver_width != last_video_width) || - (p_rarch->video_driver_height != last_video_height)) - { - gfx_ctx_metrics_t mets; - /* Note: If video_context_driver_get_metrics() fails, - * we don't know what happened to dpi - so ensure it - * is reset to a sane value */ - - mets.type = DISPLAY_METRIC_DPI; - mets.value = &dpi; - if (!video_context_driver_get_metrics(&mets)) - dpi = 0.0f; - - dpi_cached = true; - last_video_width = p_rarch->video_driver_width; - last_video_height = p_rarch->video_driver_height; - } - - /* RGUI uses a framebuffer texture, which means we - * operate in menu space, not screen space. - * DPI in a traditional sense is therefore meaningless, - * so generate a substitute value based upon framebuffer - * dimensions */ - if (dpi > 0.0f) - { - bool menu_has_fb = - menu->driver_ctx - && menu->driver_ctx->set_texture; - - /* Read framebuffer info? */ - if (menu_has_fb) - { - unsigned fb_height = p_disp->framebuf_height; - /* Rationale for current 'DPI' determination method: - * - Divide screen height by DPI, to get number of vertical - * '1 inch' squares - * - Divide RGUI framebuffer height by number of vertical - * '1 inch' squares to get number of menu space pixels - * per inch - * This is crude, but should be sufficient... */ - return ((float)fb_height / (float)p_rarch->video_driver_height) * dpi; - } - } - - return dpi; -} - -static bool menu_should_pop_stack(const char *label) -{ - /* > Info box */ - if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_INFO_SCREEN))) - return true; - /* > Help box */ - if (string_starts_with_size(label, "help", STRLEN_CONST("help"))) - if ( - string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP)) - || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_CONTROLS)) - || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_WHAT_IS_A_CORE)) - || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_LOADING_CONTENT)) - || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_SCANNING_CONTENT)) - || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_CHANGE_VIRTUAL_GAMEPAD)) - || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_AUDIO_VIDEO_TROUBLESHOOTING)) - || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_SEND_DEBUG_INFO)) - || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CHEEVOS_DESCRIPTION))) - return true; - if ( - string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CHEEVOS_DESCRIPTION))) - return true; - return false; -} - -/* Used to close an active message box (help or info) - * TODO/FIXME: The way that message boxes are handled - * is complete garbage. generic_menu_iterate() and - * message boxes in general need a total rewrite. - * I consider this current 'close_messagebox' a hack, - * but at least it prevents undefined/dangerous - * behaviour... */ -static void menu_input_pointer_close_messagebox(struct menu_state *menu_st) -{ - const char *label = NULL; - - /* Determine whether this is a help or info - * message box */ - file_list_get_last(MENU_LIST_GET(menu_st->entries.list, 0), - NULL, &label, NULL, NULL); - - /* Pop stack, if required */ - if (menu_should_pop_stack(label)) - { - size_t selection = menu_st->selection_ptr; - size_t new_selection = selection; - - menu_entries_pop_stack(&new_selection, 0, 0); - menu_st->selection_ptr = selection; - } -} - static int menu_input_pointer_post_iterate( struct rarch_state *p_rarch, gfx_display_t *p_disp, @@ -24162,7 +22823,8 @@ static int menu_input_pointer_post_iterate( { /* Pointer is being held down * (i.e. for more than one frame) */ - float dpi = menu ? menu_input_get_dpi(p_rarch, menu, p_disp) : 0.0f; + float dpi = menu ? menu_input_get_dpi(menu, p_disp, + p_rarch->video_driver_width, p_rarch->video_driver_height) : 0.0f; /* > Update deltas + acceleration & detect press direction * Note: We only do this if the pointer has moved above @@ -24431,7 +23093,7 @@ static int menu_input_pointer_post_iterate( else { /* Pointer has moved - check if this is a swipe */ - float dpi = menu ? menu_input_get_dpi(p_rarch, menu, p_disp) : 0.0f; + float dpi = menu ? menu_input_get_dpi(menu, p_disp, p_rarch->video_driver_width, p_rarch->video_driver_height) : 0.0f; if ((dpi > 0.0f) && @@ -34535,11 +33197,10 @@ static bool retroarch_validate_per_core_options(char *s, } static bool retroarch_validate_game_options( + const char *core_name, char *s, size_t len, bool mkdir) { - const char *core_name = runloop_state.system.info.library_name; const char *game_name = path_basename(path_get(RARCH_PATH_BASENAME)); - return retroarch_validate_per_core_options(s, len, mkdir, core_name, game_name); } @@ -35222,7 +33883,7 @@ void retroarch_menu_running(void) void retroarch_menu_running_finished(bool quit) { struct rarch_state *p_rarch = &rarch_st; -#if defined(HAVE_MENU) || defined(HAVE_OVERLAY) +#ifdef HAVE_OVERLAY settings_t *settings = p_rarch->configuration_settings; #endif #ifdef HAVE_MENU @@ -35311,13 +33972,13 @@ void retroarch_menu_running_finished(bool quit) * options path has been found, * otherwise false (0). **/ -static bool rarch_game_specific_options(struct rarch_state *p_rarch, - char **output) +static bool rarch_game_specific_options(char **output) { char game_options_path[PATH_MAX_LENGTH]; game_options_path[0] ='\0'; if (!retroarch_validate_game_options( + runloop_state.system.info.library_name, game_options_path, sizeof(game_options_path), false) || !path_is_valid(game_options_path)) @@ -35338,7 +33999,6 @@ static bool rarch_game_specific_options(struct rarch_state *p_rarch, * otherwise false (0). **/ static bool rarch_folder_specific_options( - struct rarch_state *p_rarch, char **output) { char folder_options_path[PATH_MAX_LENGTH]; @@ -35419,19 +34079,18 @@ static void runloop_task_msg_queue_push( * path and src_path are NULL-terminated * */ static void rarch_init_core_options_path( - struct rarch_state *p_rarch, + settings_t *settings, char *path, size_t len, char *src_path, size_t src_len) { char *game_options_path = NULL; char *folder_options_path = NULL; - settings_t *settings = p_rarch->configuration_settings; bool game_specific_options = settings->bools.game_specific_options; /* Check whether game-specific options exist */ if (game_specific_options && - rarch_game_specific_options(p_rarch, &game_options_path)) + rarch_game_specific_options(&game_options_path)) { /* Notify system that we have a valid core options * override */ @@ -35446,7 +34105,7 @@ static void rarch_init_core_options_path( } /* Check whether folder-specific options exist */ else if (game_specific_options && - rarch_folder_specific_options(p_rarch, + rarch_folder_specific_options( &folder_options_path)) { /* Notify system that we have a valid core options @@ -35522,10 +34181,9 @@ static void rarch_init_core_options_path( } static void rarch_init_core_options( - struct rarch_state *p_rarch, + settings_t *settings, const struct retro_core_options_v2 *options_v2) { - settings_t *settings = p_rarch->configuration_settings; bool categories_enabled = settings->bools.core_option_category_enable; char options_path[PATH_MAX_LENGTH]; char src_options_path[PATH_MAX_LENGTH]; @@ -35535,7 +34193,7 @@ static void rarch_init_core_options( src_options_path[0] = '\0'; /* Get core options file path */ - rarch_init_core_options_path(p_rarch, + rarch_init_core_options_path(settings, options_path, sizeof(options_path), src_options_path, sizeof(src_options_path)); @@ -35839,7 +34497,7 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data) return true; } -static void retroarch_deinit_core_options(struct rarch_state *p_rarch, +static void retroarch_deinit_core_options( const char *path_core_options) { /* Check whether game-specific options file is being used */ @@ -35892,7 +34550,7 @@ static void retroarch_deinit_core_options(struct rarch_state *p_rarch, } static void retroarch_init_core_variables( - struct rarch_state *p_rarch, + settings_t *settings, const struct retro_variable *vars) { char options_path[PATH_MAX_LENGTH]; @@ -35903,7 +34561,8 @@ static void retroarch_init_core_variables( src_options_path[0] = '\0'; /* Get core options file path */ - rarch_init_core_options_path(p_rarch, + rarch_init_core_options_path( + settings, options_path, sizeof(options_path), src_options_path, sizeof(src_options_path)); @@ -38972,6 +37631,7 @@ bool core_options_create_override(bool game_specific) { /* Get options file path (game-specific) */ if (!retroarch_validate_game_options( + runloop_state.system.info.library_name, options_path, sizeof(options_path), true)) goto error; diff --git a/retroarch_data.h b/retroarch_data.h index 728032145d..518e761025 100644 --- a/retroarch_data.h +++ b/retroarch_data.h @@ -268,18 +268,6 @@ #define MAPPER_SET_KEY(state, key) (state)->keys[(key) / 32] |= 1 << ((key) % 32) #define MAPPER_UNSET_KEY(state, key) (state)->keys[(key) / 32] &= ~(1 << ((key) % 32)) - -#ifdef HAVE_MENU -#define MENU_LIST_GET(list, idx) ((list) ? ((list)->menu_stack[(idx)]) : NULL) - -#define MENU_LIST_GET_SELECTION(list, idx) ((list) ? ((list)->selection_buf[(idx)]) : NULL) - -#define MENU_LIST_GET_STACK_SIZE(list, idx) ((list)->menu_stack[(idx)]->size) - -#define MENU_ENTRIES_GET_SELECTION_BUF_PTR_INTERNAL(menu_st, idx) ((menu_st->entries.list) ? MENU_LIST_GET_SELECTION(menu_st->entries.list, (unsigned)idx) : NULL) -#define MENU_ENTRIES_NEEDS_REFRESH(menu_st) (!(menu_st->entries_nonblocking_refresh || !menu_st->entries_need_refresh)) -#endif - #define CDN_URL "https://cdn.discordapp.com/avatars" #ifdef HAVE_DYNAMIC @@ -388,18 +376,6 @@ #define PERF_LOG_FMT "[PERF]: Avg (%s): %llu ticks, %llu runs.\n" #endif -#ifdef HAVE_MENU -#define SCROLL_INDEX_SIZE (2 * (26 + 2) + 1) - -#define POWERSTATE_CHECK_INTERVAL (30 * 1000000) -#define DATETIME_CHECK_INTERVAL 1000000 - -#define MENU_MAX_BUTTONS 219 -#define MENU_MAX_AXES 32 -#define MENU_MAX_HATS 4 -#define MENU_MAX_MBUTTONS 32 /* Enough to cover largest libretro constant*/ -#endif - /* DRIVERS */ audio_driver_t audio_null = { @@ -1244,112 +1220,6 @@ typedef struct input_game_focus_state typedef bool(*runahead_load_state_function)(const void*, size_t); #endif -#ifdef HAVE_MENU -typedef struct menu_ctx_load_image -{ - void *data; - enum menu_image_type type; -} menu_ctx_load_image_t; - -struct menu_list -{ - file_list_t **menu_stack; - size_t menu_stack_size; - file_list_t **selection_buf; - size_t selection_buf_size; -}; - -typedef struct menu_list menu_list_t; - -struct menu_state -{ - /* Timers */ - retro_time_t current_time_us; - retro_time_t powerstate_last_time_us; - retro_time_t datetime_last_time_us; - retro_time_t input_last_time_us; - - struct - { - rarch_setting_t *list_settings; - menu_list_t *list; - size_t begin; - } entries; - size_t selection_ptr; - - /* Quick jumping indices with L/R. - * Rebuilt when parsing directory. */ - struct - { - size_t index_list[SCROLL_INDEX_SIZE]; - unsigned index_size; - unsigned acceleration; - } scroll; - - /* Storage container for current menu datetime - * representation string */ - char datetime_cache[255]; - - /* When generating a menu list in menu_displaylist_build_list(), - * the entry with a label matching 'pending_selection' will - * be selected automatically */ - char pending_selection[PATH_MAX_LENGTH]; - - /* when enabled, on next iteration the 'Quick Menu' list will - * be pushed onto the stack */ - bool pending_quick_menu; - bool prevent_populate; - /* The menu driver owns the userdata */ - bool data_own; - /* Flagged when menu entries need to be refreshed */ - bool entries_need_refresh; - bool entries_nonblocking_refresh; - /* 'Close Content'-hotkey menu resetting */ - bool pending_close_content; - /* Screensaver status - * - Does menu driver support screensaver functionality? - * - Is screensaver currently active? */ - bool screensaver_supported; - bool screensaver_active; -}; - -struct menu_bind_state_port -{ - int16_t axes[MENU_MAX_AXES]; - uint16_t hats[MENU_MAX_HATS]; - bool mouse_buttons[MENU_MAX_MBUTTONS]; - bool buttons[MENU_MAX_BUTTONS]; -}; - -struct menu_bind_axis_state -{ - /* Default axis state. */ - int16_t rested_axes[MENU_MAX_AXES]; - /* Locked axis state. If we configured an axis, - * avoid having the same axis state trigger something again right away. */ - int16_t locked_axes[MENU_MAX_AXES]; -}; - -struct menu_bind_state -{ - rarch_timer_t timer_timeout; - rarch_timer_t timer_hold; - - struct retro_keybind *output; - struct retro_keybind buffer; - - struct menu_bind_state_port state[MAX_USERS]; - struct menu_bind_axis_state axis_state[MAX_USERS]; - - unsigned begin; - unsigned last; - unsigned user; - unsigned port; - - bool skip; -}; -#endif - typedef struct input_mapper { /* Left X, Left Y, Right X, Right Y */ diff --git a/retroarch_fwd_decls.h b/retroarch_fwd_decls.h index 295ffd85dc..897c39ea9c 100644 --- a/retroarch_fwd_decls.h +++ b/retroarch_fwd_decls.h @@ -44,13 +44,13 @@ static bool midi_driver_set_all_sounds_off(struct rarch_state *p_rarch); static const void *midi_driver_find_handle(int index); static bool midi_driver_flush(void); -static void retroarch_deinit_core_options(struct rarch_state *p_rarch, +static void retroarch_deinit_core_options( const char *p); static void retroarch_init_core_variables( - struct rarch_state *p_rarch, + settings_t *settings, const struct retro_variable *vars); static void rarch_init_core_options( - struct rarch_state *p_rarch, + settings_t *settings, const struct retro_core_options_v2 *options_v2); #ifdef HAVE_RUNAHEAD #if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)