/** * menu_iterate: * @input : input sample for this frame * @old_input : input sample of the previous frame * @trigger_input : difference' input sample - difference * between 'input' and 'old_input' * * Runs RetroArch menu for one frame. * * Returns: 0 on success, -1 if we need to quit out of the loop. **/ int generic_menu_iterate(enum menu_action action) { size_t selection; menu_entry_t entry; enum action_iterate_type iterate_type; const char *label = NULL; int ret = 0; uint32_t label_hash = 0; uint32_t hash = 0; menu_handle_t *menu = menu_driver_get_ptr(); file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(); file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(); menu_entries_get_last_stack(NULL, &label, NULL, NULL); if (!menu) return 0; if (!menu_navigation_ctl(MENU_NAVIGATION_CTL_GET_SELECTION, &selection)) return 0; menu->menu_state.msg[0] = '\0'; hash = menu_hash_calculate(label); iterate_type = action_iterate_type(hash); if (action != MENU_ACTION_NOOP || menu_entries_needs_refresh() || menu_display_ctl(MENU_DISPLAY_CTL_UPDATE_PENDING, NULL)) { BIT64_SET(menu->state, MENU_STATE_RENDER_FRAMEBUFFER); } switch (iterate_type) { case ITERATE_TYPE_HELP: ret = action_iterate_help(menu->menu_state.msg, sizeof(menu->menu_state.msg), label); BIT64_SET(menu->state, MENU_STATE_RENDER_MESSAGEBOX); BIT64_SET(menu->state, MENU_STATE_POST_ITERATE); if (ret == 1 || action == MENU_ACTION_OK) BIT64_SET(menu->state, MENU_STATE_POP_STACK); break; case ITERATE_TYPE_BIND: if (menu_input_key_bind_iterate(menu->menu_state.msg, sizeof(menu->menu_state.msg))) { menu_entries_pop_stack(&selection); menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &selection); } else BIT64_SET(menu->state, MENU_STATE_RENDER_MESSAGEBOX); break; case ITERATE_TYPE_INFO: { menu_file_list_cbs_t *cbs = menu_entries_get_actiondata_at_offset(selection_buf, selection); rarch_setting_t *setting = cbs->setting; if (setting) { char needle[PATH_MAX_LENGTH]; strlcpy(needle, menu_setting_get_name(setting), sizeof(needle)); label_hash = menu_hash_calculate(needle); } ret = menu_hash_get_help(label_hash, menu->menu_state.msg, sizeof(menu->menu_state.msg)); } BIT64_SET(menu->state, MENU_STATE_RENDER_MESSAGEBOX); BIT64_SET(menu->state, MENU_STATE_POST_ITERATE); if (action == MENU_ACTION_OK) BIT64_SET(menu->state, MENU_STATE_POP_STACK); break; case ITERATE_TYPE_DEFAULT: /* FIXME: Crappy hack, needed for mouse controls to not be completely broken * in case we press back. * * We need to fix this entire mess, mouse controls should not rely on a * hack like this in order to work. */ selection = max(min(selection, (menu_entries_get_size() - 1)), 0); menu_entry_get(&entry, selection, NULL, false); ret = menu_entry_action(&entry, selection, (enum menu_action)action); if (ret) goto end; BIT64_SET(menu->state, MENU_STATE_POST_ITERATE); /* Have to defer it so we let settings refresh. */ if (menu->push_help_screen) { menu_displaylist_info_t info = {0}; info.list = menu_stack; strlcpy(info.label, menu_hash_to_str(MENU_LABEL_HELP), sizeof(info.label)); menu_displaylist_push_list(&info, DISPLAYLIST_HELP); } break; } BIT64_SET(menu->state, MENU_STATE_BLIT); if (BIT64_GET(menu->state, MENU_STATE_POP_STACK)) { size_t new_selection_ptr = selection; menu_entries_pop_stack(&new_selection_ptr); menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &selection); } if (BIT64_GET(menu->state, MENU_STATE_POST_ITERATE)) menu_input_post_iterate(&ret, action); end: if (ret) return -1; return 0; }
bool menu_input_ctl(enum menu_input_ctl_state state, void *data) { static char menu_input_keyboard_label_setting[256]; static const char **menu_input_keyboard_buffer; static const char *menu_input_keyboard_label = NULL; static bool pointer_dragging = false; menu_input_t *menu_input = menu_input_get_ptr(); if (!menu_input) return false; switch (state) { case MENU_INPUT_CTL_BIND_SET_MIN_MAX: { menu_input_ctx_bind_limits_t *lim = (menu_input_ctx_bind_limits_t*)data; if (!lim || !menu_input) return false; menu_input->binds.begin = lim->min; menu_input->binds.last = lim->max; } break; case MENU_INPUT_CTL_CHECK_INSIDE_HITBOX: { menu_input_ctx_hitbox_t *hitbox = (menu_input_ctx_hitbox_t*)data; int16_t mouse_x = menu_input_mouse_state(MENU_MOUSE_X_AXIS); int16_t mouse_y = menu_input_mouse_state(MENU_MOUSE_Y_AXIS); bool inside_hitbox = (mouse_x >= hitbox->x1) && (mouse_x <= hitbox->x2) && (mouse_y >= hitbox->y1) && (mouse_y <= hitbox->y2) ; if (!inside_hitbox) return false; } break; case MENU_INPUT_CTL_DEINIT: memset(menu_input, 0, sizeof(menu_input_t)); pointer_dragging = false; break; case MENU_INPUT_CTL_SEARCH_START: { menu_handle_t *menu = NULL; if (!menu_driver_ctl( RARCH_MENU_CTL_DRIVER_DATA_GET, &menu)) return false; menu_input->keyboard.display = true; menu_input_keyboard_label = menu_hash_to_str(MENU_VALUE_SEARCH); menu_input_keyboard_buffer = input_keyboard_start_line(menu, menu_input_search_cb); } break; case MENU_INPUT_CTL_MOUSE_PTR: { unsigned *ptr = (unsigned*)data; menu_input->mouse.ptr = *ptr; } break; case MENU_INPUT_CTL_POINTER_PTR: { unsigned *ptr = (unsigned*)data; menu_input->pointer.ptr = *ptr; } break; case MENU_INPUT_CTL_POINTER_ACCEL_READ: { float *ptr = (float*)data; *ptr = menu_input->pointer.accel; } break; case MENU_INPUT_CTL_POINTER_ACCEL_WRITE: { float *ptr = (float*)data; menu_input->pointer.accel = *ptr; } break; case MENU_INPUT_CTL_IS_POINTER_DRAGGED: return pointer_dragging; case MENU_INPUT_CTL_SET_POINTER_DRAGGED: pointer_dragging = true; break; case MENU_INPUT_CTL_UNSET_POINTER_DRAGGED: pointer_dragging = false; break; case MENU_INPUT_CTL_KEYBOARD_DISPLAY: { bool *ptr = (bool*)data; *ptr = menu_input->keyboard.display; } break; case MENU_INPUT_CTL_SET_KEYBOARD_DISPLAY: { bool *ptr = (bool*)data; menu_input->keyboard.display = *ptr; } break; case MENU_INPUT_CTL_KEYBOARD_BUFF_PTR: { const char **ptr = (const char**)data; *ptr = *menu_input_keyboard_buffer; } break; case MENU_INPUT_CTL_KEYBOARD_LABEL: { const char **ptr = (const char**)data; *ptr = menu_input_keyboard_label; } break; case MENU_INPUT_CTL_SET_KEYBOARD_LABEL: { char **ptr = (char**)data; menu_input_keyboard_label = *ptr; } break; case MENU_INPUT_CTL_UNSET_KEYBOARD_LABEL: menu_input_keyboard_label = NULL; break; case MENU_INPUT_CTL_KEYBOARD_LABEL_SETTING: { const char **ptr = (const char**)data; *ptr = menu_input_keyboard_label_setting; } break; case MENU_INPUT_CTL_SET_KEYBOARD_LABEL_SETTING: { char **ptr = (char**)data; strlcpy(menu_input_keyboard_label_setting, *ptr, sizeof(menu_input_keyboard_label_setting)); } break; case MENU_INPUT_CTL_UNSET_KEYBOARD_LABEL_SETTING: menu_input_keyboard_label_setting[0] = '\0'; break; case MENU_INPUT_CTL_BIND_NONE: case MENU_INPUT_CTL_BIND_SINGLE: case MENU_INPUT_CTL_BIND_ALL: return menu_input_key_bind_set_mode(state, data); case MENU_INPUT_CTL_BIND_ITERATE: { menu_input_ctx_bind_t *bind = (menu_input_ctx_bind_t*)data; if (!bind) return false; return menu_input_key_bind_iterate(bind->s, bind->len); } case MENU_INPUT_CTL_START_LINE: { bool keyboard_display = true; menu_handle_t *menu = NULL; menu_input_ctx_line_t *line = (menu_input_ctx_line_t*)data; if (!menu_input || !line) return false; if (!menu_driver_ctl(RARCH_MENU_CTL_DRIVER_DATA_GET, &menu)) return false; menu_input_ctl(MENU_INPUT_CTL_SET_KEYBOARD_DISPLAY, &keyboard_display); menu_input_ctl(MENU_INPUT_CTL_SET_KEYBOARD_LABEL, &line->label); menu_input_ctl(MENU_INPUT_CTL_SET_KEYBOARD_LABEL_SETTING, &line->label_setting); menu_input->keyboard.type = line->type; menu_input->keyboard.idx = line->idx; menu_input_keyboard_buffer = input_keyboard_start_line(menu, line->cb); } break; default: case MENU_INPUT_CTL_NONE: break; } return true; }
/** * menu_iterate: * @input : input sample for this frame * @old_input : input sample of the previous frame * @trigger_input : difference' input sample - difference * between 'input' and 'old_input' * * Runs RetroArch menu for one frame. * * Returns: 0 on success, -1 if we need to quit out of the loop. **/ int generic_menu_iterate(void *data, void *userdata, enum menu_action action) { menu_entry_t entry; enum action_iterate_type iterate_type; size_t selection = 0; unsigned file_type = 0; int ret = 0; uint32_t hash = 0; enum msg_hash_enums enum_idx = MSG_UNKNOWN; const char *label = NULL; menu_handle_t *menu = (menu_handle_t*)data; menu_entries_get_last_stack(NULL, &label, &file_type, &enum_idx, NULL); if (!menu) return 0; if (!menu_navigation_ctl(MENU_NAVIGATION_CTL_GET_SELECTION, &selection)) return 0; menu->menu_state.msg[0] = '\0'; hash = msg_hash_calculate(label); iterate_type = action_iterate_type(hash); menu_driver_set_binding_state(iterate_type == ITERATE_TYPE_BIND); if ( action != MENU_ACTION_NOOP || menu_entries_ctl(MENU_ENTRIES_CTL_NEEDS_REFRESH, NULL) || menu_display_get_update_pending()) { BIT64_SET(menu->state, MENU_STATE_RENDER_FRAMEBUFFER); } switch (iterate_type) { case ITERATE_TYPE_HELP: ret = menu_dialog_iterate( menu->menu_state.msg, sizeof(menu->menu_state.msg), label); BIT64_SET(menu->state, MENU_STATE_RENDER_MESSAGEBOX); BIT64_SET(menu->state, MENU_STATE_POST_ITERATE); if (ret == 1 || action == MENU_ACTION_OK) { BIT64_SET(menu->state, MENU_STATE_POP_STACK); menu_dialog_set_active(false); } if (action == MENU_ACTION_CANCEL) { BIT64_SET(menu->state, MENU_STATE_POP_STACK); menu_dialog_set_active(false); } break; case ITERATE_TYPE_BIND: { menu_input_ctx_bind_t bind; bind.s = menu->menu_state.msg; bind.len = sizeof(menu->menu_state.msg); if (menu_input_key_bind_iterate(&bind)) { menu_entries_pop_stack(&selection, 0, 0); menu_navigation_ctl( MENU_NAVIGATION_CTL_SET_SELECTION, &selection); } else BIT64_SET(menu->state, MENU_STATE_RENDER_MESSAGEBOX); } break; case ITERATE_TYPE_INFO: { file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); menu_file_list_cbs_t *cbs = menu_entries_get_actiondata_at_offset(selection_buf, selection); if (cbs->enum_idx != MSG_UNKNOWN) { ret = menu_hash_get_help_enum(cbs->enum_idx, menu->menu_state.msg, sizeof(menu->menu_state.msg)); } else { unsigned type = 0; enum msg_hash_enums enum_idx = MSG_UNKNOWN; menu_entries_get_at_offset(selection_buf, selection, NULL, NULL, &type, NULL, NULL); switch (type) { case FILE_TYPE_FONT: enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_FONT; break; case FILE_TYPE_RDB: enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_RDB; break; case FILE_TYPE_OVERLAY: enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_OVERLAY; break; case FILE_TYPE_CHEAT: enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_CHEAT; break; case FILE_TYPE_SHADER_PRESET: enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_SHADER_PRESET; break; case FILE_TYPE_SHADER: enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_SHADER; break; case FILE_TYPE_REMAP: enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_REMAP; break; case FILE_TYPE_RECORD_CONFIG: enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_RECORD_CONFIG; break; case FILE_TYPE_CURSOR: enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_CURSOR; break; case FILE_TYPE_CONFIG: enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_CONFIG; break; case FILE_TYPE_CARCHIVE: enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_COMPRESSED_ARCHIVE; break; case FILE_TYPE_DIRECTORY: enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_DIRECTORY; break; case FILE_TYPE_VIDEOFILTER: /* TODO/FIXME */ case FILE_TYPE_AUDIOFILTER: /* TODO/FIXME */ case FILE_TYPE_SHADER_SLANG: /* TODO/FIXME */ case FILE_TYPE_SHADER_GLSL: /* TODO/FIXME */ case FILE_TYPE_SHADER_HLSL: /* TODO/FIXME */ case FILE_TYPE_SHADER_CG: /* TODO/FIXME */ case FILE_TYPE_SHADER_PRESET_GLSLP: /* TODO/FIXME */ case FILE_TYPE_SHADER_PRESET_HLSLP: /* TODO/FIXME */ case FILE_TYPE_SHADER_PRESET_CGP: /* TODO/FIXME */ case FILE_TYPE_SHADER_PRESET_SLANGP: /* TODO/FIXME */ case FILE_TYPE_PLAIN: enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_PLAIN_FILE; break; default: break; } if (enum_idx != MSG_UNKNOWN) ret = menu_hash_get_help_enum(enum_idx, menu->menu_state.msg, sizeof(menu->menu_state.msg)); } } BIT64_SET(menu->state, MENU_STATE_RENDER_MESSAGEBOX); BIT64_SET(menu->state, MENU_STATE_POST_ITERATE); if (action == MENU_ACTION_OK || action == MENU_ACTION_CANCEL) { BIT64_SET(menu->state, MENU_STATE_POP_STACK); } menu_dialog_set_active(false); break; case ITERATE_TYPE_DEFAULT: /* FIXME: Crappy hack, needed for mouse controls * to not be completely broken in case we press back. * * We need to fix this entire mess, mouse controls * should not rely on a hack like this in order to work. */ selection = MAX(MIN(selection, (menu_entries_get_size() - 1)), 0); menu_entry_get(&entry, 0, selection, NULL, false); ret = menu_entry_action(&entry, selection, (enum menu_action)action); if (ret) goto end; BIT64_SET(menu->state, MENU_STATE_POST_ITERATE); /* Have to defer it so we let settings refresh. */ menu_dialog_push(); break; } BIT64_SET(menu->state, MENU_STATE_BLIT); if (BIT64_GET(menu->state, MENU_STATE_POP_STACK)) { size_t new_selection_ptr = selection; menu_entries_pop_stack(&new_selection_ptr, 0, 0); menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &selection); } if (BIT64_GET(menu->state, MENU_STATE_POST_ITERATE)) menu_input_post_iterate(&ret, action); end: if (ret) return -1; return 0; }