1 #include "config.h"
2
3 #include "building/type.h"
4 #include "core/hotkey_config.h"
5 #include "core/image_group.h"
6 #include "core/lang.h"
7 #include "core/string.h"
8 #include "graphics/generic_button.h"
9 #include "graphics/graphics.h"
10 #include "graphics/image.h"
11 #include "graphics/lang_text.h"
12 #include "graphics/panel.h"
13 #include "graphics/screen.h"
14 #include "graphics/scrollbar.h"
15 #include "graphics/text.h"
16 #include "graphics/window.h"
17 #include "translation/translation.h"
18 #include "window/config.h"
19 #include "window/hotkey_editor.h"
20 #include "window/plain_message_dialog.h"
21
22 #define HOTKEY_HEADER -1
23 #define TR_NONE -1
24 #define GROUP_BUILDINGS 28
25
26 #define NUM_VISIBLE_OPTIONS 14
27 #define NUM_BOTTOM_BUTTONS 3
28
29 static void on_scroll(void);
30
31 static void button_hotkey(int row, int is_alternative);
32 static void button_reset_defaults(int param1, int param2);
33 static void button_close(int save, int param2);
34
35 static scrollbar_type scrollbar = { 580, 72, 352, on_scroll };
36
37 typedef struct {
38 int action;
39 int name_translation;
40 int name_text_group;
41 int name_text_id;
42 } hotkey_widget;
43
44 static hotkey_widget hotkey_widgets[] = {
45 {HOTKEY_HEADER, TR_HOTKEY_HEADER_ARROWS},
46 {HOTKEY_ARROW_UP, TR_HOTKEY_ARROW_UP},
47 {HOTKEY_ARROW_DOWN, TR_HOTKEY_ARROW_DOWN},
48 {HOTKEY_ARROW_LEFT, TR_HOTKEY_ARROW_LEFT},
49 {HOTKEY_ARROW_RIGHT, TR_HOTKEY_ARROW_RIGHT},
50 {HOTKEY_HEADER, TR_HOTKEY_HEADER_GLOBAL},
51 {HOTKEY_TOGGLE_FULLSCREEN, TR_HOTKEY_TOGGLE_FULLSCREEN},
52 {HOTKEY_CENTER_WINDOW, TR_HOTKEY_CENTER_WINDOW},
53 {HOTKEY_RESIZE_TO_640, TR_HOTKEY_RESIZE_TO_640},
54 {HOTKEY_RESIZE_TO_800, TR_HOTKEY_RESIZE_TO_800},
55 {HOTKEY_RESIZE_TO_1024, TR_HOTKEY_RESIZE_TO_1024},
56 {HOTKEY_SAVE_SCREENSHOT, TR_HOTKEY_SAVE_SCREENSHOT},
57 {HOTKEY_SAVE_CITY_SCREENSHOT, TR_HOTKEY_SAVE_CITY_SCREENSHOT},
58 {HOTKEY_LOAD_FILE, TR_HOTKEY_LOAD_FILE},
59 {HOTKEY_SAVE_FILE, TR_HOTKEY_SAVE_FILE},
60 {HOTKEY_HEADER, TR_HOTKEY_HEADER_CITY},
61 {HOTKEY_INCREASE_GAME_SPEED, TR_HOTKEY_INCREASE_GAME_SPEED},
62 {HOTKEY_DECREASE_GAME_SPEED, TR_HOTKEY_DECREASE_GAME_SPEED},
63 {HOTKEY_TOGGLE_PAUSE, TR_HOTKEY_TOGGLE_PAUSE},
64 {HOTKEY_CYCLE_LEGION, TR_HOTKEY_CYCLE_LEGION},
65 {HOTKEY_ROTATE_MAP_LEFT, TR_HOTKEY_ROTATE_MAP_LEFT},
66 {HOTKEY_ROTATE_MAP_RIGHT, TR_HOTKEY_ROTATE_MAP_RIGHT},
67 {HOTKEY_ROTATE_BUILDING, TR_HOTKEY_ROTATE_BUILDING},
68 {HOTKEY_ROTATE_BUILDING_BACK, TR_HOTKEY_ROTATE_BUILDING_BACK},
69 {HOTKEY_HEADER, TR_HOTKEY_HEADER_BUILD},
70 {HOTKEY_BUILD_CLONE, TR_HOTKEY_BUILD_CLONE},
71 {HOTKEY_COPY_BUILDING_SETTINGS, TR_HOTKEY_COPY_SETTINGS},
72 {HOTKEY_PASTE_BUILDING_SETTINGS, TR_HOTKEY_PASTE_SETTINGS},
73 {HOTKEY_BUILD_CLEAR_LAND, TR_NONE, 68, 21},
74 {HOTKEY_BUILD_VACANT_HOUSE, TR_NONE, 67, 7},
75 {HOTKEY_BUILD_ROAD, TR_NONE, GROUP_BUILDINGS, BUILDING_ROAD},
76 {HOTKEY_BUILD_PLAZA, TR_NONE, GROUP_BUILDINGS, BUILDING_PLAZA},
77 {HOTKEY_BUILD_GARDENS, TR_NONE, GROUP_BUILDINGS, BUILDING_GARDENS},
78 {HOTKEY_BUILD_PREFECTURE, TR_NONE, GROUP_BUILDINGS, BUILDING_PREFECTURE},
79 {HOTKEY_BUILD_ENGINEERS_POST, TR_NONE, GROUP_BUILDINGS, BUILDING_ENGINEERS_POST},
80 {HOTKEY_BUILD_DOCTOR, TR_NONE, GROUP_BUILDINGS, BUILDING_DOCTOR},
81 {HOTKEY_BUILD_GRANARY, TR_NONE, GROUP_BUILDINGS, BUILDING_GRANARY},
82 {HOTKEY_BUILD_WAREHOUSE, TR_NONE, GROUP_BUILDINGS, BUILDING_WAREHOUSE},
83 {HOTKEY_BUILD_MARKET, TR_NONE, GROUP_BUILDINGS, BUILDING_MARKET},
84 {HOTKEY_BUILD_WALL, TR_NONE, GROUP_BUILDINGS, BUILDING_WALL},
85 {HOTKEY_BUILD_GATEHOUSE, TR_NONE, GROUP_BUILDINGS, BUILDING_GATEHOUSE},
86 {HOTKEY_BUILD_RESERVOIR, TR_NONE, GROUP_BUILDINGS, BUILDING_RESERVOIR},
87 {HOTKEY_BUILD_AQUEDUCT, TR_NONE, GROUP_BUILDINGS, BUILDING_AQUEDUCT},
88 {HOTKEY_BUILD_FOUNTAIN, TR_NONE, GROUP_BUILDINGS, BUILDING_FOUNTAIN},
89 {HOTKEY_BUILD_ROADBLOCK, TR_NONE, GROUP_BUILDINGS, BUILDING_ROADBLOCK},
90 {HOTKEY_UNDO, TR_NONE, GROUP_BUILDINGS, 1},
91 {HOTKEY_HEADER, TR_HOTKEY_HEADER_ADVISORS},
92 {HOTKEY_SHOW_ADVISOR_LABOR, TR_HOTKEY_SHOW_ADVISOR_LABOR},
93 {HOTKEY_SHOW_ADVISOR_MILITARY, TR_HOTKEY_SHOW_ADVISOR_MILITARY},
94 {HOTKEY_SHOW_ADVISOR_IMPERIAL, TR_HOTKEY_SHOW_ADVISOR_IMPERIAL},
95 {HOTKEY_SHOW_ADVISOR_RATINGS, TR_HOTKEY_SHOW_ADVISOR_RATINGS},
96 {HOTKEY_SHOW_ADVISOR_TRADE, TR_HOTKEY_SHOW_ADVISOR_TRADE},
97 {HOTKEY_SHOW_ADVISOR_POPULATION, TR_HOTKEY_SHOW_ADVISOR_POPULATION},
98 {HOTKEY_SHOW_ADVISOR_HOUSING, TR_HOTKEY_SHOW_ADVISOR_HOUSING},
99 {HOTKEY_SHOW_ADVISOR_HEALTH, TR_HOTKEY_SHOW_ADVISOR_HEALTH},
100 {HOTKEY_SHOW_ADVISOR_EDUCATION, TR_HOTKEY_SHOW_ADVISOR_EDUCATION},
101 {HOTKEY_SHOW_ADVISOR_ENTERTAINMENT, TR_HOTKEY_SHOW_ADVISOR_ENTERTAINMENT},
102 {HOTKEY_SHOW_ADVISOR_RELIGION, TR_HOTKEY_SHOW_ADVISOR_RELIGION},
103 {HOTKEY_SHOW_ADVISOR_FINANCIAL, TR_HOTKEY_SHOW_ADVISOR_FINANCIAL},
104 {HOTKEY_SHOW_ADVISOR_CHIEF, TR_HOTKEY_SHOW_ADVISOR_CHIEF},
105 {HOTKEY_HEADER, TR_HOTKEY_HEADER_OVERLAYS},
106 {HOTKEY_TOGGLE_OVERLAY, TR_HOTKEY_TOGGLE_OVERLAY},
107 {HOTKEY_SHOW_OVERLAY_RELATIVE, TR_HOTKEY_SHOW_OVERLAY_RELATIVE},
108 {HOTKEY_SHOW_OVERLAY_WATER, TR_HOTKEY_SHOW_OVERLAY_WATER},
109 {HOTKEY_SHOW_OVERLAY_FIRE, TR_HOTKEY_SHOW_OVERLAY_FIRE},
110 {HOTKEY_SHOW_OVERLAY_DAMAGE, TR_HOTKEY_SHOW_OVERLAY_DAMAGE},
111 {HOTKEY_SHOW_OVERLAY_CRIME, TR_HOTKEY_SHOW_OVERLAY_CRIME},
112 {HOTKEY_SHOW_OVERLAY_PROBLEMS, TR_HOTKEY_SHOW_OVERLAY_PROBLEMS},
113 {HOTKEY_HEADER, TR_HOTKEY_HEADER_BOOKMARKS},
114 {HOTKEY_GO_TO_BOOKMARK_1, TR_HOTKEY_GO_TO_BOOKMARK_1},
115 {HOTKEY_GO_TO_BOOKMARK_2, TR_HOTKEY_GO_TO_BOOKMARK_2},
116 {HOTKEY_GO_TO_BOOKMARK_3, TR_HOTKEY_GO_TO_BOOKMARK_3},
117 {HOTKEY_GO_TO_BOOKMARK_4, TR_HOTKEY_GO_TO_BOOKMARK_4},
118 {HOTKEY_SET_BOOKMARK_1, TR_HOTKEY_SET_BOOKMARK_1},
119 {HOTKEY_SET_BOOKMARK_2, TR_HOTKEY_SET_BOOKMARK_2},
120 {HOTKEY_SET_BOOKMARK_3, TR_HOTKEY_SET_BOOKMARK_3},
121 {HOTKEY_SET_BOOKMARK_4, TR_HOTKEY_SET_BOOKMARK_4},
122 {HOTKEY_HEADER, TR_HOTKEY_HEADER_EDITOR},
123 {HOTKEY_EDITOR_TOGGLE_BATTLE_INFO, TR_HOTKEY_EDITOR_TOGGLE_BATTLE_INFO},
124 };
125
126 #define HOTKEY_X_OFFSET_1 290
127 #define HOTKEY_X_OFFSET_2 430
128 #define HOTKEY_BTN_WIDTH 140
129 #define HOTKEY_BTN_HEIGHT 22
130
131 static generic_button hotkey_buttons[] = {
132 {HOTKEY_X_OFFSET_1, 80 + 24 * 0, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 0, 0},
133 {HOTKEY_X_OFFSET_2, 80 + 24 * 0, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 0, 1},
134 {HOTKEY_X_OFFSET_1, 80 + 24 * 1, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 1, 0},
135 {HOTKEY_X_OFFSET_2, 80 + 24 * 1, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 1, 1},
136 {HOTKEY_X_OFFSET_1, 80 + 24 * 2, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 2, 0},
137 {HOTKEY_X_OFFSET_2, 80 + 24 * 2, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 2, 1},
138 {HOTKEY_X_OFFSET_1, 80 + 24 * 3, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 3, 0},
139 {HOTKEY_X_OFFSET_2, 80 + 24 * 3, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 3, 1},
140 {HOTKEY_X_OFFSET_1, 80 + 24 * 4, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 4, 0},
141 {HOTKEY_X_OFFSET_2, 80 + 24 * 4, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 4, 1},
142 {HOTKEY_X_OFFSET_1, 80 + 24 * 5, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 5, 0},
143 {HOTKEY_X_OFFSET_2, 80 + 24 * 5, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 5, 1},
144 {HOTKEY_X_OFFSET_1, 80 + 24 * 6, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 6, 0},
145 {HOTKEY_X_OFFSET_2, 80 + 24 * 6, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 6, 1},
146 {HOTKEY_X_OFFSET_1, 80 + 24 * 7, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 7, 0},
147 {HOTKEY_X_OFFSET_2, 80 + 24 * 7, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 7, 1},
148 {HOTKEY_X_OFFSET_1, 80 + 24 * 8, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 8, 0},
149 {HOTKEY_X_OFFSET_2, 80 + 24 * 8, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 8, 1},
150 {HOTKEY_X_OFFSET_1, 80 + 24 * 9, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 9, 0},
151 {HOTKEY_X_OFFSET_2, 80 + 24 * 9, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 9, 1},
152 {HOTKEY_X_OFFSET_1, 80 + 24 * 10, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 10, 0},
153 {HOTKEY_X_OFFSET_2, 80 + 24 * 10, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 10, 1},
154 {HOTKEY_X_OFFSET_1, 80 + 24 * 11, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 11, 0},
155 {HOTKEY_X_OFFSET_2, 80 + 24 * 11, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 11, 1},
156 {HOTKEY_X_OFFSET_1, 80 + 24 * 12, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 12, 0},
157 {HOTKEY_X_OFFSET_2, 80 + 24 * 12, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 12, 1},
158 {HOTKEY_X_OFFSET_1, 80 + 24 * 13, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 13, 0},
159 {HOTKEY_X_OFFSET_2, 80 + 24 * 13, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT, button_hotkey, button_none, 13, 1},
160 };
161
162 static generic_button bottom_buttons[] = {
163 {230, 430, 180, 30, button_reset_defaults, button_none},
164 {415, 430, 100, 30, button_close, button_none, 0},
165 {520, 430, 100, 30, button_close, button_none, 1},
166 };
167
168 static translation_key bottom_button_texts[] = {
169 TR_BUTTON_RESET_DEFAULTS,
170 TR_BUTTON_CANCEL,
171 TR_BUTTON_OK
172 };
173
174 static struct {
175 int focus_button;
176 int bottom_focus_button;
177 hotkey_mapping mappings[HOTKEY_MAX_ITEMS][2];
178 } data;
179
init(void)180 static void init(void)
181 {
182 scrollbar_init(&scrollbar, 0, sizeof(hotkey_widgets) / sizeof(hotkey_widget) - NUM_VISIBLE_OPTIONS);
183
184 for (int i = 0; i < HOTKEY_MAX_ITEMS; i++) {
185 hotkey_mapping empty = { KEY_TYPE_NONE, KEY_MOD_NONE, i };
186
187 const hotkey_mapping *mapping = hotkey_for_action(i, 0);
188 data.mappings[i][0] = mapping ? *mapping : empty;
189
190 mapping = hotkey_for_action(i, 1);
191 data.mappings[i][1] = mapping ? *mapping : empty;
192 }
193 }
194
draw_background(void)195 static void draw_background(void)
196 {
197 graphics_clear_screen(CANVAS_UI);
198
199 window_draw_underlying_window();
200
201 graphics_in_dialog();
202 outer_panel_draw(0, 0, 40, 30);
203
204 text_draw_centered(translation_for(TR_HOTKEY_TITLE), 16, 16, 608, FONT_LARGE_BLACK, 0);
205
206 text_draw_centered(translation_for(TR_HOTKEY_LABEL), HOTKEY_X_OFFSET_1, 55,
207 HOTKEY_BTN_WIDTH, FONT_NORMAL_BLACK, 0);
208 text_draw_centered(translation_for(TR_HOTKEY_ALTERNATIVE_LABEL), HOTKEY_X_OFFSET_2, 55,
209 HOTKEY_BTN_WIDTH, FONT_NORMAL_BLACK, 0);
210
211 inner_panel_draw(20, 72, 35, 22);
212 int y_base = 80;
213 for (int i = 0; i < NUM_VISIBLE_OPTIONS; i++) {
214 hotkey_widget *widget = &hotkey_widgets[i + scrollbar.scroll_position];
215 int text_offset = y_base + 6 + 24 * i;
216 if (widget->action == HOTKEY_HEADER) {
217 text_draw(translation_for(widget->name_translation), 32, text_offset, FONT_NORMAL_WHITE, 0);
218 } else {
219 if (widget->name_translation != TR_NONE) {
220 text_draw(translation_for(widget->name_translation),
221 32, text_offset, FONT_NORMAL_GREEN, 0);
222 } else {
223 lang_text_draw(widget->name_text_group, widget->name_text_id,
224 32, text_offset, FONT_NORMAL_GREEN);
225 }
226
227 const hotkey_mapping *mapping1 = &data.mappings[widget->action][0];
228 if (mapping1->key) {
229 const uint8_t *keyname = key_combination_display_name(mapping1->key, mapping1->modifiers);
230 graphics_set_clip_rectangle(HOTKEY_X_OFFSET_1, text_offset, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT);
231 text_draw_centered(keyname, HOTKEY_X_OFFSET_1 + 3, text_offset,
232 HOTKEY_BTN_WIDTH - 6, FONT_NORMAL_WHITE, 0);
233 graphics_reset_clip_rectangle();
234 }
235
236 const hotkey_mapping *mapping2 = &data.mappings[widget->action][1];
237 if (mapping2->key) {
238 graphics_set_clip_rectangle(HOTKEY_X_OFFSET_2, text_offset, HOTKEY_BTN_WIDTH, HOTKEY_BTN_HEIGHT);
239 const uint8_t *keyname = key_combination_display_name(mapping2->key, mapping2->modifiers);
240 text_draw_centered(keyname, HOTKEY_X_OFFSET_2 + 3, text_offset,
241 HOTKEY_BTN_WIDTH - 6, FONT_NORMAL_WHITE, 0);
242 graphics_reset_clip_rectangle();
243 }
244 }
245 }
246
247 for (int i = 0; i < NUM_BOTTOM_BUTTONS; i++) {
248 text_draw_centered(translation_for(bottom_button_texts[i]),
249 bottom_buttons[i].x, bottom_buttons[i].y + 9,
250 bottom_buttons[i].width, FONT_NORMAL_BLACK, 0);
251 }
252
253 graphics_reset_dialog();
254 }
255
draw_foreground(void)256 static void draw_foreground(void)
257 {
258 graphics_in_dialog();
259
260 scrollbar_draw(&scrollbar);
261
262 for (int i = 0; i < NUM_VISIBLE_OPTIONS; i++) {
263 hotkey_widget *widget = &hotkey_widgets[i + scrollbar.scroll_position];
264 if (widget->action != HOTKEY_HEADER) {
265 generic_button *btn = &hotkey_buttons[2 * i];
266 button_border_draw(btn->x, btn->y, btn->width, btn->height, data.focus_button == 1 + 2 * i);
267 btn++;
268 button_border_draw(btn->x, btn->y, btn->width, btn->height, data.focus_button == 2 + 2 * i);
269 }
270 }
271
272 for (int i = 0; i < NUM_BOTTOM_BUTTONS; i++) {
273 button_border_draw(bottom_buttons[i].x, bottom_buttons[i].y,
274 bottom_buttons[i].width, bottom_buttons[i].height,
275 data.bottom_focus_button == i + 1);
276 }
277 graphics_reset_dialog();
278 }
279
handle_input(const mouse * m,const hotkeys * h)280 static void handle_input(const mouse *m, const hotkeys *h)
281 {
282 const mouse *m_dialog = mouse_in_dialog(m);
283 if (scrollbar_handle_mouse(&scrollbar, m_dialog)) {
284 return;
285 }
286
287 int handled = 0;
288 handled |= generic_buttons_handle_mouse(m_dialog, 0, 0,
289 hotkey_buttons, NUM_VISIBLE_OPTIONS * 2, &data.focus_button);
290 handled |= generic_buttons_handle_mouse(m_dialog, 0, 0,
291 bottom_buttons, NUM_BOTTOM_BUTTONS, &data.bottom_focus_button);
292 if (!handled && (m->right.went_up || h->escape_pressed)) {
293 window_go_back();
294 }
295 }
296
hotkey_action_name_for(hotkey_action action)297 static const uint8_t *hotkey_action_name_for(hotkey_action action)
298 {
299 const uint8_t *name = 0;
300 for (int i = 0; i < NUM_VISIBLE_OPTIONS + scrollbar.max_scroll_position; i++) {
301 hotkey_widget *widget = &hotkey_widgets[i];
302 if (widget->action == action) {
303 if (widget->name_translation != TR_NONE) {
304 name = translation_for(widget->name_translation);
305 } else {
306 name = lang_get_string(widget->name_text_group, widget->name_text_id);
307 }
308 break;
309 }
310 }
311 return name;
312 }
313
set_hotkey(hotkey_action action,int index,key_type key,key_modifier_type modifiers)314 static void set_hotkey(hotkey_action action, int index, key_type key, key_modifier_type modifiers)
315 {
316 int is_duplicate_hotkey = 0;
317 // check if new key combination already assigned to another action
318 if (key != KEY_TYPE_NONE) {
319 for (int test_action = 0; test_action < HOTKEY_MAX_ITEMS; test_action++) {
320 for (int test_index = 0; test_index < 2; test_index++) {
321 if (data.mappings[test_action][test_index].key == key
322 && data.mappings[test_action][test_index].modifiers == modifiers) {
323 is_duplicate_hotkey = 1;
324 // example explanation next "if" check:
325 // "Fire overlay" already has hotkey "F" and user tries set same hotkey "F" again to "Fire overlay"
326 // we must skip show warning window for better user experience
327 if (!(test_action == action && test_index == index)) {
328 window_plain_message_dialog_show_with_extra(
329 TR_HOTKEY_DUPLICATE_TITLE, TR_HOTKEY_DUPLICATE_MESSAGE,
330 hotkey_action_name_for(test_action));
331 }
332 break;
333 }
334 }
335 if (is_duplicate_hotkey) {
336 break;
337 }
338 }
339 }
340 if (!is_duplicate_hotkey) {
341 data.mappings[action][index].key = key;
342 data.mappings[action][index].modifiers = modifiers;
343 }
344 }
345
button_hotkey(int row,int is_alternative)346 static void button_hotkey(int row, int is_alternative)
347 {
348 hotkey_widget *widget = &hotkey_widgets[row + scrollbar.scroll_position];
349 if (widget->action == HOTKEY_HEADER) {
350 return;
351 }
352 window_hotkey_editor_show(widget->action, is_alternative, set_hotkey);
353 }
354
button_reset_defaults(int param1,int param2)355 static void button_reset_defaults(int param1, int param2)
356 {
357 for (int action = 0; action < HOTKEY_MAX_ITEMS; action++) {
358 for (int index = 0; index < 2; index++) {
359 data.mappings[action][index] = *hotkey_default_for_action(action, index);
360 }
361 }
362 window_invalidate();
363 }
364
on_scroll(void)365 static void on_scroll(void)
366 {
367 window_invalidate();
368 }
369
button_close(int save,int param2)370 static void button_close(int save, int param2)
371 {
372 if (!save) {
373 window_go_back();
374 return;
375 }
376 hotkey_config_clear();
377 for (int action = 0; action < HOTKEY_MAX_ITEMS; action++) {
378 for (int index = 0; index < 2; index++) {
379 if (data.mappings[action][index].key != KEY_TYPE_NONE) {
380 hotkey_config_add_mapping(&data.mappings[action][index]);
381 }
382 }
383 }
384 hotkey_config_save();
385 window_go_back();
386 }
387
window_hotkey_config_show(void)388 void window_hotkey_config_show(void)
389 {
390 window_type window = {
391 WINDOW_HOTKEY_CONFIG,
392 draw_background,
393 draw_foreground,
394 handle_input
395 };
396 init();
397 window_show(&window);
398 }
399