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