102 Patches: Detours to the Rescue
C reference for DttR maintainers and modders.
Loading...
Searching...
No Matches
gui.c
Go to the documentation of this file.
1#include "gui_internal.h"
2
3#include <stdlib.h>
4
5static const char *const CONFIG_WINDOW_TITLE = "DttR Configuration";
6static const char *const CONFIG_DEBUG_SHORTCUTS_ENV = "DTTR_CONFIG_DEBUG_SHORTCUTS";
7
8static sds config_path_from_args(int argc, char **argv) {
9 if (argc > 1 && argv[1] && argv[1][0]) {
10 return sdsnew(argv[1]);
11 }
12
14}
15
19 const char *action
20) {
22 return true;
23 }
24
25 char message[256];
26 snprintf(
27 message,
28 sizeof(message),
29 "This will discard unsaved configuration changes and %s. Continue?",
30 action
31 );
32
33 const SDL_MessageBoxButtonData buttons[] = {
34 {SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 1, "Discard"},
35 {SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 0, "Cancel"},
36 };
37
38 const SDL_MessageBoxData message_box = {
39 SDL_MESSAGEBOX_WARNING,
40 ctx ? ctx->window : NULL,
41 "Discard unsaved changes?",
42 message,
43 (int)SDL_arraysize(buttons),
44 buttons,
45 NULL,
46 };
47
48 int button_id = 0;
49 return DTTR_SDL_ShowMessageBox(&message_box, &button_id) && button_id == 1;
50}
51
53 if (!igBeginMenuBar()) {
54 return;
55 }
56
57 if (igMenuItem_Bool("Save", "Ctrl+S", false, true)) {
59 }
60
61 if (igMenuItem_Bool("Load", "Ctrl+O", false, true)
62 && confirm_discard_changes(ctx, state, "reload the file from disk")) {
64 }
65
66 if (igMenuItem_Bool("Reset to Defaults", NULL, false, true)) {
68 }
69
70 igEndMenuBar();
71}
72
74 if (igShortcut_Nil(ImGuiMod_Ctrl | ImGuiKey_S, ImGuiInputFlags_RouteGlobal)) {
76 }
77
78 if (igShortcut_Nil(ImGuiMod_Ctrl | ImGuiKey_O, ImGuiInputFlags_RouteGlobal)
79 && confirm_discard_changes(ctx, state, "reload the file from disk")) {
81 }
82}
83
84static bool env_flag_enabled(const char *name) {
85 const char *value = getenv(name);
86 return value && value[0] && strcmp(value, "0") != 0;
87}
88
89static void draw_shortcut_debug_row(const char *label, ImGuiKeyChord chord) {
90 const ImGuiKey key = (ImGuiKey)(chord & ~ImGuiMod_Mask_);
91 const ImGuiKeyRoutingData *route = igGetShortcutRoutingData(chord);
92 const ImGuiKeyData *key_data = igGetKeyData_Key(key);
93
94 igTableNextRow(ImGuiTableRowFlags_None, 0.0f);
95 igTableNextColumn();
96 igTextUnformatted(label, NULL);
97 igTableNextColumn();
98 igTextUnformatted(igGetKeyChordName(chord), NULL);
99 igTableNextColumn();
100
101 if (route) {
102 igText("0x%08X / %u", route->RoutingCurr, route->RoutingCurrScore);
103 } else {
104 igTextDisabled("none");
105 }
106
107 igTableNextColumn();
108 igText(
109 "down=%d pressed=%d chord=%d duration=%.02f",
110 igIsKeyDown_ID(key, 0),
111 igIsKeyPressed_InputFlags(key, ImGuiInputFlags_None, 0),
112 igIsKeyChordPressed_InputFlags(chord, ImGuiInputFlags_None, 0),
113 key_data ? key_data->DownDuration : -1.0f
114 );
115}
116
118 if (!state->show_shortcut_debug) {
119 return;
120 }
121
122 if (!igBegin(
123 "DttR Shortcut Debug",
124 NULL,
125 ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings
126 )) {
127 igEnd();
128 return;
129 }
130
131 if (igBeginTable(
132 "##shortcut_debug_routes",
133 4,
134 ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_BordersOuterH,
135 (ImVec2_c){0.0f, 0.0f},
136 0.0f
137 )) {
138 igTableSetupColumn("Action", ImGuiTableColumnFlags_None, 0.0f, 0);
139 igTableSetupColumn("Chord", ImGuiTableColumnFlags_None, 0.0f, 0);
140 igTableSetupColumn("Route", ImGuiTableColumnFlags_None, 0.0f, 0);
141 igTableSetupColumn("Input", ImGuiTableColumnFlags_None, 0.0f, 0);
142 igTableHeadersRow();
143 draw_shortcut_debug_row("Save", ImGuiMod_Ctrl | ImGuiKey_S);
144 draw_shortcut_debug_row("Load", ImGuiMod_Ctrl | ImGuiKey_O);
145 igEndTable();
146 }
147
148 igEnd();
149}
150
151static bool init_state_from_args(config_ui_state *state, int argc, char **argv) {
152 sds config_path = config_path_from_args(argc, argv);
153 if (!DTTR_Path_CopySds(state->path, sizeof(state->path), config_path)) {
154 sdsfree(config_path);
156 SDL_MESSAGEBOX_ERROR,
158 "Config path is too long.",
159 NULL
160 );
161 return false;
162 }
163
164 sdsfree(config_path);
165
166 state->show_shortcut_debug = env_flag_enabled(CONFIG_DEBUG_SHORTCUTS_ENV);
168 DTTR_Config_SetDefaults(&state->defaults);
169 state->config = state->defaults;
170 state->saved_config = state->config;
173 return true;
174}
175
181
183 igSeparator();
184
185 const bool panel_open = begin_padded_panel(ctx);
186 if (panel_open) {
187 const bool content_open = begin_config_content_region(ctx, state);
188 if (content_open) {
190 }
191
194 }
195
197
200}
201
202static void process_events(
205 bool *running
206) {
208 while (SDL_PollEvent(&event)) {
210 if (!*running) {
211 if (confirm_discard_changes(ctx, state, "close the configuration tool")) {
212 break;
213 }
214
215 *running = true;
216 continue;
217 }
218
221 continue;
222 }
223
224 const int source = source_from_event(&event);
225 if (source >= 0) {
227 }
228 }
229}
230
231__declspec(dllexport) int dttr_config_main(int argc, char **argv) {
233 .binding_row = -1,
234 };
235
236 if (!init_state_from_args(&state, argc, argv)) {
237 return 1;
238 }
239
242 &ctx,
246 )) {
247 return 1;
248 }
249
250 if (!SDL_InitSubSystem(SDL_INIT_GAMEPAD)) {
251 char status[sizeof(state.status)];
252 snprintf(
253 status,
254 sizeof(status),
255 "Failed to initialize gamepad support: %s",
256 SDL_GetError()
257 );
258 set_status(&state, status);
259 }
260
261 bool running = true;
262 while (running) {
263 process_events(&ctx, &state, &running);
266
268 &ctx,
270 ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoScrollbar
271 | ImGuiWindowFlags_NoScrollWithMouse
272 )) {
273 draw_ui(&ctx, &state);
274 }
275
278 }
279
280 SDL_QuitSubSystem(SDL_INIT_GAMEPAD);
283 return 0;
284}
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_CONFIG_FILENAME
void DTTR_ImGuiDialog_End(DTTR_ImGuiDialogContext *ctx)
void DTTR_ImGuiDialog_DrawHeader(const DTTR_ImGuiDialogContext *ctx, const char *title, const char *version)
void DTTR_ImGuiDialog_Render(DTTR_ImGuiDialogContext *ctx)
bool DTTR_ImGuiDialog_RefreshScale(DTTR_ImGuiDialogContext *ctx)
bool DTTR_ImGuiDialog_BeginRoot(DTTR_ImGuiDialogContext *ctx, const char *title, ImGuiWindowFlags flags)
void DTTR_ImGuiDialog_EndRoot()
void DTTR_ImGuiDialog_NewFrame(const DTTR_ImGuiDialogContext *ctx)
void DTTR_ImGuiDialog_ProcessEvent(const DTTR_ImGuiDialogContext *ctx, const SDL_Event *event, bool *running)
void DTTR_ImGuiDialog_Shutdown()
bool DTTR_ImGuiDialog_Begin(DTTR_ImGuiDialogContext *ctx, const char *title, int width, int height)
union SDL_Event SDL_Event
Definition dttr_mods.h:20
sds DTTR_Path_ModuleSibling(void *module, const char *relative_path)
Definition path.c:217
bool DTTR_Path_CopySds(char *out, size_t out_size, sds value)
Definition path.c:72
bool DTTR_SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
Definition sdl.c:135
bool DTTR_SDL_ShowSimpleMessageBox(SDL_MessageBoxFlags flags, const char *title, const char *message, SDL_Window *window)
Definition sdl.c:121
static game_data_source source
Definition game_data.c:21
static bool confirm_discard_changes(const DTTR_ImGuiDialogContext *ctx, const config_ui_state *state, const char *action)
Definition gui.c:16
static void draw_shortcut_debug_row(const char *label, ImGuiKeyChord chord)
Definition gui.c:89
static sds config_path_from_args(int argc, char **argv)
Definition gui.c:8
static void process_events(const DTTR_ImGuiDialogContext *ctx, config_ui_state *state, bool *running)
Definition gui.c:202
static const char *const CONFIG_DEBUG_SHORTCUTS_ENV
Definition gui.c:6
static bool init_state_from_args(config_ui_state *state, int argc, char **argv)
Definition gui.c:151
static void draw_shortcut_debug_window(const config_ui_state *state)
Definition gui.c:117
static void handle_shortcuts(const DTTR_ImGuiDialogContext *ctx, config_ui_state *state)
Definition gui.c:73
static void draw_toolbar(const DTTR_ImGuiDialogContext *ctx, config_ui_state *state)
Definition gui.c:52
static bool env_flag_enabled(const char *name)
Definition gui.c:84
int dttr_config_main(int argc, char **argv)
Definition gui.c:231
static void draw_ui(const DTTR_ImGuiDialogContext *ctx, config_ui_state *state)
Definition gui.c:176
static const char *const CONFIG_WINDOW_TITLE
Definition gui.c:5
void capture_source(config_ui_state *state, int new_source)
Definition gui_state.c:149
void load_config(config_ui_state *state)
Definition gui_state.c:185
void set_mods_dir_from_config_path(config_ui_state *state)
Definition gui_state.c:101
bool begin_padded_panel(const DTTR_ImGuiDialogContext *ctx)
bool config_has_unsaved_changes(const config_ui_state *state)
Definition gui_state.c:286
void save_config(config_ui_state *state)
Definition gui_state.c:205
bool begin_config_content_region(const DTTR_ImGuiDialogContext *ctx, const config_ui_state *state)
void draw_tabs(const DTTR_ImGuiDialogContext *ctx, config_ui_state *state)
Definition gui_tabs.c:31
void add_scaled_vertical_spacing(const DTTR_ImGuiDialogContext *ctx, float height)
Definition gui_widgets.c:12
void draw_footer_text(const DTTR_ImGuiDialogContext *ctx, const config_ui_state *state)
void pop_config_theme()
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 source_from_event(const SDL_Event *event)
void request_reset_defaults(const DTTR_ImGuiDialogContext *ctx, config_ui_state *state)
Definition gui_state.c:223
int config_window_width()
Definition gui_widgets.c:50
#define DTTR_CONFIG_UI_WINDOW_H
bool event_cancels_binding(const SDL_Event *event)
Definition gui_state.c:135
void push_config_theme()
#define DTTR_CONFIG_UI_HEADER_TOP_SPACING
void end_config_content_region()
void end_padded_panel()
void set_status(config_ui_state *state, const char *status)
Definition gui_state.c:96
#define DTTR_VERSION