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