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 /* SDL */
19 #include <SDL/SDL.h>
20 
21 /* utility */
22 #include "log.h"
23 
24 /* gui-sdl */
25 #include "colors.h"
26 #include "graphics.h"
27 #include "gui_id.h"
28 #include "gui_tilespec.h"
29 #include "mapview.h"
30 #include "themespec.h"
31 
32 #include "widget.h"
33 #include "widget_p.h"
34 
35 struct MOVE {
36   bool moved;
37   struct widget *pWindow;
38   int prev_x;
39   int prev_y;
40 };
41 
42 static int (*baseclass_redraw)(struct widget *pwidget);
43 
44 /**************************************************************************
45   Redraw Window Graphic ( without other Widgets )
46 **************************************************************************/
redraw_window(struct widget * pWindow)47 static int redraw_window(struct widget *pWindow)
48 {
49   int ret;
50   SDL_Color title_bg_color = {255, 255, 255, 200};
51 
52   SDL_Surface *pTmp = NULL;
53   SDL_Rect dst = pWindow->size;
54 
55   ret = (*baseclass_redraw)(pWindow);
56   if (ret != 0) {
57     return ret;
58   }
59 
60   /* Draw theme */
61   clear_surface(pWindow->dst->surface, &dst);
62   alphablit(pWindow->theme, NULL, pWindow->dst->surface, &dst);
63 
64   /* window has title string == has title bar */
65   if (pWindow->string16) {
66 
67     /* Draw Window's TitleBar */
68     dst = pWindow->area;
69     dst.y -= (WINDOW_TITLE_HEIGHT + 1);
70     dst.h = WINDOW_TITLE_HEIGHT;
71     SDL_FillRectAlpha(pWindow->dst->surface, &dst, &title_bg_color);
72 
73     /* Draw Text on Window's TitleBar */
74     pTmp = create_text_surf_from_str16(pWindow->string16);
75     dst.x += adj_size(4);
76     if(pTmp) {
77       dst.y += ((WINDOW_TITLE_HEIGHT - pTmp->h) / 2);
78       alphablit(pTmp, NULL, pWindow->dst->surface, &dst);
79       FREESURFACE(pTmp);
80     }
81 
82     dst = pWindow->area;
83 
84     putline(pWindow->dst->surface,
85             dst.x, dst.y - 1,
86             dst.x + dst.w - 1, dst.y - 1,
87             get_theme_color(COLOR_THEME_WINDOW_TITLEBAR_SEPARATOR));
88   }
89 
90   /* draw frame */
91   if (get_wflags(pWindow) & WF_DRAW_FRAME_AROUND_WIDGET) {
92     widget_draw_frame(pWindow);
93   }
94 
95   return 0;
96 }
97 
98 /**************************************************************************
99 	Window mechanism.
100 
101 	Active Window schould be first on list (All Widgets on this
102 	Widndow that are on List must be above)
103 
104 	LIST:
105 
106 	*pFirst_Widget_on_Active_Window.
107 
108 	*pN__Widget_on_Active_Window.
109 	*pActive_Window. <------
110 	*pRest_Widgets.
111 
112 	This trick give us:
113 	-	if any Widget is under ( area of ) this Window and Mouse
114 		cursor is above them, 'WidgetListScaner(...)' return
115 		pointer to Active Window not to this Widget.
116 **************************************************************************/
117 
118 /**************************************************************************
119   ...
120 **************************************************************************/
window_set_position(struct widget * pWindow,int x,int y)121 static void window_set_position(struct widget *pWindow, int x, int y)
122 {
123   struct gui_layer *gui_layer;
124 
125   pWindow->size.x = 0;
126   pWindow->size.y = 0;
127 
128   gui_layer = get_gui_layer(pWindow->dst->surface);
129   gui_layer->dest_rect.x = x;
130   gui_layer->dest_rect.y = y;
131 }
132 
133 /**************************************************************************
134   ...
135 **************************************************************************/
window_select(struct widget * pWindow)136 static void window_select(struct widget *pWindow)
137 {
138   /* nothing */
139 }
140 
141 /**************************************************************************
142   ...
143 **************************************************************************/
window_unselect(struct widget * pWindow)144 static void window_unselect(struct widget *pWindow)
145 {
146   /* nothing */
147 }
148 
149 /**************************************************************************
150   ...
151 **************************************************************************/
set_client_area(struct widget * pWindow)152 static void set_client_area(struct widget *pWindow)
153 {
154   SDL_Rect area;
155 
156   if (get_wflags(pWindow) & WF_DRAW_FRAME_AROUND_WIDGET) {
157     area.x = current_theme->FR_Left->w;
158     area.y = current_theme->FR_Top->h;
159     area.w = pWindow->size.w - current_theme->FR_Left->w - current_theme->FR_Right->w;
160     area.h = pWindow->size.h - current_theme->FR_Top->h - current_theme->FR_Bottom->h;
161   } else {
162     area = pWindow->size;
163   }
164 
165   if (pWindow->string16) {
166     area.y += (WINDOW_TITLE_HEIGHT + 1);
167     area.h -= (WINDOW_TITLE_HEIGHT + 1);
168   }
169 
170   widget_set_area(pWindow, area);
171 }
172 
173 /**************************************************************************
174   Allocate Window Widget Structure.
175   Text to titlebar is taken from 'pTitle'.
176 **************************************************************************/
create_window_skeleton(struct gui_layer * pDest,SDL_String16 * pTitle,Uint32 flags)177 struct widget *create_window_skeleton(struct gui_layer *pDest,
178                                       SDL_String16 *pTitle, Uint32 flags)
179 {
180   int w = 0, h = 0;
181   struct widget *pWindow = widget_new();
182 
183   pWindow->set_position = window_set_position;
184 
185   baseclass_redraw = pWindow->redraw;
186   pWindow->redraw = redraw_window;
187   pWindow->select = window_select;
188   pWindow->unselect = window_unselect;
189 
190   pWindow->string16 = pTitle;
191   set_wflag(pWindow, WF_FREE_STRING | WF_FREE_GFX | WF_FREE_THEME |
192 				  WF_DRAW_FRAME_AROUND_WIDGET| flags);
193   set_wstate(pWindow, FC_WS_DISABLED);
194   set_wtype(pWindow, WT_WINDOW);
195   pWindow->mod = KMOD_NONE;
196 
197   if (get_wflags(pWindow) & WF_DRAW_FRAME_AROUND_WIDGET) {
198     w += current_theme->FR_Left->w + current_theme->FR_Right->w;
199     h += current_theme->FR_Top->h + current_theme->FR_Bottom->h;
200   }
201 
202   if (pTitle) {
203     SDL_Rect size = str16size(pTitle);
204 
205     w += size.w + adj_size(10);
206     h += MAX(size.h, WINDOW_TITLE_HEIGHT + 1);
207   }
208 
209   pWindow->size.w = w;
210   pWindow->size.h = h;
211 
212   set_client_area(pWindow);
213 
214   if(pDest) {
215     pWindow->dst = pDest;
216   } else {
217     pWindow->dst = add_gui_layer(w, h);
218   }
219 
220   return pWindow;
221 }
222 
create_window(struct gui_layer * pDest,SDL_String16 * pTitle,Uint16 w,Uint16 h,Uint32 flags)223 struct widget * create_window(struct gui_layer *pDest, SDL_String16 *pTitle,
224                               Uint16 w, Uint16 h, Uint32 flags)
225 {
226   struct widget *pWindow = create_window_skeleton(pDest, pTitle, flags);
227 
228   resize_window(pWindow, NULL, NULL, w, h);
229 
230   return pWindow;
231 }
232 
233 /**************************************************************************
234   Resize Window 'pWindow' to 'new_w' and 'new_h'.
235   and refresh window background ( save screen under window ).
236 
237   If pBcgd == NULL then theme is set to
238   white transparent ( ALPHA = 128 ).
239 
240   Return 1 if allocate new surface and 0 if used 'pBcgd' surface.
241 
242   Exp.
243   if ( resize_window( pWindow , pBcgd , new_w , new_h ) ) {
244     FREESURFACE( pBcgd );
245   }
246 **************************************************************************/
resize_window(struct widget * pWindow,SDL_Surface * pBcgd,SDL_Color * pColor,Uint16 new_w,Uint16 new_h)247 int resize_window(struct widget *pWindow,
248 		  SDL_Surface * pBcgd,
249 		  SDL_Color * pColor, Uint16 new_w, Uint16 new_h)
250 {
251   SDL_Color color;
252 
253   /* window */
254   if ((new_w != pWindow->size.w) || (new_h != pWindow->size.h)) {
255     pWindow->size.w = new_w;
256     pWindow->size.h = new_h;
257 
258     set_client_area(pWindow);
259 
260     if (get_wflags(pWindow) & WF_RESTORE_BACKGROUND) {
261       refresh_widget_background(pWindow);
262     }
263 
264     FREESURFACE(pWindow->dst->surface);
265     pWindow->dst->surface = create_surf_alpha(pWindow->size.w,
266                                               pWindow->size.h,
267                                               SDL_SWSURFACE);
268   }
269 
270   if (pBcgd != pWindow->theme) {
271     FREESURFACE(pWindow->theme);
272   }
273 
274   if (pBcgd) {
275     if (pBcgd->w != new_w || pBcgd->h != new_h) {
276       pWindow->theme = ResizeSurface(pBcgd, new_w, new_h, 2);
277       return 1;
278     } else {
279       pWindow->theme = pBcgd;
280       return 0;
281     }
282   } else {
283     pWindow->theme = create_surf_alpha(new_w, new_h, SDL_SWSURFACE);
284 
285     if (!pColor) {
286       color = *get_theme_color(COLOR_THEME_BACKGROUND);
287 
288       pColor = &color;
289     }
290 
291     SDL_FillRect(pWindow->theme, NULL, map_rgba(pWindow->theme->format, *pColor));
292 
293     return 1;
294   }
295 }
296 
297 /**************************************************************************
298 ...
299 **************************************************************************/
move_window_motion(SDL_MouseMotionEvent * pMotionEvent,void * pData)300 static Uint16 move_window_motion(SDL_MouseMotionEvent *pMotionEvent, void *pData)
301 {
302   struct MOVE *pMove = (struct MOVE *)pData;
303   int xrel, yrel;
304 
305   if (!pMove->moved) {
306     pMove->moved = TRUE;
307   }
308 
309   widget_mark_dirty(pMove->pWindow);
310 
311   xrel = pMotionEvent->x - pMove->prev_x;
312   yrel = pMotionEvent->y - pMove->prev_y;
313   pMove->prev_x = pMotionEvent->x;
314   pMove->prev_y = pMotionEvent->y;
315 
316   widget_set_position(pMove->pWindow,
317                       (pMove->pWindow->dst->dest_rect.x + pMove->pWindow->size.x) + xrel,
318                       (pMove->pWindow->dst->dest_rect.y + pMove->pWindow->size.y) + yrel);
319 
320   widget_mark_dirty(pMove->pWindow);
321   flush_dirty();
322 
323   return ID_ERROR;
324 }
325 
326 /**************************************************************************
327 ...
328 **************************************************************************/
move_window_button_up(SDL_MouseButtonEvent * pButtonEvent,void * pData)329 static Uint16 move_window_button_up(SDL_MouseButtonEvent * pButtonEvent, void *pData)
330 {
331   struct MOVE *pMove = (struct MOVE *)pData;
332 
333   if (pMove && pMove->moved) {
334     return (Uint16)ID_MOVED_WINDOW;
335   }
336 
337   return (Uint16)ID_WINDOW;
338 }
339 
340 
341 /**************************************************************************
342   ...
343 **************************************************************************/
move_window(struct widget * pWindow)344 bool move_window(struct widget *pWindow)
345 {
346   bool ret;
347   struct MOVE pMove;
348   pMove.pWindow = pWindow;
349   pMove.moved = FALSE;
350   SDL_GetMouseState(&pMove.prev_x, &pMove.prev_y);
351   /* Filter mouse motion events */
352   SDL_SetEventFilter(FilterMouseMotionEvents);
353   ret = (gui_event_loop((void *)&pMove, NULL, NULL, NULL, NULL,
354 	  move_window_button_up, move_window_motion) == ID_MOVED_WINDOW);
355   /* Turn off Filter mouse motion events */
356   SDL_SetEventFilter(NULL);
357   return ret;
358 }
359