Atrinik Client  4.0
buddy.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/path.h>
35 
36 enum {
37  BUTTON_ADD,
38  BUTTON_REMOVE,
39  BUTTON_CLOSE,
41 
42  BUTTON_NUM
43 };
44 
48 typedef struct buddy_struct {
52  UT_array *names;
53 
57  char *path;
58 
62  button_struct buttons[BUTTON_NUM];
63 
68 
73 } buddy_struct;
74 
75 #define WIDGET_BUDDY(_widget) ((buddy_struct *) (_widget)->subwidget)
76 
78 static void list_handle_enter(list_struct *list, SDL_Event *event)
79 {
80  widgetdata *widget;
81 
82  widget = widget_find(NULL, -1, NULL, list->surface);
83 
84  if (strcmp(widget->id, "buddy") == 0) {
85  textwin_tab_open(widget_find(NULL, CHATWIN_ID, NULL, NULL),
86  list->text[list->row_selected - 1][0]);
87  }
88 }
89 
99 void widget_buddy_add(widgetdata *widget, const char *name, uint8_t sort)
100 {
101  buddy_struct *tmp;
102 
103  tmp = WIDGET_BUDDY(widget);
104 
105  if (name != NULL) {
106  if (widget_buddy_check(widget, name) == -1) {
107  utarray_push_back(tmp->names, &name);
108  list_add(tmp->list, tmp->list->rows, 0, name);
109  }
110  }
111 
112  if (sort) {
114  }
115 
116  widget->redraw = 1;
117 }
118 
126 void widget_buddy_remove(widgetdata *widget, const char *name)
127 {
128  ssize_t idx;
129 
130  idx = widget_buddy_check(widget, name);
131 
132  if (idx != -1) {
133  buddy_struct *tmp;
134  uint32_t row;
135 
136  tmp = WIDGET_BUDDY(widget);
137  utarray_erase(tmp->names, (size_t) idx, 1);
138 
139  for (row = 0; row < tmp->list->rows; row++) {
140  if (strcmp(tmp->list->text[row][0], name) == 0) {
141  list_remove_row(tmp->list, row);
142  break;
143  }
144  }
145 
146  widget->redraw = 1;
147  }
148 }
149 
160 ssize_t widget_buddy_check(widgetdata *widget, const char *name)
161 {
162  char **p;
163 
164  if (!widget) {
165  return -1;
166  }
167 
168  p = NULL;
169 
170  while ((p = (char **) utarray_next(WIDGET_BUDDY(widget)->names, p))) {
171  if (strcasecmp(*p, name) == 0) {
172  return utarray_eltidx(WIDGET_BUDDY(widget)->names, p);
173  }
174  }
175 
176  return -1;
177 }
178 
184 static void widget_buddy_load(widgetdata *widget)
185 {
186  char buf[MAX_BUF], *end;
187  buddy_struct *tmp;
188  FILE *fp;
189 
190  tmp = WIDGET_BUDDY(widget);
191 
192  if (tmp->path) {
193  return;
194  }
195 
196  snprintf(buf, sizeof(buf), "%s.dat", widget->id);
197  tmp->path = file_path_player(buf);
198 
199  fp = path_fopen(tmp->path, "r");
200 
201  if (!fp) {
202  return;
203  }
204 
205  while (fgets(buf, sizeof(buf), fp)) {
206  end = strchr(buf, '\n');
207 
208  if (end) {
209  *end = '\0';
210  }
211 
212  widget_buddy_add(widget, buf, 0);
213  }
214 
215  fclose(fp);
216  widget_buddy_add(widget, NULL, 1);
217 }
218 
224 static void widget_buddy_save(widgetdata *widget)
225 {
226  buddy_struct *tmp;
227  FILE *fp;
228 
229  tmp = WIDGET_BUDDY(widget);
230 
231  if (!tmp->path) {
232  return;
233  }
234 
235  fp = path_fopen(tmp->path, "w");
236 
237  if (!fp) {
238  LOG(BUG, "Could not open file for writing: %s",
239  tmp->path);
240  } else {
241  char **p;
242 
243  p = NULL;
244 
245  while ((p = (char **) utarray_next(tmp->names, p))) {
246  fprintf(fp, "%s\n", *p);
247  }
248 
249  fclose(fp);
250  }
251 
252  efree(tmp->path);
253  tmp->path = NULL;
254 }
255 
257 static void widget_draw(widgetdata *widget)
258 {
259  buddy_struct *tmp;
260 
261  tmp = WIDGET_BUDDY(widget);
262 
263  if (widget->redraw) {
264  SDL_Rect box;
265  char buf[MAX_BUF];
266  size_t i;
267 
268  box.w = widget->w;
269  box.h = 0;
270  snprintf(buf, sizeof(buf), "%s list", widget->id);
271  string_title(buf);
272  text_show(widget->surface, FONT_SERIF12, buf, 0, 3, COLOR_HGOLD,
273  TEXT_ALIGN_CENTER, &box);
274 
275  tmp->list->surface = widget->surface;
276  list_set_parent(tmp->list, widget->x, widget->y);
277  list_show(tmp->list, 10, 2);
278 
279  for (i = 0; i < BUTTON_NUM; i++) {
280  tmp->buttons[i].surface = widget->surface;
281  button_set_parent(&tmp->buttons[i], widget->x, widget->y);
282  }
283 
284  tmp->buttons[BUTTON_CLOSE].x = widget->w -
285  texture_surface(tmp->buttons[BUTTON_CLOSE].texture)->w - 4;
286  tmp->buttons[BUTTON_CLOSE].y = 4;
287  button_show(&tmp->buttons[BUTTON_CLOSE], "X");
288 
289  tmp->buttons[BUTTON_HELP].x = widget->w -
291  texture_surface(tmp->buttons[BUTTON_CLOSE].texture)->w - 4;
292  tmp->buttons[BUTTON_HELP].y = 4;
293  button_show(&tmp->buttons[BUTTON_HELP], "?");
294 
295  tmp->buttons[BUTTON_REMOVE].x = 10;
296  tmp->buttons[BUTTON_REMOVE].y = 2 + LIST_HEIGHT_FULL(tmp->list) + 3;
297  button_show(&tmp->buttons[BUTTON_REMOVE], "Remove");
298 
299  tmp->buttons[BUTTON_ADD].x = tmp->buttons[BUTTON_REMOVE].x +
300  texture_surface(tmp->buttons[BUTTON_REMOVE].texture)->w + 5;
301  tmp->buttons[BUTTON_ADD].y = tmp->buttons[BUTTON_REMOVE].y;
302  button_show(&tmp->buttons[BUTTON_ADD], "Add");
303 
304  text_input_set_parent(&tmp->text_input, widget->x, widget->y);
305  text_input_show(&tmp->text_input, widget->surface,
306  tmp->buttons[BUTTON_ADD].x +
307  texture_surface(tmp->buttons[BUTTON_REMOVE].texture)->w + 5,
308  tmp->buttons[BUTTON_ADD].y);
309  }
310 }
311 
313 static void widget_background(widgetdata *widget, int draw)
314 {
315  buddy_struct *tmp;
316 
317  tmp = WIDGET_BUDDY(widget);
318 
319  if (!widget->redraw) {
320  widget->redraw = list_need_redraw(tmp->list);
321  }
322 
323  if (!widget->redraw) {
324  size_t i;
325 
326  for (i = 0; i < BUTTON_NUM; i++) {
327  if (button_need_redraw(&tmp->buttons[i])) {
328  widget->redraw = 1;
329  break;
330  }
331  }
332  }
333 
334  if (cpl.state == ST_PLAY) {
335  widget_buddy_load(widget);
336  } else {
337  widget_buddy_save(widget);
338  }
339 }
340 
346 static void widget_event_buddy_add(widgetdata *widget)
347 {
348  buddy_struct *tmp;
349 
350  tmp = WIDGET_BUDDY(widget);
351 
352  if (*tmp->text_input.str != '\0') {
353  widget_buddy_add(widget, tmp->text_input.str, 1);
354  text_input_set(&tmp->text_input, NULL);
355  }
356 
357  tmp->text_input.focus = 0;
358 }
359 
361 static int widget_event(widgetdata *widget, SDL_Event *event)
362 {
363  buddy_struct *tmp;
364  size_t i;
365 
366  tmp = WIDGET_BUDDY(widget);
367 
368  if (list_handle_mouse(tmp->list, event)) {
369  widget->redraw = 1;
370  return 1;
371  }
372 
373  for (i = 0; i < BUTTON_NUM; i++) {
374  if (button_event(&tmp->buttons[i], event)) {
375  switch (i) {
376  case BUTTON_ADD:
377  if (tmp->text_input.focus) {
378  widget_event_buddy_add(widget);
379  } else {
380  tmp->text_input.focus = 1;
381  }
382 
383  break;
384 
385  case BUTTON_REMOVE:
386  {
387  const char *selected;
388 
389  selected = list_get_selected(tmp->list, 0);
390 
391  if (selected != NULL) {
392  widget_buddy_remove(widget, selected);
393  }
394 
395  break;
396  }
397 
398  case BUTTON_CLOSE:
399  widget->show = 0;
400  break;
401 
402  case BUTTON_HELP:
403  {
404  char buf[MAX_BUF];
405 
406  snprintf(buf, sizeof(buf), "%s list", widget->id);
407  help_show(buf);
408  break;
409  }
410  }
411 
412  widget->redraw = 1;
413  return 1;
414  }
415 
416  if (tmp->buttons[i].redraw) {
417  widget->redraw = 1;
418  }
419  }
420 
421  if (event->type == SDL_KEYDOWN && tmp->text_input.focus) {
422  if (event->key.keysym.sym == SDLK_ESCAPE) {
423  tmp->text_input.focus = 0;
424  widget->redraw = 1;
425  return 1;
426  } else if (IS_ENTER(event->key.keysym.sym)) {
427  widget_event_buddy_add(widget);
428  widget->redraw = 1;
429  return 1;
430  }
431  }
432 
433  if (text_input_event(&tmp->text_input, event)) {
434  widget->redraw = 1;
435  return 1;
436  }
437 
438  if (event->type == SDL_MOUSEBUTTONDOWN) {
439  if (event->button.button == SDL_BUTTON_LEFT &&
440  text_input_mouse_over(&tmp->text_input, event->motion.x,
441  event->motion.y)) {
442  tmp->text_input.focus = 1;
443  widget->redraw = 1;
444  return 1;
445  }
446 
447  if (tmp->text_input.focus) {
448  tmp->text_input.focus = 0;
449  widget->redraw = 1;
450  }
451  }
452 
453  return 0;
454 }
455 
457 static void widget_deinit(widgetdata *widget)
458 {
459  buddy_struct *tmp;
460 
461  widget_buddy_save(widget);
462 
463  tmp = WIDGET_BUDDY(widget);
464  utarray_free(tmp->names);
465  list_remove(tmp->list);
466 
468 
469  for (size_t i = 0; i < BUTTON_NUM; i++) {
470  button_destroy(&tmp->buttons[i]);
471  }
472 }
473 
478 {
479  buddy_struct *tmp;
480  size_t i;
481 
482  widget->draw_func = widget_draw;
483  widget->event_func = widget_event;
484  widget->background_func = widget_background;
485  widget->deinit_func = widget_deinit;
486 
487  widget->subwidget = tmp = ecalloc(1, sizeof(*tmp));
488  utarray_new(tmp->names, &ut_str_icd);
489 
490  /* Create the list and set up settings. */
491  tmp->list = list_create(12, 1, 8);
494  list_set_column(tmp->list, 0, widget->w - 10 * 2 -
495  LIST_WIDTH_FULL(tmp->list) - tmp->list->frame_offset, 0, NULL, -1);
496  list_set_font(tmp->list, FONT_ARIAL10);
497 
498  for (i = 0; i < BUTTON_NUM; i++) {
499  button_create(&tmp->buttons[i]);
500 
501  if (i == BUTTON_CLOSE || i == BUTTON_HELP) {
502  tmp->buttons[i].texture = texture_get(TEXTURE_TYPE_CLIENT,
503  "button_round");
504  tmp->buttons[i].texture_pressed = texture_get(TEXTURE_TYPE_CLIENT,
505  "button_round_down");
506  tmp->buttons[i].texture_over = texture_get(TEXTURE_TYPE_CLIENT,
507  "button_round_over");
508  }
509  }
510 
511  text_input_create(&tmp->text_input);
512  tmp->text_input.focus = 0;
513  tmp->text_input.coords.w = LIST_WIDTH_FULL(tmp->list) -
514  texture_surface(tmp->buttons[BUTTON_ADD].texture)->w * 2 - 5 * 2;
515 }
list_struct * list_create(uint32_t max_rows, uint32_t cols, int spacing)
Definition: list.c:113
static void widget_event_buddy_add(widgetdata *widget)
Definition: buddy.c:346
Definition: main.h:332
ssize_t widget_buddy_check(widgetdata *widget, const char *name)
Definition: buddy.c:160
uint8_t redraw
Definition: button.h:132
void * subwidget
Definition: widget.h:107
void list_remove(list_struct *list)
Definition: list.c:522
SDL_Surface * texture_surface(texture_struct *texture)
Definition: texture.c:303
SDL_Surface * surface
Definition: widget.h:110
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
SDL_Rect coords
Definition: text_input.h:96
void button_destroy(button_struct *button)
Definition: button.c:94
#define LIST_SORT_ALPHA
Definition: list.h:285
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
int16_t frame_offset
Definition: list.h:94
void widget_buddy_remove(widgetdata *widget, const char *name)
Definition: buddy.c:126
char * path
Definition: buddy.c:57
void widget_buddy_init(widgetdata *widget)
Definition: buddy.c:477
static void widget_deinit(widgetdata *widget)
Definition: buddy.c:457
#define COLOR_HGOLD
Definition: text.h:319
static void widget_buddy_save(widgetdata *widget)
Definition: buddy.c:224
texture_struct * texture_get(texture_type_t type, const char *name)
Definition: texture.c:279
char *** text
Definition: list.h:85
struct buddy_struct buddy_struct
#define TEXT_ALIGN_CENTER
Definition: text.h:230
list_struct * list
Definition: buddy.c:67
char * id
Definition: widget.h:42
char * file_path_player(const char *path)
Definition: wrapper.c:452
widgetdata * widget_find(widgetdata *where, int type, const char *id, SDL_Surface *surface)
Definition: widget.c:2091
void help_show(const char *name)
Definition: help.c:219
UT_array * names
Definition: buddy.c:52
uint8_t show
Definition: widget.h:69
void list_remove_row(list_struct *list, uint32_t row)
Definition: list.c:198
Client_Player cpl
Definition: client.c:50
int list_need_redraw(list_struct *list)
Definition: list.c:315
texture_struct * texture_over
Definition: button.h:67
#define LIST_WIDTH_FULL(list)
Definition: list.h:276
uint8_t redraw
Definition: widget.h:72
void button_create(button_struct *button)
Definition: button.c:65
int x
Definition: widget.h:48
static void widget_background(widgetdata *widget, int draw)
Definition: buddy.c:313
static void widget_buddy_load(widgetdata *widget)
Definition: buddy.c:184
texture_struct * texture
Definition: button.h:61
char str[HUGE_BUF]
Definition: text_input.h:55
void list_sort(list_struct *list, int type)
Definition: list.c:832
#define LIST_HEIGHT_FULL(list)
Definition: list.h:271
SDL_Surface * surface
Definition: list.h:138
SDL_Surface * surface
Definition: button.h:46
int w
Definition: widget.h:54
button_struct buttons[BUTTON_NUM]
Definition: buddy.c:62
texture_struct * texture_pressed
Definition: button.h:73
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
static int widget_event(widgetdata *widget, SDL_Event *event)
Definition: buddy.c:361
void list_set_parent(list_struct *list, int px, int py)
Definition: list.c:96
void list_scrollbar_enable(list_struct *list)
Definition: list.c:302
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
text_input_struct text_input
Definition: buddy.c:72
static void widget_draw(widgetdata *widget)
Definition: buddy.c:257
uint32_t rows
Definition: list.h:60
void(* handle_enter_func)(struct list_struct *list, SDL_Event *event)
Definition: list.h:201
const char * list_get_selected(list_struct *list, uint32_t col)
Definition: list.c:879
static void list_handle_enter(list_struct *list, SDL_Event *event)
Definition: buddy.c:78
void text_input_destroy(text_input_struct *text_input)
Definition: text_input.c:96
uint32_t row_selected
Definition: list.h:109
int y
Definition: widget.h:51