102 Patches: Detours to the Rescue
C reference for DttR maintainers and modders.
Loading...
Searching...
No Matches
gui_state.c
Go to the documentation of this file.
1#include "gui_internal.h"
2
3static const char *const GAME_ACTION_TOOLTIPS[] = {
4 "Disables this gamepad action.",
5 "Moves up.",
6 "Moves down.",
7 "Moves left.",
8 "Moves right.",
9 "Activates POV up.",
10 "Activates POV down.",
11 "Acts as joy_1. In menus, joy_1 is the confirm button.",
12 "Acts as joy_2. In menus, joy_2 is the back button.",
13 "Acts as joy_3.",
14 "Acts as joy_4.",
15 "Acts as joy_5.",
16 "Acts as joy_6.",
17 "Acts as joy_7.",
18 "Acts as joy_8.",
19 "Acts as joy_9. joy_9 is the start/pause button.",
20 "Acts as joy_10.",
21 "Acts as joy_11.",
22 "Acts as joy_12.",
23 "Acts as joy_13.",
24};
25
26const char *game_action_tooltip(int action) {
27 const int index = action - DTTR_GAMEPAD_MAPPING_NONE;
28
29 if (index >= 0 && index < (int)SDL_arraysize(GAME_ACTION_TOOLTIPS)) {
30 return GAME_ACTION_TOOLTIPS[index];
31 }
32
33 return "Bind each PCDOGS game action to the controller input you want to press.";
34}
35
36static void clear_mods_dir(config_ui_state *state) { state->mods_dir[0] = '\0'; }
37
40}
41
44 state->binding_row = -1;
45}
46
47static bool button_action_in_range(int action) {
48 return action >= PCDOGS_GAMEPAD_IDX_UP && action <= PCDOGS_GAMEPAD_IDX_BTN_12;
49}
50
51static int source_for_action(const int *map, int action) {
52 if (!map || !button_action_in_range(action)) {
54 }
55
56 for (int source = 0; source < DTTR_GAMEPAD_SOURCE_COUNT; source++) {
57 if (map[source] == action) {
58 return source;
59 }
60 }
61
63}
64
67 return choice_count > 0 ? choice_count - 1 : 0;
68}
69
71 if (row < 0 || row >= gamepad_button_row_count()) {
72 return NULL;
73 }
74
76}
77
80 return choice ? choice->value : DTTR_GAMEPAD_MAPPING_NONE;
81}
82
83const char *gamepad_button_row_label(int row) {
85 return choice ? choice->label : "unknown";
86}
87
89 if (!state) {
91 }
92
93 return source_for_action(state->defaults.gamepad_button_map, action);
94}
95
96void set_status(config_ui_state *state, const char *status) {
97 snprintf(state->status, sizeof(state->status), "%s", status ? status : "");
98 state->status_expires_at_ms = SDL_GetTicks() + DTTR_CONFIG_UI_STATUS_TIMEOUT_MS;
99}
100
102 if (!state) {
103 return;
104 }
105
106 sds mods_dir = DTTR_Path_ModuleDir(NULL);
107
108 if (!mods_dir
110 || !DTTR_Path_CopySds(state->mods_dir, sizeof(state->mods_dir), mods_dir)) {
112 }
113
114 sdsfree(mods_dir);
115}
116
118 const int row_count = gamepad_button_row_count();
119
120 for (int i = 0; i < DTTR_GAMEPAD_SOURCE_COUNT; i++) {
121 state->button_actions[i] = DTTR_GAMEPAD_MAPPING_NONE;
122 state->button_sources[i] = DTTR_GAMEPAD_MAPPING_NONE;
123 }
124
125 for (int row = 0; row < row_count; row++) {
126 const int action = gamepad_button_row_action(row);
127 state->button_actions[row] = action;
128 state->button_sources[row] = source_for_action(
129 state->config.gamepad_button_map,
130 action
131 );
132 }
133}
134
136 return event && event->type == SDL_EVENT_KEY_DOWN
137 && event->key.scancode == SDL_SCANCODE_ESCAPE;
138}
139
141 if (state->binding_row < 0) {
142 return;
143 }
144
145 state->binding_row = -1;
146 set_status(state, "Cancelled controller input capture.");
147}
148
149void capture_source(config_ui_state *state, int new_source) {
150 const int binding_row = state->binding_row;
151 const int row_count = gamepad_button_row_count();
152
153 if (binding_row < 0 || binding_row >= row_count
154 || !button_source_in_range(new_source)) {
155 return;
156 }
157
158 const int old_source = state->button_sources[binding_row];
159
160 for (int row = 0; row < row_count; row++) {
161 if (row != binding_row && state->button_sources[row] == new_source) {
162 state->button_sources[row] = old_source;
163 break;
164 }
165 }
166
167 state->button_sources[binding_row] = new_source;
168 state->binding_row = -1;
169 set_status(state, "Captured controller input.");
170}
171
173 DTTR_Config_ClearGamepadButtonMap(state->config.gamepad_button_map);
174 const int row_count = gamepad_button_row_count();
175
176 for (int row = 0; row < row_count; row++) {
177 const int source = state->button_sources[row];
178
180 state->config.gamepad_button_map[source] = state->button_actions[row];
181 }
182 }
183}
184
186 if (!DTTR_Config_Load(state->path)) {
187 const char *details = DTTR_Config_LastError();
188 if (details) {
189 char status[sizeof(state->status)];
190 snprintf(status, sizeof(status), "Failed to load config: %s", details);
191 set_status(state, status);
192 } else {
193 set_status(state, "Failed to load config.");
194 }
195
196 return;
197 }
198
199 state->config = dttr_config;
200 state->saved_config = state->config;
202 set_status(state, "Loaded config.");
203}
204
207
208 if (!DTTR_Config_Save(state->path, &state->config)) {
209 set_status(state, "Failed to save config.");
210 return;
211 }
212
213 state->saved_config = state->config;
214 set_status(state, "Saved config.");
215}
216
220 set_status(state, "Reset to built-in defaults. Save to write changes.");
221}
222
224 const SDL_MessageBoxButtonData buttons[] = {
225 {SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 1, "Reset"},
226 {SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 0, "Cancel"},
227 };
228
229 const SDL_MessageBoxData message_box = {
230 SDL_MESSAGEBOX_WARNING,
231 ctx ? ctx->window : NULL,
232 "Reset to defaults?",
233 "This will reset every configuration value to its default. Continue?",
234 (int)SDL_arraysize(buttons),
235 buttons,
236 NULL,
237 };
238
239 int button_id = 0;
240
241 if (DTTR_SDL_ShowMessageBox(&message_box, &button_id) && button_id == 1) {
243 }
244}
245
246config_label_state make_config_label_state(bool unsaved_changed, bool default_changed) {
247 if (unsaved_changed) {
249 }
250
251 return default_changed ? CONFIG_LABEL_SAVED_CHANGED : CONFIG_LABEL_DEFAULT;
252}
253
255 const int row_count = gamepad_button_row_count();
256
257 for (int row = 0; row < row_count; row++) {
258 const int action = state->button_actions[row];
259
260 if (state->button_sources[row]
261 != source_for_action(state->saved_config.gamepad_button_map, action)) {
262 return true;
263 }
264 }
265
266 return false;
267}
268
270 const config_ui_state *state,
271 int source,
272 int action
273) {
274 const int saved_source = source_for_action(
275 state->saved_config.gamepad_button_map,
276 action
277 );
278 const int default_source = source_for_action(
279 state->defaults.gamepad_button_map,
280 action
281 );
282
283 return make_config_label_state(source != saved_source, source != default_source);
284}
285
const DTTR_BackendState * state
void void * ctx
void void DWORD HANDLE event
DTTR_Graphics_COM_DirectDrawSurface7 DWORD flags void NULL
void DTTR_Config_SetDefaults(DTTR_Config *config)
Resets a config object to built-in defaults.
Definition defaults.c:196
#define DTTR_GAMEPAD_SOURCE_COUNT
Definition dttr_config.h:53
#define DTTR_GAMEPAD_MAPPING_NONE
Definition dttr_config.h:48
void DTTR_Config_ClearGamepadButtonMap(int *map)
Definition defaults.c:72
bool DTTR_Config_SchemaChanged(const DTTR_Config *current, const DTTR_Config *base)
Definition schema.c:128
@ DTTR_CONFIG_CHOICES_GAME_ACTION
const char * DTTR_Config_LastError()
Returns details from the most recent config load failure, or NULL when none exist.
Definition io.c:46
DTTR_Config dttr_config
Definition defaults.c:53
bool DTTR_Config_DisabledModsChanged(const DTTR_Config *current, const DTTR_Config *base)
Definition defaults.c:166
const DTTR_ConfigChoice * DTTR_Config_ChoiceGet(DTTR_ConfigChoiceList list, int index)
Definition parse.c:203
bool DTTR_Config_Save(const char *filename, const DTTR_Config *config)
Saves config values back to a strict JSON file.
Definition io.c:483
bool DTTR_Config_Load(const char *filename)
Loads config values from a strict JSON file into the global config object.
Definition io.c:259
#define PCDOGS_GAMEPAD_IDX_UP
Definition dttr_config.h:64
#define PCDOGS_GAMEPAD_IDX_BTN_12
Definition dttr_config.h:82
int DTTR_Config_ChoiceCount(DTTR_ConfigChoiceList list)
Definition parse.c:198
union SDL_Event SDL_Event
Definition dttr_mods.h:20
bool DTTR_Path_CopySds(char *out, size_t out_size, sds value)
Definition path.c:72
sds DTTR_Path_ModuleDir(void *module)
Definition path.c:201
#define DTTR_PATH_NATIVE_SEPARATOR
Definition dttr_path.h:9
bool DTTR_Path_AppendSegment(sds *path, const char *segment, char separator)
Definition path.c:276
bool DTTR_SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
Definition sdl.c:135
static game_data_source source
Definition game_data.c:21
config_label_state
@ CONFIG_LABEL_DEFAULT
@ CONFIG_LABEL_SAVED_CHANGED
@ CONFIG_LABEL_UNSAVED
#define DTTR_CONFIG_UI_STATUS_TIMEOUT_MS
void capture_source(config_ui_state *state, int new_source)
Definition gui_state.c:149
bool gamepad_button_rows_have_unsaved_changes(const config_ui_state *state)
Definition gui_state.c:254
void load_config(config_ui_state *state)
Definition gui_state.c:185
int gamepad_default_source_for_action(const config_ui_state *state, int action)
Definition gui_state.c:88
void set_mods_dir_from_config_path(config_ui_state *state)
Definition gui_state.c:101
static const char *const GAME_ACTION_TOOLTIPS[]
Definition gui_state.c:3
static void refresh_button_rows(config_ui_state *state)
Definition gui_state.c:42
void sync_config_from_rows(config_ui_state *state)
Definition gui_state.c:172
config_label_state make_config_label_state(bool unsaved_changed, bool default_changed)
Definition gui_state.c:246
static const DTTR_ConfigChoice * gamepad_button_row_choice(int row)
Definition gui_state.c:70
const char * gamepad_button_row_label(int row)
Definition gui_state.c:83
static void clear_mods_dir(config_ui_state *state)
Definition gui_state.c:36
bool config_has_unsaved_changes(const config_ui_state *state)
Definition gui_state.c:286
static bool button_action_in_range(int action)
Definition gui_state.c:47
void save_config(config_ui_state *state)
Definition gui_state.c:205
void sync_rows_from_config(config_ui_state *state)
Definition gui_state.c:117
void cancel_binding(config_ui_state *state)
Definition gui_state.c:140
int gamepad_button_row_action(int row)
Definition gui_state.c:78
static int source_for_action(const int *map, int action)
Definition gui_state.c:51
static bool button_source_in_range(int source)
Definition gui_state.c:38
void request_reset_defaults(const DTTR_ImGuiDialogContext *ctx, config_ui_state *state)
Definition gui_state.c:223
bool event_cancels_binding(const SDL_Event *event)
Definition gui_state.c:135
int gamepad_button_row_count()
Definition gui_state.c:65
config_label_state gamepad_button_label_state(const config_ui_state *state, int source, int action)
Definition gui_state.c:269
void reset_defaults(config_ui_state *state)
Definition gui_state.c:217
void set_status(config_ui_state *state, const char *status)
Definition gui_state.c:96
const char * game_action_tooltip(int action)
Definition gui_state.c:26
const char * label