Atrinik Client  4.0
textwin.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 
39 const char *const textwin_tab_names[] = {
40  "[ALL]", "[GAME]", "[CHAT]", "[LOCAL]", "[PRIVATE]", "[GUILD]", "[PARTY]", "[OPERATOR]"
41 };
42 
43 const char *const textwin_tab_commands[] = {
44  "say", NULL, "chat", "say", "reply", "guild", "party say", "opsay"
45 };
46 
54 {
55  textwin_struct *textwin = TEXTWIN(widget);
56 
57  if (!textwin->tabs) {
58  return;
59  }
60 
61  textwin->tabs[textwin->tab_selected].unread = 0;
62 
63  if (textwin->tabs[textwin->tab_selected].entries) {
64  SDL_Rect box;
65 
66  box.w = TEXTWIN_TEXT_WIDTH(widget);
67  box.h = 0;
68  box.x = 0;
69  box.y = 0;
70  text_show(NULL, textwin->font, textwin->tabs[textwin->tab_selected].entries, TEXTWIN_TEXT_STARTX(widget), 0, COLOR_BLACK, TEXTWIN_TEXT_FLAGS(widget) | TEXT_LINES_CALC, &box);
71 
72  /* Adjust the counts. */
73  textwin->tabs[textwin->tab_selected].num_lines = box.h - 1;
74  }
75 
78  WIDGET_REDRAW(widget);
79 }
80 
82 static int text_anchor_handle(const char *anchor_action, const char *buf, size_t len, void *custom_data)
83 {
84  if (strcmp(anchor_action, "#charname") == 0) {
85  StringBuffer *sb;
86 
87  if (custom_data != NULL) {
88  sb = custom_data;
89 
90  if (stringbuffer_length(sb) != 0) {
91  stringbuffer_append_char(sb, ':');
92  }
93 
94  stringbuffer_append_string(sb, buf);
95  } else {
96  char *cp;
97 
98  sb = stringbuffer_new();
99  stringbuffer_append_printf(sb, "/tell \"%s\" ", buf);
100  cp = stringbuffer_finish(sb);
101  widget_textwin_handle_console(cp);
102  efree(cp);
103  }
104 
105  return 1;
106  }
107 
108  return 0;
109 }
110 
111 static void textwin_tab_append(widgetdata *widget, uint8_t id, uint8_t type, const char *color, const char *str)
112 {
113  textwin_struct *textwin;
114  SDL_Rect box;
115  size_t len, scroll;
116  char timebuf[MAX_BUF], tabname[MAX_BUF], *cp;
117 
118  textwin = TEXTWIN(widget);
119  box.w = TEXTWIN_TEXT_WIDTH(widget);
120  box.h = 0;
121 
122  timebuf[0] = tabname[0] = '\0';
123 
124  if (setting_get_int(OPT_CAT_GENERAL, OPT_CHAT_TIMESTAMPS) && textwin->timestamps) {
125  time_t now = time(NULL);
126  char tmptimebuf[MAX_BUF];
127  struct tm *tm = localtime(&now);
128  size_t timelen;
129 
130  const char *format;
132  /* HH:MM */
133  case 1:
134  default:
135  format = "%H:%M";
136  break;
137 
138  /* HH:MM:SS */
139  case 2:
140  format = "%H:%M:%S";
141  break;
142 
143  /* H:MM AM/PM */
144  case 3:
145  format = "%I:%M %p";
146  break;
147 
148  /* H:MM:SS AM/PM */
149  case 4:
150  format = "%I:%M:%S %p";
151  break;
152  }
153 
154  timelen = strftime(tmptimebuf, sizeof(tmptimebuf), format, tm);
155 
156  if (timelen != 0) {
157  snprintf(timebuf, sizeof(timebuf), "&lsqb;%s&rsqb; ", tmptimebuf);
158  }
159  }
160 
161  if (textwin->tabs[id].type == CHAT_TYPE_ALL) {
162  cp = text_escape_markup(textwin_tab_names[type - 1]);
163  snprintf(tabname, sizeof(tabname), "%s ", cp);
164  efree(cp);
165  } else if (textwin->tabs[textwin->tab_selected].type != CHAT_TYPE_ALL) {
166  textwin->tabs[id].unread = 1;
167  }
168 
169  cp = string_join("", "[c=#", color, " 1]", timebuf, tabname, str, "\n", NULL);
170  len = strlen(cp);
171  /* Resize the characters array as needed. */
172  textwin->tabs[id].entries = erealloc(textwin->tabs[id].entries, textwin->tabs[id].entries_size + len + 1);
173  memcpy(textwin->tabs[id].entries + textwin->tabs[id].entries_size, cp, len);
174  textwin->tabs[id].entries[textwin->tabs[id].entries_size + len] = '\0';
175  textwin->tabs[id].entries_size += len;
176 
177  box.y = 0;
178  /* Get the string's height. */
179  text_show(NULL, textwin->font, cp, TEXTWIN_TEXT_STARTX(widget), 0, COLOR_BLACK, TEXTWIN_TEXT_FLAGS(widget) | TEXT_LINES_CALC, &box);
180  scroll = box.h - 1;
181 
182  efree(cp);
183 
184  /* Adjust the counts. */
185  textwin->tabs[id].num_lines += scroll;
186 
187  /* Have the entries gone over maximum allowed lines? */
188  if (textwin->tabs[id].entries && textwin->tabs[id].num_lines >= (size_t) setting_get_int(OPT_CAT_GENERAL, OPT_MAX_CHAT_LINES)) {
189  while (textwin->tabs[id].num_lines >= (size_t) setting_get_int(OPT_CAT_GENERAL, OPT_MAX_CHAT_LINES) && (cp = strchr(textwin->tabs[id].entries, '\n'))) {
190  size_t pos = cp - textwin->tabs[id].entries + 1;
191  char *buf = emalloc(pos + 1);
192 
193  /* Copy the string together with the newline to a temporary
194  * buffer. */
195  memcpy(buf, textwin->tabs[id].entries, pos);
196  buf[pos] = '\0';
197 
198  /* Get the string's height. */
199  box.h = 0;
200  text_show(NULL, textwin->font, buf, TEXTWIN_TEXT_STARTX(widget), 0, COLOR_BLACK, TEXTWIN_TEXT_FLAGS(widget) | TEXT_LINES_CALC, &box);
201  scroll = box.h - 1;
202 
203  efree(buf);
204 
205  /* Move the string after the found newline to the beginning,
206  * effectively erasing the previous line. */
207  textwin->tabs[id].entries_size -= pos;
208  memmove(textwin->tabs[id].entries, textwin->tabs[id].entries + pos, textwin->tabs[id].entries_size);
209  textwin->tabs[id].entries[textwin->tabs[id].entries_size] = '\0';
210 
211  /* Adjust the counts. */
212  textwin->tabs[id].num_lines -= scroll;
213  }
214  }
215 }
216 
217 static int textwin_tab_compare(const void *a, const void *b)
218 {
219  const textwin_tab_struct *tab_one, *tab_two;
220 
221  tab_one = a;
222  tab_two = b;
223 
224  if (tab_one->name && !tab_two->name) {
225  return 1;
226  } else if (!tab_one->name && tab_two->name) {
227  return -1;
228  } else if (tab_one->name && tab_two->name) {
229  return strcmp(tab_one->name, tab_two->name);
230  }
231 
232  return tab_one->type - tab_two->type;
233 }
234 
235 size_t textwin_tab_name_to_id(const char *name)
236 {
237  size_t i;
238 
239  for (i = 0; i < arraysize(textwin_tab_names); i++) {
240  if (strcmp(textwin_tab_names[i], name) == 0) {
241  return i + 1;
242 
243  }
244  }
245 
246  return CHAT_TYPE_PRIVATE;
247 }
248 
249 void textwin_tab_free(textwin_tab_struct *tab)
250 {
251  if (tab->name) {
252  efree(tab->name);
253  }
254 
255  if (tab->entries) {
256  efree(tab->entries);
257  }
258 
259  if (tab->charnames) {
260  efree(tab->charnames);
261  }
262 
263  text_input_destroy(&tab->text_input);
264  text_input_history_free(tab->text_input_history);
265  button_destroy(&tab->button);
266 }
267 
268 void textwin_tab_remove(widgetdata *widget, const char *name)
269 {
270  textwin_struct *textwin;
271  size_t i;
272 
273  textwin = TEXTWIN(widget);
274 
275  for (i = 0; i < textwin->tabs_num; i++) {
276  if (strcmp(TEXTWIN_TAB_NAME(&textwin->tabs[i]), name) != 0) {
277  continue;
278  }
279 
280  textwin_tab_free(&textwin->tabs[i]);
281 
282  for (i = i + 1; i < textwin->tabs_num; i++) {
283  textwin->tabs[i - 1] = textwin->tabs[i];
284  }
285 
286  textwin->tabs = erealloc(textwin->tabs, sizeof(*textwin->tabs) * (textwin->tabs_num - 1));
287  textwin->tabs_num--;
288  textwin->tab_selected = MIN(textwin->tab_selected, textwin->tabs_num - 1);
289  textwin_readjust(widget);
290  break;
291  }
292 }
293 
294 void textwin_tab_add(widgetdata *widget, const char *name)
295 {
296  textwin_struct *textwin;
297  int wd;
298  char buf[MAX_BUF];
299 
300  textwin = TEXTWIN(widget);
301  textwin->tabs = ereallocz(textwin->tabs, sizeof(*textwin->tabs) * textwin->tabs_num, sizeof(*textwin->tabs) * (textwin->tabs_num + 1));
302 
303  textwin->tabs[textwin->tabs_num].type = textwin_tab_name_to_id(name);
304 
305  if (!string_startswith(name, "[") && !string_endswith(name, "]")) {
306  textwin->tabs[textwin->tabs_num].name = estrdup(name);
307  }
308 
309  button_create(&textwin->tabs[textwin->tabs_num].button);
310  wd = text_get_width(textwin->tabs[textwin->tabs_num].button.font, TEXTWIN_TAB_NAME(&textwin->tabs[textwin->tabs_num]), 0) + 10;
311  snprintf(buf, sizeof(buf), "rectangle:%d,20,255;[border=widget_border %d 20]", wd, wd);
312  textwin->tabs[textwin->tabs_num].button.texture = texture_get(TEXTURE_TYPE_SOFTWARE, buf);
313  textwin->tabs[textwin->tabs_num].button.texture_over = textwin->tabs[textwin->tabs_num].button.texture_pressed = NULL;
314 
315  text_input_create(&textwin->tabs[textwin->tabs_num].text_input);
316  text_input_set_font(&textwin->tabs[textwin->tabs_num].text_input, textwin->font);
317  textwin->tabs[textwin->tabs_num].text_input.focus = 0;
318  textwin->tabs[textwin->tabs_num].text_input.max = 250;
319  textwin->tabs[textwin->tabs_num].text_input_history = text_input_history_create();
320  text_input_set_history(&textwin->tabs[textwin->tabs_num].text_input, textwin->tabs[textwin->tabs_num].text_input_history);
321 
322  textwin->tabs_num++;
323 
324  qsort(textwin->tabs, textwin->tabs_num, sizeof(*textwin->tabs), textwin_tab_compare);
325  textwin_readjust(widget);
326 }
327 
328 int textwin_tab_find(widgetdata *widget, uint8_t type, const char *name, size_t *id)
329 {
330  textwin_struct *textwin;
331 
332  textwin = TEXTWIN(widget);
333 
334  for (*id = 0; *id < textwin->tabs_num; (*id)++) {
335  if (textwin->tabs[*id].type == type && (string_isempty(name) || (string_startswith(name, "[") && string_endswith(name, "]")) || (textwin->tabs[*id].name && strcmp(textwin->tabs[*id].name, name) == 0))) {
336  return 1;
337  }
338  }
339 
340  return 0;
341 }
342 
343 void textwin_tab_open(widgetdata *widget, const char *name)
344 {
345  textwin_struct *textwin;
346  size_t i;
347 
348  textwin = TEXTWIN(widget);
349 
350  if (textwin_tab_find(widget, CHAT_TYPE_PRIVATE, name, &i)) {
351  textwin->tab_selected = i;
352  textwin_readjust(widget);
353  } else {
354  textwin_tab_add(widget, name);
355  }
356 }
357 
358 void draw_info_tab(size_t type, const char *color, const char *str)
359 {
360  text_info_struct info;
361  StringBuffer *sb;
362  char *name;
363  widgetdata *widget;
364  textwin_struct *textwin;
365  uint32_t bottom;
366  uint8_t found;
367  size_t i;
368 
369  sb = stringbuffer_new();
370  text_anchor_parse(&info, str);
372  text_anchor_execute(&info, sb);
374  name = stringbuffer_finish(sb);
375 
376  if (!string_isempty(name)) {
377  widgetdata *ignore_widget;
378 
379  ignore_widget = widget_find_create_id(BUDDY_ID, "ignore");
380 
381  if (widget_buddy_check(ignore_widget, name) != -1) {
382  efree(name);
383  return;
384  }
385  }
386 
387  for (widget = cur_widget[CHATWIN_ID]; widget; widget = widget->type_next) {
388  textwin = TEXTWIN(widget);
389 
390  if (!textwin->tabs) {
391  continue;
392  }
393 
394  WIDGET_REDRAW(widget);
395  bottom = SCROLL_BOTTOM(&textwin->scrollbar);
396  found = 0;
397 
398  if (textwin_tab_find(widget, type, NULL, &i)) {
399  textwin_tab_append(widget, i, type, color, str);
400  found = 1;
401  }
402 
403  if (!string_isempty(name) && textwin_tab_find(widget, type, name, &i)) {
404  textwin_tab_append(widget, i, type, color, str);
405  found = 1;
406  }
407 
408  if (found) {
409  if (textwin_tab_find(widget, CHAT_TYPE_ALL, NULL, &i)) {
410  textwin_tab_append(widget, i, type, color, str);
411  }
412  }
413 
414  if (textwin->tabs[textwin->tab_selected].scroll_offset == bottom) {
415  scrollbar_scroll_to(&textwin->scrollbar, SCROLL_BOTTOM(&textwin->scrollbar));
416  }
417  }
418 
419  efree(name);
420 }
421 
429 void draw_info_format(const char *color, const char *format, ...)
430 {
431  char buf[HUGE_BUF * 2];
432  va_list ap;
433 
434  va_start(ap, format);
435  vsnprintf(buf, sizeof(buf), format, ap);
436  va_end(ap);
437 
438  draw_info_tab(CHAT_TYPE_GAME, color, buf);
439 }
440 
448 void draw_info(const char *color, const char *str)
449 {
450  draw_info_tab(CHAT_TYPE_GAME, color, str);
451 }
452 
460 {
461  int64_t start, end;
462  textwin_struct *textwin;
463  char *str, *cp;
464  size_t i, pos;
465 
466  if (!widget) {
467  widget = widget_find(NULL, CHATWIN_ID, NULL, NULL);
468 
469  if (!widget) {
470  return;
471  }
472  }
473 
474  textwin = TEXTWIN(widget);
475 
476  start = textwin->selection_start;
477  end = textwin->selection_end;
478 
479  if (end < start) {
480  start = textwin->selection_end;
481  end = textwin->selection_start;
482  }
483 
484  if (end - start <= 0) {
485  return;
486  }
487 
488  /* Get the string to copy, depending on the start and end positions. */
489  str = emalloc(sizeof(char) * (end - start + 1 + 1));
490  memcpy(str, textwin->tabs[textwin->tab_selected].entries + start, end - start + 1);
491  str[end - start + 1] = '\0';
492 
493  cp = emalloc(sizeof(char) * (end - start + 1 + 1));
494  i = 0;
495 
496  /* Remove the special \r color changers. */
497  for (pos = 0; pos < (size_t) (end - start + 1); pos++) {
498  cp[i++] = str[pos];
499  }
500 
501  cp[i] = '\0';
502  cp = text_strip_markup(cp, NULL, 1);
503 
504  x11_clipboard_set(SDL_display, SDL_window, cp);
505  efree(str);
506  efree(cp);
507 }
508 
523 void textwin_show(SDL_Surface *surface, int x, int y, int w, int h)
524 {
525  widgetdata *widget;
526  textwin_struct *textwin;
527  size_t i;
528  SDL_Rect box;
529  int scroll;
530 
531  for (widget = cur_widget[CHATWIN_ID]; widget; widget = widget->type_next) {
532  textwin = TEXTWIN(widget);
533 
534  for (i = 0; i < textwin->tabs_num; i++) {
535  if (textwin->tabs[i].type == CHAT_TYPE_GAME &&
536  textwin->tabs[i].entries != NULL) {
537  box.w = w - 3;
538  box.h = 0;
539  box.x = 0;
540  box.y = 0;
541  text_show(NULL, textwin->font, textwin->tabs[i].entries, 3, 0, COLOR_BLACK, TEXTWIN_TEXT_FLAGS(widget) | TEXT_LINES_CALC, &box);
542  scroll = box.h;
543 
544  box.x = x;
545  box.y = y;
546  box.w = w;
547  box.h = h;
548  SDL_FillRect(surface, &box, SDL_MapRGB(surface->format, 0, 0, 0));
549  draw_frame(surface, x, y, box.w, box.h);
550 
551  box.w = w - 3;
552  box.h = h;
553 
554  box.y = MAX(0, scroll - (h / FONT_HEIGHT(textwin->font)));
555 
556  text_show(surface, textwin->font, textwin->tabs[i].entries, x + 3, y + 1, COLOR_BLACK, TEXTWIN_TEXT_FLAGS(widget) | TEXT_LINES_SKIP, &box);
557  break;
558  }
559  }
560  }
561 }
562 
563 int textwin_tabs_height(widgetdata *widget)
564 {
565  textwin_struct *textwin;
566  int button_x, button_y;
567  size_t i;
568 
569  textwin = TEXTWIN(widget);
570  button_x = button_y = 0;
571 
572  if (textwin->tabs_num <= 1) {
573  return 0;
574  }
575 
576  for (i = 0; i < textwin->tabs_num; i++) {
577  if (button_x + texture_surface(textwin->tabs[i].button.texture)->w > widget->w) {
578  button_x = 0;
579  button_y += TEXTWIN_TAB_HEIGHT - 1;
580  }
581 
582  button_x += texture_surface(textwin->tabs[i].button.texture)->w - 1;
583  }
584 
585  return button_y + TEXTWIN_TAB_HEIGHT - 1;
586 }
587 
594 {
595  textwin_struct *textwin = TEXTWIN(widget);
596 
597  scrollbar_create(&textwin->scrollbar, TEXTWIN_SCROLLBAR_WIDTH(widget), TEXTWIN_SCROLLBAR_HEIGHT(widget), &textwin->tabs[textwin->tab_selected].scroll_offset, &textwin->tabs[textwin->tab_selected].num_lines, TEXTWIN_ROWS_VISIBLE(widget));
598  textwin->scrollbar.redraw = &widget->redraw;
599 }
600 
602 static void widget_draw(widgetdata *widget)
603 {
604  SDL_Rect box;
605  textwin_struct *textwin = TEXTWIN(widget);
606  int alpha;
607 
608  /* Sanity check. */
609  if (!textwin) {
610  return;
611  }
612 
613  /* If we don't have a backbuffer, create it */
614  if (!widget->surface || widget->w != widget->surface->w || widget->h != widget->surface->h) {
615  if (widget->surface) {
616  SDL_FreeSurface(widget->surface);
617  }
618 
619  widget->surface = SDL_CreateRGBSurface(get_video_flags(), widget->w, widget->h, video_get_bpp(), 0, 0, 0, 0);
620  SDL_SetColorKey(widget->surface, SDL_SRCCOLORKEY | SDL_ANYFORMAT, 0);
621  textwin_readjust(widget);
622  }
623 
625  if (alpha != 0) {
626  SDL_Color bg_color;
627 
629  OPT_TEXT_WINDOW_BG_COLOR), &bg_color)) {
630  Uint32 color = ((uint32_t) bg_color.r << 24) |
631  ((uint32_t) bg_color.g << 16) |
632  ((uint32_t) bg_color.b << 8) |
633  (uint32_t) alpha;
634  filledRectAlpha(ScreenSurface, widget->x, widget->y,
635  widget->x + widget->w - 1, widget->y + widget->h - 1,
636  color);
637  }
638  }
639 
640  /* Let's draw the widgets in the backbuffer */
641  if (widget->redraw) {
642  SDL_FillRect(widget->surface, NULL, 0);
643 
644  if (textwin->tabs) {
645  int yadjust;
646 
647  yadjust = 0;
648 
649  if (textwin->tabs_num > 1) {
650  size_t i;
651  int button_x, button_y;
652 
653  button_x = button_y = 0;
654 
655  for (i = 0; i < textwin->tabs_num; i++) {
656  if (button_x + texture_surface(textwin->tabs[i].button.texture)->w > widget->w) {
657  button_x = 0;
658  button_y += TEXTWIN_TAB_HEIGHT - 1;
659  }
660 
661  if (textwin->tabs[i].unread) {
662  textwin->tabs[i].button.color = COLOR_NAVY;
663  } else {
664  textwin->tabs[i].button.color = COLOR_WHITE;
665  }
666 
667  textwin->tabs[i].button.x = button_x;
668  textwin->tabs[i].button.y = button_y;
669  textwin->tabs[i].button.surface = widget->surface;
670  button_set_parent(&textwin->tabs[i].button, widget->x, widget->y);
671  button_show(&textwin->tabs[i].button, TEXTWIN_TAB_NAME(&textwin->tabs[i]));
672 
673  button_x += texture_surface(textwin->tabs[i].button.texture)->w - 1;
674  }
675 
676  yadjust = button_y + TEXTWIN_TAB_HEIGHT;
677  box.w = widget->w;
678  box.h = 1;
679  surface_show_fill(widget->surface, 0, yadjust - box.h, NULL, TEXTURE_CLIENT("widget_border"), &box);
680  yadjust -= 1;
681  }
682 
683  /* Show the text entries, if any. */
684  if (textwin->tabs[textwin->tab_selected].entries) {
685  SDL_Rect box_text;
686  StringBuffer *sb;
687  char *charnames;
688 
689  sb = stringbuffer_new();
690 
691  box_text.w = TEXTWIN_TEXT_WIDTH(widget);
692  box_text.h = TEXTWIN_TEXT_HEIGHT(widget);
693  box_text.y = textwin->tabs[textwin->tab_selected].scroll_offset;
694  text_set_selection(&textwin->selection_start, &textwin->selection_end, &textwin->selection_started);
697  text_show(widget->surface, textwin->font, textwin->tabs[textwin->tab_selected].entries, TEXTWIN_TEXT_STARTX(widget), TEXTWIN_TEXT_STARTY(widget) + yadjust, COLOR_BLACK, TEXTWIN_TEXT_FLAGS(widget) | TEXT_LINES_SKIP, &box_text);
698  text_set_anchor_info(NULL);
700  text_set_selection(NULL, NULL, NULL);
701 
702  charnames = stringbuffer_finish(sb);
703 
704  if (textwin->tabs[textwin->tab_selected].charnames) {
705  efree(textwin->tabs[textwin->tab_selected].charnames);
706  }
707 
708  textwin->tabs[textwin->tab_selected].charnames = charnames;
709  }
710 
711  if (textwin_tab_commands[textwin->tabs[textwin->tab_selected].type - 1]) {
712  text_input_set_parent(&textwin->tabs[textwin->tab_selected].text_input, widget->x, widget->y);
713  textwin->tabs[textwin->tab_selected].text_input.coords.w = TEXTWIN_TEXT_INPUT_WIDTH(widget);
714  text_input_show(&textwin->tabs[textwin->tab_selected].text_input, widget->surface, TEXTWIN_TEXT_INPUT_STARTX(widget), TEXTWIN_TEXT_INPUT_STARTY(widget) + yadjust);
715  }
716 
717  textwin->scrollbar.max_lines = TEXTWIN_ROWS_VISIBLE(widget);
718  textwin->scrollbar.px = widget->x;
719  textwin->scrollbar.py = widget->y;
720  scrollbar_show(&textwin->scrollbar, widget->surface, widget->w - 1 - textwin->scrollbar.background.w, TEXTWIN_TEXT_STARTY(widget) + yadjust);
721  }
722  }
723 
724  if (scrollbar_need_redraw(&textwin->scrollbar)) {
725  widget->redraw++;
726  }
727 
728  box.x = widget->x;
729  box.y = widget->y;
730  SDL_BlitSurface(widget->surface, NULL, ScreenSurface, &box);
731 
732  box.x = widget->x;
733  box.y = widget->y;
734  box.w = widget->w;
735  box.h = widget->h;
736  border_create_texture(ScreenSurface, &box, 1, TEXTURE_CLIENT("widget_border"));
737 }
738 
740 static void widget_background(widgetdata *widget, int draw)
741 {
742  textwin_struct *textwin;
743  size_t i;
744 
745  textwin = TEXTWIN(widget);
746 
747  for (i = 0; i < textwin->tabs_num; i++) {
748  if (button_need_redraw(&textwin->tabs[i].button)) {
749  WIDGET_REDRAW(widget);
750  }
751  }
752 }
753 
755 static int widget_event(widgetdata *widget, SDL_Event *event)
756 {
757  textwin_struct *textwin = TEXTWIN(widget);
758 
759  if (event->type == SDL_MOUSEBUTTONDOWN) {
760  widgetdata *tmp;
762 
763  if (textwin->tabs != NULL) {
764  text_input = &textwin->tabs[textwin->tab_selected].text_input;
765 
766  if (text_input->focus == 0 && *text_input->str != '\0') {
767  text_input->focus = 1;
768  WIDGET_REDRAW(widget);
769  }
770  }
771 
772  for (tmp = cur_widget[CHATWIN_ID]; tmp != NULL; tmp = tmp->type_next) {
773  if (tmp != widget && TEXTWIN(tmp)->tabs != NULL) {
774  text_input = &TEXTWIN(tmp)->tabs[TEXTWIN(tmp)->tab_selected].text_input;
775 
776  if (text_input->focus == 1) {
777  text_input->focus = 0;
778  WIDGET_REDRAW(tmp);
779  }
780  }
781  }
782  }
783 
784  if (textwin->tabs_num > 1 && (event->type == SDL_MOUSEMOTION || event->type == SDL_MOUSEBUTTONDOWN)) {
785  size_t i;
786 
787  for (i = 0; i < textwin->tabs_num; i++) {
788  if (button_event(&textwin->tabs[i].button, event)) {
789  textwin->tab_selected = i;
790  textwin_readjust(widget);
791  return 1;
792  }
793  }
794  }
795 
796  if (textwin->tabs != NULL && event->type == SDL_KEYDOWN && textwin->tabs[textwin->tab_selected].text_input.focus == 1 && widget == widget_find(NULL, CHATWIN_ID, NULL, NULL)) {
797  if (IS_ENTER(event->key.keysym.sym) && *(textwin->tabs[textwin->tab_selected].text_input.str) != '\0') {
798  StringBuffer *sb;
799  char *cp, *str;
800 
801  sb = stringbuffer_new();
802 
803  if (*(textwin->tabs[textwin->tab_selected].text_input.str) != '/') {
804  if (textwin->tabs[textwin->tab_selected].name != NULL) {
805  stringbuffer_append_printf(sb, "/tell \"%s\" ", textwin->tabs[textwin->tab_selected].name);
806  } else {
807  stringbuffer_append_printf(sb, "/%s ", textwin_tab_commands[textwin->tabs[textwin->tab_selected].type - 1]);
808  }
809  }
810 
811  str = text_escape_markup(textwin->tabs[textwin->tab_selected].text_input.str);
812  stringbuffer_append_string(sb, str);
813  efree(str);
814 
815  cp = stringbuffer_finish(sb);
816  send_command_check(cp);
817  efree(cp);
818  }
819 
820  if (event->key.keysym.sym == SDLK_ESCAPE) {
821  textwin->tabs[textwin->tab_selected].text_input.focus = 0;
822  text_input_reset(&textwin->tabs[textwin->tab_selected].text_input);
823  WIDGET_REDRAW(widget);
824  return 1;
825  } else if (event->key.keysym.sym == SDLK_TAB) {
826  help_handle_tabulator(&textwin->tabs[textwin->tab_selected].text_input);
827  WIDGET_REDRAW(widget);
828  return 1;
829  } else if (text_input_event(&textwin->tabs[textwin->tab_selected].text_input, event)) {
830  if (IS_ENTER(event->key.keysym.sym)) {
831  text_input_reset(&textwin->tabs[textwin->tab_selected].text_input);
832  textwin->tabs[textwin->tab_selected].text_input.focus = 0;
833  }
834 
835  WIDGET_REDRAW(widget);
836  return 1;
837  }
838  }
839 
840  if (scrollbar_event(&textwin->scrollbar, event)) {
841  WIDGET_REDRAW(widget);
842  return 1;
843  }
844 
845  if (event->type == SDL_MOUSEMOTION) {
846  WIDGET_REDRAW(widget);
847  }
848 
849  if (event->button.button == SDL_BUTTON_LEFT) {
850  if (event->type == SDL_MOUSEBUTTONUP) {
851  return 1;
852  } else if (event->type == SDL_MOUSEBUTTONDOWN) {
853  textwin->selection_started = 0;
854  textwin->selection_start = -1;
855  textwin->selection_end = -1;
856  WIDGET_REDRAW(widget);
857  return 1;
858  } else if (event->type == SDL_MOUSEMOTION) {
859  textwin->selection_started = 1;
860  return 1;
861  }
862  }
863 
864  if (event->type == SDL_MOUSEBUTTONDOWN) {
865  if (event->button.button == SDL_BUTTON_WHEELUP) {
866  scrollbar_scroll_adjust(&textwin->scrollbar, -1);
867  return 1;
868  } else if (event->button.button == SDL_BUTTON_WHEELDOWN) {
869  scrollbar_scroll_adjust(&textwin->scrollbar, 1);
870  return 1;
871  }
872  }
873 
874  if (event->type == SDL_KEYDOWN) {
875  if (event->key.keysym.sym == SDLK_PAGEUP) {
877  return 1;
878  } else if (event->key.keysym.sym == SDLK_PAGEDOWN) {
880  return 1;
881  }
882  }
883 
884  return 0;
885 }
886 
888 static void widget_deinit(widgetdata *widget)
889 {
890  textwin_struct *textwin;
891  size_t i;
892 
893  textwin = TEXTWIN(widget);
894 
895  for (i = 0; i < textwin->tabs_num; i++) {
896  textwin_tab_free(&textwin->tabs[i]);
897  }
898 
899  if (textwin->tabs) {
900  efree(textwin->tabs);
901  }
902 
903  font_free(textwin->font);
904 }
905 
907 static int widget_load(widgetdata *widget, const char *keyword, const char *parameter)
908 {
909  textwin_struct *textwin;
910 
911  textwin = TEXTWIN(widget);
912 
913  if (strcmp(keyword, "font") == 0) {
914  char font_name[MAX_BUF];
915  int font_size;
916 
917  if (sscanf(parameter, "%s %d", font_name, &font_size) == 2) {
918  font_free(textwin->font);
919  textwin->font = font_get(font_name, font_size);
920  return 1;
921  }
922  } else if (strcmp(keyword, "tabs") == 0) {
923  size_t pos;
924  char word[MAX_BUF];
925 
926  pos = 0;
927 
928  while (string_get_word(parameter, &pos, ':', word, sizeof(word), 0)) {
929  if (string_startswith(word, "/")) {
930  textwin_tab_remove(widget, word + 1);
931  } else {
932  if (strcmp(word, "*") == 0) {
933  size_t i;
934 
935  for (i = 0; i < arraysize(textwin_tab_names); i++) {
936  textwin_tab_add(widget, textwin_tab_names[i]);
937  }
938  } else {
939  textwin_tab_add(widget, word);
940  }
941  }
942  }
943 
944  return 1;
945  } else if (strcmp(keyword, "timestamps") == 0) {
946  KEYWORD_TO_BOOLEAN(parameter, textwin->timestamps);
947  return 1;
948  }
949 
950  return 0;
951 }
952 
954 static void widget_save(widgetdata *widget, FILE *fp, const char *padding)
955 {
956  textwin_struct *textwin;
957 
958  textwin = TEXTWIN(widget);
959 
960  fprintf(fp, "%sfont = %s %d\n", padding, textwin->font->name, textwin->font->size);
961  fprintf(fp, "%stimestamps = %s\n", padding, textwin->timestamps ? "yes" : "no");
962 
963  if (textwin->tabs_num) {
964  size_t i;
965 
966  fprintf(fp, "%stabs = ", padding);
967 
968  for (i = 0; i < textwin->tabs_num; i++) {
969  fprintf(fp, "%s%s", i == 0 ? "" : ":", TEXTWIN_TAB_NAME(&textwin->tabs[i]));
970  }
971 
972  fprintf(fp, "\n");
973  }
974 }
975 
976 static void menu_textwin_clear(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
977 {
978  textwin_struct *textwin = TEXTWIN(widget);
979 
980  /* No tabs. */
981  if (textwin->tabs == NULL) {
982  return;
983  }
984 
985  /* The tab has no text. */
986  if (textwin->tabs[textwin->tab_selected].entries == NULL) {
987  return;
988  }
989 
990  efree(textwin->tabs[textwin->tab_selected].entries);
991  textwin->tabs[textwin->tab_selected].entries = NULL;
992  textwin->tabs[textwin->tab_selected].num_lines = textwin->tabs[textwin->tab_selected].entries_size = textwin->tabs[textwin->tab_selected].scroll_offset = 0;
993  WIDGET_REDRAW(widget);
994 }
995 
996 static void menu_textwin_copy(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
997 {
998  textwin_handle_copy(widget);
999 }
1000 
1001 static void textwin_font_adjust(widgetdata *widget, int adjust)
1002 {
1003  textwin_struct *textwin;
1004  font_struct *font;
1005  size_t i;
1006 
1007  textwin = TEXTWIN(widget);
1008  font = font_get_size(textwin->font, adjust);
1009 
1010  if (font == NULL) {
1011  return;
1012  }
1013 
1014  for (i = 0; i < textwin->tabs_num; i++) {
1015  text_input_set_font(&textwin->tabs[i].text_input, font);
1016  }
1017 
1018  font_free(textwin->font);
1019  FONT_INCREF(font);
1020  textwin->font = font;
1021  textwin_readjust(widget);
1022  WIDGET_REDRAW(widget);
1023 }
1024 
1025 static void menu_textwin_font_inc(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
1026 {
1027  textwin_font_adjust(widget, 1);
1028 }
1029 
1030 static void menu_textwin_font_dec(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
1031 {
1032  textwin_font_adjust(widget, -1);
1033 }
1034 
1035 static void menu_textwin_tabs_one(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
1036 {
1037  widgetdata *tmp;
1038  _widget_label *label;
1039  size_t id;
1040  char *cp;
1041 
1042  for (tmp = menuitem->inv; tmp; tmp = tmp->next) {
1043  if (tmp->type == LABEL_ID) {
1044  label = LABEL(menuitem->inv);
1045  cp = text_strip_markup(label->text, NULL, 0);
1046 
1047  if (textwin_tab_find(widget, textwin_tab_name_to_id(cp), cp, &id)) {
1048  textwin_tab_remove(widget, cp);
1049  } else {
1050  textwin_tab_add(widget, cp);
1051  }
1052 
1053  efree(cp);
1054  WIDGET_REDRAW(widget);
1055  break;
1056  }
1057  }
1058 }
1059 
1060 static void menu_textwin_tabs(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
1061 {
1062  widgetdata *tmp, *tmp2, *submenu;
1063  textwin_struct *textwin;
1064  size_t i, id;
1065  uint8_t found;
1066  _widget_label *label;
1067  char *cp;
1068 
1069  submenu = MENU(menuitem->env)->submenu;
1070 
1071  for (i = 0; i < arraysize(textwin_tab_names); i++) {
1072  if (i + 1 == CHAT_TYPE_OPERATOR && !setting_get_int(OPT_CAT_DEVEL, OPT_OPERATOR)) {
1073  continue;
1074  }
1075 
1077  add_menuitem(submenu, cp, &menu_textwin_tabs_one, MENU_CHECKBOX, textwin_tab_find(widget, i + 1, NULL, &id));
1078  efree(cp);
1079  }
1080 
1081  for (tmp = cur_widget[CHATWIN_ID]; tmp; tmp = tmp->type_next) {
1082  textwin = TEXTWIN(tmp);
1083 
1084  for (i = 0; i < textwin->tabs_num; i++) {
1085  if (!textwin->tabs[i].name) {
1086  continue;
1087  }
1088 
1089  found = 0;
1090 
1091  for (tmp2 = submenu->inv; tmp2; tmp2 = tmp2->next) {
1092  if (tmp2->inv->type == LABEL_ID) {
1093  label = LABEL(tmp2->inv);
1094 
1095  if (strcmp(label->text, textwin->tabs[i].name) == 0) {
1096  found = 1;
1097  break;
1098  }
1099  }
1100  }
1101 
1102  if (!found) {
1103  add_menuitem(submenu, textwin->tabs[i].name, &menu_textwin_tabs_one, MENU_CHECKBOX, tmp == widget);
1104  }
1105  }
1106  }
1107 }
1108 
1110 static int text_anchor_handle_players_tab(const char *anchor_action, const char *buf, size_t len, void *custom_data)
1111 {
1112  widgetdata *widget;
1113 
1114  if (strcmp(anchor_action, "#buddy") == 0 || strcmp(anchor_action, "#ignore") == 0) {
1115  widget = widget_find_create_id(BUDDY_ID, anchor_action + 1);
1116 
1117  if (widget_buddy_check(widget, buf) == -1) {
1118  widget_buddy_add(widget, buf, 1);
1119  } else {
1120  widget_buddy_remove(widget, buf);
1121  }
1122 
1123  return 1;
1124  } else if (strcmp(anchor_action, "#opentab") == 0) {
1125  widget = widget_find(NULL, CHATWIN_ID, NULL, NULL);
1126  textwin_tab_open(widget, buf);
1127 
1128  return 1;
1129  }
1130 
1131  return 0;
1132 }
1133 
1134 static void menu_textwin_players_one_tab(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
1135 {
1136  widgetdata *tmp;
1137  _widget_label *label;
1138  text_info_struct info;
1139 
1140  for (tmp = menuitem->inv; tmp; tmp = tmp->next) {
1141  if (tmp->type == LABEL_ID) {
1142  label = LABEL(menuitem->inv);
1143 
1144  text_anchor_parse(&info, label->text);
1146  text_anchor_execute(&info, NULL);
1147  text_set_anchor_handle(NULL);
1148  }
1149  }
1150 }
1151 
1152 static void menu_textwin_players_one(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
1153 {
1154  widgetdata *submenu, *tmp;
1155  _widget_label *label;
1156  char *cp, buf[HUGE_BUF];
1157 
1158  submenu = MENU(menuitem->env)->submenu;
1159 
1160  for (tmp = menuitem->inv; tmp; tmp = tmp->next) {
1161  if (tmp->type == LABEL_ID) {
1162  label = LABEL(menuitem->inv);
1163 
1164  cp = string_sub(label->text, 0, -3);
1165 
1166  snprintf(buf, sizeof(buf), "[a=#buddy:%s]%s[/a]", cp, widget_buddy_check(widget_find(NULL, BUDDY_ID, "buddy", NULL), cp) == -1 ? "Add Buddy" : "Remove Buddy");
1167  add_menuitem(submenu, buf, &menu_textwin_players_one_tab, MENU_NORMAL, 0);
1168 
1169  snprintf(buf, sizeof(buf), "[a=#opentab:%s]Open Tab[/a]", cp);
1170  add_menuitem(submenu, buf, &menu_textwin_players_one_tab, MENU_NORMAL, 0);
1171 
1172  snprintf(buf, sizeof(buf), "[a=#ignore:%s]%s[/a]", cp, widget_buddy_check(widget_find(NULL, BUDDY_ID, "ignore", NULL), cp) == -1 ? "Ignore" : "Unignore");
1173  add_menuitem(submenu, buf, &menu_textwin_players_one_tab, MENU_NORMAL, 0);
1174 
1175  efree(cp);
1176  break;
1177  }
1178  }
1179 }
1180 
1181 static void menu_textwin_players(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
1182 {
1183  textwin_struct *textwin;
1184  size_t pos;
1185  char charname[MAX_BUF], buf[HUGE_BUF];
1186  uint8_t found;
1187  widgetdata *tmp, *submenu;
1188  _widget_label *label;
1189 
1190  textwin = TEXTWIN(widget);
1191  submenu = MENU(menuitem->env)->submenu;
1192  pos = 0;
1193 
1194  if (textwin->tabs == NULL) {
1195  return;
1196  }
1197 
1198  while (string_get_word(textwin->tabs[textwin->tab_selected].charnames, &pos, ':', charname, sizeof(charname), 0)) {
1199  found = 0;
1200 
1201  snprintf(buf, sizeof(buf), "%s >", charname);
1202 
1203  for (tmp = submenu->inv; tmp; tmp = tmp->next) {
1204  if (tmp->inv->type == LABEL_ID) {
1205  label = LABEL(tmp->inv);
1206 
1207  if (strcmp(label->text, buf) == 0) {
1208  found = 1;
1209  break;
1210  }
1211  }
1212  }
1213 
1214  if (!found) {
1215  add_menuitem(submenu, buf, &menu_textwin_players_one, MENU_SUBMENU, 0);
1216  }
1217  }
1218 }
1219 
1220 static int widget_menu_handle(widgetdata *widget, SDL_Event *event)
1221 {
1222  widgetdata *menu;
1223 
1224  menu = create_menu(event->motion.x, event->motion.y, widget);
1225 
1226  widget_menu_standard_items(widget, menu);
1227  add_menuitem(menu, "New Window", &menu_create_widget, MENU_NORMAL, 0);
1228  add_menuitem(menu, "Remove Window", &menu_remove_widget, MENU_NORMAL, 0);
1229 
1230  add_menuitem(menu, "Clear", &menu_textwin_clear, MENU_NORMAL, 0);
1231  add_menuitem(menu, "Copy", &menu_textwin_copy, MENU_NORMAL, 0);
1232  add_menuitem(menu, "Increase Font Size", &menu_textwin_font_inc, MENU_NORMAL, 0);
1233  add_menuitem(menu, "Decrease Font Size", &menu_textwin_font_dec, MENU_NORMAL, 0);
1234  add_menuitem(menu, "Tabs >", &menu_textwin_tabs, MENU_SUBMENU, 0);
1235  add_menuitem(menu, "Players >", &menu_textwin_players, MENU_SUBMENU, 0);
1236 
1237  menu_finalize(menu);
1238 
1239  return 1;
1240 }
1241 
1242 void widget_textwin_init(widgetdata *widget)
1243 {
1244  textwin_struct *textwin;
1245 
1246  textwin = ecalloc(1, sizeof(*textwin));
1247  textwin->font = font_get("arial", 11);
1248  textwin->selection_start = -1;
1249  textwin->selection_end = -1;
1250 
1251  widget->draw_func = widget_draw;
1252  widget->background_func = widget_background;
1253  widget->event_func = widget_event;
1254  widget->save_func = widget_save;
1255  widget->load_func = widget_load;
1256  widget->deinit_func = widget_deinit;
1257  widget->menu_handle_func = widget_menu_handle;
1258  widget->subwidget = textwin;
1259 
1260  textwin_create_scrollbar(widget);
1261 }
1262 
1263 void widget_textwin_handle_console(const char *text)
1264 {
1265  widgetdata *widget;
1266  textwin_struct *textwin;
1267 
1268  widget = NULL;
1269 
1270  while (widget == NULL || widget->next != NULL) {
1271  widget = widget_find(widget != NULL ? widget->next : NULL, CHATWIN_ID, NULL, NULL);
1272 
1273  if (widget == NULL) {
1274  break;
1275  }
1276 
1277  textwin = TEXTWIN(widget);
1278 
1279  if (textwin->tabs != NULL && textwin_tab_commands[textwin->tabs[textwin->tab_selected].type - 1] != NULL) {
1280  break;
1281  }
1282  }
1283 
1284  if (widget == NULL) {
1285  LOG(BUG, "Failed to find a text window.");
1286  return;
1287  }
1288 
1289  text_input_reset(&textwin->tabs[textwin->tab_selected].text_input);
1290  textwin->tabs[textwin->tab_selected].text_input.focus = 1;
1291 
1292  if (text != NULL) {
1293  text_input_set(&textwin->tabs[textwin->tab_selected].text_input, text);
1294  }
1295 
1296  SetPriorityWidget(widget);
1297  WIDGET_REDRAW(widget);
1298 }
void scrollbar_scroll_to(scrollbar_struct *scrollbar, int scroll)
Definition: scrollbar.c:397
int type
Definition: widget.h:118
#define COLOR_BLACK
Definition: text.h:323
void textwin_show(SDL_Surface *surface, int x, int y, int w, int h)
Definition: textwin.c:523
#define TEXTWIN_TEXT_HEIGHT(_widget)
Definition: textwin.h:102
int text_color_parse(const char *color_notation, SDL_Color *color)
Definition: text.c:603
font_struct * font
Definition: button.h:76
struct widgetdata * env
Definition: widget.h:98
void text_set_selection(int64_t *start, int64_t *end, uint8_t *started)
Definition: text.c:425
#define TEXT_LINES_SKIP
Definition: text.h:263
void draw_info(const char *color, const char *str)
Definition: textwin.c:448
ssize_t widget_buddy_check(widgetdata *widget, const char *name)
Definition: buddy.c:160
scrollbar_struct scrollbar
Definition: textwin.h:69
void * subwidget
Definition: widget.h:107
#define TEXTWIN(__textwin)
Definition: widget.h:417
SDL_Surface * texture_surface(texture_struct *texture)
Definition: texture.c:303
static void widget_save(widgetdata *widget, FILE *fp, const char *padding)
Definition: textwin.c:954
SDL_Surface * surface
Definition: widget.h:110
int button_event(button_struct *button, SDL_Event *event)
Definition: button.c:222
font_struct * font_get_size(font_struct *font, int8_t size)
Definition: text.c:242
uint32_t get_video_flags(void)
Definition: video.c:365
SDL_Rect coords
Definition: text_input.h:96
void button_destroy(button_struct *button)
Definition: button.c:94
static void widget_background(widgetdata *widget, int draw)
Definition: textwin.c:740
char * name
Definition: text.h:39
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
static int widget_event(widgetdata *widget, SDL_Event *event)
Definition: textwin.c:755
void draw_frame(SDL_Surface *surface, int x, int y, int w, int h)
Definition: sprite.c:1185
void widget_buddy_remove(widgetdata *widget, const char *name)
Definition: buddy.c:126
font_struct * font
Definition: textwin.h:66
int scrollbar_need_redraw(scrollbar_struct *scrollbar)
Definition: scrollbar.c:267
#define SCROLL_BOTTOM(_scrollbar)
Definition: scrollbar.h:157
static int text_anchor_handle_players_tab(const char *anchor_action, const char *buf, size_t len, void *custom_data)
Definition: textwin.c:1110
void menu_finalize(widgetdata *widget)
Definition: widget.c:2524
struct widgetdata * type_next
Definition: widget.h:101
static text_input_struct text_input
Definition: interface.c:59
void textwin_readjust(widgetdata *widget)
Definition: textwin.c:53
texture_struct * texture_get(texture_type_t type, const char *name)
Definition: texture.c:279
void font_free(font_struct *font)
Definition: text.c:262
struct widgetdata * next
Definition: widget.h:86
font_struct * font_get(const char *name, uint8_t size)
Definition: text.c:216
int64_t selection_end
Definition: textwin.h:78
SDL_Surface * ScreenSurface
Definition: main.c:47
uint32_t max_lines
Definition: scrollbar.h:77
struct widgetdata * inv
Definition: widget.h:92
int64_t selection_start
Definition: textwin.h:75
#define TEXTWIN_TEXT_STARTX(_widget)
Definition: textwin.h:96
void help_handle_tabulator(text_input_struct *text_input)
Definition: help.c:249
void scrollbar_show(scrollbar_struct *scrollbar, SDL_Surface *surface, int x, int y)
Definition: scrollbar.c:443
scrollbar_element background
Definition: scrollbar.h:117
uint8_t selection_started
Definition: textwin.h:72
widgetdata * widget_find(widgetdata *where, int type, const char *id, SDL_Surface *surface)
Definition: widget.c:2091
static int widget_load(widgetdata *widget, const char *keyword, const char *parameter)
Definition: textwin.c:907
int video_get_bpp(void)
Definition: video.c:334
#define TEXTWIN_TEXT_WIDTH(_widget)
Definition: textwin.h:100
void text_set_anchor_handle(text_anchor_handle_func func)
Definition: text.c:437
texture_struct * texture_over
Definition: button.h:67
void textwin_create_scrollbar(widgetdata *widget)
Definition: textwin.c:593
#define FONT_INCREF(font)
Definition: text.h:67
int64_t setting_get_int(int cat, int setting)
Definition: settings.c:414
widgetdata * cur_widget[TOTAL_SUBWIDGETS]
Definition: widget.c:75
uint8_t redraw
Definition: widget.h:72
void button_create(button_struct *button)
Definition: button.c:65
#define FONT_HEIGHT(font)
Definition: text.h:327
void text_set_anchor_info(void *ptr)
Definition: text.c:447
#define TEXTWIN_TEXT_STARTY(_widget)
Definition: textwin.h:98
static void widget_deinit(widgetdata *widget)
Definition: textwin.c:888
uint32_t num_lines
Definition: textwin.h:50
x11_display_type SDL_display
Definition: video.c:36
int x
Definition: widget.h:48
#define WIDGET_REDRAW(__tmp)
Definition: widget.h:398
void scrollbar_scroll_adjust(scrollbar_struct *scrollbar, int adjust)
Definition: scrollbar.c:427
void scrollbar_create(scrollbar_struct *scrollbar, int w, int h, uint32_t *scroll_offset, uint32_t *num_lines, uint32_t max_lines)
Definition: scrollbar.c:350
void text_anchor_execute(text_info_struct *info, void *custom_data)
Definition: text.c:632
uint8_t size
Definition: text.h:42
static int text_anchor_handle(const char *anchor_action, const char *buf, size_t len, void *custom_data)
Definition: textwin.c:82
texture_struct * texture
Definition: button.h:61
void text_anchor_parse(text_info_struct *info, const char *text)
Definition: text.c:2471
widgetdata * create_menu(int x, int y, widgetdata *owner)
Definition: widget.c:2428
char str[HUGE_BUF]
Definition: text_input.h:55
#define TEXTWIN_TEXT_FLAGS(widget)
Definition: textwin.h:115
const char * setting_get_str(int cat, int setting)
Definition: settings.c:400
SDL_Surface * surface
Definition: button.h:46
int w
Definition: widget.h:54
uint8_t * redraw
Definition: scrollbar.h:87
int h
Definition: widget.h:57
void textwin_handle_copy(widgetdata *widget)
Definition: textwin.c:459
void border_create_texture(SDL_Surface *surface, SDL_Rect *coords, int thickness, SDL_Surface *texture)
Definition: sprite.c:1388
texture_struct * texture_pressed
Definition: button.h:73
void surface_show_fill(SDL_Surface *surface, int x, int y, SDL_Rect *srcsize, SDL_Surface *src, SDL_Rect *box)
Definition: sprite.c:792
int text_get_width(font_struct *font, const char *text, uint64_t flags)
Definition: text.c:2328
static void widget_draw(widgetdata *widget)
Definition: textwin.c:602
int send_command_check(const char *cmd)
Definition: menu.c:376
x11_window_type SDL_window
Definition: video.c:40
const char *const textwin_tab_names[]
Definition: textwin.c:39
int scrollbar_event(scrollbar_struct *scrollbar, SDL_Event *event)
Definition: scrollbar.c:529
#define TEXTWIN_ROWS_VISIBLE(widget)
Definition: textwin.h:113
#define TEXT_LINES_CALC
Definition: text.h:259
char * text_strip_markup(char *buf, size_t *buf_len, uint8_t do_free)
Definition: text.c:468
void SetPriorityWidget(widgetdata *node)
Definition: widget.c:1788
void draw_info_format(const char *color, const char *format,...)
Definition: textwin.c:429
uint32_t scroll_offset
Definition: textwin.h:47
void widget_buddy_add(widgetdata *widget, const char *name, uint8_t sort)
Definition: buddy.c:99
void button_show(button_struct *button, const char *text)
Definition: button.c:161
#define COLOR_NAVY
Definition: text.h:293
void add_menuitem(widgetdata *menu, const char *text, void(*menu_func_ptr)(widgetdata *, widgetdata *, SDL_Event *event), int menu_type, int val)
Definition: widget.c:2451
void text_input_destroy(text_input_struct *text_input)
Definition: text_input.c:96
#define COLOR_WHITE
Definition: text.h:289
const char * color
Definition: button.h:87
char * text_escape_markup(const char *buf)
Definition: text.c:532
int y
Definition: widget.h:51
char * text
Definition: widget.h:210