Atrinik Client  4.0
text_input.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 #include <toolkit/string.h>
34 #include <toolkit/x11.h>
35 
36 text_input_history_struct *text_input_history_create(void)
37 {
39 
40  tmp = ecalloc(1, sizeof(*tmp));
41  utarray_new(tmp->history, &ut_str_icd);
42 
43  return tmp;
44 }
45 
46 void text_input_history_free(text_input_history_struct *history)
47 {
48  utarray_free(history->history);
49  efree(history);
50 }
51 
59 static void text_input_history_add(text_input_history_struct *history, const char *text)
60 {
61  char **p;
62 
63  if (!history) {
64  return;
65  }
66 
67  p = (char **) utarray_back(history->history);
68 
69  if (p && !strcmp(*p, text)) {
70  return;
71  }
72 
73  utarray_push_back(history->history, &text);
74 
75  if (utarray_len(history->history) > (size_t) setting_get_int(OPT_CAT_GENERAL, OPT_MAX_INPUT_HISTORY_LINES)) {
76  utarray_erase(history->history, 0, utarray_len(history->history) - (size_t) setting_get_int(OPT_CAT_GENERAL, OPT_MAX_INPUT_HISTORY_LINES));
77  }
78 }
79 
80 void text_input_create(text_input_struct *text_input)
81 {
82  memset(text_input, 0, sizeof(*text_input));
83  text_input->focus = 1;
84  text_input->coords.w = 200;
85  text_input->max = MIN(sizeof(text_input->str), 256);
86 
87  text_input_set_font(text_input, FONT_ARIAL11);
88 }
89 
97 {
98  if (text_input->font != NULL) {
99  font_free(text_input->font);
100  }
101 }
102 
103 void text_input_set_font(text_input_struct *text_input, font_struct *font)
104 {
105  if (text_input->font != NULL) {
106  font_free(text_input->font);
107  }
108 
109  FONT_INCREF(font);
110  text_input->font = font;
111  text_input->coords.h = FONT_HEIGHT(font) + TEXT_INPUT_PADDING * 2;
112 }
113 
114 void text_input_reset(text_input_struct *text_input)
115 {
116  if (text_input->history) {
117  text_input->history->pos = 0;
118  }
119 
120  text_input_set(text_input, NULL);
121 }
122 
123 void text_input_set_history(text_input_struct *text_input, text_input_history_struct *history)
124 {
125  text_input->history = history;
126 }
127 
128 void text_input_set(text_input_struct *text_input, const char *str)
129 {
130  strncpy(text_input->str, str ? str : "", text_input->max - 1);
131  text_input->str[text_input->max - 1] = '\0';
132  text_input->pos = text_input->num = strlen(text_input->str);
133 }
134 
135 void text_input_set_parent(text_input_struct *text_input, int px, int py)
136 {
137  text_input->px = px;
138  text_input->py = py;
139 }
140 
141 int text_input_mouse_over(text_input_struct *text_input, int mx, int my)
142 {
143  mx -= text_input->px;
144  my -= text_input->py;
145 
146  if (mx >= text_input->coords.x &&
147  my >= text_input->coords.y &&
148  mx < text_input->coords.x + text_input->coords.w &&
149  my < text_input->coords.y + text_input->coords.h) {
150  return 1;
151  }
152 
153  return 0;
154 }
155 
156 void text_input_show_edit_password(text_input_struct *text_input)
157 {
158  string_replace_char(text_input->str, NULL, '*');
159 }
160 
161 int text_input_number_character_check(text_input_struct *text_input, char c)
162 {
163  return isdigit(c);
164 }
165 
166 void text_input_show(text_input_struct *text_input, SDL_Surface *surface,
167  int x, int y)
168 {
169  text_info_struct info;
170  int underscore_width;
171  size_t pos;
172  char *cp, *cp2;
173  SDL_Rect box;
174  StringBuffer *sb;
175 
176  text_input->coords.x = x;
177  text_input->coords.y = y;
178 
179  rectangle_create(surface, text_input->coords.x, text_input->coords.y,
180  text_input->coords.w, text_input->coords.h, "000000");
181  border_create_color(surface, &text_input->coords, 1, "303030");
182 
183  cp = NULL;
184  box.w = 0;
185 
186  if (text_input->show_edit_func) {
187  cp = estrdup(text_input->str);
188  text_input->show_edit_func(text_input);
189  }
190 
192  underscore_width = glyph_get_width(text_input->font, '_');
193 
194  /* Figure out the width by going backwards. */
195  for (pos = text_input->pos; pos; pos--) {
196  /* Reached the maximum yet? */
197  if (box.w + glyph_get_width(text_input->font,
198  *(text_input->str + pos)) +
199  underscore_width > text_input->coords.w - TEXT_INPUT_PADDING * 2) {
200  break;
201  }
202 
203  text_show_character(&text_input->font, text_input->font, NULL, &box,
204  text_input->str + pos, NULL, NULL, 0, NULL, NULL,
205  &info);
206  }
207 
208  sb = stringbuffer_new();
209  stringbuffer_append_string_len(sb, text_input->str + pos,
210  text_input->pos - pos);
211 
212  if (text_input->focus) {
213  stringbuffer_append_char(sb, '_');
214  }
215 
216  if ((text_input->str + pos) + (text_input->pos - pos)) {
217  stringbuffer_append_string(sb,
218  (text_input->str + pos) + (text_input->pos - pos));
219  }
220 
221  box.w = text_input->coords.w - TEXT_INPUT_PADDING * 2;
222  box.h = text_input->coords.h - TEXT_INPUT_PADDING * 2;
223 
224  cp2 = stringbuffer_finish(sb);
225  text_show(surface, text_input->font, cp2,
226  text_input->coords.x + TEXT_INPUT_PADDING,
227  text_input->coords.y + TEXT_INPUT_PADDING,
228  COLOR_WHITE, text_input->text_flags | TEXT_WIDTH, &box);
229  efree(cp2);
230 
231  if (cp) {
232  text_input_set(text_input, cp);
233  efree(cp);
234  }
235 }
236 
237 void text_input_add_char(text_input_struct *text_input, char c)
238 {
239  size_t i;
240 
241  if (text_input->num >= text_input->max) {
242  return;
243  }
244 
245  i = text_input->num;
246 
247  for (i = text_input->num; i >= text_input->pos; i--) {
248  text_input->str[i + 1] = text_input->str[i];
249 
250  if (i == 0) {
251  break;
252  }
253  }
254 
255  text_input->str[text_input->pos] = c;
256  text_input->pos++;
257  text_input->num++;
258  text_input->str[text_input->num] = '\0';
259 }
260 
261 int text_input_event(text_input_struct *text_input, SDL_Event *event)
262 {
263  if (!text_input->focus) {
264  return 0;
265  }
266 
267  if (event->type == SDL_KEYDOWN) {
268  if (keybind_command_matches_event("?PASTE", &event->key)) {
269  char *clipboard_contents;
270 
271  clipboard_contents = x11_clipboard_get(SDL_display, SDL_window);
272 
273  if (clipboard_contents) {
274  strncat(text_input->str, clipboard_contents, text_input->max - text_input->num - 1);
275  text_input->str[text_input->max - 1] = '\0';
276  text_input->pos = text_input->num = strlen(text_input->str);
277  string_replace_unprintable_chars(text_input->str);
278 
279  efree(clipboard_contents);
280  }
281 
282  return 1;
283  } else if (IS_ENTER(event->key.keysym.sym)) {
284  if (*text_input->str != '\0') {
285  text_input_history_add(text_input->history, text_input->str);
286  }
287 
288  return 1;
289  } else if (event->key.keysym.sym == SDLK_BACKSPACE) {
290  if (text_input->num && text_input->pos) {
291  size_t i, j;
292 
293  i = j = text_input->pos;
294 
295  if (event->key.keysym.mod & KMOD_CTRL) {
296  string_skip_word(text_input->str, &i, -1);
297  } else {
298  i--;
299  }
300 
301  while (j <= text_input->num) {
302  text_input->str[i++] = text_input->str[j++];
303  }
304 
305  text_input->pos -= (j - i);
306  text_input->num -= (j - i);
307  }
308 
309  return 1;
310  } else if (event->key.keysym.sym == SDLK_DELETE) {
311  if (text_input->pos != text_input->num) {
312  size_t i, j;
313 
314  i = j = text_input->pos;
315 
316  if (event->key.keysym.mod & KMOD_CTRL) {
317  string_skip_word(text_input->str, &i, 1);
318  } else {
319  i++;
320  }
321 
322  while (i <= text_input->num) {
323  text_input->str[j++] = text_input->str[i++];
324  }
325 
326  text_input->num -= (i - j);
327  }
328 
329  return 1;
330  } else if (event->key.keysym.sym == SDLK_LEFT) {
331  if (event->key.keysym.mod & KMOD_CTRL) {
332  size_t i;
333 
334  i = text_input->pos;
335  string_skip_word(text_input->str, &i, -1);
336  text_input->pos = i;
337  } else if (text_input->pos != 0) {
338  text_input->pos--;
339  }
340 
341  return 1;
342  } else if (event->key.keysym.sym == SDLK_RIGHT) {
343  if (event->key.keysym.mod & KMOD_CTRL) {
344  size_t i;
345 
346  i = text_input->pos;
347  string_skip_word(text_input->str, &i, 1);
348  text_input->pos = i;
349  } else if (text_input->pos < text_input->num) {
350  text_input->pos++;
351  }
352 
353  return 1;
354  } else if (event->key.keysym.sym == SDLK_UP) {
355  if (text_input->history) {
356  char **p;
357 
358  p = (char **) utarray_eltptr(text_input->history->history, utarray_len(text_input->history->history) - 1 - text_input->history->pos);
359 
360  if (p) {
361  if (text_input->history->pos == 0) {
362  strncpy(text_input->str_editing, text_input->str, sizeof(text_input->str_editing) - 1);
363  text_input->str_editing[sizeof(text_input->str_editing) - 1] = '\0';
364  }
365 
366  text_input->history->pos++;
367  text_input_set(text_input, *p);
368  }
369  }
370 
371  return 1;
372  } else if (event->key.keysym.sym == SDLK_DOWN) {
373  if (text_input->history) {
374  if (text_input->history->pos > 0) {
375  text_input->history->pos--;
376 
377  if (text_input->history->pos == 0) {
378  text_input_set(text_input, text_input->str_editing);
379  text_input->str_editing[0] = '\0';
380  } else {
381  char **p;
382 
383  p = (char **) utarray_eltptr(text_input->history->history, utarray_len(text_input->history->history) - text_input->history->pos);
384 
385  if (p) {
386  text_input_set(text_input, *p);
387  }
388  }
389  } else if (*text_input->str != '\0') {
390  text_input_history_add(text_input->history, text_input->str);
391  text_input_set(text_input, NULL);
392  }
393  }
394 
395  return 1;
396  } else if (event->key.keysym.sym == SDLK_HOME) {
397  text_input->pos = 0;
398  return 1;
399  } else if (event->key.keysym.sym == SDLK_END) {
400  text_input->pos = text_input->num;
401  return 1;
402  } else if (event->key.keysym.sym == SDLK_RSHIFT || event->key.keysym.sym == SDLK_LSHIFT) {
403  return 1;
404  } else {
405  char c;
406 
407  c = event->key.keysym.unicode & 0xff;
408 
409  if (isprint(c) && (!text_input->character_check_func || text_input->character_check_func(text_input, c))) {
410  if (event->key.keysym.mod & KMOD_SHIFT) {
411  c = toupper(c);
412  }
413 
414  text_input_add_char(text_input, c);
415  return 1;
416  }
417  }
418  }
419 
420  return 0;
421 }
void rectangle_create(SDL_Surface *surface, int x, int y, int w, int h, const char *color_notation)
Definition: sprite.c:1443
SDL_Rect coords
Definition: text_input.h:96
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 text_show_character_init(text_info_struct *info)
Definition: text.c:704
text_input_history_struct * history
Definition: text_input.h:80
static void text_input_history_add(text_input_history_struct *history, const char *text)
Definition: text_input.c:59
static text_input_struct text_input
Definition: interface.c:59
void font_free(font_struct *font)
Definition: text.c:262
int text_show_character(font_struct **font, font_struct *orig_font, SDL_Surface *surface, SDL_Rect *dest, const char *cp, SDL_Color *color, SDL_Color *orig_color, uint64_t flags, SDL_Rect *box, int *x_adjust, text_info_struct *info)
Definition: text.c:753
font_struct * font
Definition: text_input.h:85
#define FONT_INCREF(font)
Definition: text.h:67
int64_t setting_get_int(int cat, int setting)
Definition: settings.c:414
#define FONT_HEIGHT(font)
Definition: text.h:327
x11_display_type SDL_display
Definition: video.c:36
char str[HUGE_BUF]
Definition: text_input.h:55
int keybind_command_matches_event(const char *cmd, SDL_KeyboardEvent *event)
Definition: keybind.c:391
#define TEXT_WIDTH
Definition: text.h:272
char str_editing[HUGE_BUF]
Definition: text_input.h:60
x11_window_type SDL_window
Definition: video.c:40
int glyph_get_width(font_struct *font, char c)
Definition: text.c:1855
void border_create_color(SDL_Surface *surface, SDL_Rect *coords, int thickness, const char *color_notation)
Definition: sprite.c:1359
void text_input_destroy(text_input_struct *text_input)
Definition: text_input.c:96
#define COLOR_WHITE
Definition: text.h:289