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