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 /* SDL2 */
21 #ifdef SDL2_PLAIN_INCLUDE
22 #include <SDL.h>
23 #else  /* SDL2_PLAIN_INCLUDE */
24 #include <SDL2/SDL.h>
25 #endif /* SDL2_PLAIN_INCLUDE */
26 
27 /* utility */
28 #include "fcintl.h"
29 #include "log.h"
30 
31 /* common */
32 #include "game.h"
33 
34 /* gui-sdl2 */
35 #include "colors.h"
36 #include "graphics.h"
37 #include "gui_id.h"
38 #include "gui_main.h"
39 #include "gui_tilespec.h"
40 #include "mapctrl.h"
41 #include "mapview.h"
42 #include "sprite.h"
43 #include "widget.h"
44 
45 #include "finddlg.h"
46 
47 /* ====================================================================== */
48 /* ============================= FIND CITY MENU ========================= */
49 /* ====================================================================== */
50 static struct ADVANCED_DLG  *pFind_City_Dlg = NULL;
51 
52 /**************************************************************************
53   User interacted with find city dialog window.
54 **************************************************************************/
find_city_window_dlg_callback(struct widget * pWindow)55 static int find_city_window_dlg_callback(struct widget *pWindow)
56 {
57   if (PRESSED_EVENT(Main.event)) {
58     move_window_group(pFind_City_Dlg->pBeginWidgetList, pWindow);
59   }
60 
61   return -1;
62 }
63 
64 /**************************************************************************
65   Close find city dialog.
66 **************************************************************************/
exit_find_city_dlg_callback(struct widget * pWidget)67 static int exit_find_city_dlg_callback(struct widget *pWidget)
68 {
69   if (PRESSED_EVENT(Main.event)) {
70     int orginal_x = pWidget->data.cont->id0;
71     int orginal_y = pWidget->data.cont->id1;
72 
73     popdown_find_dialog();
74 
75     center_tile_mapcanvas(map_pos_to_tile(orginal_x, orginal_y));
76 
77     flush_dirty();
78   }
79 
80   return -1;
81 }
82 
83 /**************************************************************************
84   User has selected city to find.
85 **************************************************************************/
find_city_callback(struct widget * pWidget)86 static int find_city_callback(struct widget *pWidget)
87 {
88   if (PRESSED_EVENT(Main.event)) {
89     struct city *pCity = pWidget->data.city;
90 
91     if (pCity) {
92       center_tile_mapcanvas(pCity->tile);
93       if (Main.event.button.button == SDL_BUTTON_RIGHT) {
94         popdown_find_dialog();
95       }
96       flush_dirty();
97     }
98   }
99 
100   return -1;
101 }
102 
103 /**************************************************************************
104   Popdown a dialog to ask for a city to find.
105 **************************************************************************/
popdown_find_dialog(void)106 void popdown_find_dialog(void)
107 {
108   if (pFind_City_Dlg) {
109     popdown_window_group_dialog(pFind_City_Dlg->pBeginWidgetList,
110                                 pFind_City_Dlg->pEndWidgetList);
111     FC_FREE(pFind_City_Dlg->pScroll);
112     FC_FREE(pFind_City_Dlg);
113     enable_and_redraw_find_city_button();
114   }
115 }
116 
117 /**************************************************************************
118   Popup a dialog to ask for a city to find.
119 **************************************************************************/
popup_find_dialog(void)120 void popup_find_dialog(void)
121 {
122   struct widget *pWindow = NULL, *pBuf = NULL;
123   SDL_Surface *pLogo = NULL;
124   utf8_str *pstr;
125   char cBuf[128];
126   int h = 0, n = 0, w = 0, units_h = 0;
127   struct player *owner = NULL;
128   struct tile *original;
129   int window_x = 0, window_y = 0;
130   bool mouse = (Main.event.type == SDL_MOUSEBUTTONDOWN);
131   SDL_Rect area;
132 
133   /* check that there are any cities to find */
134   players_iterate(pplayer) {
135     h = city_list_size(pplayer->cities);
136     if (h > 0) {
137       break;
138     }
139   } players_iterate_end;
140 
141   if (pFind_City_Dlg && !h) {
142     return;
143   }
144 
145   original = canvas_pos_to_tile(Main.map->w / 2, Main.map->h / 2);
146 
147   pFind_City_Dlg = fc_calloc(1, sizeof(struct ADVANCED_DLG));
148 
149   pstr = create_utf8_from_char(_("Find City") , adj_font(12));
150   pstr->style |= TTF_STYLE_BOLD;
151 
152   pWindow = create_window_skeleton(NULL, pstr, 0);
153 
154   pWindow->action = find_city_window_dlg_callback;
155   set_wstate(pWindow , FC_WS_NORMAL);
156 
157   add_to_gui_list(ID_TERRAIN_ADV_DLG_WINDOW, pWindow);
158   pFind_City_Dlg->pEndWidgetList = pWindow;
159 
160   area = pWindow->area;
161 
162   /* ---------- */
163   /* exit button */
164   pBuf = create_themeicon(current_theme->Small_CANCEL_Icon, pWindow->dst,
165                           WF_WIDGET_HAS_INFO_LABEL | WF_RESTORE_BACKGROUND
166                           | WF_FREE_DATA);
167   pBuf->info_label = create_utf8_from_char(_("Close Dialog (Esc)"),
168                                            adj_font(12));
169   area.w = MAX(area.w, pBuf->size.w + adj_size(10));
170   pBuf->action = exit_find_city_dlg_callback;
171   set_wstate(pBuf, FC_WS_NORMAL);
172   pBuf->key = SDLK_ESCAPE;
173   pBuf->data.cont = fc_calloc(1, sizeof(struct CONTAINER));
174   pBuf->data.cont->id0 = index_to_map_pos_x(tile_index(original));
175   pBuf->data.cont->id1 = index_to_map_pos_y(tile_index(original));
176 
177   add_to_gui_list(ID_TERRAIN_ADV_DLG_EXIT_BUTTON, pBuf);
178   /* ---------- */
179 
180   players_iterate(pPlayer) {
181     city_list_iterate(pPlayer->cities, pCity) {
182       fc_snprintf(cBuf , sizeof(cBuf), "%s (%d)", city_name_get(pCity),
183                   city_size_get(pCity));
184 
185       pstr = create_utf8_from_char(cBuf, adj_font(10));
186       pstr->style |= (TTF_STYLE_BOLD|SF_CENTER);
187 
188       if (!player_owns_city(owner, pCity)) {
189         pLogo = get_nation_flag_surface(nation_of_player(city_owner(pCity)));
190         pLogo = crop_visible_part_from_surface(pLogo);
191       }
192 
193       pBuf = create_iconlabel(pLogo, pWindow->dst, pstr,
194     	(WF_RESTORE_BACKGROUND|WF_DRAW_TEXT_LABEL_WITH_SPACE));
195 
196       if (!player_owns_city(owner, pCity)) {
197         set_wflag(pBuf, WF_FREE_THEME);
198         owner = city_owner(pCity);
199       }
200 
201       pBuf->string_utf8->style &= ~SF_CENTER;
202       pBuf->string_utf8->fgcol = *(get_player_color(tileset, city_owner(pCity))->color);
203       pBuf->string_utf8->bgcol = (SDL_Color) {0, 0, 0, 0};
204 
205       pBuf->data.city = pCity;
206 
207       pBuf->action = find_city_callback;
208       set_wstate(pBuf, FC_WS_NORMAL);
209 
210       add_to_gui_list(ID_LABEL , pBuf);
211 
212       area.w = MAX(area.w, pBuf->size.w);
213       area.h += pBuf->size.h;
214 
215       if (n > 19) {
216         set_wflag(pBuf , WF_HIDDEN);
217       }
218 
219       n++;
220     } city_list_iterate_end;
221   } players_iterate_end;
222 
223   pFind_City_Dlg->pBeginWidgetList = pBuf;
224   pFind_City_Dlg->pBeginActiveWidgetList = pFind_City_Dlg->pBeginWidgetList;
225   pFind_City_Dlg->pEndActiveWidgetList = pWindow->prev->prev;
226   pFind_City_Dlg->pActiveWidgetList = pFind_City_Dlg->pEndActiveWidgetList;
227 
228 
229   /* ---------- */
230   if (n > 20) {
231     units_h = create_vertical_scrollbar(pFind_City_Dlg, 1, 20, TRUE, TRUE);
232     pFind_City_Dlg->pScroll->count = n;
233 
234     n = units_h;
235     area.w += n;
236 
237     units_h = 20 * pBuf->size.h + adj_size(2);
238 
239   } else {
240     units_h = area.h;
241   }
242 
243   /* ---------- */
244 
245   area.h = units_h;
246 
247   resize_window(pWindow , NULL, NULL,
248                 (pWindow->size.w - pWindow->area.w) + area.w,
249                 (pWindow->size.h - pWindow->area.h) + area.h);
250 
251   area = pWindow->area;
252 
253   if (!mouse) {
254     window_x = adj_size(10);
255     window_y = (main_window_height() - pWindow->size.h) / 2;
256   } else {
257     window_x = (Main.event.motion.x + pWindow->size.w + adj_size(10) < main_window_width()) ?
258                 (Main.event.motion.x + adj_size(10)) :
259                 (main_window_width() - pWindow->size.w - adj_size(10));
260     window_y = (Main.event.motion.y - adj_size(2) + pWindow->size.h < main_window_height()) ?
261              (Main.event.motion.y - adj_size(2)) :
262              (main_window_height() - pWindow->size.h - adj_size(10));
263   }
264 
265   widget_set_position(pWindow, window_x, window_y);
266 
267   w = area.w;
268 
269   if (pFind_City_Dlg->pScroll) {
270     w -= n;
271   }
272 
273   /* exit button */
274   pBuf = pWindow->prev;
275 
276   pBuf->size.x = area.x + area.w - pBuf->size.w - 1;
277   pBuf->size.y = pWindow->size.y + adj_size(2);
278 
279   /* cities */
280   pBuf = pBuf->prev;
281   setup_vertical_widgets_position(1, area.x, area.y, w, 0,
282                                   pFind_City_Dlg->pBeginActiveWidgetList,
283                                   pBuf);
284 
285   if (pFind_City_Dlg->pScroll) {
286     setup_vertical_scrollbar_area(pFind_City_Dlg->pScroll,
287                                   area.x + area.w, area.y,
288                                   area.h, TRUE);
289   }
290 
291   /* -------------------- */
292   /* redraw */
293   redraw_group(pFind_City_Dlg->pBeginWidgetList, pWindow, 0);
294   widget_mark_dirty(pWindow);
295 
296   flush_dirty();
297 }
298