JSON protocol: fix field_addr memory leak.
[freeciv.git] / client / gui-sdl2 / widget_label.c
blob331e1ad6fb00330270b91e7bc9d6dbcf7e562eca
1 /***********************************************************************
2 Freeciv - Copyright (C) 2006 - The Freeciv Project
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 /* SDL2 */
19 #ifdef SDL2_PLAIN_INCLUDE
20 #include <SDL.h>
21 #else /* SDL2_PLAIN_INCLUDE */
22 #include <SDL2/SDL.h>
23 #endif /* SDL2_PLAIN_INCLUDE */
25 /* utility */
26 #include "log.h"
27 #include "mem.h"
29 /* client/gui-sdl2 */
30 #include "colors.h"
31 #include "graphics.h"
32 #include "themespec.h"
34 #include "widget.h"
35 #include "widget_p.h"
37 static int (*baseclass_redraw)(struct widget *pwidget);
39 /**************************************************************************
40 Blit themelabel2 gfx to surface its on.
41 **************************************************************************/
42 static inline int redraw_themelabel2(struct widget *pLabel)
44 SDL_Rect src = {0,0, pLabel->size.w, pLabel->size.h};
45 SDL_Rect dst = {pLabel->size.x, pLabel->size.y, 0, 0};
47 if (!pLabel) {
48 return -3;
51 if (get_wstate(pLabel) == FC_WS_SELECTED) {
52 src.y = pLabel->size.h;
55 return alphablit(pLabel->theme, &src, pLabel->dst->surface, &dst, 255);
58 /**************************************************************************
59 Blit label gfx to surface its on.
60 **************************************************************************/
61 static int redraw_label(struct widget *pLabel)
63 int ret;
64 SDL_Rect area = pLabel->size;
65 SDL_Color bar_color = *get_theme_color(COLOR_THEME_LABEL_BAR);
66 SDL_Color backup_color = {0, 0, 0, 0};
68 ret = (*baseclass_redraw)(pLabel);
69 if (ret != 0) {
70 return ret;
73 if (get_wtype(pLabel) == WT_T2_LABEL) {
74 return redraw_themelabel2(pLabel);
77 /* redraw selected bar */
78 if (get_wstate(pLabel) == FC_WS_SELECTED) {
79 if (get_wflags(pLabel) & WF_SELECT_WITHOUT_BAR) {
80 if (pLabel->string_utf8 != NULL) {
81 backup_color = pLabel->string_utf8->fgcol;
82 pLabel->string_utf8->fgcol = bar_color;
83 if (pLabel->string_utf8->style & TTF_STYLE_BOLD) {
84 pLabel->string_utf8->style |= TTF_STYLE_UNDERLINE;
85 } else {
86 pLabel->string_utf8->style |= TTF_STYLE_BOLD;
89 } else {
90 fill_rect_alpha(pLabel->dst->surface, &area, &bar_color);
94 /* redraw icon label */
95 ret = redraw_iconlabel(pLabel);
97 if ((get_wstate(pLabel) == FC_WS_SELECTED) && (pLabel->string_utf8 != NULL)) {
98 if (get_wflags(pLabel) & WF_SELECT_WITHOUT_BAR) {
99 if (pLabel->string_utf8->style & TTF_STYLE_UNDERLINE) {
100 pLabel->string_utf8->style &= ~TTF_STYLE_UNDERLINE;
101 } else {
102 pLabel->string_utf8->style &= ~TTF_STYLE_BOLD;
104 pLabel->string_utf8->fgcol = backup_color;
105 } else {
106 if (pLabel->string_utf8->render == 3) {
107 pLabel->string_utf8->bgcol = backup_color;
112 return ret;
115 /**************************************************************************
116 Calculate new size for a label.
117 **************************************************************************/
118 void remake_label_size(struct widget *pLabel)
120 SDL_Surface *pIcon = pLabel->theme;
121 utf8_str *text = pLabel->string_utf8;
122 Uint32 flags = get_wflags(pLabel);
123 SDL_Rect buf = { 0, 0, 0, 0 };
124 Uint16 w = 0, h = 0, space;
126 if (flags & WF_DRAW_TEXT_LABEL_WITH_SPACE) {
127 space = adj_size(10);
128 } else {
129 space = 0;
132 if (text != NULL) {
133 bool without_box = ((get_wflags(pLabel) & WF_SELECT_WITHOUT_BAR) == WF_SELECT_WITHOUT_BAR);
134 bool bold = TRUE;
136 if (without_box) {
137 bold = ((text->style & TTF_STYLE_BOLD) == TTF_STYLE_BOLD);
138 text->style |= TTF_STYLE_BOLD;
141 utf8_str_size(text, &buf);
143 if (without_box && !bold) {
144 text->style &= ~TTF_STYLE_BOLD;
147 w = MAX(w, buf.w + space);
148 h = MAX(h, buf.h);
151 if (pIcon) {
152 if (text != NULL) {
153 if ((flags & WF_ICON_UNDER_TEXT) || (flags & WF_ICON_ABOVE_TEXT)) {
154 w = MAX(w, pIcon->w + space);
155 h = MAX(h, buf.h + pIcon->h + adj_size(3));
156 } else {
157 if (flags & WF_ICON_CENTER) {
158 w = MAX(w, pIcon->w + space);
159 h = MAX(h, pIcon->h);
160 } else {
161 w = MAX(w, buf.w + pIcon->w + adj_size(5) + space);
162 h = MAX(h, pIcon->h);
165 /* text */
166 } else {
167 w = MAX(w, pIcon->w + space);
168 h = MAX(h, pIcon->h);
172 /* pIcon */
173 pLabel->size.w = w;
174 pLabel->size.h = h;
177 /**************************************************************************
178 ThemeLabel is utf8_str with Background ( pIcon ).
179 **************************************************************************/
180 struct widget *create_themelabel(SDL_Surface *pIcon, struct gui_layer *pDest,
181 utf8_str *pstr, Uint16 w, Uint16 h,
182 Uint32 flags)
184 struct widget *pLabel = NULL;
186 if (pIcon == NULL && pstr == NULL) {
187 return NULL;
190 pLabel = widget_new();
191 pLabel->theme = pIcon;
192 pLabel->string_utf8 = pstr;
193 set_wflag(pLabel,
194 (WF_ICON_CENTER | WF_FREE_STRING | WF_FREE_GFX |
195 WF_RESTORE_BACKGROUND | flags));
196 set_wstate(pLabel, FC_WS_DISABLED);
197 set_wtype(pLabel, WT_T_LABEL);
198 pLabel->mod = KMOD_NONE;
199 pLabel->dst = pDest;
201 baseclass_redraw = pLabel->redraw;
202 pLabel->redraw = redraw_label;
204 remake_label_size(pLabel);
206 pLabel->size.w = MAX(pLabel->size.w, w);
207 pLabel->size.h = MAX(pLabel->size.h, h);
209 return pLabel;
212 /**************************************************************************
213 This Label is UTF8 string with Icon.
214 **************************************************************************/
215 struct widget *create_iconlabel(SDL_Surface *pIcon, struct gui_layer *pDest,
216 utf8_str *pstr, Uint32 flags)
218 struct widget *pILabel = NULL;
220 pILabel = widget_new();
222 pILabel->theme = pIcon;
223 pILabel->string_utf8 = pstr;
224 set_wflag(pILabel, WF_FREE_STRING | WF_FREE_GFX | flags);
225 set_wstate(pILabel, FC_WS_DISABLED);
226 set_wtype(pILabel, WT_I_LABEL);
227 pILabel->mod = KMOD_NONE;
228 pILabel->dst = pDest;
230 baseclass_redraw = pILabel->redraw;
231 pILabel->redraw = redraw_label;
233 remake_label_size(pILabel);
235 return pILabel;
238 /**************************************************************************
239 ThemeLabel is UTF8 string with Background ( pIcon ).
240 **************************************************************************/
241 struct widget *create_themelabel2(SDL_Surface *pIcon, struct gui_layer *pDest,
242 utf8_str *pstr, Uint16 w, Uint16 h,
243 Uint32 flags)
245 struct widget *pLabel = NULL;
246 SDL_Surface *ptheme = NULL;
247 SDL_Rect area;
248 SDL_Color store = {0, 0, 0, 0};
249 SDL_Color bg_color = *get_theme_color(COLOR_THEME_THEMELABEL2_BG);
250 Uint32 colorkey;
252 if (pIcon == NULL && pstr == NULL) {
253 return NULL;
256 pLabel = widget_new();
257 pLabel->theme = pIcon;
258 pLabel->string_utf8 = pstr;
259 set_wflag(pLabel, (WF_FREE_THEME | WF_FREE_STRING | WF_FREE_GFX | flags));
260 set_wstate(pLabel, FC_WS_DISABLED);
261 set_wtype(pLabel, WT_T2_LABEL);
262 pLabel->mod = KMOD_NONE;
263 baseclass_redraw = pLabel->redraw;
264 pLabel->redraw = redraw_label;
266 remake_label_size(pLabel);
268 pLabel->size.w = MAX(pLabel->size.w, w);
269 pLabel->size.h = MAX(pLabel->size.h, h);
271 ptheme = create_surf(pLabel->size.w, pLabel->size.h * 2, SDL_SWSURFACE);
273 colorkey = SDL_MapRGBA(ptheme->format, pstr->bgcol.r,
274 pstr->bgcol.g, pstr->bgcol.b, pstr->bgcol.a);
275 SDL_FillRect(ptheme, NULL, colorkey);
277 pLabel->size.x = 0;
278 pLabel->size.y = 0;
279 area = pLabel->size;
280 pLabel->dst = gui_layer_new(0, 0, ptheme);
282 /* normal */
283 redraw_iconlabel(pLabel);
285 /* selected */
286 area.x = 0;
287 area.y = pLabel->size.h;
289 if (flags & WF_RESTORE_BACKGROUND) {
290 SDL_FillRect(ptheme, &area, map_rgba(ptheme->format, bg_color));
291 store = pstr->bgcol;
292 SDL_GetRGBA(getpixel(ptheme, area.x , area.y), ptheme->format,
293 &pstr->bgcol.r, &pstr->bgcol.g,
294 &pstr->bgcol.b, &pstr->bgcol.a);
295 } else {
296 fill_rect_alpha(ptheme, &area, &bg_color);
299 pLabel->size.y = pLabel->size.h;
300 redraw_iconlabel(pLabel);
302 if (flags & WF_RESTORE_BACKGROUND) {
303 pstr->bgcol = store;
306 pLabel->size.x = 0;
307 pLabel->size.y = 0;
308 if (flags & WF_FREE_THEME) {
309 FREESURFACE(pLabel->theme);
311 pLabel->theme = ptheme;
312 FC_FREE(pLabel->dst);
313 pLabel->dst = pDest;
315 return pLabel;
318 /**************************************************************************
319 Make themeiconlabel2 widget out of iconlabel widget.
320 **************************************************************************/
321 struct widget *convert_iconlabel_to_themeiconlabel2(struct widget *pIconLabel)
323 SDL_Rect start, area;
324 SDL_Color store = {0, 0, 0, 0};
325 SDL_Color bg_color = *get_theme_color(COLOR_THEME_THEMELABEL2_BG);
326 Uint32 colorkey, flags = get_wflags(pIconLabel);
327 SDL_Surface *pDest;
328 SDL_Surface *ptheme = create_surf(pIconLabel->size.w,
329 pIconLabel->size.h * 2, SDL_SWSURFACE);
331 colorkey = SDL_MapRGBA(ptheme->format,
332 pIconLabel->string_utf8->bgcol.r,
333 pIconLabel->string_utf8->bgcol.g,
334 pIconLabel->string_utf8->bgcol.b,
335 pIconLabel->string_utf8->bgcol.a);
336 SDL_FillRect(ptheme, NULL, colorkey);
338 start = pIconLabel->size;
339 pIconLabel->size.x = 0;
340 pIconLabel->size.y = 0;
341 area = start;
342 pDest = pIconLabel->dst->surface;
343 pIconLabel->dst->surface = ptheme;
345 /* normal */
346 redraw_iconlabel(pIconLabel);
348 /* selected */
349 area.x = 0;
350 area.y = pIconLabel->size.h;
352 if (flags & WF_RESTORE_BACKGROUND) {
353 SDL_FillRect(ptheme, &area, map_rgba(ptheme->format, bg_color));
354 store = pIconLabel->string_utf8->bgcol;
355 SDL_GetRGBA(getpixel(ptheme, area.x , area.y), ptheme->format,
356 &pIconLabel->string_utf8->bgcol.r,
357 &pIconLabel->string_utf8->bgcol.g,
358 &pIconLabel->string_utf8->bgcol.b,
359 &pIconLabel->string_utf8->bgcol.a);
360 } else {
361 fill_rect_alpha(ptheme, &area, &bg_color);
364 pIconLabel->size.y = pIconLabel->size.h;
365 redraw_iconlabel(pIconLabel);
367 if (flags & WF_RESTORE_BACKGROUND) {
368 pIconLabel->string_utf8->bgcol = store;
371 pIconLabel->size = start;
372 if (flags & WF_FREE_THEME) {
373 FREESURFACE(pIconLabel->theme);
375 pIconLabel->theme = ptheme;
376 if (flags & WF_FREE_STRING) {
377 FREEUTF8STR(pIconLabel->string_utf8);
379 pIconLabel->dst->surface = pDest;
380 set_wtype(pIconLabel, WT_T2_LABEL);
382 pIconLabel->redraw = redraw_label;
384 return pIconLabel;
387 #if 0
388 /**************************************************************************
389 Blit themelabel gfx to surface its on.
390 **************************************************************************/
391 static int redraw_themelabel(struct widget *pLabel)
393 int ret;
394 Sint16 x, y;
395 SDL_Surface *pText = NULL;
397 if (!pLabel) {
398 return -3;
401 if ((pText = create_text_surf_from_utf8(pLabel->string_utf8)) == NULL) {
402 return (-4);
405 if (pLabel->string_utf8->style & SF_CENTER) {
406 x = (pLabel->size.w - pText->w) / 2;
407 } else {
408 if (pLabel->string_utf8->style & SF_CENTER_RIGHT) {
409 x = pLabel->size.w - pText->w - adj_size(5);
410 } else {
411 x = adj_size(5);
415 y = (pLabel->size.h - pText->h) / 2;
417 /* redraw theme */
418 if (pLabel->theme) {
419 ret = blit_entire_src(pLabel->theme, pLabel->dst->surface, pLabel->size.x, pLabel->size.y);
420 if (ret) {
421 return ret;
425 ret = blit_entire_src(pText, pLabel->dst->surface, pLabel->size.x + x, pLabel->size.y + y);
427 FREESURFACE(pText);
429 return ret;
431 #endif /* 0 */
433 /**************************************************************************
434 Blit iconlabel gfx to surface its on.
435 **************************************************************************/
436 int redraw_iconlabel(struct widget *pLabel)
438 int space, ret = 0; /* FIXME: possibly uninitialized */
439 Sint16 x, xI, yI;
440 Sint16 y = 0; /* FIXME: possibly uninitialized */
441 SDL_Surface *pText;
442 SDL_Rect dst;
443 Uint32 flags;
445 if (!pLabel) {
446 return -3;
449 SDL_SetClipRect(pLabel->dst->surface, &pLabel->size);
451 flags = get_wflags(pLabel);
453 if (flags & WF_DRAW_TEXT_LABEL_WITH_SPACE) {
454 space = adj_size(5);
455 } else {
456 space = 0;
459 pText = create_text_surf_from_utf8(pLabel->string_utf8);
461 if (pLabel->theme) { /* Icon */
462 if (pText) {
463 if (flags & WF_ICON_CENTER_RIGHT) {
464 xI = pLabel->size.w - pLabel->theme->w - space;
465 } else {
466 if (flags & WF_ICON_CENTER) {
467 xI = (pLabel->size.w - pLabel->theme->w) / 2;
468 } else {
469 xI = space;
473 if (flags & WF_ICON_ABOVE_TEXT) {
474 yI = 0;
475 y = pLabel->theme->h + adj_size(3)
476 + (pLabel->size.h - (pLabel->theme->h + adj_size(3)) - pText->h) / 2;
477 } else {
478 if (flags & WF_ICON_UNDER_TEXT) {
479 y = (pLabel->size.h - (pLabel->theme->h + adj_size(3)) - pText->h) / 2;
480 yI = y + pText->h + adj_size(3);
481 } else {
482 yI = (pLabel->size.h - pLabel->theme->h) / 2;
483 y = (pLabel->size.h - pText->h) / 2;
486 /* pText */
487 } else {
488 #if 0
489 yI = (pLabel->size.h - pLabel->theme->h) / 2;
490 xI = (pLabel->size.w - pLabel->theme->w) / 2;
491 #endif /* 0 */
492 yI = 0;
493 xI = space;
496 dst.x = pLabel->size.x + xI;
497 dst.y = pLabel->size.y + yI;
499 ret = alphablit(pLabel->theme, NULL, pLabel->dst->surface, &dst, 255);
501 if (ret) {
502 return ret - 10;
506 if (pText) {
507 if (pLabel->theme) { /* Icon */
508 if (!(flags & WF_ICON_ABOVE_TEXT) && !(flags & WF_ICON_UNDER_TEXT)) {
509 if (flags & WF_ICON_CENTER_RIGHT) {
510 if (pLabel->string_utf8->style & SF_CENTER) {
511 x = (pLabel->size.w - (pLabel->theme->w + 5 + space) -
512 pText->w) / 2;
513 } else {
514 if (pLabel->string_utf8->style & SF_CENTER_RIGHT) {
515 x = pLabel->size.w - (pLabel->theme->w + 5 + space) - pText->w;
516 } else {
517 x = space;
520 /* WF_ICON_CENTER_RIGHT */
521 } else {
522 if (flags & WF_ICON_CENTER) {
523 /* text is blit on icon */
524 goto Alone;
525 } else { /* WF_ICON_CENTER_LEFT */
526 if (pLabel->string_utf8->style & SF_CENTER) {
527 x = space + pLabel->theme->w + adj_size(5) + ((pLabel->size.w -
528 (space +
529 pLabel->theme->w + adj_size(5)) -
530 pText->w) / 2);
531 } else {
532 if (pLabel->string_utf8->style & SF_CENTER_RIGHT) {
533 x = pLabel->size.w - pText->w - space;
534 } else {
535 x = space + pLabel->theme->w + adj_size(5);
538 } /* WF_ICON_CENTER_LEFT */
540 /* !WF_ICON_ABOVE_TEXT && !WF_ICON_UNDER_TEXT */
541 } else {
542 goto Alone;
544 /* pLabel->theme == Icon */
545 } else {
546 y = (pLabel->size.h - pText->h) / 2;
547 Alone:
548 if (pLabel->string_utf8->style & SF_CENTER) {
549 x = (pLabel->size.w - pText->w) / 2;
550 } else {
551 if (pLabel->string_utf8->style & SF_CENTER_RIGHT) {
552 x = pLabel->size.w - pText->w - space;
553 } else {
554 x = space;
559 dst.x = pLabel->size.x + x;
560 dst.y = pLabel->size.y + y;
562 ret = alphablit(pText, NULL, pLabel->dst->surface, &dst, 255);
563 FREESURFACE(pText);
566 SDL_SetClipRect(pLabel->dst->surface, NULL);
568 return ret;
571 /**************************************************************************
572 Draw the label widget.
573 **************************************************************************/
574 int draw_label(struct widget *pLabel, Sint16 start_x, Sint16 start_y)
576 pLabel->size.x = start_x;
577 pLabel->size.y = start_y;
579 return redraw_label(pLabel);