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.
7
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 ***********************************************************************/
13
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17
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 */
24
25 /* utility */
26 #include "log.h"
27 #include "mem.h"
28
29 /* client/gui-sdl2 */
30 #include "colors.h"
31 #include "graphics.h"
32 #include "themespec.h"
33
34 #include "widget.h"
35 #include "widget_p.h"
36
37 static int (*baseclass_redraw)(struct widget *pwidget);
38
39 /**************************************************************************
40 Blit themelabel2 gfx to surface its on.
41 **************************************************************************/
redraw_themelabel2(struct widget * pLabel)42 static inline int redraw_themelabel2(struct widget *pLabel)
43 {
44 SDL_Rect src = {0,0, pLabel->size.w, pLabel->size.h};
45 SDL_Rect dst = {pLabel->size.x, pLabel->size.y, 0, 0};
46 /*
47 if (!pLabel) {
48 return -3;
49 }
50 */
51 if (get_wstate(pLabel) == FC_WS_SELECTED) {
52 src.y = pLabel->size.h;
53 }
54
55 return alphablit(pLabel->theme, &src, pLabel->dst->surface, &dst, 255);
56 }
57
58 /**************************************************************************
59 Blit label gfx to surface its on.
60 **************************************************************************/
redraw_label(struct widget * pLabel)61 static int redraw_label(struct widget *pLabel)
62 {
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};
67
68 ret = (*baseclass_redraw)(pLabel);
69 if (ret != 0) {
70 return ret;
71 }
72
73 if (get_wtype(pLabel) == WT_T2_LABEL) {
74 return redraw_themelabel2(pLabel);
75 }
76
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;
87 }
88 }
89 } else {
90 fill_rect_alpha(pLabel->dst->surface, &area, &bar_color);
91 }
92 }
93
94 /* redraw icon label */
95 ret = redraw_iconlabel(pLabel);
96
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;
103 }
104 pLabel->string_utf8->fgcol = backup_color;
105 } else {
106 if (pLabel->string_utf8->render == 3) {
107 pLabel->string_utf8->bgcol = backup_color;
108 }
109 }
110 }
111
112 return ret;
113 }
114
115 /**************************************************************************
116 Calculate new size for a label.
117 **************************************************************************/
remake_label_size(struct widget * pLabel)118 void remake_label_size(struct widget *pLabel)
119 {
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;
125
126 if (flags & WF_DRAW_TEXT_LABEL_WITH_SPACE) {
127 space = adj_size(10);
128 } else {
129 space = 0;
130 }
131
132 if (text != NULL) {
133 bool without_box = ((get_wflags(pLabel) & WF_SELECT_WITHOUT_BAR) == WF_SELECT_WITHOUT_BAR);
134 bool bold = TRUE;
135
136 if (without_box) {
137 bold = ((text->style & TTF_STYLE_BOLD) == TTF_STYLE_BOLD);
138 text->style |= TTF_STYLE_BOLD;
139 }
140
141 utf8_str_size(text, &buf);
142
143 if (without_box && !bold) {
144 text->style &= ~TTF_STYLE_BOLD;
145 }
146
147 w = MAX(w, buf.w + space);
148 h = MAX(h, buf.h);
149 }
150
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);
163 }
164 }
165 /* text */
166 } else {
167 w = MAX(w, pIcon->w + space);
168 h = MAX(h, pIcon->h);
169 }
170 }
171
172 /* pIcon */
173 pLabel->size.w = w;
174 pLabel->size.h = h;
175 }
176
177 /**************************************************************************
178 ThemeLabel is utf8_str with Background ( pIcon ).
179 **************************************************************************/
create_themelabel(SDL_Surface * pIcon,struct gui_layer * pDest,utf8_str * pstr,Uint16 w,Uint16 h,Uint32 flags)180 struct widget *create_themelabel(SDL_Surface *pIcon, struct gui_layer *pDest,
181 utf8_str *pstr, Uint16 w, Uint16 h,
182 Uint32 flags)
183 {
184 struct widget *pLabel = NULL;
185
186 if (pIcon == NULL && pstr == NULL) {
187 return NULL;
188 }
189
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;
200
201 baseclass_redraw = pLabel->redraw;
202 pLabel->redraw = redraw_label;
203
204 remake_label_size(pLabel);
205
206 pLabel->size.w = MAX(pLabel->size.w, w);
207 pLabel->size.h = MAX(pLabel->size.h, h);
208
209 return pLabel;
210 }
211
212 /**************************************************************************
213 This Label is UTF8 string with Icon.
214 **************************************************************************/
create_iconlabel(SDL_Surface * pIcon,struct gui_layer * pDest,utf8_str * pstr,Uint32 flags)215 struct widget *create_iconlabel(SDL_Surface *pIcon, struct gui_layer *pDest,
216 utf8_str *pstr, Uint32 flags)
217 {
218 struct widget *pILabel = NULL;
219
220 pILabel = widget_new();
221
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;
229
230 baseclass_redraw = pILabel->redraw;
231 pILabel->redraw = redraw_label;
232
233 remake_label_size(pILabel);
234
235 return pILabel;
236 }
237
238 /**************************************************************************
239 ThemeLabel is UTF8 string with Background ( pIcon ).
240 **************************************************************************/
create_themelabel2(SDL_Surface * pIcon,struct gui_layer * pDest,utf8_str * pstr,Uint16 w,Uint16 h,Uint32 flags)241 struct widget *create_themelabel2(SDL_Surface *pIcon, struct gui_layer *pDest,
242 utf8_str *pstr, Uint16 w, Uint16 h,
243 Uint32 flags)
244 {
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;
251
252 if (pIcon == NULL && pstr == NULL) {
253 return NULL;
254 }
255
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;
265
266 remake_label_size(pLabel);
267
268 pLabel->size.w = MAX(pLabel->size.w, w);
269 pLabel->size.h = MAX(pLabel->size.h, h);
270
271 ptheme = create_surf(pLabel->size.w, pLabel->size.h * 2, SDL_SWSURFACE);
272
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);
276
277 pLabel->size.x = 0;
278 pLabel->size.y = 0;
279 area = pLabel->size;
280 pLabel->dst = gui_layer_new(0, 0, ptheme);
281
282 /* normal */
283 redraw_iconlabel(pLabel);
284
285 /* selected */
286 area.x = 0;
287 area.y = pLabel->size.h;
288
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);
297 }
298
299 pLabel->size.y = pLabel->size.h;
300 redraw_iconlabel(pLabel);
301
302 if (flags & WF_RESTORE_BACKGROUND) {
303 pstr->bgcol = store;
304 }
305
306 pLabel->size.x = 0;
307 pLabel->size.y = 0;
308 if (flags & WF_FREE_THEME) {
309 FREESURFACE(pLabel->theme);
310 }
311 pLabel->theme = ptheme;
312 FC_FREE(pLabel->dst);
313 pLabel->dst = pDest;
314
315 return pLabel;
316 }
317
318 /**************************************************************************
319 Make themeiconlabel2 widget out of iconlabel widget.
320 **************************************************************************/
convert_iconlabel_to_themeiconlabel2(struct widget * pIconLabel)321 struct widget *convert_iconlabel_to_themeiconlabel2(struct widget *pIconLabel)
322 {
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);
330
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);
337
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;
344
345 /* normal */
346 redraw_iconlabel(pIconLabel);
347
348 /* selected */
349 area.x = 0;
350 area.y = pIconLabel->size.h;
351
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);
362 }
363
364 pIconLabel->size.y = pIconLabel->size.h;
365 redraw_iconlabel(pIconLabel);
366
367 if (flags & WF_RESTORE_BACKGROUND) {
368 pIconLabel->string_utf8->bgcol = store;
369 }
370
371 pIconLabel->size = start;
372 if (flags & WF_FREE_THEME) {
373 FREESURFACE(pIconLabel->theme);
374 }
375 pIconLabel->theme = ptheme;
376 if (flags & WF_FREE_STRING) {
377 FREEUTF8STR(pIconLabel->string_utf8);
378 }
379 pIconLabel->dst->surface = pDest;
380 set_wtype(pIconLabel, WT_T2_LABEL);
381
382 pIconLabel->redraw = redraw_label;
383
384 return pIconLabel;
385 }
386
387 #if 0
388 /**************************************************************************
389 Blit themelabel gfx to surface its on.
390 **************************************************************************/
391 static int redraw_themelabel(struct widget *pLabel)
392 {
393 int ret;
394 Sint16 x, y;
395 SDL_Surface *pText = NULL;
396
397 if (!pLabel) {
398 return -3;
399 }
400
401 if ((pText = create_text_surf_from_utf8(pLabel->string_utf8)) == NULL) {
402 return (-4);
403 }
404
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);
412 }
413 }
414
415 y = (pLabel->size.h - pText->h) / 2;
416
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;
422 }
423 }
424
425 ret = blit_entire_src(pText, pLabel->dst->surface, pLabel->size.x + x, pLabel->size.y + y);
426
427 FREESURFACE(pText);
428
429 return ret;
430 }
431 #endif /* 0 */
432
433 /**************************************************************************
434 Blit iconlabel gfx to surface its on.
435 **************************************************************************/
redraw_iconlabel(struct widget * pLabel)436 int redraw_iconlabel(struct widget *pLabel)
437 {
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;
444
445 if (!pLabel) {
446 return -3;
447 }
448
449 SDL_SetClipRect(pLabel->dst->surface, &pLabel->size);
450
451 flags = get_wflags(pLabel);
452
453 if (flags & WF_DRAW_TEXT_LABEL_WITH_SPACE) {
454 space = adj_size(5);
455 } else {
456 space = 0;
457 }
458
459 pText = create_text_surf_from_utf8(pLabel->string_utf8);
460
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;
470 }
471 }
472
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;
484 }
485 }
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;
494 }
495
496 dst.x = pLabel->size.x + xI;
497 dst.y = pLabel->size.y + yI;
498
499 ret = alphablit(pLabel->theme, NULL, pLabel->dst->surface, &dst, 255);
500
501 if (ret) {
502 return ret - 10;
503 }
504 }
505
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;
518 }
519 }
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);
536 }
537 }
538 } /* WF_ICON_CENTER_LEFT */
539 }
540 /* !WF_ICON_ABOVE_TEXT && !WF_ICON_UNDER_TEXT */
541 } else {
542 goto Alone;
543 }
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;
555 }
556 }
557 }
558
559 dst.x = pLabel->size.x + x;
560 dst.y = pLabel->size.y + y;
561
562 ret = alphablit(pText, NULL, pLabel->dst->surface, &dst, 255);
563 FREESURFACE(pText);
564 }
565
566 SDL_SetClipRect(pLabel->dst->surface, NULL);
567
568 return ret;
569 }
570
571 /**************************************************************************
572 Draw the label widget.
573 **************************************************************************/
draw_label(struct widget * pLabel,Sint16 start_x,Sint16 start_y)574 int draw_label(struct widget *pLabel, Sint16 start_x, Sint16 start_y)
575 {
576 pLabel->size.x = start_x;
577 pLabel->size.y = start_y;
578
579 return redraw_label(pLabel);
580 }
581