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