1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
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 #include <stdlib.h>
19
20 /* SDL */
21 #include <SDL/SDL.h>
22
23 /* utility */
24 #include "bitvector.h"
25 #include "fcintl.h"
26 #include "log.h"
27
28 /* common */
29 #include "game.h"
30 #include "fc_types.h" /* bv_player */
31 #include "unitlist.h"
32
33 /* client */
34 #include "client_main.h"
35 #include "control.h"
36 #include "goto.h"
37
38 /* gui-sdl */
39 #include "colors.h"
40 #include "graphics.h"
41 #include "gui_id.h"
42 #include "gui_main.h"
43 #include "gui_tilespec.h"
44 #include "mapview.h"
45 #include "sprite.h"
46 #include "widget.h"
47
48 #include "gotodlg.h"
49
50 static struct ADVANCED_DLG *pGotoDlg = NULL;
51 bv_player all_players;
52 static bool GOTO = TRUE;
53
54 static void update_goto_dialog(void);
55
56 /**************************************************************************
57 User interacted with goto dialog window.
58 **************************************************************************/
goto_dialog_window_callback(struct widget * pWindow)59 static int goto_dialog_window_callback(struct widget *pWindow)
60 {
61 if (Main.event.button.button == SDL_BUTTON_LEFT) {
62 move_window_group(pGotoDlg->pBeginWidgetList, pWindow);
63 }
64 return -1;
65 }
66
67 /**************************************************************************
68 Close goto dialog.
69 **************************************************************************/
exit_goto_dialog_callback(struct widget * pWidget)70 static int exit_goto_dialog_callback(struct widget *pWidget)
71 {
72 if (Main.event.button.button == SDL_BUTTON_LEFT) {
73 popdown_goto_airlift_dialog();
74 flush_dirty();
75 }
76 return -1;
77 }
78
79 /**************************************************************************
80 Toggle whether player cities are listed as possible destinations.
81 **************************************************************************/
toggle_goto_nations_cities_dialog_callback(struct widget * pWidget)82 static int toggle_goto_nations_cities_dialog_callback(struct widget *pWidget)
83 {
84 if (Main.event.button.button == SDL_BUTTON_LEFT) {
85 int plr_id = player_index(player_by_number(MAX_ID - pWidget->ID));
86 if (BV_ISSET(all_players, plr_id)) {
87 BV_CLR(all_players, plr_id);
88 } else {
89 BV_SET(all_players, plr_id);
90 }
91 update_goto_dialog();
92 }
93 return -1;
94 }
95
96 /**************************************************************************
97 User has selected city for unit to go to.
98 **************************************************************************/
goto_city_callback(struct widget * pWidget)99 static int goto_city_callback(struct widget *pWidget)
100 {
101 if (Main.event.button.button == SDL_BUTTON_LEFT) {
102 struct city *pDestcity = game_city_by_number(MAX_ID - pWidget->ID);
103
104 if (pDestcity) {
105 struct unit *pUnit = head_of_units_in_focus();
106 if (pUnit) {
107 if(GOTO) {
108 send_goto_tile(pUnit, pDestcity->tile);
109 } else {
110 request_unit_airlift(pUnit, pDestcity);
111 }
112 }
113 }
114
115 popdown_goto_airlift_dialog();
116 flush_dirty();
117 }
118 return -1;
119 }
120
121 /**************************************************************************
122 Refresh goto dialog.
123 **************************************************************************/
update_goto_dialog(void)124 static void update_goto_dialog(void)
125 {
126 struct widget *pBuf = NULL, *pAdd_Dock, *pLast;
127 SDL_Surface *pLogo = NULL;
128 SDL_String16 *pStr;
129 char cBuf[128];
130 int n = 0;
131 struct player *owner = NULL;
132
133 if(pGotoDlg->pEndActiveWidgetList) {
134 pAdd_Dock = pGotoDlg->pEndActiveWidgetList->next;
135 pGotoDlg->pBeginWidgetList = pAdd_Dock;
136 del_group(pGotoDlg->pBeginActiveWidgetList, pGotoDlg->pEndActiveWidgetList);
137 pGotoDlg->pActiveWidgetList = NULL;
138 } else {
139 pAdd_Dock = pGotoDlg->pBeginWidgetList;
140 }
141
142 pLast = pAdd_Dock;
143
144 players_iterate(pPlayer) {
145 if (!BV_ISSET(all_players, player_index(pPlayer))) {
146 continue;
147 }
148
149 city_list_iterate(pPlayer->cities, pCity) {
150
151 /* FIXME: should use unit_can_airlift_to(). */
152 if (!GOTO && !pCity->airlift) {
153 continue;
154 }
155
156 fc_snprintf(cBuf, sizeof(cBuf), "%s (%d)", city_name_get(pCity),
157 city_size_get(pCity));
158
159 pStr = create_str16_from_char(cBuf, adj_font(12));
160 pStr->style |= TTF_STYLE_BOLD;
161
162 if(!player_owns_city(owner, pCity)) {
163 pLogo = get_nation_flag_surface(nation_of_player(city_owner(pCity)));
164 pLogo = crop_visible_part_from_surface(pLogo);
165 }
166
167 pBuf = create_iconlabel(pLogo, pGotoDlg->pEndWidgetList->dst, pStr,
168 (WF_RESTORE_BACKGROUND|WF_DRAW_TEXT_LABEL_WITH_SPACE));
169
170 if (!player_owns_city(owner, pCity)) {
171 set_wflag(pBuf, WF_FREE_THEME);
172 owner = city_owner(pCity);
173 }
174
175 pBuf->string16->fgcol =
176 *(get_player_color(tileset, city_owner(pCity))->color);
177 pBuf->action = goto_city_callback;
178
179 if (GOTO || pCity->airlift) {
180 set_wstate(pBuf, FC_WS_NORMAL);
181 }
182
183 fc_assert((MAX_ID - pCity->id) > 0);
184 pBuf->ID = MAX_ID - pCity->id;
185
186 DownAdd(pBuf, pAdd_Dock);
187 pAdd_Dock = pBuf;
188
189 if (n > (pGotoDlg->pScroll->active - 1)) {
190 set_wflag(pBuf, WF_HIDDEN);
191 }
192
193 n++;
194 } city_list_iterate_end;
195 } players_iterate_end;
196
197 if (n > 0) {
198 pGotoDlg->pBeginWidgetList = pBuf;
199
200 pGotoDlg->pBeginActiveWidgetList = pGotoDlg->pBeginWidgetList;
201 pGotoDlg->pEndActiveWidgetList = pLast->prev;
202 pGotoDlg->pActiveWidgetList = pGotoDlg->pEndActiveWidgetList;
203 pGotoDlg->pScroll->count = n;
204
205 if (n > pGotoDlg->pScroll->active) {
206 show_scrollbar(pGotoDlg->pScroll);
207 pGotoDlg->pScroll->pScrollBar->size.y = pGotoDlg->pEndWidgetList->area.y +
208 pGotoDlg->pScroll->pUp_Left_Button->size.h;
209 pGotoDlg->pScroll->pScrollBar->size.h = scrollbar_size(pGotoDlg->pScroll);
210 } else {
211 hide_scrollbar(pGotoDlg->pScroll);
212 }
213
214 setup_vertical_widgets_position(1,
215 pGotoDlg->pEndWidgetList->area.x,
216 pGotoDlg->pEndWidgetList->area.y,
217 pGotoDlg->pScroll->pUp_Left_Button->size.x -
218 pGotoDlg->pEndWidgetList->area.x - adj_size(2),
219 0, pGotoDlg->pBeginActiveWidgetList, pGotoDlg->pEndActiveWidgetList);
220
221 } else {
222 hide_scrollbar(pGotoDlg->pScroll);
223 }
224
225 /* redraw */
226 redraw_group(pGotoDlg->pBeginWidgetList, pGotoDlg->pEndWidgetList, 0);
227 widget_flush(pGotoDlg->pEndWidgetList);
228
229 }
230
231 /**************************************************************************
232 Popup a dialog to have the focus unit goto to a city.
233 **************************************************************************/
popup_goto_airlift_dialog(void)234 static void popup_goto_airlift_dialog(void)
235 {
236 SDL_Color bg_color = {0, 0, 0, 96};
237
238 struct widget *pBuf, *pWindow;
239 SDL_String16 *pStr;
240 SDL_Surface *pFlag, *pEnabled, *pDisabled;
241 SDL_Rect dst;
242 int i, col, block_x, x, y;
243 SDL_Rect area;
244
245 if (pGotoDlg) {
246 return;
247 }
248
249 pGotoDlg = fc_calloc(1, sizeof(struct ADVANCED_DLG));
250
251 pStr = create_str16_from_char(_("Select destination"), adj_font(12));
252 pStr->style |= TTF_STYLE_BOLD;
253
254 pWindow = create_window_skeleton(NULL, pStr, 0);
255
256 pWindow->action = goto_dialog_window_callback;
257 set_wstate(pWindow, FC_WS_NORMAL);
258
259 add_to_gui_list(ID_WINDOW, pWindow);
260 pGotoDlg->pEndWidgetList = pWindow;
261
262 area = pWindow->area;
263
264 /* ---------- */
265 /* create exit button */
266 pBuf = create_themeicon(current_theme->Small_CANCEL_Icon, pWindow->dst,
267 WF_WIDGET_HAS_INFO_LABEL | WF_RESTORE_BACKGROUND);
268 pBuf->info_label = create_str16_from_char(_("Close Dialog (Esc)"),
269 adj_font(12));
270 pBuf->action = exit_goto_dialog_callback;
271 set_wstate(pBuf, FC_WS_NORMAL);
272 pBuf->key = SDLK_ESCAPE;
273 area.w = MAX(area.w, pBuf->size.w) + adj_size(10);
274
275 add_to_gui_list(ID_BUTTON, pBuf);
276
277 col = 0;
278 /* --------------------------------------------- */
279 players_iterate(pPlayer) {
280 if (pPlayer != client.conn.playing
281 && DS_NO_CONTACT
282 == player_diplstate_get(client.conn.playing, pPlayer)->type) {
283 continue;
284 }
285
286 pFlag = ResizeSurfaceBox(get_nation_flag_surface(pPlayer->nation),
287 adj_size(30), adj_size(30), 1, TRUE, FALSE);
288
289 pEnabled = create_icon_theme_surf(pFlag);
290 SDL_FillRectAlpha(pFlag, NULL, &bg_color);
291 pDisabled = create_icon_theme_surf(pFlag);
292 FREESURFACE(pFlag);
293
294 pBuf = create_checkbox(pWindow->dst,
295 BV_ISSET(all_players, player_index(pPlayer)),
296 WF_FREE_THEME | WF_RESTORE_BACKGROUND
297 | WF_WIDGET_HAS_INFO_LABEL);
298 set_new_checkbox_theme(pBuf, pEnabled, pDisabled);
299
300 pBuf->info_label =
301 create_str16_from_char(nation_adjective_for_player(pPlayer),
302 adj_font(12));
303 pBuf->info_label->style &= ~SF_CENTER;
304 set_wstate(pBuf, FC_WS_NORMAL);
305
306 pBuf->action = toggle_goto_nations_cities_dialog_callback;
307 add_to_gui_list(MAX_ID - player_number(pPlayer), pBuf);
308 col++;
309 } players_iterate_end;
310
311 pGotoDlg->pBeginWidgetList = pBuf;
312
313 create_vertical_scrollbar(pGotoDlg, 1, adj_size(320) / adj_size(30), TRUE, TRUE);
314 hide_scrollbar(pGotoDlg->pScroll);
315
316 area.w = MAX(area.w, adj_size(300));
317 area.h = adj_size(320);
318
319 resize_window(pWindow, NULL, NULL,
320 (pWindow->size.w - pWindow->area.w) + area.w,
321 (pWindow->size.h - pWindow->area.h) + area.h);
322
323 /* background */
324 col = (col + 15) / 16; /* number of flag columns */
325
326 pFlag = ResizeSurface(current_theme->Block,
327 (col * pBuf->size.w + (col - 1) * adj_size(5) + adj_size(10)),
328 area.h, 1);
329
330 block_x = dst.x = area.x + area.w - pFlag->w;
331 dst.y = area.y;
332 alphablit(pFlag, NULL, pWindow->theme, &dst);
333 FREESURFACE(pFlag);
334
335 widget_set_position(pWindow,
336 (Main.screen->w - pWindow->size.w) / 2,
337 (Main.screen->h - pWindow->size.h) / 2);
338
339 /* exit button */
340 pBuf = pWindow->prev;
341 pBuf->size.x = area.x + area.w - pBuf->size.w - 1;
342 pBuf->size.y = pWindow->size.y + adj_size(2);
343
344 /* nations buttons */
345 pBuf = pBuf->prev;
346 i = 0;
347 x = block_x + adj_size(5);
348 y = area.y + adj_size(1);
349 while (pBuf) {
350 pBuf->size.x = x;
351 pBuf->size.y = y;
352
353 if (!((i + 1) % col)) {
354 x = block_x + adj_size(5);
355 y += pBuf->size.h + adj_size(1);
356 } else {
357 x += pBuf->size.w + adj_size(5);
358 }
359
360 if (pBuf == pGotoDlg->pBeginWidgetList) {
361 break;
362 }
363
364 i++;
365 pBuf = pBuf->prev;
366 }
367
368 setup_vertical_scrollbar_area(pGotoDlg->pScroll,
369 block_x, area.y,
370 area.h, TRUE);
371
372 update_goto_dialog();
373 }
374
375
376 /**************************************************************************
377 Popup a dialog to have the focus unit goto to a city.
378 **************************************************************************/
popup_goto_dialog(void)379 void popup_goto_dialog(void)
380 {
381 if (!can_client_issue_orders() || 0 == get_num_units_in_focus()) {
382 return;
383 }
384 BV_CLR_ALL(all_players);
385 BV_SET(all_players, player_index(client.conn.playing));
386 /* FIXME: Should we include allies in all_players */
387 popup_goto_airlift_dialog();
388 }
389
390 /**************************************************************************
391 Popup a dialog to have the focus unit airlift to a city.
392 **************************************************************************/
popup_airlift_dialog(void)393 void popup_airlift_dialog(void)
394 {
395 if (!can_client_issue_orders() || 0 == get_num_units_in_focus()) {
396 return;
397 }
398 BV_CLR_ALL(all_players);
399 BV_SET(all_players, player_index(client.conn.playing));
400 /* FIXME: Should we include allies in all_players */
401 GOTO = FALSE;
402 popup_goto_airlift_dialog();
403 }
404
405 /**************************************************************************
406 Popdown goto/airlift to a city dialog.
407 **************************************************************************/
popdown_goto_airlift_dialog(void)408 void popdown_goto_airlift_dialog(void)
409 {
410 if (pGotoDlg) {
411 popdown_window_group_dialog(pGotoDlg->pBeginWidgetList,
412 pGotoDlg->pEndWidgetList);
413 FC_FREE(pGotoDlg->pScroll);
414 FC_FREE(pGotoDlg);
415 }
416 GOTO = TRUE;
417 }
418