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