Atrinik Client  4.0
settings_keybinding.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
32 #include <global.h>
33 
34 enum {
35  KEYBINDING_STATE_LIST,
36  KEYBINDING_STATE_ADD,
37  KEYBINDING_STATE_EDIT
38 } ;
39 
43 static button_struct button_new, button_remove, button_apply;
47 static text_input_struct text_input_command, text_input_key;
51 static int keybinding_state;
55 static size_t keybinding_id;
60 
61 static void keybinding_list_reload(void)
62 {
63  size_t i;
64  char buf[MAX_BUF];
65 
66  /* Clear all the rows. */
67  list_clear_rows(list_keybindings);
68 
69  for (i = 0; i < keybindings_num; i++) {
70  list_add(list_keybindings, i, 0, keybindings[i]->command);
71  list_add(list_keybindings, i, 1, keybind_get_key_shortcut(keybindings[i]->key, keybindings[i]->mod, buf, sizeof(buf)));
72  list_add(list_keybindings, i, 2, keybindings[i]->repeat ? "on" : "off");
73  }
74 
75  list_offsets_ensure(list_keybindings);
76 }
77 
78 static void keybinding_apply(void)
79 {
80  int key, mod;
81 
82  /* Nothing to apply. */
83  if (*text_input_command.str == '\0' || sscanf(text_input_key.str, "%d %d", &key, &mod) != 2) {
84  return;
85  }
86 
87  if (keybinding_state == KEYBINDING_STATE_ADD) {
88  keybind_add(key, mod, text_input_command.str);
89  /* It'll be added to the end, so select it. */
90  list_keybindings->row_selected = list_keybindings->rows + 1;
91  list_keybindings->row_offset = MIN(list_keybindings->rows + 1 - list_keybindings->max_rows, list_keybindings->row_selected - 1);
92  } else if (keybinding_state == KEYBINDING_STATE_EDIT) {
93  keybind_edit(keybinding_id, key, mod, text_input_command.str);
94  }
95 
96  keybinding_state = KEYBINDING_STATE_LIST;
97  keybinding_list_reload();
98 }
99 
107 static int keybinding_action(SDLKey key)
108 {
109  if (key == SDLK_n) {
110  /* Create a new keybinding. */
111  keybinding_state = KEYBINDING_STATE_ADD;
112  text_input_command.focus = 1;
113  text_input_set(&text_input_command, NULL);
114  text_input_key.focus = 0;
115  text_input_set(&text_input_key, "0 0");
116  return 1;
117  } else if (key == SDLK_DELETE) {
118  /* Delete existing keybinding. */
119  keybind_remove(list_keybindings->row_selected - 1);
120  keybinding_list_reload();
121  return 1;
122  } else if (key == SDLK_r) {
123  /* Toggle repeat on/off. */
124  keybind_repeat_toggle(list_keybindings->row_selected - 1);
125  keybinding_list_reload();
126  return 1;
127  }
128 
129  return 0;
130 }
131 
133 static void list_handle_enter(list_struct *list, SDL_Event *event)
134 {
135  if (list->row_selected) {
136  char buf[MAX_BUF];
137 
138  keybinding_action(SDLK_n);
139 
140  keybinding_state = KEYBINDING_STATE_EDIT;
141  keybinding_id = list->row_selected - 1;
142 
143  text_input_command.focus = !EVENT_IS_KEY(event);
144  text_input_set(&text_input_command, keybindings[keybinding_id]->command);
145  snprintf(buf, sizeof(buf), "%d %d", keybindings[keybinding_id]->key, keybindings[keybinding_id]->mod);
146  text_input_set(&text_input_key, buf);
147  }
148 }
149 
152 {
153  *text_input->str = '\0';
154 }
155 
157 static int popup_draw(popup_struct *popup)
158 {
159  SDL_Rect box;
160 
161  box.w = popup->surface->w;
162  box.h = 38;
163  text_show(popup->surface, FONT_SERIF20, "Keybinding Settings", 0, 0, COLOR_HGOLD, TEXT_ALIGN_CENTER | TEXT_VALIGN_CENTER, &box);
164 
165  list_show(list_keybindings, 30, 50);
166  list_set_parent(list_keybindings, popup->x, popup->y);
167 
168  button_set_parent(&button_new, popup->x, popup->y);
169  button_set_parent(&button_remove, popup->x, popup->y);
170  button_set_parent(&button_apply, popup->x, popup->y);
171 
172  button_new.x = 30;
173  button_new.y = popup->surface->h - 72;
174  button_show(&button_new, "Add");
175 
176  button_remove.x = 30;
177  button_remove.y = popup->surface->h - 49;
178  button_show(&button_remove, "Remove");
179 
180  if (keybinding_state == KEYBINDING_STATE_ADD || keybinding_state == KEYBINDING_STATE_EDIT) {
181  int key, mod;
182 
183  text_show_shadow_format(popup->surface, FONT_ARIAL11, 100, popup->surface->h - 72, COLOR_WHITE, COLOR_BLACK, TEXT_MARKUP, NULL, "[hcenter=%d]Command: [/hcenter]", text_input_command.coords.h);
184  text_show_shadow_format(popup->surface, FONT_ARIAL11, 100, popup->surface->h - 49, COLOR_WHITE, COLOR_BLACK, TEXT_MARKUP, NULL, "[hcenter=%d]Key: [/hcenter]", text_input_command.coords.h);
185  text_show_shadow_format(popup->surface, FONT_ARIAL10, 160, text_input_key.coords.y + text_input_key.coords.h + 5, COLOR_WHITE, COLOR_BLACK, TEXT_MARKUP, NULL, "[hcenter=%d]Press ESC to cancel.[/hcenter]", button_apply.texture->surface->h);
186 
187  text_input_set_parent(&text_input_command, popup->x, popup->y);
188  text_input_set_parent(&text_input_key, popup->x, popup->y);
189 
190  text_input_show(&text_input_command, popup->surface, 160, popup->surface->h - 72);
191  text_input_show(&text_input_key, popup->surface, 160, popup->surface->h - 49);
192 
193  box.w = text_input_key.coords.w;
194  box.h = text_input_key.coords.h;
195 
196  if (sscanf(text_input_key.str, "%d %d", &key, &mod) == 2 && key != SDLK_UNKNOWN) {
197  char buf[MAX_BUF];
198 
199  keybind_get_key_shortcut(key, mod, buf, sizeof(buf));
200  text_show(popup->surface, text_input_key.font, buf, text_input_key.coords.x, text_input_key.coords.y + TEXT_INPUT_PADDING, COLOR_WHITE, TEXT_ALIGN_CENTER, &box);
201  } else if (text_input_key.focus) {
202  text_show(popup->surface, text_input_key.font, "Press keyboard shortcut", text_input_key.coords.x, text_input_key.coords.y + TEXT_INPUT_PADDING, COLOR_WHITE, TEXT_ALIGN_CENTER, &box);
203  }
204 
205  button_apply.x = text_input_key.coords.x + text_input_key.coords.w - texture_surface(button_apply.texture)->w;
206  button_apply.y = text_input_key.coords.y + text_input_key.coords.h + 5;
207  button_show(&button_apply, "Apply");
208  }
209 
210  return 1;
211 }
212 
214 static int popup_event(popup_struct *popup, SDL_Event *event)
215 {
216  if (keybinding_state == KEYBINDING_STATE_ADD || keybinding_state == KEYBINDING_STATE_EDIT) {
217  if (event->type == SDL_KEYDOWN) {
218  if (event->key.keysym.sym == SDLK_ESCAPE) {
219  keybinding_state = KEYBINDING_STATE_LIST;
220  return 1;
221  }
222 
223  if (text_input_command.focus) {
224  text_input_event(&text_input_command, event);
225  }
226 
227  return 1;
228  } else if (event->type == SDL_KEYUP) {
229  if (text_input_command.focus) {
230  if (IS_NEXT(event->key.keysym.sym)) {
231  text_input_command.focus = 0;
232  text_input_key.focus = 1;
233 
234  if (keybinding_state == KEYBINDING_STATE_EDIT) {
235  text_input_set(&text_input_key, "0 0");
236  }
237 
238  return 1;
239  }
240  } else if (text_input_key.focus) {
241  if (strcmp(text_input_key.str, "0 0") == 0) {
242  char buf[MAX_BUF];
243 
244  snprintf(buf, sizeof(buf), "%d %d", event->key.keysym.sym, event->key.keysym.mod);
245  text_input_set(&text_input_key, buf);
246  return 1;
247  } else if (IS_ENTER(event->key.keysym.sym)) {
248  keybinding_apply();
249  return 1;
250  }
251  } else if (IS_ENTER(event->key.keysym.sym)) {
252  text_input_command.focus = 1;
253  return 1;
254  }
255  }
256  }
257 
258  if (event->type == SDL_KEYDOWN) {
259  if (event->key.keysym.sym == SDLK_ESCAPE) {
260  popup_destroy(popup);
261  return 1;
262  } else if (keybinding_action(event->key.keysym.sym)) {
263  return 1;
264  }
265  } else if (event->type == SDL_MOUSEBUTTONDOWN) {
266  if (event->button.button == SDL_BUTTON_LEFT) {
267  uint32_t row, col;
268 
269  if (text_input_mouse_over(&text_input_command, event->motion.x, event->motion.y)) {
270  text_input_command.focus = 1;
271  text_input_key.focus = 0;
272 
273  /* If we are editing and we switched from the key text
274  * input, restore the original value. */
275  if (keybinding_state == KEYBINDING_STATE_EDIT && strcmp(text_input_key.str, "0 0") == 0) {
276  char buf[MAX_BUF];
277 
278  snprintf(buf, sizeof(buf), "%d %d", keybindings[keybinding_id]->key, keybindings[keybinding_id]->mod);
279  text_input_set(&text_input_key, buf);
280  }
281 
282  return 1;
283  } else if (text_input_mouse_over(&text_input_key, event->motion.x, event->motion.y)) {
284  text_input_set(&text_input_key, "0 0");
285  text_input_key.focus = 1;
286  text_input_command.focus = 0;
287  return 1;
288  } else if (list_mouse_get_pos(list_keybindings, event->motion.x, event->motion.y, &row, &col)) {
289  if (col == 2) {
291  keybinding_list_reload();
292  }
293  }
294  }
295  }
296 
297  if (button_event(&button_new, event)) {
298  keybinding_action(SDLK_n);
299  return 1;
300  } else if (button_event(&button_remove, event)) {
301  keybinding_action(SDLK_DELETE);
302  return 1;
303  } else if (button_event(&button_apply, event)) {
304  keybinding_apply();
305  return 1;
306  } else if (list_handle_keyboard(list_keybindings, event)) {
307  return 1;
308  } else if (list_handle_mouse(list_keybindings, event)) {
309  return 1;
310  }
311 
312  return -1;
313 }
314 
317 {
318  list_remove(list_keybindings);
319  list_keybindings = NULL;
320  keybind_save();
321 
322  button_destroy(&button_new);
323  button_destroy(&button_remove);
324  button_destroy(&button_apply);
325 
326  text_input_destroy(&text_input_command);
327  text_input_destroy(&text_input_key);
328 
329  return 1;
330 }
331 
333 static int popup_button_event(popup_button *button)
334 {
335  help_show("keybinding settings");
336  return 1;
337 }
338 
339 void settings_keybinding_open(void)
340 {
341  popup_struct *popup;
342 
343  popup = popup_create(texture_get(TEXTURE_TYPE_CLIENT, "popup"));
344  popup->draw_func = popup_draw;
345  popup->event_func = popup_event;
347 
349  popup_button_set_text(&popup->button_left, "?");
350 
351  button_create(&button_new);
352  button_create(&button_remove);
353  button_create(&button_apply);
354 
355  button_new.surface = button_remove.surface = button_apply.surface = popup->surface;
356 
357  text_input_create(&text_input_command);
358  text_input_create(&text_input_key);
359 
360  text_input_command.focus = text_input_key.focus = 0;
361  text_input_key.show_edit_func = text_input_show_edit;
362 
363  list_keybindings = list_create(12, 3, 8);
364  list_keybindings->handle_enter_func = list_handle_enter;
365  list_keybindings->surface = popup->surface;
366  list_keybindings->header_height = 7;
367  list_set_font(list_keybindings, FONT_ARIAL11);
368  list_set_column(list_keybindings, 0, 273, 7, "Command", -1);
369  list_set_column(list_keybindings, 1, 93, 7, "Key", 1);
370  list_set_column(list_keybindings, 2, 50, 7, "Repeat", 1);
371  list_scrollbar_enable(list_keybindings);
372  keybinding_list_reload();
373 
374  keybinding_state = KEYBINDING_STATE_LIST;
375 }
void keybind_save(void)
Definition: keybind.c:122
list_struct * list_create(uint32_t max_rows, uint32_t cols, int spacing)
Definition: list.c:113
#define COLOR_BLACK
Definition: text.h:323
static button_struct button_new
int(* event_func)(struct popup_struct *popup, SDL_Event *event)
Definition: popup.h:148
int(* draw_func)(struct popup_struct *popup)
Definition: popup.h:127
static int popup_event(popup_struct *popup, SDL_Event *event)
void list_remove(list_struct *list)
Definition: list.c:522
SDL_Surface * texture_surface(texture_struct *texture)
Definition: texture.c:303
int x
Definition: list.h:36
int button_event(button_struct *button, SDL_Event *event)
Definition: button.c:222
void list_set_column(list_struct *list, uint32_t col, int width, int spacing, const char *name, int centered)
Definition: list.c:242
int(* destroy_callback_func)(struct popup_struct *popup)
Definition: popup.h:159
SDL_Rect coords
Definition: text_input.h:96
void button_destroy(button_struct *button)
Definition: button.c:94
int list_handle_mouse(list_struct *list, SDL_Event *event)
Definition: list.c:698
void text_show(SDL_Surface *surface, font_struct *font, const char *text, int x, int y, const char *color_notation, uint64_t flags, SDL_Rect *box)
Definition: text.c:1983
void list_add(list_struct *list, uint32_t row, uint32_t col, const char *str)
Definition: list.c:163
int x
Definition: popup.h:87
#define COLOR_HGOLD
Definition: text.h:319
static int keybinding_state
uint32_t row_offset
Definition: list.h:117
static text_input_struct text_input
Definition: interface.c:59
texture_struct * texture_get(texture_type_t type, const char *name)
Definition: texture.c:279
#define TEXT_MARKUP
Definition: text.h:224
#define TEXT_ALIGN_CENTER
Definition: text.h:230
keybind_struct ** keybindings
Definition: keybind.c:53
void help_show(const char *name)
Definition: help.c:219
static int popup_draw(popup_struct *popup)
void list_clear_rows(list_struct *list)
Definition: list.c:457
void text_show_shadow_format(SDL_Surface *surface, font_struct *font, int x, int y, const char *color_notation, const char *color_shadow_notation, uint64_t flags, SDL_Rect *box, const char *format,...)
Definition: text.c:2305
void list_offsets_ensure(list_struct *list)
Definition: list.c:501
char * keybind_get_key_shortcut(SDLKey key, SDLMod mod, char *buf, size_t len)
Definition: keybind.c:336
static void text_input_show_edit(text_input_struct *text_input)
font_struct * font
Definition: text_input.h:85
int(* event_func)(struct popup_button *button)
Definition: popup.h:56
void button_create(button_struct *button)
Definition: button.c:65
static int keybinding_action(SDLKey key)
static int popup_button_event(popup_button *button)
void keybind_edit(size_t i, SDLKey key, SDLMod mod, const char *command)
Definition: keybind.c:266
uint32_t max_rows
Definition: list.h:57
keybind_struct * keybind_add(SDLKey key, SDLMod mod, const char *command)
Definition: keybind.c:237
texture_struct * texture
Definition: button.h:61
char str[HUGE_BUF]
Definition: text_input.h:55
int list_handle_keyboard(list_struct *list, SDL_Event *event)
Definition: list.c:622
SDL_Surface * surface
Definition: list.h:138
int y
Definition: popup.h:90
SDL_Surface * surface
Definition: button.h:46
popup_button button_left
Definition: popup.h:93
uint16_t header_height
Definition: list.h:97
void list_set_font(list_struct *list, font_struct *font)
Definition: list.c:284
void list_show(list_struct *list, int x, int y)
Definition: list.c:337
void keybind_repeat_toggle(size_t i)
Definition: keybind.c:313
static list_struct * list_keybindings
static size_t keybinding_id
void list_set_parent(list_struct *list, int px, int py)
Definition: list.c:96
static text_input_struct text_input_command
SDL_Surface * surface
Definition: popup.h:65
void list_scrollbar_enable(list_struct *list)
Definition: list.c:302
void keybind_remove(size_t i)
Definition: keybind.c:285
static void list_handle_enter(list_struct *list, SDL_Event *event)
void button_show(button_struct *button, const char *text)
Definition: button.c:161
#define TEXT_VALIGN_CENTER
Definition: text.h:246
size_t keybindings_num
Definition: keybind.c:55
static int popup_destroy_callback(popup_struct *popup)
uint32_t rows
Definition: list.h:60
void(* handle_enter_func)(struct list_struct *list, SDL_Event *event)
Definition: list.h:201
void text_input_destroy(text_input_struct *text_input)
Definition: text_input.c:96
uint32_t row_selected
Definition: list.h:109
#define COLOR_WHITE
Definition: text.h:289