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 
28 /* gui-sdl2 */
29 #include "colors.h"
30 #include "graphics.h"
31 #include "gui_tilespec.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   Create Icon Button image with text and Icon then blit to Dest(ination)
41   on position pIButton->size.x , pIButton->size.y.
42   WARNING: pDest must exist.
43 
44   Text with attributes is taken from pIButton->string_utf8 parameter.
45 
46   Graphic for button is taken from pIButton->theme surface
47   and blit to new created image.
48 
49   Graphic for Icon is taken from pIButton->theme2 surface and blit to new
50   created image.
51 
52   function return (-1) if there are no Icon nor Text.
53   Else return 0.
54 **************************************************************************/
redraw_ibutton(struct widget * pIButton)55 static int redraw_ibutton(struct widget *pIButton)
56 {
57   SDL_Rect dest = { 0, 0, 0, 0 };
58   utf8_str TMPString;
59   SDL_Surface *pButton = NULL, *pText = NULL, *pIcon = pIButton->theme2;
60   Uint16 Ix, Iy, x;
61   Uint16 y = 0; /* FIXME: possibly uninitialized */
62   int ret;
63 
64   ret = (*baseclass_redraw)(pIButton);
65   if (ret != 0) {
66     return ret;
67   }
68 
69   if (pIButton->string_utf8 != NULL) {
70     /* make copy of string_utf8 */
71     TMPString = *pIButton->string_utf8;
72 
73     if (get_wstate(pIButton) == FC_WS_NORMAL) {
74       TMPString.fgcol = *get_theme_color(COLOR_THEME_WIDGET_NORMAL_TEXT);
75     } else if (get_wstate(pIButton) == FC_WS_SELECTED) {
76       TMPString.fgcol = *get_theme_color(COLOR_THEME_WIDGET_SELECTED_TEXT);
77       TMPString.style |= TTF_STYLE_BOLD;
78     } else if (get_wstate(pIButton) == FC_WS_PRESSED) {
79       TMPString.fgcol = *get_theme_color(COLOR_THEME_WIDGET_PRESSED_TEXT);
80     } else if (get_wstate(pIButton) == FC_WS_DISABLED) {
81       TMPString.fgcol = *get_theme_color(COLOR_THEME_WIDGET_DISABLED_TEXT);
82     }
83 
84     pText = create_text_surf_from_utf8(&TMPString);
85   }
86 
87   if (!pText && !pIcon) {
88     return -1;
89   }
90 
91   /* create Button graphic */
92   pButton = create_bcgnd_surf(pIButton->theme, get_wstate(pIButton),
93                               pIButton->size.w, pIButton->size.h);
94 
95   clear_surface(pIButton->dst->surface, &pIButton->size);
96   alphablit(pButton, NULL, pIButton->dst->surface, &pIButton->size, 255);
97   FREESURFACE(pButton);
98 
99   if (pIcon) { /* Icon */
100     if (pText) {
101       if (get_wflags(pIButton) & WF_ICON_CENTER_RIGHT) {
102         Ix = pIButton->size.w - pIcon->w - 5;
103       } else {
104         if (get_wflags(pIButton) & WF_ICON_CENTER) {
105           Ix = (pIButton->size.w - pIcon->w) / 2;
106         } else {
107           Ix = 5;
108         }
109       }
110 
111       if (get_wflags(pIButton) & WF_ICON_ABOVE_TEXT) {
112         Iy = 3;
113         y = 3 + pIcon->h + 3 + (pIButton->size.h -
114                                 (pIcon->h + 6) - pText->h) / 2;
115       } else {
116         if (get_wflags(pIButton) & WF_ICON_UNDER_TEXT) {
117           y = 3 + (pIButton->size.h - (pIcon->h + 3) - pText->h) / 2;
118           Iy = y + pText->h + 3;
119         } else { /* center */
120           Iy = (pIButton->size.h - pIcon->h) / 2;
121           y = (pIButton->size.h - pText->h) / 2;
122         }
123       }
124     } else { /* no text */
125       Iy = (pIButton->size.h - pIcon->h) / 2;
126       Ix = (pIButton->size.w - pIcon->w) / 2;
127     }
128 
129     if (get_wstate(pIButton) == FC_WS_PRESSED) {
130       Ix += 1;
131       Iy += 1;
132     }
133 
134     dest.x = pIButton->size.x + Ix;
135     dest.y = pIButton->size.y + Iy;
136 
137     ret = alphablit(pIcon, NULL, pIButton->dst->surface, &dest, 255);
138     if (ret) {
139       FREESURFACE(pText);
140       return ret - 10;
141     }
142   }
143 
144   if (pText) {
145     if (pIcon) {
146       if (!(get_wflags(pIButton) & WF_ICON_ABOVE_TEXT)
147           && !(get_wflags(pIButton) & WF_ICON_UNDER_TEXT)) {
148         if (get_wflags(pIButton) & WF_ICON_CENTER_RIGHT) {
149           if (pIButton->string_utf8->style & SF_CENTER) {
150             x = (pIButton->size.w - (pIcon->w + 5) - pText->w) / 2;
151           } else {
152             if (pIButton->string_utf8->style & SF_CENTER_RIGHT) {
153               x = pIButton->size.w - (pIcon->w + 7) - pText->w;
154             } else {
155               x = 5;
156             }
157           }
158           /* end WF_ICON_CENTER_RIGHT */
159         } else {
160           if (get_wflags(pIButton) & WF_ICON_CENTER) {
161             /* text is blit on icon */
162             goto Alone;
163             /* end WF_ICON_CENTER */
164           } else { /* icon center left - default */
165             if (pIButton->string_utf8->style & SF_CENTER) {
166               x = 5 + pIcon->w + ((pIButton->size.w -
167                                    (pIcon->w + 5) - pText->w) / 2);
168             } else {
169               if (pIButton->string_utf8->style & SF_CENTER_RIGHT) {
170                 x = pIButton->size.w - pText->w - 5;
171               } else { /* text center left */
172                 x = 5 + pIcon->w + 3;
173               }
174             }
175           } /* end icon center left - default */
176         }
177         /* 888888888888888888 */
178       } else {
179         goto Alone;
180       }
181     } else {
182       /* !pIcon */
183       y = (pIButton->size.h - pText->h) / 2;
184     Alone:
185       if (pIButton->string_utf8->style & SF_CENTER) {
186         x = (pIButton->size.w - pText->w) / 2;
187       } else {
188         if (pIButton->string_utf8->style & SF_CENTER_RIGHT) {
189           x = pIButton->size.w - pText->w - 5;
190         } else {
191           x = 5;
192         }
193       }
194     }
195 
196     if (get_wstate(pIButton) == FC_WS_PRESSED) {
197       x += 1;
198     } else {
199       y -= 1;
200     }
201 
202     dest.x = pIButton->size.x + x;
203     dest.y = pIButton->size.y + y;
204 
205     ret = alphablit(pText, NULL, pIButton->dst->surface, &dest, 255);
206   }
207 
208   FREESURFACE(pText);
209 
210   return 0;
211 }
212 
213 /**************************************************************************
214   Create Icon Button image with text and Icon then blit to Dest(ination)
215   on position pTIButton->size.x, pTIButton->size.y. WARNING: pDest must
216   exist.
217 
218   Text with attributes is taken from pTIButton->string_utf8 parameter.
219 
220   Graphic for button is taken from pTIButton->theme surface
221   and blit to new created image.
222 
223   Graphic for Icon Theme is taken from pTIButton->theme2 surface
224   and blit to new created image.
225 
226   function return (-1) if there are no Icon and Text.  Else return 0.
227 **************************************************************************/
redraw_tibutton(struct widget * pTIButton)228 static int redraw_tibutton(struct widget *pTIButton)
229 {
230   int iRet = 0;
231   SDL_Surface *pIcon;
232   SDL_Surface *pCopy_Of_Icon_Theme;
233 
234   iRet = (*baseclass_redraw)(pTIButton);
235   if (iRet != 0) {
236     return iRet;
237   }
238 
239   pIcon = create_icon_from_theme(pTIButton->theme2, get_wstate(pTIButton));
240   pCopy_Of_Icon_Theme = pTIButton->theme2;
241 
242   pTIButton->theme2 = pIcon;
243 
244   iRet = redraw_ibutton(pTIButton);
245 
246   FREESURFACE(pTIButton->theme2);
247   pTIButton->theme2 = pCopy_Of_Icon_Theme;
248 
249   return iRet;
250 }
251 
252 /**************************************************************************
253   Create ( malloc ) Icon (theme)Button Widget structure.
254 
255   Icon graphic is taken from 'pIcon' surface (don't change with button
256   changes );  Button Theme graphic is taken from current_theme->Button surface;
257   Text is taken from 'pstr'.
258 
259   This function determinate future size of Button ( width, height ) and
260   save this in: pWidget->size rectangle ( SDL_Rect )
261 
262   function return pointer to allocated Button Widget.
263 **************************************************************************/
create_icon_button(SDL_Surface * pIcon,struct gui_layer * pDest,utf8_str * pstr,Uint32 flags)264 struct widget *create_icon_button(SDL_Surface *pIcon, struct gui_layer *pDest,
265                                   utf8_str *pstr, Uint32 flags)
266 {
267   SDL_Rect buf = {0, 0, 0, 0};
268   int w = 0, h = 0;
269   struct widget *pButton;
270 
271   if (!pIcon && !pstr) {
272     return NULL;
273   }
274 
275   pButton = widget_new();
276 
277   pButton->theme = current_theme->Button;
278   pButton->theme2 = pIcon;
279   pButton->string_utf8 = pstr;
280   set_wflag(pButton, (WF_FREE_STRING | flags));
281   set_wstate(pButton, FC_WS_DISABLED);
282   set_wtype(pButton, WT_I_BUTTON);
283   pButton->mod = KMOD_NONE;
284   pButton->dst = pDest;
285 
286   baseclass_redraw = pButton->redraw;
287   pButton->redraw = redraw_ibutton;
288 
289   if (pstr) {
290     pButton->string_utf8->style |= SF_CENTER;
291     /* if BOLD == true then longest wight */
292     if (!(pstr->style & TTF_STYLE_BOLD)) {
293       pstr->style |= TTF_STYLE_BOLD;
294       utf8_str_size(pstr, &buf);
295       pstr->style &= ~TTF_STYLE_BOLD;
296     } else {
297       utf8_str_size(pstr, &buf);
298     }
299 
300     w = MAX(w, buf.w);
301     h = MAX(h, buf.h);
302   }
303 
304   if (pIcon) {
305     if (pstr) {
306       if ((flags & WF_ICON_UNDER_TEXT) || (flags & WF_ICON_ABOVE_TEXT)) {
307         w = MAX(w, pIcon->w + adj_size(2));
308         h = MAX(h, buf.h + pIcon->h + adj_size(4));
309       } else {
310         w = MAX(w, buf.w + pIcon->w + adj_size(20));
311         h = MAX(h, pIcon->h + adj_size(2));
312       }
313     } else {
314       w = MAX(w, pIcon->w + adj_size(2));
315       h = MAX(h, pIcon->h + adj_size(2));
316     }
317   } else {
318     w += adj_size(10);
319     h += adj_size(2);
320   }
321 
322   correct_size_bcgnd_surf(current_theme->Button, &w, &h);
323 
324   pButton->size.w = w;
325   pButton->size.h = h;
326 
327   return pButton;
328 }
329 
330 /**************************************************************************
331   Create ( malloc ) Theme Icon (theme)Button Widget structure.
332 
333   Icon Theme graphic is taken from 'pIcon_theme' surface ( change with
334   button changes ); Button Theme graphic is taken from current_theme->Button
335   surface; Text is taken from 'pstr'.
336 
337   This function determinate future size of Button ( width, height ) and
338   save this in: pWidget->size rectangle ( SDL_Rect )
339 
340   function return pointer to allocated Button Widget.
341 **************************************************************************/
create_themeicon_button(SDL_Surface * pIcon_theme,struct gui_layer * pDest,utf8_str * pstr,Uint32 flags)342 struct widget *create_themeicon_button(SDL_Surface *pIcon_theme,
343                                        struct gui_layer *pDest,
344                                        utf8_str *pstr,
345                                        Uint32 flags)
346 {
347   /* extract a single icon */
348   SDL_Surface *pIcon = create_icon_from_theme(pIcon_theme, 1);
349   struct widget *pButton = create_icon_button(pIcon, pDest, pstr, flags);
350 
351   FREESURFACE(pButton->theme2);
352   pButton->theme2 = pIcon_theme;
353   set_wtype(pButton, WT_TI_BUTTON);
354 
355   pButton->redraw = redraw_tibutton;
356 
357   return pButton;
358 }
359 
360 /**************************************************************************
361   Create Button image with text and Icon. Then blit to Main.screen on
362   position start_x, start_y.
363 
364   Text with atributes is taken from pButton->string_utf8 parameter.
365 
366   Graphic for button is taken from pButton->theme surface and blit to new
367   created image.
368 
369   Graphic for Icon theme is taken from pButton->theme2 surface and blit to
370   new created image.
371 
372   function return (-1) if there are no Icon and Text.
373   Else return 0.
374 **************************************************************************/
draw_tibutton(struct widget * pButton,Sint16 start_x,Sint16 start_y)375 int draw_tibutton(struct widget *pButton, Sint16 start_x, Sint16 start_y)
376 {
377   pButton->size.x = start_x;
378   pButton->size.y = start_y;
379 
380   return redraw_tibutton(pButton);
381 }
382 
383 /**************************************************************************
384   Create Button image with text and Icon.
385   Then blit to Main.screen on position start_x, start_y.
386 
387   Text with atributes is taken from pButton->string_utf8 parameter.
388 
389   Graphic for button is taken from pButton->theme surface
390   and blit to new created image.
391 
392   Graphic for Icon is taken from pButton->theme2 surface
393   and blit to new created image.
394 
395   function return (-1) if there are no Icon and Text.
396   Else return 0.
397 **************************************************************************/
draw_ibutton(struct widget * pButton,Sint16 start_x,Sint16 start_y)398 int draw_ibutton(struct widget *pButton, Sint16 start_x, Sint16 start_y)
399 {
400   pButton->size.x = start_x;
401   pButton->size.y = start_y;
402 
403   return redraw_ibutton(pButton);
404 }
405