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 /* 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 "fcintl.h"
27 #include "log.h"
28
29 /* common */
30 #include "government.h"
31 #include "research.h"
32
33 /* client */
34 #include "client_main.h"
35
36 /* gui-sdl2 */
37 #include "graphics.h"
38 #include "gui_id.h"
39 #include "gui_main.h"
40 #include "gui_tilespec.h"
41 #include "mapview.h"
42 #include "repodlgs.h"
43 #include "spaceshipdlg.h"
44 #include "sprite.h"
45 #include "widget.h"
46
47 #include "inteldlg.h"
48
49 struct intel_dialog {
50 struct player *pplayer;
51 struct ADVANCED_DLG *pdialog;
52 int pos_x, pos_y;
53 };
54
55 #define SPECLIST_TAG dialog
56 #define SPECLIST_TYPE struct intel_dialog
57 #include "speclist.h"
58
59 #define dialog_list_iterate(dialoglist, pdialog) \
60 TYPED_LIST_ITERATE(struct intel_dialog, dialoglist, pdialog)
61 #define dialog_list_iterate_end LIST_ITERATE_END
62
63 static struct dialog_list *dialog_list;
64 static struct intel_dialog *create_intel_dialog(struct player *p);
65
66 /****************************************************************
67 Allocate intelligence dialog
68 *****************************************************************/
intel_dialog_init(void)69 void intel_dialog_init(void)
70 {
71 dialog_list = dialog_list_new();
72 }
73
74 /****************************************************************
75 Free intelligence dialog
76 *****************************************************************/
intel_dialog_done(void)77 void intel_dialog_done(void)
78 {
79 dialog_list_destroy(dialog_list);
80 }
81
82 /****************************************************************
83 Get intelligence dialog towards given player
84 *****************************************************************/
get_intel_dialog(struct player * pplayer)85 static struct intel_dialog *get_intel_dialog(struct player *pplayer)
86 {
87 dialog_list_iterate(dialog_list, pdialog) {
88 if (pdialog->pplayer == pplayer) {
89 return pdialog;
90 }
91 } dialog_list_iterate_end;
92
93 return NULL;
94 }
95
96 /****************************************************************
97 User interacted with the intelligence dialog window
98 *****************************************************************/
intel_window_dlg_callback(struct widget * pWindow)99 static int intel_window_dlg_callback(struct widget *pWindow)
100 {
101 if (PRESSED_EVENT(Main.event)) {
102 struct intel_dialog *pSelectedDialog = get_intel_dialog(pWindow->data.player);
103
104 move_window_group(pSelectedDialog->pdialog->pBeginWidgetList, pWindow);
105 }
106
107 return -1;
108 }
109
110 /****************************************************************
111 User interacted with tech widget
112 *****************************************************************/
tech_callback(struct widget * pWidget)113 static int tech_callback(struct widget *pWidget)
114 {
115 /* get tech help - PORT ME */
116 return -1;
117 }
118
119 /****************************************************************
120 User interacted with spaceship widget
121 *****************************************************************/
spaceship_callback(struct widget * pWidget)122 static int spaceship_callback(struct widget *pWidget)
123 {
124 if (PRESSED_EVENT(Main.event)) {
125 struct player *pPlayer = pWidget->data.player;
126
127 popdown_intel_dialog(pPlayer);
128 popup_spaceship_dialog(pPlayer);
129 }
130
131 return -1;
132 }
133
134 /****************************************************************
135 User interacted with intelligence dialog close button
136 *****************************************************************/
exit_intel_dlg_callback(struct widget * pWidget)137 static int exit_intel_dlg_callback(struct widget *pWidget)
138 {
139 if (PRESSED_EVENT(Main.event)) {
140 popdown_intel_dialog(pWidget->data.player);
141 flush_dirty();
142 }
143
144 return -1;
145 }
146
147 /**************************************************************************
148 Close an intelligence dialog towards given player.
149 **************************************************************************/
close_intel_dialog(struct player * p)150 void close_intel_dialog(struct player *p)
151 {
152 popdown_intel_dialog(p);
153 }
154
155 /**************************************************************************
156 Create an intelligence dialog towards given player.
157 **************************************************************************/
create_intel_dialog(struct player * pPlayer)158 static struct intel_dialog *create_intel_dialog(struct player *pPlayer)
159 {
160 struct intel_dialog *pdialog = fc_calloc(1, sizeof(struct intel_dialog));
161
162 pdialog->pplayer = pPlayer;
163
164 pdialog->pdialog = fc_calloc(1, sizeof(struct ADVANCED_DLG));
165
166 pdialog->pos_x = 0;
167 pdialog->pos_y = 0;
168
169 dialog_list_prepend(dialog_list, pdialog);
170
171 return pdialog;
172 }
173
174 /**************************************************************************
175 Popup an intelligence dialog for the given player.
176 **************************************************************************/
popup_intel_dialog(struct player * p)177 void popup_intel_dialog(struct player *p)
178 {
179 struct intel_dialog *pdialog;
180
181 if (!(pdialog = get_intel_dialog(p))) {
182 pdialog = create_intel_dialog(p);
183 } else {
184 /* bring existing dialog to front */
185 select_window_group_dialog(pdialog->pdialog->pBeginWidgetList,
186 pdialog->pdialog->pEndWidgetList);
187 }
188
189 update_intel_dialog(p);
190 }
191
192 /**************************************************************************
193 Popdown an intelligence dialog for the given player.
194 **************************************************************************/
popdown_intel_dialog(struct player * p)195 void popdown_intel_dialog(struct player *p)
196 {
197 struct intel_dialog *pdialog = get_intel_dialog(p);
198
199 if (pdialog) {
200 popdown_window_group_dialog(pdialog->pdialog->pBeginWidgetList,
201 pdialog->pdialog->pEndWidgetList);
202
203 dialog_list_remove(dialog_list, pdialog);
204
205 FC_FREE(pdialog->pdialog->pScroll);
206 FC_FREE(pdialog->pdialog);
207 FC_FREE(pdialog);
208 }
209 }
210
211 /**************************************************************************
212 Popdown all intelligence dialogs
213 **************************************************************************/
popdown_intel_dialogs(void)214 void popdown_intel_dialogs(void)
215 {
216 dialog_list_iterate(dialog_list, pdialog) {
217 popdown_intel_dialog(pdialog->pplayer);
218 } dialog_list_iterate_end;
219 }
220
221 /****************************************************************************
222 Update the intelligence dialog for the given player. This is called by
223 the core client code when that player's information changes.
224 ****************************************************************************/
update_intel_dialog(struct player * p)225 void update_intel_dialog(struct player *p)
226 {
227 const struct research *mresearch, *presearch;
228 struct intel_dialog *pdialog = get_intel_dialog(p);
229 struct widget *pWindow = NULL, *pBuf = NULL, *pLast;
230 SDL_Surface *pLogo = NULL, *pTmpSurf = NULL;
231 SDL_Surface *pText1, *pInfo, *pText2 = NULL;
232 utf8_str *pstr;
233 SDL_Rect dst;
234 char cBuf[256], plr_buf[4 * MAX_LEN_NAME];
235 int n = 0, count = 0, col;
236 struct city *pCapital;
237 SDL_Rect area;
238 struct research *research;
239
240 if (pdialog) {
241 /* save window position and delete old content */
242 if (pdialog->pdialog->pEndWidgetList) {
243 pdialog->pos_x = pdialog->pdialog->pEndWidgetList->size.x;
244 pdialog->pos_y = pdialog->pdialog->pEndWidgetList->size.y;
245
246 popdown_window_group_dialog(pdialog->pdialog->pBeginWidgetList,
247 pdialog->pdialog->pEndWidgetList);
248 }
249
250 pstr = create_utf8_from_char(_("Foreign Intelligence Report") , adj_font(12));
251 pstr->style |= TTF_STYLE_BOLD;
252
253 pWindow = create_window_skeleton(NULL, pstr, 0);
254
255 pWindow->action = intel_window_dlg_callback;
256 set_wstate(pWindow , FC_WS_NORMAL);
257 pWindow->data.player = p;
258
259 add_to_gui_list(ID_WINDOW, pWindow);
260 pdialog->pdialog->pEndWidgetList = pWindow;
261
262 area = pWindow->area;
263
264 /* ---------- */
265 /* exit button */
266 pBuf = create_themeicon(current_theme->Small_CANCEL_Icon, pWindow->dst,
267 WF_WIDGET_HAS_INFO_LABEL
268 | WF_RESTORE_BACKGROUND);
269 pBuf->info_label = create_utf8_from_char(_("Close Dialog (Esc)"),
270 adj_font(12));
271 area.w = MAX(area.w, pBuf->size.w + adj_size(10));
272 pBuf->action = exit_intel_dlg_callback;
273 set_wstate(pBuf, FC_WS_NORMAL);
274 pBuf->data.player = p;
275 pBuf->key = SDLK_ESCAPE;
276
277 add_to_gui_list(ID_BUTTON, pBuf);
278 /* ---------- */
279
280 pLogo = get_nation_flag_surface(nation_of_player(p));
281
282 {
283 double zoom = DEFAULT_ZOOM * 60.0 / pLogo->h;
284
285 pText1 = zoomSurface(pLogo, zoom, zoom, 1);
286 }
287
288 pLogo = pText1;
289
290 pBuf = create_icon2(pLogo, pWindow->dst,
291 WF_RESTORE_BACKGROUND | WF_WIDGET_HAS_INFO_LABEL
292 | WF_FREE_THEME);
293 pBuf->action = spaceship_callback;
294 set_wstate(pBuf, FC_WS_NORMAL);
295 pBuf->data.player = p;
296 fc_snprintf(cBuf, sizeof(cBuf),
297 _("Intelligence Information about the %s Spaceship"),
298 nation_adjective_for_player(p));
299 pBuf->info_label = create_utf8_from_char(cBuf, adj_font(12));
300
301 add_to_gui_list(ID_ICON, pBuf);
302
303 /* ---------- */
304 fc_snprintf(cBuf, sizeof(cBuf),
305 _("Intelligence Information for the %s Empire"),
306 nation_adjective_for_player(p));
307
308 pstr = create_utf8_from_char(cBuf, adj_font(14));
309 pstr->style |= TTF_STYLE_BOLD;
310 pstr->bgcol = (SDL_Color) {0, 0, 0, 0};
311
312 pText1 = create_text_surf_from_utf8(pstr);
313 area.w = MAX(area.w, pText1->w + adj_size(20));
314 area.h += pText1->h + adj_size(20);
315
316 /* ---------- */
317
318 pCapital = player_capital(p);
319 research = research_get(p);
320 change_ptsize_utf8(pstr, adj_font(10));
321 pstr->style &= ~TTF_STYLE_BOLD;
322
323 /* FIXME: these should use common gui code, and avoid duplication! */
324 if (client_is_global_observer() || player_has_embassy(client_player(), p)) {
325 switch (research->researching) {
326 case A_UNKNOWN:
327 case A_UNSET:
328 fc_snprintf(cBuf, sizeof(cBuf),
329 _("Ruler: %s Government: %s\n"
330 "Capital: %s Gold: %d\n"
331 "Tax: %d%% Science: %d%% Luxury: %d%%\n"
332 "Researching: %s"),
333 ruler_title_for_player(p, plr_buf, sizeof(plr_buf)),
334 government_name_for_player(p),
335 /* TRANS: "unknown" location */
336 NULL != pCapital ? city_name_get(pCapital) : _("(Unknown)"),
337 p->economic.gold, p->economic.tax,
338 p->economic.science, p->economic.luxury,
339 research->researching == A_UNSET ? _("(none)") : _("(Unknown)"));
340 break;
341 default:
342 fc_snprintf(cBuf, sizeof(cBuf),
343 _("Ruler: %s Government: %s\n"
344 "Capital: %s Gold: %d\n"
345 "Tax: %d%% Science: %d%% Luxury: %d%%\n"
346 "Researching: %s(%d/%d)"),
347 ruler_title_for_player(p, plr_buf, sizeof(plr_buf)),
348 government_name_for_player(p),
349 /* TRANS: "unknown" location */
350 NULL != pCapital ? city_name_get(pCapital) : _("(Unknown)"),
351 p->economic.gold, p->economic.tax, p->economic.science,
352 p->economic.luxury,
353 research_advance_name_translation(research,
354 research->researching),
355 research->bulbs_researched,
356 research->client.researching_cost);
357 break;
358 };
359 } else {
360 fc_snprintf(cBuf, sizeof(cBuf),
361 _("Ruler: %s Government: %s\n"
362 "Capital: %s Gold: %d\n"
363 "Tax rates unknown\n"
364 "Researching: (Unknown)"),
365 ruler_title_for_player(p, plr_buf, sizeof(plr_buf)),
366 government_name_for_player(p),
367 /* TRANS: "unknown" location */
368 NULL != pCapital ? city_name_get(pCapital) : _("(Unknown)"),
369 p->economic.gold);
370 }
371
372 copy_chars_to_utf8_str(pstr, cBuf);
373 pInfo = create_text_surf_from_utf8(pstr);
374 area.w = MAX(area.w, pLogo->w + adj_size(10) + pInfo->w + adj_size(20));
375 area.h += MAX(pLogo->h + adj_size(20), pInfo->h + adj_size(20));
376
377 /* ---------- */
378 pTmpSurf = get_tech_icon(A_FIRST);
379 col = area.w / (pTmpSurf->w + adj_size(4));
380 FREESURFACE(pTmpSurf);
381 n = 0;
382 pLast = pBuf;
383 mresearch = research_get(client_player());
384 presearch = research_get(p);
385 advance_index_iterate(A_FIRST, i) {
386 if (TECH_KNOWN == research_invention_state(presearch, i)
387 && research_invention_reachable(mresearch, i)
388 && TECH_KNOWN != research_invention_state(mresearch, i)) {
389
390 pBuf = create_icon2(get_tech_icon(i), pWindow->dst,
391 WF_RESTORE_BACKGROUND | WF_WIDGET_HAS_INFO_LABEL
392 | WF_FREE_THEME);
393 pBuf->action = tech_callback;
394 set_wstate(pBuf, FC_WS_NORMAL);
395
396 pBuf->info_label =
397 create_utf8_from_char(advance_name_translation
398 (advance_by_number(i)), adj_font(12));
399
400 add_to_gui_list(ID_ICON, pBuf);
401
402 if (n > ((2 * col) - 1)) {
403 set_wflag(pBuf, WF_HIDDEN);
404 }
405
406 n++;
407 }
408 } advance_index_iterate_end;
409
410 pdialog->pdialog->pBeginWidgetList = pBuf;
411
412 if (n > 0) {
413 pdialog->pdialog->pEndActiveWidgetList = pLast->prev;
414 pdialog->pdialog->pBeginActiveWidgetList = pdialog->pdialog->pBeginWidgetList;
415 if (n > 2 * col) {
416 pdialog->pdialog->pActiveWidgetList = pdialog->pdialog->pEndActiveWidgetList;
417 count = create_vertical_scrollbar(pdialog->pdialog, col, 2, TRUE, TRUE);
418 area.h += (2 * pBuf->size.h + adj_size(10));
419 } else {
420 count = 0;
421 if (n > col) {
422 area.h += pBuf->size.h;
423 }
424 area.h += (adj_size(10) + pBuf->size.h);
425 }
426
427 area.w = MAX(area.w, col * pBuf->size.w + count);
428
429 fc_snprintf(cBuf, sizeof(cBuf), _("Their techs that we don't have :"));
430 copy_chars_to_utf8_str(pstr, cBuf);
431 pstr->style |= TTF_STYLE_BOLD;
432 pText2 = create_text_surf_from_utf8(pstr);
433 }
434
435 FREEUTF8STR(pstr);
436
437 resize_window(pWindow, NULL, NULL,
438 (pWindow->size.w - pWindow->area.w) + area.w,
439 (pWindow->size.h - pWindow->area.h) + area.h);
440
441 area = pWindow->area;
442
443 /* ------------------------ */
444 widget_set_position(pWindow,
445 (pdialog->pos_x) ? (pdialog->pos_x) : ((main_window_width() - pWindow->size.w) / 2),
446 (pdialog->pos_y) ? (pdialog->pos_y) : ((main_window_height() - pWindow->size.h) / 2));
447
448 /* exit button */
449 pBuf = pWindow->prev;
450 pBuf->size.x = area.x + area.w - pBuf->size.w - 1;
451 pBuf->size.y = pWindow->size.y + adj_size(2);
452
453 dst.x = area.x + (area.w - pText1->w) / 2;
454 dst.y = area.y + adj_size(8);
455
456 alphablit(pText1, NULL, pWindow->theme, &dst, 255);
457 dst.y += pText1->h + adj_size(10);
458 FREESURFACE(pText1);
459
460 /* spaceship button */
461 pBuf = pBuf->prev;
462 dst.x = area.x + (area.w - (pBuf->size.w + adj_size(10) + pInfo->w)) / 2;
463 pBuf->size.x = dst.x;
464 pBuf->size.y = dst.y;
465
466 dst.x += pBuf->size.w + adj_size(10);
467 alphablit(pInfo, NULL, pWindow->theme, &dst, 255);
468 dst.y += pInfo->h + adj_size(10);
469 FREESURFACE(pInfo);
470
471 /* --------------------- */
472
473 if (n) {
474 dst.x = area.x + adj_size(5);
475 alphablit(pText2, NULL, pWindow->theme, &dst, 255);
476 dst.y += pText2->h + adj_size(2);
477 FREESURFACE(pText2);
478
479 setup_vertical_widgets_position(col, area.x, dst.y, 0, 0,
480 pdialog->pdialog->pBeginActiveWidgetList,
481 pdialog->pdialog->pEndActiveWidgetList);
482
483 if (pdialog->pdialog->pScroll) {
484 setup_vertical_scrollbar_area(pdialog->pdialog->pScroll,
485 area.x + area.w, dst.y,
486 area.h - (dst.y + 1), TRUE);
487 }
488 }
489
490 redraw_group(pdialog->pdialog->pBeginWidgetList, pdialog->pdialog->pEndWidgetList, 0);
491 widget_mark_dirty(pWindow);
492
493 flush_dirty();
494 }
495 }
496