diff --git a/data/tr1/ship/cfg/TR1X_strings.json5 b/data/tr1/ship/cfg/TR1X_strings.json5 index 838b9c7f0..a429562bc 100644 --- a/data/tr1/ship/cfg/TR1X_strings.json5 +++ b/data/tr1/ship/cfg/TR1X_strings.json5 @@ -341,15 +341,15 @@ }, "game_strings": { - "CONTROL_BACKEND_CONTROLLER": "Controller", - "CONTROL_BACKEND_KEYBOARD": "Keyboard", - "CONTROL_CUSTOMIZE": "Customize Controls", - "CONTROL_CUSTOM_1": "User Keys 1", - "CONTROL_CUSTOM_2": "User Keys 2", - "CONTROL_CUSTOM_3": "User Keys 3", - "CONTROL_DEFAULT_KEYS": "Default Keys", - "CONTROL_RESET_DEFAULTS": "Reset All: Hold %s", - "CONTROL_UNBIND": "Unbind: Hold %s", + "CONTROLS_BACKEND_CONTROLLER": "Controller", + "CONTROLS_BACKEND_KEYBOARD": "Keyboard", + "CONTROLS_CUSTOMIZE": "Customize Controls", + "CONTROLS_CUSTOM_1": "User Keys 1", + "CONTROLS_CUSTOM_2": "User Keys 2", + "CONTROLS_CUSTOM_3": "User Keys 3", + "CONTROLS_DEFAULT_KEYS": "Default Keys", + "CONTROLS_RESET_DEFAULTS": "Reset All: Hold %s", + "CONTROLS_UNBIND": "Unbind: Hold %s", "DETAIL_BILINEAR": "Bilinear", "DETAIL_BRIGHTNESS": "Brightness", "DETAIL_FBO_FILTER": "FBO filter", diff --git a/data/tr2/ship/cfg/TR2X_strings.json5 b/data/tr2/ship/cfg/TR2X_strings.json5 index ca290f7c6..81f5f45c5 100644 --- a/data/tr2/ship/cfg/TR2X_strings.json5 +++ b/data/tr2/ship/cfg/TR2X_strings.json5 @@ -464,13 +464,13 @@ }, "game_strings": { - "CONTROL_BACKEND_CONTROLLER": "Controller", - "CONTROL_BACKEND_KEYBOARD": "Keyboard", - "CONTROL_CUSTOMIZE": "Customize Controls", - "CONTROL_CUSTOM_1": "User Keys 1", - "CONTROL_CUSTOM_2": "User Keys 2", - "CONTROL_CUSTOM_3": "User Keys 3", - "CONTROL_DEFAULT_KEYS": "Default Keys", + "CONTROLS_BACKEND_CONTROLLER": "Controller", + "CONTROLS_BACKEND_KEYBOARD": "Keyboard", + "CONTROLS_CUSTOMIZE": "Customize Controls", + "CONTROLS_CUSTOM_1": "User Keys 1", + "CONTROLS_CUSTOM_2": "User Keys 2", + "CONTROLS_CUSTOM_3": "User Keys 3", + "CONTROLS_DEFAULT_KEYS": "Default Keys", "DETAIL_FLOAT_FMT": "%.1f", "DETAIL_FOG_END": "Fog end", "DETAIL_FOG_START": "Fog start", diff --git a/src/libtrx/game/input/common.c b/src/libtrx/game/input/common.c index 16ae6e33e..e4202f48f 100644 --- a/src/libtrx/game/input/common.c +++ b/src/libtrx/game/input/common.c @@ -53,10 +53,10 @@ static bool m_IsRoleHardcoded[INPUT_ROLE_NUMBER_OF] = { }; static const GAME_STRING_ID m_LayoutMap[INPUT_LAYOUT_NUMBER_OF] = { - [INPUT_LAYOUT_DEFAULT] = GS_ID(CONTROL_DEFAULT_KEYS), - [INPUT_LAYOUT_CUSTOM_1] = GS_ID(CONTROL_CUSTOM_1), - [INPUT_LAYOUT_CUSTOM_2] = GS_ID(CONTROL_CUSTOM_2), - [INPUT_LAYOUT_CUSTOM_3] = GS_ID(CONTROL_CUSTOM_3), + [INPUT_LAYOUT_DEFAULT] = GS_ID(CONTROLS_DEFAULT_KEYS), + [INPUT_LAYOUT_CUSTOM_1] = GS_ID(CONTROLS_CUSTOM_1), + [INPUT_LAYOUT_CUSTOM_2] = GS_ID(CONTROLS_CUSTOM_2), + [INPUT_LAYOUT_CUSTOM_3] = GS_ID(CONTROLS_CUSTOM_3), }; static INPUT_BACKEND_IMPL *M_GetBackend(INPUT_BACKEND backend); diff --git a/src/libtrx/game/ui2/dialogs/controls.c b/src/libtrx/game/ui2/dialogs/controls.c new file mode 100644 index 000000000..4ea214ea4 --- /dev/null +++ b/src/libtrx/game/ui2/dialogs/controls.c @@ -0,0 +1,88 @@ +#include "game/ui2/dialogs/controls.h" + +#include "config.h" +#include "game/game_string.h" +#include "game/input.h" +#include "game/ui2/dialogs/controls_backend.h" +#include "game/ui2/dialogs/controls_editor.h" +#include "game/ui2/elements/requester.h" + +typedef enum { + M_PHASE_BACKEND, + M_PHASE_EDITOR, +} M_PHASE; + +void UI2_Controls_Init(UI2_CONTROLS_STATE *const s) +{ + s->events = EventManager_Create(); + s->phase = M_PHASE_BACKEND; + s->backend = INPUT_BACKEND_KEYBOARD; + s->active_layout = g_Config.input.keyboard_layout; + UI2_ControlsBackend_Init(&s->backend_state); + UI2_ControlsEditor_Init(&s->editor_state, s->events); +} + +void UI2_Controls_Free(UI2_CONTROLS_STATE *const s) +{ + UI2_ControlsEditor_Free(&s->editor_state); + UI2_ControlsBackend_Free(&s->backend_state); + EventManager_Free(s->events); + s->events = nullptr; +} + +bool UI2_Controls_Control(UI2_CONTROLS_STATE *const s) +{ + switch (s->phase) { + case M_PHASE_BACKEND: { + const int32_t choice = UI2_ControlsBackend_Control(&s->backend_state); + switch (choice) { + case UI2_REQUESTER_NO_CHOICE: + return false; + case UI2_REQUESTER_CANCEL: + return true; + case INPUT_BACKEND_KEYBOARD: + s->backend = choice; + s->phase = M_PHASE_EDITOR; + UI2_ControlsEditor_Reinit( + &s->editor_state, choice, g_Config.input.keyboard_layout); + break; + case INPUT_BACKEND_CONTROLLER: + s->backend = choice; + s->phase = M_PHASE_EDITOR; + UI2_ControlsEditor_Reinit( + &s->editor_state, choice, g_Config.input.controller_layout); + break; + } + break; + } + + case M_PHASE_EDITOR: { + const UI2_CONTROLS_CHOICE choice = + UI2_ControlsEditor_Control(&s->editor_state); + switch (choice) { + case UI2_CONTROLS_CHOICE_NOOP: + break; + case UI2_CONTROLS_CHOICE_GO_BACK: + s->phase = M_PHASE_BACKEND; + break; + case UI2_CONTROLS_CHOICE_EXIT: + return true; + } + break; + } + } + + return false; +} + +void UI2_Controls(UI2_CONTROLS_STATE *const s) +{ + switch (s->phase) { + case M_PHASE_BACKEND: + UI2_ControlsBackend(&s->backend_state); + break; + case M_PHASE_EDITOR: + UI2_ControlsEditor(&s->editor_state); + break; + } +} diff --git a/src/libtrx/game/ui2/dialogs/controls_backend.c b/src/libtrx/game/ui2/dialogs/controls_backend.c new file mode 100644 index 000000000..0291716c6 --- /dev/null +++ b/src/libtrx/game/ui2/dialogs/controls_backend.c @@ -0,0 +1,57 @@ +#include "game/ui2/dialogs/controls_backend.h" + +#include "game/game_string.h" +#include "game/input.h" +#include "game/ui2/elements/anchor.h" +#include "game/ui2/elements/label.h" +#include "game/ui2/elements/modal.h" +#include "game/ui2/elements/requester.h" + +static const GAME_STRING_ID m_Options[] = { + GS_ID(CONTROLS_BACKEND_KEYBOARD), + GS_ID(CONTROLS_BACKEND_CONTROLLER), + nullptr, +}; + +void UI2_ControlsBackend_Init(UI2_CONTROLS_BACKEND_STATE *const s) +{ + int32_t count = 0; + for (count = 0; m_Options[count] != nullptr; count++) { } + UI2_Requester_Init(&s->req, count, count, true); +} + +void UI2_ControlsBackend_Free(UI2_CONTROLS_BACKEND_STATE *const s) +{ + UI2_Requester_Free(&s->req); +} + +int32_t UI2_ControlsBackend_Control(UI2_CONTROLS_BACKEND_STATE *const s) +{ + const int32_t choice = UI2_Requester_Control(&s->req); + switch (choice) { + case 0: + return INPUT_BACKEND_KEYBOARD; + case 1: + return INPUT_BACKEND_CONTROLLER; + default: + return choice; + } +} + +void UI2_ControlsBackend(UI2_CONTROLS_BACKEND_STATE *const s) +{ + UI2_BeginModal(0.5f, 2.0f / 3.0f); + UI2_BeginRequester(&s->req, GS(CONTROLS_CUSTOMIZE)); + + for (int32_t i = UI2_Requester_GetFirstRow(&s->req); + i < UI2_Requester_GetLastRow(&s->req); i++) { + UI2_BeginRequesterRow(&s->req, i); + UI2_BeginAnchor(0.5f, 0.5f); + UI2_Label(GameString_Get(m_Options[i])); + UI2_EndAnchor(); + UI2_EndRequesterRow(&s->req, i); + } + + UI2_EndRequester(&s->req); + UI2_EndModal(); +} diff --git a/src/libtrx/game/ui2/dialogs/controls_editor.c b/src/libtrx/game/ui2/dialogs/controls_editor.c new file mode 100644 index 000000000..5413151c0 --- /dev/null +++ b/src/libtrx/game/ui2/dialogs/controls_editor.c @@ -0,0 +1,377 @@ +#include "game/ui2/dialogs/controls_editor.h" + +#include "config.h" +#include "game/const.h" +#include "game/game_string.h" +#include "game/input.h" +#include "game/shell.h" +#include "game/ui2/elements/anchor.h" +#include "game/ui2/elements/frame.h" +#include "game/ui2/elements/label.h" +#include "game/ui2/elements/modal.h" +#include "game/ui2/elements/pad.h" +#include "game/ui2/elements/requester.h" +#include "game/ui2/elements/spacer.h" +#include "game/ui2/elements/stack.h" +#include "game/ui2/elements/window.h" +#include "utils.h" + +typedef enum { + M_PHASE_NAVIGATE_LAYOUT, + M_PHASE_NAVIGATE_INPUTS, + M_PHASE_NAVIGATE_INPUTS_DEBOUNCE, + M_PHASE_LISTEN, + M_PHASE_LISTEN_DEBOUNCE, + M_PHASE_EXIT, +} M_PHASE; + +static const INPUT_ROLE m_LeftRoles[] = { + // clang-format off + INPUT_ROLE_UP, + INPUT_ROLE_DOWN, + INPUT_ROLE_LEFT, + INPUT_ROLE_RIGHT, + INPUT_ROLE_STEP_L, + INPUT_ROLE_STEP_R, + INPUT_ROLE_SLOW, + INPUT_ROLE_ENTER_CONSOLE, + INPUT_ROLE_PAUSE, + INPUT_ROLE_TOGGLE_PHOTO_MODE, + INPUT_ROLE_TOGGLE_UI, + // INPUT_ROLE_CAMERA_RESET, // same as look, no need to configure + INPUT_ROLE_CAMERA_UP, + INPUT_ROLE_CAMERA_DOWN, + INPUT_ROLE_CAMERA_LEFT, + INPUT_ROLE_CAMERA_RIGHT, + INPUT_ROLE_CAMERA_FORWARD, + INPUT_ROLE_CAMERA_BACK, + (INPUT_ROLE)-1, + // clang-format on +}; + +static const INPUT_ROLE m_RightRoles_CheatsOff[] = { + // clang-format off + INPUT_ROLE_JUMP, + INPUT_ROLE_ACTION, + INPUT_ROLE_DRAW, +#if TR_VERSION == 2 + INPUT_ROLE_USE_FLARE, +#endif + INPUT_ROLE_LOOK, + INPUT_ROLE_ROLL, + INPUT_ROLE_OPTION, + (INPUT_ROLE)-1, + // clang-format on +}; + +static const INPUT_ROLE m_RightRoles_CheatsOn[] = { + // clang-format off + INPUT_ROLE_JUMP, + INPUT_ROLE_ACTION, + INPUT_ROLE_DRAW, +#if TR_VERSION == 2 + INPUT_ROLE_USE_FLARE, +#endif + INPUT_ROLE_LOOK, + INPUT_ROLE_ROLL, + INPUT_ROLE_OPTION, + INPUT_ROLE_FLY_CHEAT, + INPUT_ROLE_ITEM_CHEAT, + INPUT_ROLE_LEVEL_SKIP_CHEAT, + INPUT_ROLE_TURBO_CHEAT, + (INPUT_ROLE)-1, + // clang-format on +}; + +static const INPUT_ROLE *m_RightRoles = nullptr; + +static INPUT_ROLE M_GetInputRole(int32_t col, int32_t row); +static int32_t M_GetInputRoleCount(int32_t col); +static void M_CycleLayout(UI2_CONTROLS_EDITOR_STATE *s, int32_t dir); +static UI2_CONTROLS_CHOICE M_NavigateLayout(UI2_CONTROLS_EDITOR_STATE *s); +static UI2_CONTROLS_CHOICE M_NavigateInputs(UI2_CONTROLS_EDITOR_STATE *s); +static UI2_CONTROLS_CHOICE M_NavigateInputsDebounce( + UI2_CONTROLS_EDITOR_STATE *s); +static UI2_CONTROLS_CHOICE M_Listen(UI2_CONTROLS_EDITOR_STATE *s); +static UI2_CONTROLS_CHOICE M_ListenDebounce(UI2_CONTROLS_EDITOR_STATE *s); + +static void M_Title(const UI2_CONTROLS_EDITOR_STATE *s); +static void M_InputChoice(UI2_CONTROLS_EDITOR_STATE *s, INPUT_ROLE role); +static void M_InputLabel(const UI2_CONTROLS_EDITOR_STATE *s, INPUT_ROLE role); +static void M_Column(UI2_CONTROLS_EDITOR_STATE *s, const INPUT_ROLE *roles); + +static INPUT_ROLE M_GetInputRole(const int32_t col, const int32_t row) +{ + if (col == 0) { + return m_LeftRoles[row]; + } else { + return m_RightRoles[row]; + } +} + +static int32_t M_GetInputRoleCount(const int32_t col) +{ + int32_t row = 0; + while (M_GetInputRole(col, row) != (INPUT_ROLE)-1) { + row++; + } + return row; +} + +static void M_CycleLayout(UI2_CONTROLS_EDITOR_STATE *const s, const int32_t dir) +{ + s->active_layout += dir; + s->active_layout += INPUT_LAYOUT_NUMBER_OF; + s->active_layout %= INPUT_LAYOUT_NUMBER_OF; + + const EVENT event = { + .name = "layout_change", + .sender = nullptr, + .data = nullptr, + }; + EventManager_Fire(s->events, &event); +} + +static UI2_CONTROLS_CHOICE M_NavigateLayout(UI2_CONTROLS_EDITOR_STATE *const s) +{ + if (g_InputDB.menu_confirm) { + return UI2_CONTROLS_CHOICE_EXIT; + } else if (g_InputDB.menu_back) { + return UI2_CONTROLS_CHOICE_GO_BACK; + } else if (g_InputDB.menu_left) { + M_CycleLayout(s, -1); + } else if (g_InputDB.menu_right) { + M_CycleLayout(s, 1); + } else if (g_InputDB.menu_down && s->active_layout != 0) { + s->phase = M_PHASE_NAVIGATE_INPUTS; + s->active_col = 0; + s->active_row = 0; + } else if (g_InputDB.menu_up && s->active_layout != 0) { + s->phase = M_PHASE_NAVIGATE_INPUTS; + s->active_col = 1; + s->active_row = M_GetInputRoleCount(1) - 1; + } else { + return UI2_CONTROLS_CHOICE_NOOP; + } + s->active_role = M_GetInputRole(s->active_col, s->active_row); + return UI2_CONTROLS_CHOICE_NOOP; +} + +static UI2_CONTROLS_CHOICE M_NavigateInputs(UI2_CONTROLS_EDITOR_STATE *const s) +{ + if (g_InputDB.menu_confirm) { + s->phase = M_PHASE_NAVIGATE_INPUTS_DEBOUNCE; + } else if (g_InputDB.menu_back) { + return UI2_CONTROLS_CHOICE_GO_BACK; + } else if (g_InputDB.menu_left || g_InputDB.menu_right) { + s->active_col ^= 1; + CLAMP(s->active_row, 0, M_GetInputRoleCount(s->active_col) - 1); + } else if (g_InputDB.menu_up) { + s->active_row--; + if (s->active_row < 0) { + if (s->active_col == 0) { + s->phase = M_PHASE_NAVIGATE_LAYOUT; + } else { + s->active_col = 0; + s->active_row = M_GetInputRoleCount(0) - 1; + } + } + } else if (g_InputDB.menu_down) { + s->active_row++; + if (s->active_row >= M_GetInputRoleCount(s->active_col)) { + if (s->active_col == 0) { + s->active_col = 1; + s->active_row = 0; + } else { + s->phase = M_PHASE_NAVIGATE_LAYOUT; + } + } + } else { + return UI2_CONTROLS_CHOICE_NOOP; + } + s->active_role = M_GetInputRole(s->active_col, s->active_row); + return UI2_CONTROLS_CHOICE_NOOP; +} + +static UI2_CONTROLS_CHOICE M_NavigateInputsDebounce( + UI2_CONTROLS_EDITOR_STATE *const s) +{ + Shell_ProcessEvents(); + Input_Update(); + if (g_Input.any) { + return UI2_CONTROLS_CHOICE_NOOP; + } + Input_EnterListenMode(); + s->phase = M_PHASE_LISTEN; + return UI2_CONTROLS_CHOICE_NOOP; +} + +static UI2_CONTROLS_CHOICE M_Listen(UI2_CONTROLS_EDITOR_STATE *const s) +{ + if (!Input_ReadAndAssignRole( + s->backend, s->active_layout, s->active_role)) { + return UI2_CONTROLS_CHOICE_NOOP; + } + + Input_ExitListenMode(); + + const EVENT event = { + .name = "key_change", + .sender = nullptr, + .data = nullptr, + }; + EventManager_Fire(s->events, &event); + + s->phase = M_PHASE_LISTEN_DEBOUNCE; + return UI2_CONTROLS_CHOICE_NOOP; +} + +static UI2_CONTROLS_CHOICE M_ListenDebounce(UI2_CONTROLS_EDITOR_STATE *const s) +{ + if (!g_Input.any) { + s->phase = M_PHASE_NAVIGATE_INPUTS; + } + return UI2_CONTROLS_CHOICE_NOOP; +} + +static void M_Title(const UI2_CONTROLS_EDITOR_STATE *const s) +{ + UI2_BeginAnchor(0.5f, 0.5f); + if (s->phase == M_PHASE_NAVIGATE_LAYOUT) { + UI2_BeginFrame(UI2_FRAME_SELECTED_OPTION); + } + UI2_BeginPad(2.0f, 1.0f); + UI2_Label(Input_GetLayoutName(s->active_layout)); + UI2_EndPad(); + if (s->phase == M_PHASE_NAVIGATE_LAYOUT) { + UI2_EndFrame(); + } + UI2_EndAnchor(); +} + +static void M_InputLabel( + const UI2_CONTROLS_EDITOR_STATE *const s, const INPUT_ROLE role) +{ + const bool is_selected = s->active_role == role + && (s->phase == M_PHASE_NAVIGATE_INPUTS + || s->phase == M_PHASE_NAVIGATE_INPUTS_DEBOUNCE); + if (is_selected) { + UI2_BeginFrame(UI2_FRAME_SELECTED_OPTION); + } + UI2_Label(Input_GetRoleName(role)); + if (is_selected) { + UI2_EndFrame(); + } +} + +static void M_InputChoice( + UI2_CONTROLS_EDITOR_STATE *const s, const INPUT_ROLE role) +{ + const bool is_flashing = + Input_IsKeyConflicted(s->backend, s->active_layout, role); + const bool is_selected = + s->active_role == role && s->phase == M_PHASE_LISTEN; + + if (is_flashing) { + UI2_BeginFlash(&s->flash); + } + if (is_selected) { + UI2_BeginFrame(UI2_FRAME_SELECTED_OPTION); + } + UI2_Label(Input_GetKeyName(s->backend, s->active_layout, role)); + if (is_selected) { + UI2_EndFrame(); + } + if (is_flashing) { + UI2_EndFlash(); + } +} + +static void M_Column( + UI2_CONTROLS_EDITOR_STATE *const s, const INPUT_ROLE *const roles) +{ + UI2_BeginStack(UI2_STACK_HORIZONTAL); + UI2_BeginStack(UI2_STACK_VERTICAL); + for (const INPUT_ROLE *role = roles; *role != (INPUT_ROLE)-1; role++) { + M_InputChoice(s, *role); + } + UI2_EndStack(); + UI2_Spacer(10.0f, 0.0f); + UI2_BeginStack(UI2_STACK_VERTICAL); + for (const INPUT_ROLE *role = roles; *role != (INPUT_ROLE)-1; role++) { + M_InputLabel(s, *role); + } + UI2_EndStack(); + UI2_EndStack(); +} + +void UI2_ControlsEditor_Init( + UI2_CONTROLS_EDITOR_STATE *const s, EVENT_MANAGER *events) +{ + m_RightRoles = g_Config.gameplay.enable_cheats ? m_RightRoles_CheatsOn + : m_RightRoles_CheatsOff; + s->events = events; + UI2_Flash_Init(&s->flash, LOGIC_FPS * 2 / 3); +} + +void UI2_ControlsEditor_Free(UI2_CONTROLS_EDITOR_STATE *const s) +{ + UI2_Flash_Free(&s->flash); +} + +void UI2_ControlsEditor_Reinit( + UI2_CONTROLS_EDITOR_STATE *s, INPUT_BACKEND backend, int32_t layout) +{ + s->backend = backend; + s->active_layout = layout; + s->active_row = 0; + s->active_col = 0; + s->active_role = M_GetInputRole(s->active_col, s->active_row); + s->phase = M_PHASE_NAVIGATE_LAYOUT; +} + +UI2_CONTROLS_CHOICE UI2_ControlsEditor_Control( + UI2_CONTROLS_EDITOR_STATE *const s) +{ + UI2_Flash_Control(&s->flash); + switch (s->phase) { + case M_PHASE_NAVIGATE_LAYOUT: + return M_NavigateLayout(s); + case M_PHASE_NAVIGATE_INPUTS: + return M_NavigateInputs(s); + case M_PHASE_NAVIGATE_INPUTS_DEBOUNCE: + return M_NavigateInputsDebounce(s); + case M_PHASE_LISTEN: + return M_Listen(s); + case M_PHASE_LISTEN_DEBOUNCE: + return M_ListenDebounce(s); + default: + return UI2_CONTROLS_CHOICE_NOOP; + } +} + +void UI2_ControlsEditor(UI2_CONTROLS_EDITOR_STATE *const s) +{ + UI2_BeginModal(0.5f, 0.5f); + UI2_BeginWindow(); + UI2_WindowTitle(GS(CONTROLS_CUSTOMIZE)); + UI2_BeginWindowBody(); + + UI2_BeginStackEx((UI2_STACK_SETTINGS) { + .orientation = UI2_STACK_VERTICAL, + .align = { .h = UI2_STACK_H_ALIGN_SPAN }, + }); + M_Title(s); + UI2_Spacer(0.0f, 5.0f); + + UI2_BeginStack(UI2_STACK_HORIZONTAL); + M_Column(s, m_LeftRoles); + UI2_Spacer(10.0f, 0.0f); + M_Column(s, m_RightRoles); + UI2_EndStack(); + + UI2_EndStack(); + UI2_EndWindowBody(); + UI2_EndWindow(); + UI2_EndModal(); +} diff --git a/src/libtrx/include/libtrx/game/game_string.def b/src/libtrx/include/libtrx/game/game_string.def index 17495e52e..beab0311a 100644 --- a/src/libtrx/include/libtrx/game/game_string.def +++ b/src/libtrx/include/libtrx/game/game_string.def @@ -61,13 +61,13 @@ GS_DEFINE(OSD_AMBIGUOUS_INPUT_2, "Ambiguous input: %s and %s") GS_DEFINE(OSD_AMBIGUOUS_INPUT_3, "Ambiguous input: %s, %s, ...") GS_DEFINE(OSD_UI_ON, "UI enabled") GS_DEFINE(OSD_UI_OFF, "UI disabled") -GS_DEFINE(CONTROL_DEFAULT_KEYS, "Default Keys") -GS_DEFINE(CONTROL_CUSTOM_1, "User Keys 1") -GS_DEFINE(CONTROL_CUSTOM_2, "User Keys 2") -GS_DEFINE(CONTROL_CUSTOM_3, "User Keys 3") -GS_DEFINE(CONTROL_BACKEND_KEYBOARD, "Keyboard") -GS_DEFINE(CONTROL_BACKEND_CONTROLLER, "Controller") -GS_DEFINE(CONTROL_CUSTOMIZE, "Customize Controls") +GS_DEFINE(CONTROLS_DEFAULT_KEYS, "Default Keys") +GS_DEFINE(CONTROLS_CUSTOM_1, "User Keys 1") +GS_DEFINE(CONTROLS_CUSTOM_2, "User Keys 2") +GS_DEFINE(CONTROLS_CUSTOM_3, "User Keys 3") +GS_DEFINE(CONTROLS_BACKEND_KEYBOARD, "Keyboard") +GS_DEFINE(CONTROLS_BACKEND_CONTROLLER, "Controller") +GS_DEFINE(CONTROLS_CUSTOMIZE, "Customize Controls") GS_DEFINE(KEYMAP_RUN, "Run") GS_DEFINE(KEYMAP_BACK, "Back") GS_DEFINE(KEYMAP_LEFT, "Left") diff --git a/src/libtrx/include/libtrx/game/input/common.h b/src/libtrx/include/libtrx/game/input/common.h index 9e1ec9b8a..01ad55caa 100644 --- a/src/libtrx/include/libtrx/game/input/common.h +++ b/src/libtrx/include/libtrx/game/input/common.h @@ -101,3 +101,5 @@ bool Input_AssignToJSONObject( INPUT_ROLE role); INPUT_STATE Input_GetDebounced(const INPUT_STATE input); + +extern const char *Input_GetRoleName(INPUT_ROLE role); diff --git a/src/libtrx/include/libtrx/game/ui2.h b/src/libtrx/include/libtrx/game/ui2.h index ea353a690..34ea3254e 100644 --- a/src/libtrx/include/libtrx/game/ui2.h +++ b/src/libtrx/include/libtrx/game/ui2.h @@ -1,6 +1,8 @@ #pragma once #include "./ui2/common.h" +#include "./ui2/dialogs/controls.h" +#include "./ui2/dialogs/controls_backend.h" #include "./ui2/dialogs/examine_item.h" #include "./ui2/dialogs/new_game.h" #include "./ui2/dialogs/pause.h" diff --git a/src/libtrx/include/libtrx/game/ui2/dialogs/controls.h b/src/libtrx/include/libtrx/game/ui2/dialogs/controls.h new file mode 100644 index 000000000..abc4b1c7b --- /dev/null +++ b/src/libtrx/include/libtrx/game/ui2/dialogs/controls.h @@ -0,0 +1,27 @@ +#pragma once + +// A controls editor dialog. + +#include "../../../event_manager.h" +#include "../../input.h" +#include "../common.h" +#include "./controls_backend.h" +#include "./controls_editor.h" + +typedef struct { + int32_t phase; + INPUT_BACKEND backend; + int32_t active_layout; + + EVENT_MANAGER *events; + UI2_CONTROLS_BACKEND_STATE backend_state; + UI2_CONTROLS_EDITOR_STATE editor_state; +} UI2_CONTROLS_STATE; + +// state functions +void UI2_Controls_Init(UI2_CONTROLS_STATE *s); +void UI2_Controls_Free(UI2_CONTROLS_STATE *s); +bool UI2_Controls_Control(UI2_CONTROLS_STATE *s); + +// draw functions +void UI2_Controls(UI2_CONTROLS_STATE *s); diff --git a/src/libtrx/include/libtrx/game/ui2/dialogs/controls_backend.h b/src/libtrx/include/libtrx/game/ui2/dialogs/controls_backend.h new file mode 100644 index 000000000..de548237f --- /dev/null +++ b/src/libtrx/include/libtrx/game/ui2/dialogs/controls_backend.h @@ -0,0 +1,18 @@ +#pragma once + +// A control backend (keyboard/controller) choice dialog. + +#include "../common.h" +#include "../elements/requester.h" + +typedef struct { + UI2_REQUESTER_STATE req; +} UI2_CONTROLS_BACKEND_STATE; + +// state functions +void UI2_ControlsBackend_Init(UI2_CONTROLS_BACKEND_STATE *s); +void UI2_ControlsBackend_Free(UI2_CONTROLS_BACKEND_STATE *s); +int32_t UI2_ControlsBackend_Control(UI2_CONTROLS_BACKEND_STATE *s); + +// draw functions +void UI2_ControlsBackend(UI2_CONTROLS_BACKEND_STATE *s); diff --git a/src/libtrx/include/libtrx/game/ui2/dialogs/controls_editor.h b/src/libtrx/include/libtrx/game/ui2/dialogs/controls_editor.h new file mode 100644 index 000000000..5dcdb243a --- /dev/null +++ b/src/libtrx/include/libtrx/game/ui2/dialogs/controls_editor.h @@ -0,0 +1,36 @@ +#pragma once + +// A controls remapper dialog. + +#include "../../input.h" +#include "../common.h" +#include "../elements/flash.h" +#include "../elements/requester.h" + +typedef struct { + int32_t phase; + INPUT_BACKEND backend; + int32_t active_layout; + INPUT_ROLE active_role; + int32_t active_col; + int32_t active_row; + UI2_FLASH_STATE flash; + EVENT_MANAGER *events; +} UI2_CONTROLS_EDITOR_STATE; + +typedef enum { + UI2_CONTROLS_CHOICE_EXIT, + UI2_CONTROLS_CHOICE_GO_BACK, + UI2_CONTROLS_CHOICE_NOOP, +} UI2_CONTROLS_CHOICE; + +// state functions +void UI2_ControlsEditor_Init( + UI2_CONTROLS_EDITOR_STATE *s, EVENT_MANAGER *events); +void UI2_ControlsEditor_Free(UI2_CONTROLS_EDITOR_STATE *s); +void UI2_ControlsEditor_Reinit( + UI2_CONTROLS_EDITOR_STATE *s, INPUT_BACKEND backend, int32_t layout); +UI2_CONTROLS_CHOICE UI2_ControlsEditor_Control(UI2_CONTROLS_EDITOR_STATE *s); + +// draw functions +void UI2_ControlsEditor(UI2_CONTROLS_EDITOR_STATE *s); diff --git a/src/libtrx/meson.build b/src/libtrx/meson.build index 65a5f5544..19d50c70a 100644 --- a/src/libtrx/meson.build +++ b/src/libtrx/meson.build @@ -209,11 +209,14 @@ sources = [ 'game/ui/widgets/stack.c', 'game/ui/widgets/window.c', 'game/ui2/common.c', + 'game/ui2/dialogs/controls.c', + 'game/ui2/dialogs/controls_backend.c', + 'game/ui2/dialogs/controls_editor.c', 'game/ui2/dialogs/examine_item.c', - 'game/ui2/dialogs/stats.c', 'game/ui2/dialogs/new_game.c', 'game/ui2/dialogs/pause.c', 'game/ui2/dialogs/photo_mode.c', + 'game/ui2/dialogs/stats.c', 'game/ui2/elements/anchor.c', 'game/ui2/elements/fade.c', 'game/ui2/elements/flash.c', diff --git a/src/tr1/game/game_string.def b/src/tr1/game/game_string.def index 4e76cac9a..7b77a46a2 100644 --- a/src/tr1/game/game_string.def +++ b/src/tr1/game/game_string.def @@ -18,8 +18,8 @@ GS_DEFINE(DETAIL_RENDER_MODE_FBO, "Framebuffer") GS_DEFINE(DETAIL_RESOLUTION, "Resolution") GS_DEFINE(DETAIL_STRING_FMT, "%s") GS_DEFINE(DETAIL_RESOLUTION_FMT, "%dx%d") -GS_DEFINE(CONTROL_RESET_DEFAULTS, "Reset All: Hold %s") -GS_DEFINE(CONTROL_UNBIND, "Unbind: Hold %s") +GS_DEFINE(CONTROLS_RESET_DEFAULTS, "Reset All: Hold %s") +GS_DEFINE(CONTROLS_UNBIND, "Unbind: Hold %s") GS_DEFINE(KEYMAP_CHANGE_TARGET, "Change Target") GS_DEFINE(KEYMAP_EQUIP_PISTOLS, "Equip Pistols") GS_DEFINE(KEYMAP_EQUIP_SHOTGUN, "Equip Shotgun") diff --git a/src/tr1/game/input.c b/src/tr1/game/input.c index cec011580..bb0417b1b 100644 --- a/src/tr1/game/input.c +++ b/src/tr1/game/input.c @@ -129,3 +129,9 @@ void Input_Update(void) g_InputDB.any = 0; } } + +const char *Input_GetRoleName(const INPUT_ROLE role) +{ + // TODO: implement me + return nullptr; +} diff --git a/src/tr1/game/option/option_controls.c b/src/tr1/game/option/option_controls.c index 7164ca10a..fdc60db28 100644 --- a/src/tr1/game/option/option_controls.c +++ b/src/tr1/game/option/option_controls.c @@ -295,10 +295,10 @@ static void M_InitText(INPUT_BACKEND backend, INPUT_LAYOUT layout) Text_AddOutline(m_Text[TEXT_TITLE_BORDER], TS_BACKGROUND); sprintf( - m_ResetGS, GS(CONTROL_RESET_DEFAULTS), + m_ResetGS, GS(CONTROLS_RESET_DEFAULTS), Input_GetKeyName(backend, layout, INPUT_ROLE_RESET_BINDINGS)); sprintf( - m_UnbindGS, GS(CONTROL_UNBIND), + m_UnbindGS, GS(CONTROLS_UNBIND), Input_GetKeyName(backend, layout, INPUT_ROLE_UNBIND_KEY)); m_Text[TEXT_RESET] = @@ -340,11 +340,11 @@ static void M_UpdateText(INPUT_BACKEND backend, INPUT_LAYOUT layout) } sprintf( - m_ResetGS, GS(CONTROL_RESET_DEFAULTS), + m_ResetGS, GS(CONTROLS_RESET_DEFAULTS), Input_GetKeyName(backend, layout, INPUT_ROLE_RESET_BINDINGS)); Text_ChangeText(m_Text[TEXT_RESET], m_ResetGS); sprintf( - m_UnbindGS, GS(CONTROL_UNBIND), + m_UnbindGS, GS(CONTROLS_UNBIND), Input_GetKeyName(backend, layout, INPUT_ROLE_UNBIND_KEY)); Text_ChangeText(m_Text[TEXT_UNBIND], m_UnbindGS); diff --git a/src/tr1/game/option/option_controls_pick.c b/src/tr1/game/option/option_controls_pick.c index 6b887371b..746debb0d 100644 --- a/src/tr1/game/option/option_controls_pick.c +++ b/src/tr1/game/option/option_controls_pick.c @@ -29,13 +29,13 @@ static void M_InitText(void) Text_AddBackground(m_Text[TEXT_TITLE_BORDER], 180, 85, 0, 0, TS_BACKGROUND); Text_AddOutline(m_Text[TEXT_TITLE_BORDER], TS_BACKGROUND); - m_Text[TEXT_TITLE] = Text_Create(0, -30, GS(CONTROL_CUSTOMIZE)); + m_Text[TEXT_TITLE] = Text_Create(0, -30, GS(CONTROLS_CUSTOMIZE)); Text_AddBackground(m_Text[TEXT_TITLE], 176, 0, 0, 0, TS_HEADING); Text_AddOutline(m_Text[TEXT_TITLE], TS_HEADING); - m_Text[TEXT_KEYBOARD] = Text_Create(0, 0, GS(CONTROL_BACKEND_KEYBOARD)); + m_Text[TEXT_KEYBOARD] = Text_Create(0, 0, GS(CONTROLS_BACKEND_KEYBOARD)); m_Text[TEXT_CONTROLLER] = - Text_Create(0, 25, GS(CONTROL_BACKEND_CONTROLLER)); + Text_Create(0, 25, GS(CONTROLS_BACKEND_CONTROLLER)); Text_AddBackground(m_Text[g_OptionSelected], 128, 0, 0, 0, TS_REQUESTED); Text_AddOutline(m_Text[g_OptionSelected], TS_REQUESTED); diff --git a/src/tr2/game/input.h b/src/tr2/game/input.h index e4e59f254..6f2d02c9b 100644 --- a/src/tr2/game/input.h +++ b/src/tr2/game/input.h @@ -1,5 +1,3 @@ #pragma once #include - -const char *Input_GetRoleName(INPUT_ROLE role); diff --git a/src/tr2/game/option/option_controls.c b/src/tr2/game/option/option_controls.c index b544d4cb0..d466f2af3 100644 --- a/src/tr2/game/option/option_controls.c +++ b/src/tr2/game/option/option_controls.c @@ -1,61 +1,57 @@ #include "game/option/option.h" -#include "game/ui/widgets/controls_dialog.h" #include "global/vars.h" #include -#include +#include -static UI_WIDGET *m_Dialog; -static UI_CONTROLS_CONTROLLER m_Controller; -static int32_t m_Listener1; -static int32_t m_Listener2; +typedef struct { + int32_t listeners[2]; + struct { + bool is_ready; + UI2_CONTROLS_STATE state; + } ui; +} M_PRIV; -static void M_Init(void); -static void M_Shutdown(void); +static M_PRIV m_Priv = {}; + +static void M_Init(M_PRIV *p); +static void M_Shutdown(M_PRIV *p); static void M_HandleLayoutChange(const EVENT *event, void *user_data); static void M_HandleKeyChange(const EVENT *event, void *user_data); -static void M_Init(void) +static void M_Init(M_PRIV *const p) { - UI_ControlsController_Init(&m_Controller); - m_Controller.active_layout = g_Config.input.keyboard_layout; - - m_Dialog = UI_ControlsDialog_Create(&m_Controller); - m_Listener1 = EventManager_Subscribe( - m_Controller.events, "layout_change", nullptr, M_HandleLayoutChange, - nullptr); - m_Listener2 = EventManager_Subscribe( - m_Controller.events, "key_change", nullptr, M_HandleKeyChange, nullptr); + UI2_Controls_Init(&p->ui.state); + p->ui.is_ready = true; + p->listeners[0] = EventManager_Subscribe( + p->ui.state.events, "layout_change", nullptr, M_HandleLayoutChange, p); + p->listeners[1] = EventManager_Subscribe( + p->ui.state.events, "key_change", nullptr, M_HandleKeyChange, p); } -static void M_Shutdown(void) +static void M_Shutdown(M_PRIV *const p) { - if (m_Dialog == nullptr) { - return; + if (p->ui.is_ready) { + EventManager_Unsubscribe(p->ui.state.events, p->listeners[0]); + EventManager_Unsubscribe(p->ui.state.events, p->listeners[1]); + UI2_Controls_Free(&p->ui.state); + p->ui.is_ready = false; } - - m_Dialog->free(m_Dialog); - m_Dialog = nullptr; - - EventManager_Unsubscribe(m_Controller.events, m_Listener1); - EventManager_Unsubscribe(m_Controller.events, m_Listener2); - - UI_ControlsController_Shutdown(&m_Controller); } static void M_HandleLayoutChange(const EVENT *event, void *user_data) { - switch (m_Controller.backend) { + const M_PRIV *const p = user_data; + switch (p->ui.state.backend) { case INPUT_BACKEND_KEYBOARD: - g_Config.input.keyboard_layout = m_Controller.active_layout; + g_Config.input.keyboard_layout = p->ui.state.active_layout; break; case INPUT_BACKEND_CONTROLLER: - g_Config.input.controller_layout = m_Controller.active_layout; + g_Config.input.controller_layout = p->ui.state.active_layout; break; default: break; } - Config_Write(); } @@ -66,22 +62,22 @@ static void M_HandleKeyChange(const EVENT *event, void *user_data) void Option_Controls_Shutdown(void) { - M_Shutdown(); + M_Shutdown(&m_Priv); } void Option_Controls_Control(INVENTORY_ITEM *const item, const bool is_busy) { + M_PRIV *const p = &m_Priv; if (is_busy) { return; } - if (m_Dialog == nullptr) { - M_Init(); + if (!p->ui.is_ready) { + M_Init(p); } - m_Dialog->control(m_Dialog); - if (m_Controller.state == UI_CONTROLS_STATE_EXIT) { - Option_Controls_Shutdown(); + if (UI2_Controls_Control(&p->ui.state)) { + M_Shutdown(p); } else { g_Input = (INPUT_STATE) {}; g_InputDB = (INPUT_STATE) {}; @@ -90,7 +86,8 @@ void Option_Controls_Control(INVENTORY_ITEM *const item, const bool is_busy) void Option_Controls_Draw(INVENTORY_ITEM *const item) { - if (m_Dialog != nullptr) { - m_Dialog->draw(m_Dialog); + M_PRIV *const p = &m_Priv; + if (p->ui.is_ready) { + UI2_Controls(&p->ui.state); } } diff --git a/src/tr2/game/ui/controllers/controls.c b/src/tr2/game/ui/controllers/controls.c deleted file mode 100644 index 6012394c4..000000000 --- a/src/tr2/game/ui/controllers/controls.c +++ /dev/null @@ -1,285 +0,0 @@ -#include "game/ui/controllers/controls.h" - -#include "game/input.h" -#include "game/shell.h" -#include "global/vars.h" - -#include -#include -#include -#include - -static const INPUT_ROLE m_LeftRoles[] = { - // clang-format off - INPUT_ROLE_UP, - INPUT_ROLE_DOWN, - INPUT_ROLE_LEFT, - INPUT_ROLE_RIGHT, - INPUT_ROLE_STEP_L, - INPUT_ROLE_STEP_R, - INPUT_ROLE_SLOW, - INPUT_ROLE_ENTER_CONSOLE, - INPUT_ROLE_PAUSE, - INPUT_ROLE_TOGGLE_PHOTO_MODE, - INPUT_ROLE_TOGGLE_UI, - // INPUT_ROLE_CAMERA_RESET, // same as look, no need to configure - INPUT_ROLE_CAMERA_UP, - INPUT_ROLE_CAMERA_DOWN, - INPUT_ROLE_CAMERA_LEFT, - INPUT_ROLE_CAMERA_RIGHT, - INPUT_ROLE_CAMERA_FORWARD, - INPUT_ROLE_CAMERA_BACK, - (INPUT_ROLE)-1, - // clang-format on -}; - -static const INPUT_ROLE m_RightRoles_CheatsOff[] = { - // clang-format off - INPUT_ROLE_JUMP, - INPUT_ROLE_ACTION, - INPUT_ROLE_DRAW, - INPUT_ROLE_USE_FLARE, - INPUT_ROLE_LOOK, - INPUT_ROLE_ROLL, - INPUT_ROLE_OPTION, - (INPUT_ROLE)-1, - // clang-format on -}; - -static const INPUT_ROLE m_RightRoles_CheatsOn[] = { - // clang-format off - INPUT_ROLE_JUMP, - INPUT_ROLE_ACTION, - INPUT_ROLE_DRAW, - INPUT_ROLE_USE_FLARE, - INPUT_ROLE_LOOK, - INPUT_ROLE_ROLL, - INPUT_ROLE_OPTION, - INPUT_ROLE_FLY_CHEAT, - INPUT_ROLE_ITEM_CHEAT, - INPUT_ROLE_LEVEL_SKIP_CHEAT, - INPUT_ROLE_TURBO_CHEAT, - (INPUT_ROLE)-1, - // clang-format on -}; - -static INPUT_ROLE M_GetInputRole(int32_t col, int32_t row); -static void M_CycleLayout(UI_CONTROLS_CONTROLLER *controller, int32_t dir); -static bool M_NavigateLayout(UI_CONTROLS_CONTROLLER *controller); -static bool M_NavigateInputs(UI_CONTROLS_CONTROLLER *controller); -static bool M_NavigateInputsDebounce(UI_CONTROLS_CONTROLLER *controller); -static bool M_Listen(UI_CONTROLS_CONTROLLER *controller); -static bool M_ListenDebounce(UI_CONTROLS_CONTROLLER *controller); - -static INPUT_ROLE M_GetInputRole(const int32_t col, const int32_t row) -{ - if (col == 0) { - return m_LeftRoles[row]; - } else if (g_Config.gameplay.enable_cheats) { - return m_RightRoles_CheatsOn[row]; - } else { - return m_RightRoles_CheatsOff[row]; - } -} - -static void M_CycleLayout( - UI_CONTROLS_CONTROLLER *const controller, const int32_t dir) -{ - controller->active_layout += dir; - controller->active_layout += INPUT_LAYOUT_NUMBER_OF; - controller->active_layout %= INPUT_LAYOUT_NUMBER_OF; - - const EVENT event = { - .name = "layout_change", - .sender = nullptr, - .data = nullptr, - }; - EventManager_Fire(controller->events, &event); -} - -static bool M_NavigateBackend(UI_CONTROLS_CONTROLLER *const controller) -{ - if (g_InputDB.menu_down && controller->backend == INPUT_BACKEND_KEYBOARD) { - controller->backend = INPUT_BACKEND_CONTROLLER; - return true; - } - - if (g_InputDB.menu_up && controller->backend == INPUT_BACKEND_CONTROLLER) { - controller->backend = INPUT_BACKEND_KEYBOARD; - return true; - } - - if (g_InputDB.menu_back) { - controller->state = UI_CONTROLS_STATE_EXIT; - return true; - } - - if (g_InputDB.menu_confirm) { - controller->state = UI_CONTROLS_STATE_NAVIGATE_LAYOUT; - return true; - } - - return false; -} - -static bool M_NavigateLayout(UI_CONTROLS_CONTROLLER *const controller) -{ - if (g_InputDB.menu_confirm) { - controller->state = UI_CONTROLS_STATE_EXIT; - } else if (g_InputDB.menu_back) { - controller->state = UI_CONTROLS_STATE_NAVIGATE_BACKEND; - } else if (g_InputDB.menu_left) { - M_CycleLayout(controller, -1); - } else if (g_InputDB.menu_right) { - M_CycleLayout(controller, 1); - } else if (g_InputDB.menu_down && controller->active_layout != 0) { - controller->state = UI_CONTROLS_STATE_NAVIGATE_INPUTS; - controller->active_col = 0; - controller->active_row = 0; - } else if (g_InputDB.menu_up && controller->active_layout != 0) { - controller->state = UI_CONTROLS_STATE_NAVIGATE_INPUTS; - controller->active_col = 1; - controller->active_row = UI_ControlsController_GetInputRoleCount(1) - 1; - } else { - return false; - } - controller->active_role = - M_GetInputRole(controller->active_col, controller->active_row); - return true; -} - -static bool M_NavigateInputs(UI_CONTROLS_CONTROLLER *const controller) -{ - if (g_InputDB.menu_back) { - controller->state = UI_CONTROLS_STATE_NAVIGATE_BACKEND; - } else if (g_InputDB.menu_left || g_InputDB.menu_right) { - controller->active_col ^= 1; - CLAMP( - controller->active_row, 0, - UI_ControlsController_GetInputRoleCount(controller->active_col) - - 1); - } else if (g_InputDB.menu_up) { - controller->active_row--; - if (controller->active_row < 0) { - if (controller->active_col == 0) { - controller->state = UI_CONTROLS_STATE_NAVIGATE_LAYOUT; - } else { - controller->active_col = 0; - controller->active_row = - UI_ControlsController_GetInputRoleCount(0) - 1; - } - } - } else if (g_InputDB.menu_down) { - controller->active_row++; - if (controller->active_row >= UI_ControlsController_GetInputRoleCount( - controller->active_col)) { - if (controller->active_col == 0) { - controller->active_col = 1; - controller->active_row = 0; - } else { - controller->state = UI_CONTROLS_STATE_NAVIGATE_LAYOUT; - } - } - } else if (g_InputDB.menu_confirm) { - controller->state = UI_CONTROLS_STATE_NAVIGATE_INPUTS_DEBOUNCE; - } else { - return false; - } - controller->active_role = - M_GetInputRole(controller->active_col, controller->active_row); - return true; -} - -static bool M_NavigateInputsDebounce(UI_CONTROLS_CONTROLLER *const controller) -{ - Shell_ProcessEvents(); - Input_Update(); - if (g_Input.any) { - return false; - } - Input_EnterListenMode(); - controller->state = UI_CONTROLS_STATE_LISTEN; - return true; -} - -static bool M_Listen(UI_CONTROLS_CONTROLLER *const controller) -{ - if (!Input_ReadAndAssignRole( - controller->backend, controller->active_layout, - controller->active_role)) { - return false; - } - - Input_ExitListenMode(); - - const EVENT event = { - .name = "key_change", - .sender = nullptr, - .data = nullptr, - }; - EventManager_Fire(controller->events, &event); - - controller->state = UI_CONTROLS_STATE_LISTEN_DEBOUNCE; - return true; -} - -static bool M_ListenDebounce(UI_CONTROLS_CONTROLLER *const controller) -{ - if (g_Input.any) { - return false; - } - - controller->state = UI_CONTROLS_STATE_NAVIGATE_INPUTS; - return true; -} - -void UI_ControlsController_Init(UI_CONTROLS_CONTROLLER *const controller) -{ - ASSERT(controller->events == nullptr); - controller->backend = INPUT_BACKEND_KEYBOARD; - controller->state = UI_CONTROLS_STATE_NAVIGATE_BACKEND; - - controller->events = EventManager_Create(); -} - -void UI_ControlsController_Shutdown(UI_CONTROLS_CONTROLLER *const controller) -{ - EventManager_Free(controller->events); - controller->events = nullptr; -} - -bool UI_ControlsController_Control(UI_CONTROLS_CONTROLLER *const controller) -{ - switch (controller->state) { - case UI_CONTROLS_STATE_NAVIGATE_BACKEND: - return M_NavigateBackend(controller); - case UI_CONTROLS_STATE_NAVIGATE_LAYOUT: - return M_NavigateLayout(controller); - case UI_CONTROLS_STATE_NAVIGATE_INPUTS: - return M_NavigateInputs(controller); - case UI_CONTROLS_STATE_NAVIGATE_INPUTS_DEBOUNCE: - return M_NavigateInputsDebounce(controller); - case UI_CONTROLS_STATE_LISTEN: - return M_Listen(controller); - case UI_CONTROLS_STATE_LISTEN_DEBOUNCE: - return M_ListenDebounce(controller); - default: - return false; - } - return false; -} - -INPUT_ROLE UI_ControlsController_GetInputRole( - const int32_t col, const int32_t row) -{ - return M_GetInputRole(col, row); -} - -int32_t UI_ControlsController_GetInputRoleCount(const int32_t col) -{ - int32_t row = 0; - while (M_GetInputRole(col, row) != (INPUT_ROLE)-1) { - row++; - } - return row; -} diff --git a/src/tr2/game/ui/controllers/controls.h b/src/tr2/game/ui/controllers/controls.h deleted file mode 100644 index 60d4985d2..000000000 --- a/src/tr2/game/ui/controllers/controls.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include "game/input.h" - -#include - -typedef enum { - UI_CONTROLS_STATE_NAVIGATE_BACKEND, - UI_CONTROLS_STATE_NAVIGATE_LAYOUT, - UI_CONTROLS_STATE_NAVIGATE_INPUTS, - UI_CONTROLS_STATE_NAVIGATE_INPUTS_DEBOUNCE, - UI_CONTROLS_STATE_LISTEN, - UI_CONTROLS_STATE_LISTEN_DEBOUNCE, - UI_CONTROLS_STATE_EXIT, -} UI_CONTROLS_STATE; - -typedef struct { - INPUT_BACKEND backend; - UI_CONTROLS_STATE state; - int32_t active_layout; - INPUT_ROLE active_role; - int32_t active_col; - int32_t active_row; - - EVENT_MANAGER *events; -} UI_CONTROLS_CONTROLLER; - -void UI_ControlsController_Init(UI_CONTROLS_CONTROLLER *controller); -void UI_ControlsController_Shutdown(UI_CONTROLS_CONTROLLER *controller); -bool UI_ControlsController_Control(UI_CONTROLS_CONTROLLER *controller); - -INPUT_ROLE UI_ControlsController_GetInputRole(int32_t col, int32_t row); -int32_t UI_ControlsController_GetInputRoleCount(int32_t col); diff --git a/src/tr2/game/ui/widgets/controls_backend_selector.c b/src/tr2/game/ui/widgets/controls_backend_selector.c deleted file mode 100644 index 7ad4b6e49..000000000 --- a/src/tr2/game/ui/widgets/controls_backend_selector.c +++ /dev/null @@ -1,111 +0,0 @@ -#include "game/ui/widgets/controls_backend_selector.h" - -#include "game/game_string.h" - -#include -#include -#include - -typedef struct { - UI_WIDGET_VTABLE vtable; - UI_WIDGET *keyboard_label; - UI_WIDGET *controller_label; - UI_WIDGET *container; - UI_CONTROLS_CONTROLLER *controller; -} UI_CONTROLS_BACKEND_SELECTOR; - -static void M_SyncOutlines(UI_CONTROLS_BACKEND_SELECTOR *self); - -static void M_UpdateText(UI_CONTROLS_BACKEND_SELECTOR *self); -static int32_t M_GetWidth(const UI_CONTROLS_BACKEND_SELECTOR *self); -static int32_t M_GetHeight(const UI_CONTROLS_BACKEND_SELECTOR *self); -static void M_SetPosition( - UI_CONTROLS_BACKEND_SELECTOR *self, int32_t x, int32_t y); -static void M_Control(UI_CONTROLS_BACKEND_SELECTOR *self); -static void M_Draw(UI_CONTROLS_BACKEND_SELECTOR *self); -static void M_Free(UI_CONTROLS_BACKEND_SELECTOR *self); - -static void M_SyncOutlines(UI_CONTROLS_BACKEND_SELECTOR *const self) -{ - UI_Label_RemoveFrame(self->keyboard_label); - UI_Label_RemoveFrame(self->controller_label); - switch (self->controller->backend) { - case INPUT_BACKEND_KEYBOARD: - UI_Label_AddFrame(self->keyboard_label); - break; - case INPUT_BACKEND_CONTROLLER: - UI_Label_AddFrame(self->controller_label); - break; - default: - break; - } -} - -static int32_t M_GetWidth(const UI_CONTROLS_BACKEND_SELECTOR *const self) -{ - return self->container->get_width(self->container); -} - -static int32_t M_GetHeight(const UI_CONTROLS_BACKEND_SELECTOR *const self) -{ - return self->container->get_height(self->container); -} - -static void M_SetPosition( - UI_CONTROLS_BACKEND_SELECTOR *const self, const int32_t x, const int32_t y) -{ - self->container->set_position(self->container, x, y); -} - -static void M_Control(UI_CONTROLS_BACKEND_SELECTOR *const self) -{ - M_SyncOutlines(self); -} - -static void M_Draw(UI_CONTROLS_BACKEND_SELECTOR *const self) -{ - if (self->container->draw != nullptr) { - self->container->draw(self->container); - } -} - -static void M_Free(UI_CONTROLS_BACKEND_SELECTOR *const self) -{ - self->keyboard_label->free(self->keyboard_label); - self->controller_label->free(self->controller_label); - self->container->free(self->container); - Memory_Free(self); -} - -UI_WIDGET *UI_ControlsBackendSelector_Create( - UI_CONTROLS_CONTROLLER *const controller) -{ - UI_CONTROLS_BACKEND_SELECTOR *const self = - Memory_Alloc(sizeof(UI_CONTROLS_BACKEND_SELECTOR)); - self->vtable = (UI_WIDGET_VTABLE) { - .get_width = (UI_WIDGET_GET_WIDTH)M_GetWidth, - .get_height = (UI_WIDGET_GET_HEIGHT)M_GetHeight, - .set_position = (UI_WIDGET_SET_POSITION)M_SetPosition, - .control = (UI_WIDGET_CONTROL)M_Control, - .draw = (UI_WIDGET_DRAW)M_Draw, - .free = (UI_WIDGET_FREE)M_Free, - }; - - self->controller = controller; - - self->keyboard_label = - UI_Label_Create(GS(CONTROL_BACKEND_KEYBOARD), UI_LABEL_AUTO_SIZE, 16); - self->controller_label = - UI_Label_Create(GS(CONTROL_BACKEND_CONTROLLER), UI_LABEL_AUTO_SIZE, 16); - - self->container = UI_Stack_Create( - UI_STACK_LAYOUT_VERTICAL, UI_STACK_AUTO_SIZE, UI_STACK_AUTO_SIZE); - - UI_Stack_AddChild(self->container, self->keyboard_label); - UI_Stack_AddChild(self->container, self->controller_label); - UI_Stack_SetHAlign(self->container, UI_STACK_H_ALIGN_CENTER); - - M_SyncOutlines(self); - - return (UI_WIDGET *)self; -} diff --git a/src/tr2/game/ui/widgets/controls_backend_selector.h b/src/tr2/game/ui/widgets/controls_backend_selector.h deleted file mode 100644 index b2c085757..000000000 --- a/src/tr2/game/ui/widgets/controls_backend_selector.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include "game/ui/controllers/controls.h" - -#include - -UI_WIDGET *UI_ControlsBackendSelector_Create( - UI_CONTROLS_CONTROLLER *controller); diff --git a/src/tr2/game/ui/widgets/controls_column.c b/src/tr2/game/ui/widgets/controls_column.c deleted file mode 100644 index 162d3b765..000000000 --- a/src/tr2/game/ui/widgets/controls_column.c +++ /dev/null @@ -1,87 +0,0 @@ -#include "game/ui/widgets/controls_column.h" - -#include "game/ui/widgets/controls_input_selector.h" - -#include -#include - -typedef struct { - UI_WIDGET_VTABLE vtable; - UI_WIDGET *container; - int32_t selector_count; - UI_WIDGET **selectors; -} UI_CONTROLS_COLUMN; - -static int32_t M_GetWidth(const UI_CONTROLS_COLUMN *self); -static int32_t M_GetHeight(const UI_CONTROLS_COLUMN *self); -static void M_SetPosition(UI_CONTROLS_COLUMN *self, int32_t x, int32_t y); -static void M_Control(UI_CONTROLS_COLUMN *self); -static void M_Draw(UI_CONTROLS_COLUMN *self); -static void M_Free(UI_CONTROLS_COLUMN *self); - -static int32_t M_GetWidth(const UI_CONTROLS_COLUMN *const self) -{ - return self->container->get_width(self->container); -} - -static int32_t M_GetHeight(const UI_CONTROLS_COLUMN *const self) -{ - return self->container->get_height(self->container); -} - -static void M_SetPosition( - UI_CONTROLS_COLUMN *const self, const int32_t x, const int32_t y) -{ - self->container->set_position(self->container, x, y); -} - -static void M_Control(UI_CONTROLS_COLUMN *const self) -{ - if (self->container->control != nullptr) { - self->container->control(self->container); - } -} - -static void M_Draw(UI_CONTROLS_COLUMN *const self) -{ - if (self->container->draw != nullptr) { - self->container->draw(self->container); - } -} - -static void M_Free(UI_CONTROLS_COLUMN *const self) -{ - for (int32_t i = 0; i < self->selector_count; i++) { - self->selectors[i]->free(self->selectors[i]); - } - self->container->free(self->container); - Memory_FreePointer(&self->selectors); - Memory_Free(self); -} - -UI_WIDGET *UI_ControlsColumn_Create( - const int32_t column, UI_CONTROLS_CONTROLLER *const controller) -{ - UI_CONTROLS_COLUMN *const self = Memory_Alloc(sizeof(UI_CONTROLS_COLUMN)); - self->vtable = (UI_WIDGET_VTABLE) { - .get_width = (UI_WIDGET_GET_WIDTH)M_GetWidth, - .get_height = (UI_WIDGET_GET_HEIGHT)M_GetHeight, - .set_position = (UI_WIDGET_SET_POSITION)M_SetPosition, - .control = (UI_WIDGET_CONTROL)M_Control, - .draw = (UI_WIDGET_DRAW)M_Draw, - .free = (UI_WIDGET_FREE)M_Free, - }; - - self->selector_count = UI_ControlsController_GetInputRoleCount(column); - self->container = UI_Stack_Create( - UI_STACK_LAYOUT_VERTICAL, UI_STACK_AUTO_SIZE, UI_STACK_AUTO_SIZE); - self->selectors = Memory_Alloc(sizeof(UI_WIDGET *) * self->selector_count); - - for (int32_t i = 0; i < self->selector_count; i++) { - self->selectors[i] = UI_ControlsInputSelector_Create( - UI_ControlsController_GetInputRole(column, i), controller); - UI_Stack_AddChild(self->container, self->selectors[i]); - } - - return (UI_WIDGET *)self; -} diff --git a/src/tr2/game/ui/widgets/controls_column.h b/src/tr2/game/ui/widgets/controls_column.h deleted file mode 100644 index 3589dd486..000000000 --- a/src/tr2/game/ui/widgets/controls_column.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include "game/ui/controllers/controls.h" - -#include - -UI_WIDGET *UI_ControlsColumn_Create( - int32_t column, UI_CONTROLS_CONTROLLER *controller); diff --git a/src/tr2/game/ui/widgets/controls_dialog.c b/src/tr2/game/ui/widgets/controls_dialog.c deleted file mode 100644 index b28bf21e1..000000000 --- a/src/tr2/game/ui/widgets/controls_dialog.c +++ /dev/null @@ -1,122 +0,0 @@ -#include "game/ui/widgets/controls_dialog.h" - -#include "game/game_string.h" -#include "game/ui/widgets/controls_backend_selector.h" -#include "game/ui/widgets/controls_column.h" -#include "game/ui/widgets/controls_layout_editor.h" - -#include -#include -#include - -typedef struct { - UI_WIDGET_VTABLE vtable; - UI_CONTROLS_CONTROLLER *controller; - UI_WIDGET *window; - UI_WIDGET *backend_selector; - UI_WIDGET *layout_editor; - int32_t listener; -} UI_CONTROLS_DIALOG; - -static void M_DoLayout(UI_CONTROLS_DIALOG *self); -static void M_HandleCanvasResize(const EVENT *event, void *data); -static int32_t M_GetWidth(const UI_CONTROLS_DIALOG *self); -static int32_t M_GetHeight(const UI_CONTROLS_DIALOG *self); -static void M_SetPosition(UI_CONTROLS_DIALOG *self, int32_t x, int32_t y); -static void M_Control(UI_CONTROLS_DIALOG *self); -static void M_Draw(UI_CONTROLS_DIALOG *self); -static void M_Free(UI_CONTROLS_DIALOG *self); - -static void M_DoLayout(UI_CONTROLS_DIALOG *const self) -{ - M_SetPosition( - self, (UI_GetCanvasWidth() - M_GetWidth(self)) / 2, - (UI_GetCanvasHeight() - M_GetHeight(self)) * 2 / 3); -} - -static void M_HandleCanvasResize(const EVENT *event, void *data) -{ - UI_CONTROLS_DIALOG *const self = (UI_CONTROLS_DIALOG *)data; - M_DoLayout(self); -} - -static int32_t M_GetWidth(const UI_CONTROLS_DIALOG *const self) -{ - return self->window->get_width(self->window); -} - -static int32_t M_GetHeight(const UI_CONTROLS_DIALOG *const self) -{ - return self->window->get_height(self->window); -} - -static void M_SetPosition( - UI_CONTROLS_DIALOG *const self, const int32_t x, const int32_t y) -{ - self->window->set_position(self->window, x, y); -} - -static void M_Control(UI_CONTROLS_DIALOG *const self) -{ - // Trigger the UI updates only if anything has changed. - if (UI_ControlsController_Control(self->controller)) { - // Set the root widget - backend selector modal or the inputs modal - if (self->controller->state == UI_CONTROLS_STATE_NAVIGATE_BACKEND - || self->controller->state == UI_CONTROLS_STATE_EXIT) { - UI_Window_SetTitle(self->window, GS(CONTROL_CUSTOMIZE)); - UI_Window_SetRootWidget(self->window, self->backend_selector); - } else { - UI_Window_SetTitle(self->window, nullptr); - UI_Window_SetRootWidget(self->window, self->layout_editor); - } - M_DoLayout(self); - - if (self->window->control != nullptr) { - self->window->control(self->window); - } - } -} - -static void M_Draw(UI_CONTROLS_DIALOG *const self) -{ - if (self->window->draw != nullptr) { - self->window->draw(self->window); - } -} - -static void M_Free(UI_CONTROLS_DIALOG *const self) -{ - self->layout_editor->free(self->layout_editor); - self->backend_selector->free(self->backend_selector); - self->window->free(self->window); - UI_Events_Unsubscribe(self->listener); - Memory_Free(self); -} - -UI_WIDGET *UI_ControlsDialog_Create(UI_CONTROLS_CONTROLLER *const controller) -{ - UI_CONTROLS_DIALOG *const self = Memory_Alloc(sizeof(UI_CONTROLS_DIALOG)); - self->vtable = (UI_WIDGET_VTABLE) { - .get_width = (UI_WIDGET_GET_WIDTH)M_GetWidth, - .get_height = (UI_WIDGET_GET_HEIGHT)M_GetHeight, - .set_position = (UI_WIDGET_SET_POSITION)M_SetPosition, - .control = (UI_WIDGET_CONTROL)M_Control, - .draw = (UI_WIDGET_DRAW)M_Draw, - .free = (UI_WIDGET_FREE)M_Free, - }; - - self->controller = controller; - - self->layout_editor = UI_ControlsLayoutEditor_Create(self->controller); - self->backend_selector = - UI_ControlsBackendSelector_Create(self->controller); - self->window = UI_Window_Create(self->backend_selector, 5, 5, 10, 5); - - UI_Window_SetTitle(self->window, GS(CONTROL_CUSTOMIZE)); - - self->listener = UI_Events_Subscribe( - "canvas_resize", nullptr, M_HandleCanvasResize, self); - - M_DoLayout(self); - return (UI_WIDGET *)self; -} diff --git a/src/tr2/game/ui/widgets/controls_dialog.h b/src/tr2/game/ui/widgets/controls_dialog.h deleted file mode 100644 index 8cec14bb8..000000000 --- a/src/tr2/game/ui/widgets/controls_dialog.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "game/ui/controllers/controls.h" - -#include - -UI_WIDGET *UI_ControlsDialog_Create(UI_CONTROLS_CONTROLLER *controller); diff --git a/src/tr2/game/ui/widgets/controls_input_selector.c b/src/tr2/game/ui/widgets/controls_input_selector.c deleted file mode 100644 index edc34c25c..000000000 --- a/src/tr2/game/ui/widgets/controls_input_selector.c +++ /dev/null @@ -1,135 +0,0 @@ -#include "game/ui/widgets/controls_input_selector.h" - -#include -#include -#include - -#include -#include - -typedef struct { - UI_WIDGET_VTABLE vtable; - INPUT_ROLE input_role; - UI_WIDGET *label; - UI_WIDGET *choice; - UI_WIDGET *container; - UI_CONTROLS_CONTROLLER *controller; -} UI_CONTROLS_INPUT_SELECTOR; - -static void M_UpdateText(UI_CONTROLS_INPUT_SELECTOR *self); -static int32_t M_GetWidth(const UI_CONTROLS_INPUT_SELECTOR *self); -static int32_t M_GetHeight(const UI_CONTROLS_INPUT_SELECTOR *self); -static void M_SetPosition( - UI_CONTROLS_INPUT_SELECTOR *self, int32_t x, int32_t y); -static void M_Control(UI_CONTROLS_INPUT_SELECTOR *self); -static void M_Draw(UI_CONTROLS_INPUT_SELECTOR *self); -static void M_Free(UI_CONTROLS_INPUT_SELECTOR *self); - -static void M_UpdateText(UI_CONTROLS_INPUT_SELECTOR *const self) -{ - const char *const key_name = Input_GetKeyName( - self->controller->backend, self->controller->active_layout, - self->input_role); - UI_Label_ChangeText(self->choice, key_name); - const char *const role_name = Input_GetRoleName(self->input_role); - char role_name_padded[strlen(role_name) + 2]; - sprintf(role_name_padded, "%s ", role_name); - UI_Label_ChangeText(self->label, role_name_padded); -} - -static int32_t M_GetWidth(const UI_CONTROLS_INPUT_SELECTOR *const self) -{ - return self->container->get_width(self->container); -} - -static int32_t M_GetHeight(const UI_CONTROLS_INPUT_SELECTOR *const self) -{ - return self->container->get_height(self->container); -} - -static void M_SetPosition( - UI_CONTROLS_INPUT_SELECTOR *const self, const int32_t x, const int32_t y) -{ - self->container->set_position(self->container, x, y); -} - -static void M_Control(UI_CONTROLS_INPUT_SELECTOR *const self) -{ - if (self->label->control != nullptr) { - self->label->control(self->label); - } - if (self->choice->control != nullptr) { - self->choice->control(self->choice); - } - - // Sync outlines - UI_Label_RemoveFrame(self->label); - UI_Label_RemoveFrame(self->choice); - if (self->controller->active_role == self->input_role) { - if (self->controller->state == UI_CONTROLS_STATE_NAVIGATE_INPUTS - || self->controller->state - == UI_CONTROLS_STATE_NAVIGATE_INPUTS_DEBOUNCE) { - UI_Label_AddFrame(self->label); - } else if (self->controller->state == UI_CONTROLS_STATE_LISTEN) { - UI_Label_AddFrame(self->choice); - } - } - - M_UpdateText(self); - - // Flash conflicts - UI_Label_Flash(self->choice, false, 0); - if (Input_IsKeyConflicted( - self->controller->backend, self->controller->active_layout, - self->input_role)) { - UI_Label_Flash(self->choice, true, 20); - } -} - -static void M_Draw(UI_CONTROLS_INPUT_SELECTOR *const self) -{ - if (self->label->draw != nullptr) { - self->label->draw(self->label); - } - if (self->choice->draw != nullptr) { - self->choice->draw(self->choice); - } -} - -static void M_Free(UI_CONTROLS_INPUT_SELECTOR *const self) -{ - self->label->free(self->label); - self->choice->free(self->choice); - self->container->free(self->container); - Memory_Free(self); -} - -UI_WIDGET *UI_ControlsInputSelector_Create( - const INPUT_ROLE input_role, UI_CONTROLS_CONTROLLER *const controller) -{ - UI_CONTROLS_INPUT_SELECTOR *const self = - Memory_Alloc(sizeof(UI_CONTROLS_INPUT_SELECTOR)); - self->vtable = (UI_WIDGET_VTABLE) { - .get_width = (UI_WIDGET_GET_WIDTH)M_GetWidth, - .get_height = (UI_WIDGET_GET_HEIGHT)M_GetHeight, - .set_position = (UI_WIDGET_SET_POSITION)M_SetPosition, - .control = (UI_WIDGET_CONTROL)M_Control, - .draw = (UI_WIDGET_DRAW)M_Draw, - .free = (UI_WIDGET_FREE)M_Free, - }; - - self->controller = controller; - self->input_role = input_role; - - self->label = UI_Label_Create("", UI_LABEL_AUTO_SIZE, 15); - self->choice = UI_Label_Create("", 70, 15); - self->container = UI_Stack_Create( - UI_STACK_LAYOUT_HORIZONTAL, UI_STACK_AUTO_SIZE, UI_STACK_AUTO_SIZE); - UI_Stack_AddChild(self->container, self->choice); - UI_Stack_AddChild(self->container, self->label); - - // update the text on init - M_UpdateText(self); - - return (UI_WIDGET *)self; -} diff --git a/src/tr2/game/ui/widgets/controls_input_selector.h b/src/tr2/game/ui/widgets/controls_input_selector.h deleted file mode 100644 index 6c514c471..000000000 --- a/src/tr2/game/ui/widgets/controls_input_selector.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include "game/ui/controllers/controls.h" - -#include - -UI_WIDGET *UI_ControlsInputSelector_Create( - INPUT_ROLE input_role, UI_CONTROLS_CONTROLLER *controller); diff --git a/src/tr2/game/ui/widgets/controls_layout_editor.c b/src/tr2/game/ui/widgets/controls_layout_editor.c deleted file mode 100644 index da5689965..000000000 --- a/src/tr2/game/ui/widgets/controls_layout_editor.c +++ /dev/null @@ -1,103 +0,0 @@ -#include "game/ui/widgets/controls_layout_editor.h" - -#include "game/ui/widgets/controls_column.h" -#include "game/ui/widgets/controls_layout_selector.h" - -#include -#include -#include - -typedef struct { - UI_WIDGET_VTABLE vtable; - UI_CONTROLS_CONTROLLER *controller; - UI_WIDGET *layout_selector; - UI_WIDGET *outer_stack; - UI_WIDGET *column_stack; - UI_WIDGET *left_column; - UI_WIDGET *right_column; -} UI_CONTROLS_LAYOUT_EDITOR; - -static void M_DoLayout(UI_CONTROLS_LAYOUT_EDITOR *self); -static int32_t M_GetWidth(const UI_CONTROLS_LAYOUT_EDITOR *self); -static int32_t M_GetHeight(const UI_CONTROLS_LAYOUT_EDITOR *self); -static void M_SetPosition( - UI_CONTROLS_LAYOUT_EDITOR *self, int32_t x, int32_t y); -static void M_Control(UI_CONTROLS_LAYOUT_EDITOR *self); -static void M_Draw(UI_CONTROLS_LAYOUT_EDITOR *self); -static void M_Free(UI_CONTROLS_LAYOUT_EDITOR *self); - -static int32_t M_GetWidth(const UI_CONTROLS_LAYOUT_EDITOR *const self) -{ - return self->outer_stack->get_width(self->outer_stack); -} - -static int32_t M_GetHeight(const UI_CONTROLS_LAYOUT_EDITOR *const self) -{ - return self->outer_stack->get_height(self->outer_stack); -} - -static void M_SetPosition( - UI_CONTROLS_LAYOUT_EDITOR *const self, const int32_t x, const int32_t y) -{ - self->outer_stack->set_position(self->outer_stack, x, y); -} - -static void M_Control(UI_CONTROLS_LAYOUT_EDITOR *const self) -{ - if (self->outer_stack->control != nullptr) { - self->outer_stack->control(self->outer_stack); - } - // Reposition the header. - UI_Stack_DoLayout(self->outer_stack); -} - -static void M_Draw(UI_CONTROLS_LAYOUT_EDITOR *const self) -{ - if (self->outer_stack->draw != nullptr) { - self->outer_stack->draw(self->outer_stack); - } -} - -static void M_Free(UI_CONTROLS_LAYOUT_EDITOR *const self) -{ - self->left_column->free(self->left_column); - self->right_column->free(self->right_column); - self->column_stack->free(self->column_stack); - self->outer_stack->free(self->outer_stack); - self->layout_selector->free(self->layout_selector); - Memory_Free(self); -} - -UI_WIDGET *UI_ControlsLayoutEditor_Create( - UI_CONTROLS_CONTROLLER *const controller) -{ - UI_CONTROLS_LAYOUT_EDITOR *const self = - Memory_Alloc(sizeof(UI_CONTROLS_LAYOUT_EDITOR)); - self->vtable = (UI_WIDGET_VTABLE) { - .get_width = (UI_WIDGET_GET_WIDTH)M_GetWidth, - .get_height = (UI_WIDGET_GET_HEIGHT)M_GetHeight, - .set_position = (UI_WIDGET_SET_POSITION)M_SetPosition, - .control = (UI_WIDGET_CONTROL)M_Control, - .draw = (UI_WIDGET_DRAW)M_Draw, - .free = (UI_WIDGET_FREE)M_Free, - }; - - self->controller = controller; - - self->layout_selector = UI_ControlsLayoutSelector_Create(self->controller); - self->left_column = UI_ControlsColumn_Create(0, self->controller); - self->right_column = UI_ControlsColumn_Create(1, self->controller); - - self->column_stack = UI_Stack_Create( - UI_STACK_LAYOUT_HORIZONTAL, UI_STACK_AUTO_SIZE, UI_STACK_AUTO_SIZE); - UI_Stack_AddChild(self->column_stack, self->left_column); - UI_Stack_AddChild(self->column_stack, self->right_column); - - self->outer_stack = UI_Stack_Create( - UI_STACK_LAYOUT_VERTICAL, UI_STACK_AUTO_SIZE, UI_STACK_AUTO_SIZE); - UI_Stack_SetHAlign(self->outer_stack, UI_STACK_H_ALIGN_CENTER); - UI_Stack_AddChild(self->outer_stack, self->layout_selector); - UI_Stack_AddChild(self->outer_stack, self->column_stack); - - return (UI_WIDGET *)self; -} diff --git a/src/tr2/game/ui/widgets/controls_layout_editor.h b/src/tr2/game/ui/widgets/controls_layout_editor.h deleted file mode 100644 index 0e3a08ea1..000000000 --- a/src/tr2/game/ui/widgets/controls_layout_editor.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "game/ui/controllers/controls.h" - -#include - -UI_WIDGET *UI_ControlsLayoutEditor_Create(UI_CONTROLS_CONTROLLER *controller); diff --git a/src/tr2/game/ui/widgets/controls_layout_selector.c b/src/tr2/game/ui/widgets/controls_layout_selector.c deleted file mode 100644 index ba956759d..000000000 --- a/src/tr2/game/ui/widgets/controls_layout_selector.c +++ /dev/null @@ -1,83 +0,0 @@ -#include "game/ui/widgets/controls_layout_selector.h" - -#include -#include - -typedef struct { - UI_WIDGET_VTABLE vtable; - UI_WIDGET *label; - UI_CONTROLS_CONTROLLER *controller; -} UI_CONTROLS_LAYOUT_SELECTOR; - -static int32_t M_GetWidth(const UI_CONTROLS_LAYOUT_SELECTOR *self); -static int32_t M_GetHeight(const UI_CONTROLS_LAYOUT_SELECTOR *self); -static void M_SetPosition( - UI_CONTROLS_LAYOUT_SELECTOR *self, int32_t x, int32_t y); -static void M_Control(UI_CONTROLS_LAYOUT_SELECTOR *self); -static void M_Draw(UI_CONTROLS_LAYOUT_SELECTOR *self); -static void M_Free(UI_CONTROLS_LAYOUT_SELECTOR *self); - -static int32_t M_GetWidth(const UI_CONTROLS_LAYOUT_SELECTOR *const self) -{ - return self->label->get_width(self->label); -} - -static int32_t M_GetHeight(const UI_CONTROLS_LAYOUT_SELECTOR *const self) -{ - return self->label->get_height(self->label); -} - -static void M_SetPosition( - UI_CONTROLS_LAYOUT_SELECTOR *const self, const int32_t x, const int32_t y) -{ - self->label->set_position(self->label, x, y); -} - -static void M_Control(UI_CONTROLS_LAYOUT_SELECTOR *const self) -{ - if (self->controller->state == UI_CONTROLS_STATE_NAVIGATE_LAYOUT) { - UI_Label_AddFrame(self->label); - UI_Label_ChangeText( - self->label, Input_GetLayoutName(self->controller->active_layout)); - } else { - UI_Label_RemoveFrame(self->label); - } - if (self->label->control != nullptr) { - self->label->control(self->label); - } -} - -static void M_Draw(UI_CONTROLS_LAYOUT_SELECTOR *const self) -{ - if (self->label->draw != nullptr) { - self->label->draw(self->label); - } -} - -static void M_Free(UI_CONTROLS_LAYOUT_SELECTOR *const self) -{ - self->label->free(self->label); - Memory_Free(self); -} - -UI_WIDGET *UI_ControlsLayoutSelector_Create( - UI_CONTROLS_CONTROLLER *const controller) -{ - UI_CONTROLS_LAYOUT_SELECTOR *self = - Memory_Alloc(sizeof(UI_CONTROLS_LAYOUT_SELECTOR)); - self->vtable = (UI_WIDGET_VTABLE) { - .get_width = (UI_WIDGET_GET_WIDTH)M_GetWidth, - .get_height = (UI_WIDGET_GET_HEIGHT)M_GetHeight, - .set_position = (UI_WIDGET_SET_POSITION)M_SetPosition, - .control = (UI_WIDGET_CONTROL)M_Control, - .draw = (UI_WIDGET_DRAW)M_Draw, - .free = (UI_WIDGET_FREE)M_Free, - }; - - self->controller = controller; - self->label = UI_Label_Create( - Input_GetLayoutName(self->controller->active_layout), - UI_LABEL_AUTO_SIZE, 25); - UI_Label_AddFrame(self->label); - return (UI_WIDGET *)self; -} diff --git a/src/tr2/game/ui/widgets/controls_layout_selector.h b/src/tr2/game/ui/widgets/controls_layout_selector.h deleted file mode 100644 index a14cead06..000000000 --- a/src/tr2/game/ui/widgets/controls_layout_selector.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "game/ui/controllers/controls.h" - -#include - -UI_WIDGET *UI_ControlsLayoutSelector_Create(UI_CONTROLS_CONTROLLER *controller); diff --git a/src/tr2/meson.build b/src/tr2/meson.build index f1bfe7f20..eb4a92ddc 100644 --- a/src/tr2/meson.build +++ b/src/tr2/meson.build @@ -270,13 +270,6 @@ sources = [ 'game/stats.c', 'game/text.c', 'game/ui/common.c', - 'game/ui/controllers/controls.c', - 'game/ui/widgets/controls_backend_selector.c', - 'game/ui/widgets/controls_column.c', - 'game/ui/widgets/controls_dialog.c', - 'game/ui/widgets/controls_input_selector.c', - 'game/ui/widgets/controls_layout_editor.c', - 'game/ui/widgets/controls_layout_selector.c', 'game/ui/widgets/graphics_dialog.c', 'game/ui2/dialogs/stats.c', 'game/viewport.c',