Remove hard limitation that AI wonder cities never build settlers
[freeciv.git] / client / gui-sdl2 / gotodlg.c
blobc23e7d12a1db0ed6c19e9663af79c42e11509a67
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.
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 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 #include <stdlib.h>
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 */
27 /* utility */
28 #include "bitvector.h"
29 #include "fcintl.h"
30 #include "log.h"
32 /* common */
33 #include "game.h"
34 #include "fc_types.h" /* bv_player */
35 #include "unitlist.h"
37 /* client */
38 #include "client_main.h"
39 #include "control.h"
40 #include "goto.h"
42 /* gui-sdl2 */
43 #include "colors.h"
44 #include "graphics.h"
45 #include "gui_id.h"
46 #include "gui_main.h"
47 #include "gui_tilespec.h"
48 #include "mapview.h"
49 #include "sprite.h"
50 #include "widget.h"
52 #include "gotodlg.h"
54 static struct ADVANCED_DLG *pGotoDlg = NULL;
55 bv_player all_players;
56 static bool GOTO = TRUE;
58 static void update_goto_dialog(void);
60 /**************************************************************************
61 User interacted with goto dialog window.
62 **************************************************************************/
63 static int goto_dialog_window_callback(struct widget *pWindow)
65 if (Main.event.button.button == SDL_BUTTON_LEFT) {
66 move_window_group(pGotoDlg->pBeginWidgetList, pWindow);
69 return -1;
72 /**************************************************************************
73 Close goto dialog.
74 **************************************************************************/
75 static int exit_goto_dialog_callback(struct widget *pWidget)
77 if (Main.event.button.button == SDL_BUTTON_LEFT) {
78 popdown_goto_airlift_dialog();
79 flush_dirty();
82 return -1;
85 /**************************************************************************
86 Toggle whether player cities are listed as possible destinations.
87 **************************************************************************/
88 static int toggle_goto_nations_cities_dialog_callback(struct widget *pWidget)
90 if (Main.event.button.button == SDL_BUTTON_LEFT) {
91 int plr_id = player_index(player_by_number(MAX_ID - pWidget->ID));
93 if (BV_ISSET(all_players, plr_id)) {
94 BV_CLR(all_players, plr_id);
95 } else {
96 BV_SET(all_players, plr_id);
98 update_goto_dialog();
101 return -1;
104 /**************************************************************************
105 User has selected city for unit to go to.
106 **************************************************************************/
107 static int goto_city_callback(struct widget *pWidget)
109 if (Main.event.button.button == SDL_BUTTON_LEFT) {
110 struct city *pDestcity = game_city_by_number(MAX_ID - pWidget->ID);
112 if (pDestcity) {
113 struct unit *pUnit = head_of_units_in_focus();
115 if (pUnit) {
116 if (GOTO) {
117 send_goto_tile(pUnit, pDestcity->tile);
118 } else {
119 request_unit_airlift(pUnit, pDestcity);
124 popdown_goto_airlift_dialog();
125 flush_dirty();
128 return -1;
131 /**************************************************************************
132 Refresh goto dialog.
133 **************************************************************************/
134 static void update_goto_dialog(void)
136 struct widget *pBuf = NULL, *pAdd_Dock, *pLast;
137 SDL_Surface *pLogo = NULL;
138 utf8_str *pstr;
139 char cBuf[128];
140 int n = 0;
141 struct player *owner = NULL;
143 if (pGotoDlg->pEndActiveWidgetList) {
144 pAdd_Dock = pGotoDlg->pEndActiveWidgetList->next;
145 pGotoDlg->pBeginWidgetList = pAdd_Dock;
146 del_group(pGotoDlg->pBeginActiveWidgetList, pGotoDlg->pEndActiveWidgetList);
147 pGotoDlg->pActiveWidgetList = NULL;
148 } else {
149 pAdd_Dock = pGotoDlg->pBeginWidgetList;
152 pLast = pAdd_Dock;
154 players_iterate(pPlayer) {
155 if (!BV_ISSET(all_players, player_index(pPlayer))) {
156 continue;
159 city_list_iterate(pPlayer->cities, pCity) {
161 /* FIXME: should use unit_can_airlift_to(). */
162 if (!GOTO && !pCity->airlift) {
163 continue;
166 fc_snprintf(cBuf, sizeof(cBuf), "%s (%d)", city_name_get(pCity),
167 city_size_get(pCity));
169 pstr = create_utf8_from_char(cBuf, adj_font(12));
170 pstr->style |= TTF_STYLE_BOLD;
172 if (!player_owns_city(owner, pCity)) {
173 pLogo = get_nation_flag_surface(nation_of_player(city_owner(pCity)));
174 pLogo = crop_visible_part_from_surface(pLogo);
177 pBuf = create_iconlabel(pLogo, pGotoDlg->pEndWidgetList->dst, pstr,
178 (WF_RESTORE_BACKGROUND|WF_DRAW_TEXT_LABEL_WITH_SPACE));
180 if (!player_owns_city(owner, pCity)) {
181 set_wflag(pBuf, WF_FREE_THEME);
182 owner = city_owner(pCity);
185 pBuf->string_utf8->fgcol =
186 *(get_player_color(tileset, city_owner(pCity))->color);
187 pBuf->action = goto_city_callback;
189 if (GOTO || pCity->airlift) {
190 set_wstate(pBuf, FC_WS_NORMAL);
193 fc_assert((MAX_ID - pCity->id) > 0);
194 pBuf->ID = MAX_ID - pCity->id;
196 DownAdd(pBuf, pAdd_Dock);
197 pAdd_Dock = pBuf;
199 if (n > (pGotoDlg->pScroll->active - 1)) {
200 set_wflag(pBuf, WF_HIDDEN);
203 n++;
204 } city_list_iterate_end;
205 } players_iterate_end;
207 if (n > 0) {
208 pGotoDlg->pBeginWidgetList = pBuf;
210 pGotoDlg->pBeginActiveWidgetList = pGotoDlg->pBeginWidgetList;
211 pGotoDlg->pEndActiveWidgetList = pLast->prev;
212 pGotoDlg->pActiveWidgetList = pGotoDlg->pEndActiveWidgetList;
213 pGotoDlg->pScroll->count = n;
215 if (n > pGotoDlg->pScroll->active) {
216 show_scrollbar(pGotoDlg->pScroll);
217 pGotoDlg->pScroll->pScrollBar->size.y = pGotoDlg->pEndWidgetList->area.y +
218 pGotoDlg->pScroll->pUp_Left_Button->size.h;
219 pGotoDlg->pScroll->pScrollBar->size.h = scrollbar_size(pGotoDlg->pScroll);
220 } else {
221 hide_scrollbar(pGotoDlg->pScroll);
224 setup_vertical_widgets_position(1,
225 pGotoDlg->pEndWidgetList->area.x,
226 pGotoDlg->pEndWidgetList->area.y,
227 pGotoDlg->pScroll->pUp_Left_Button->size.x -
228 pGotoDlg->pEndWidgetList->area.x - adj_size(2),
229 0, pGotoDlg->pBeginActiveWidgetList,
230 pGotoDlg->pEndActiveWidgetList);
232 } else {
233 hide_scrollbar(pGotoDlg->pScroll);
236 /* redraw */
237 redraw_group(pGotoDlg->pBeginWidgetList, pGotoDlg->pEndWidgetList, 0);
238 widget_flush(pGotoDlg->pEndWidgetList);
241 /**************************************************************************
242 Popup a dialog to have the focus unit goto to a city.
243 **************************************************************************/
244 static void popup_goto_airlift_dialog(void)
246 SDL_Color bg_color = {0, 0, 0, 96};
247 struct widget *pBuf, *pWindow;
248 utf8_str *pstr;
249 SDL_Surface *pFlag, *pEnabled, *pDisabled;
250 SDL_Rect dst;
251 int i, col, block_x, x, y;
252 SDL_Rect area;
254 if (pGotoDlg) {
255 return;
258 pGotoDlg = fc_calloc(1, sizeof(struct ADVANCED_DLG));
260 pstr = create_utf8_from_char(_("Select destination"), adj_font(12));
261 pstr->style |= TTF_STYLE_BOLD;
263 pWindow = create_window_skeleton(NULL, pstr, 0);
265 pWindow->action = goto_dialog_window_callback;
266 set_wstate(pWindow, FC_WS_NORMAL);
268 add_to_gui_list(ID_WINDOW, pWindow);
269 pGotoDlg->pEndWidgetList = pWindow;
271 area = pWindow->area;
273 /* ---------- */
274 /* create exit button */
275 pBuf = create_themeicon(current_theme->Small_CANCEL_Icon, pWindow->dst,
276 WF_WIDGET_HAS_INFO_LABEL | WF_RESTORE_BACKGROUND);
277 pBuf->info_label = create_utf8_from_char(_("Close Dialog (Esc)"),
278 adj_font(12));
279 pBuf->action = exit_goto_dialog_callback;
280 set_wstate(pBuf, FC_WS_NORMAL);
281 pBuf->key = SDLK_ESCAPE;
282 area.w = MAX(area.w, pBuf->size.w) + adj_size(10);
284 add_to_gui_list(ID_BUTTON, pBuf);
286 col = 0;
287 /* --------------------------------------------- */
288 players_iterate(pPlayer) {
289 if (pPlayer != client.conn.playing
290 && DS_NO_CONTACT == player_diplstate_get(client.conn.playing, pPlayer)->type) {
291 continue;
294 pFlag = ResizeSurfaceBox(get_nation_flag_surface(pPlayer->nation),
295 adj_size(30), adj_size(30), 1, TRUE, FALSE);
297 pEnabled = create_icon_theme_surf(pFlag);
298 fill_rect_alpha(pFlag, NULL, &bg_color);
299 pDisabled = create_icon_theme_surf(pFlag);
300 FREESURFACE(pFlag);
302 pBuf = create_checkbox(pWindow->dst,
303 BV_ISSET(all_players, player_index(pPlayer)),
304 WF_FREE_THEME | WF_RESTORE_BACKGROUND
305 | WF_WIDGET_HAS_INFO_LABEL);
306 set_new_checkbox_theme(pBuf, pEnabled, pDisabled);
308 pBuf->info_label =
309 create_utf8_from_char(nation_adjective_for_player(pPlayer),
310 adj_font(12));
311 pBuf->info_label->style &= ~SF_CENTER;
312 set_wstate(pBuf, FC_WS_NORMAL);
314 pBuf->action = toggle_goto_nations_cities_dialog_callback;
315 add_to_gui_list(MAX_ID - player_number(pPlayer), pBuf);
316 col++;
317 } players_iterate_end;
319 pGotoDlg->pBeginWidgetList = pBuf;
321 create_vertical_scrollbar(pGotoDlg, 1, adj_size(320) / adj_size(30), TRUE, TRUE);
322 hide_scrollbar(pGotoDlg->pScroll);
324 area.w = MAX(area.w, adj_size(300));
325 area.h = adj_size(320);
327 resize_window(pWindow, NULL, NULL,
328 (pWindow->size.w - pWindow->area.w) + area.w,
329 (pWindow->size.h - pWindow->area.h) + area.h);
331 /* background */
332 col = (col + 15) / 16; /* number of flag columns */
334 pFlag = ResizeSurface(current_theme->Block,
335 (col * pBuf->size.w + (col - 1) * adj_size(5) + adj_size(10)),
336 area.h, 1);
338 block_x = dst.x = area.x + area.w - pFlag->w;
339 dst.y = area.y;
340 alphablit(pFlag, NULL, pWindow->theme, &dst, 255);
341 FREESURFACE(pFlag);
343 widget_set_position(pWindow,
344 (main_window_width() - pWindow->size.w) / 2,
345 (main_window_height() - pWindow->size.h) / 2);
347 /* exit button */
348 pBuf = pWindow->prev;
349 pBuf->size.x = area.x + area.w - pBuf->size.w - 1;
350 pBuf->size.y = pWindow->size.y + adj_size(2);
352 /* nations buttons */
353 pBuf = pBuf->prev;
354 i = 0;
355 x = block_x + adj_size(5);
356 y = area.y + adj_size(1);
357 while (pBuf) {
358 pBuf->size.x = x;
359 pBuf->size.y = y;
361 if (!((i + 1) % col)) {
362 x = block_x + adj_size(5);
363 y += pBuf->size.h + adj_size(1);
364 } else {
365 x += pBuf->size.w + adj_size(5);
368 if (pBuf == pGotoDlg->pBeginWidgetList) {
369 break;
372 i++;
373 pBuf = pBuf->prev;
376 setup_vertical_scrollbar_area(pGotoDlg->pScroll,
377 block_x, area.y,
378 area.h, TRUE);
380 update_goto_dialog();
384 /**************************************************************************
385 Popup a dialog to have the focus unit goto to a city.
386 **************************************************************************/
387 void popup_goto_dialog(void)
389 if (!can_client_issue_orders() || 0 == get_num_units_in_focus()) {
390 return;
393 BV_CLR_ALL(all_players);
394 BV_SET(all_players, player_index(client.conn.playing));
395 /* FIXME: Should we include allies in all_players */
396 popup_goto_airlift_dialog();
399 /**************************************************************************
400 Popup a dialog to have the focus unit airlift to a city.
401 **************************************************************************/
402 void popup_airlift_dialog(void)
404 if (!can_client_issue_orders() || 0 == get_num_units_in_focus()) {
405 return;
408 BV_CLR_ALL(all_players);
409 BV_SET(all_players, player_index(client.conn.playing));
410 /* FIXME: Should we include allies in all_players */
411 GOTO = FALSE;
412 popup_goto_airlift_dialog();
415 /**************************************************************************
416 Popdown goto/airlift to a city dialog.
417 **************************************************************************/
418 void popdown_goto_airlift_dialog(void)
420 if (pGotoDlg) {
421 popdown_window_group_dialog(pGotoDlg->pBeginWidgetList,
422 pGotoDlg->pEndWidgetList);
423 FC_FREE(pGotoDlg->pScroll);
424 FC_FREE(pGotoDlg);
426 GOTO = TRUE;