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 /***********************************************************************
15                           repodlgs.c  -  description
16                              -------------------
17     begin                : Nov 15 2002
18     copyright            : (C) 2002 by Rafał Bursig
19     email                : Rafał Bursig <bursig@poczta.fm>
20 ***********************************************************************/
21 
22 #ifdef HAVE_CONFIG_H
23 #include <fc_config.h>
24 #endif
25 
26 /* utility */
27 #include "fcintl.h"
28 #include "log.h"
29 
30 /* common */
31 #include "game.h"
32 #include "government.h"
33 #include "research.h"
34 #include "unitlist.h"
35 
36 /* client */
37 #include "client_main.h"
38 #include "text.h"
39 
40 /* gui-sdl2 */
41 #include "cityrep.h"
42 #include "colors.h"
43 #include "dialogs.h"
44 #include "graphics.h"
45 #include "gui_id.h"
46 #include "gui_main.h"
47 #include "gui_tilespec.h"
48 #include "helpdlg.h"
49 #include "mapctrl.h"
50 #include "mapview.h"
51 #include "sprite.h"
52 #include "themespec.h"
53 #include "widget.h"
54 
55 #include "repodlgs.h"
56 
57 
58 /* ===================================================================== */
59 /* ======================== Active Units Report ======================== */
60 /* ===================================================================== */
61 static struct ADVANCED_DLG *pUnitsDlg = NULL;
62 static struct SMALL_DLG *pUnits_Upg_Dlg = NULL;
63 
64 struct units_entry {
65   int active_count;
66   int upkeep[O_LAST];
67   int building_count;
68   int soonest_completions;
69 };
70 
71 /**************************************************************************
72   Fill unit types specific report data + totals.
73 **************************************************************************/
get_units_report_data(struct units_entry * entries,struct units_entry * total)74 static void get_units_report_data(struct units_entry *entries,
75                                   struct units_entry *total)
76 {
77   int time_to_build;
78 
79   memset(entries, '\0', U_LAST * sizeof(struct units_entry));
80   memset(total, '\0', sizeof(struct units_entry));
81   for (time_to_build = 0; time_to_build < U_LAST; time_to_build++) {
82     entries[time_to_build].soonest_completions = FC_INFINITY;
83   }
84 
85   unit_list_iterate(client.conn.playing->units, punit) {
86     Unit_type_id uti = utype_index(unit_type_get(punit));
87 
88     (entries[uti].active_count)++;
89     (total->active_count)++;
90     if (punit->homecity) {
91       output_type_iterate(o) {
92         entries[uti].upkeep[o] += punit->upkeep[o];
93         total->upkeep[o] += punit->upkeep[o];
94       } output_type_iterate_end;
95     }
96   } unit_list_iterate_end;
97 
98   city_list_iterate(client.conn.playing->cities, pCity) {
99     if (VUT_UTYPE == pCity->production.kind) {
100       struct unit_type *pUnitType = pCity->production.value.utype;
101       Unit_type_id uti = utype_index(pUnitType);
102       int num_units;
103 
104       /* Account for build slots in city */
105       (void) city_production_build_units(pCity, TRUE, &num_units);
106       /* Unit is in progress even if it won't be done this turn */
107       num_units = MAX(num_units, 1);
108       (entries[uti].building_count) += num_units;
109       (total->building_count) += num_units;
110       entries[uti].soonest_completions =
111         MIN(entries[uti].soonest_completions,
112             city_production_turns_to_build(pCity, TRUE));
113     }
114   } city_list_iterate_end;
115 }
116 
117 /**************************************************************************
118   User interacted with Units Report button.
119 **************************************************************************/
units_dialog_callback(struct widget * pWindow)120 static int units_dialog_callback(struct widget *pWindow)
121 {
122   if (PRESSED_EVENT(Main.event)) {
123     move_window_group(pUnitsDlg->pBeginWidgetList, pWindow);
124   }
125 
126   return -1;
127 }
128 
129 /* --------------------------------------------------------------- */
130 
131 /**************************************************************************
132   User interacted with accept button of the unit upgrade dialog.
133 **************************************************************************/
ok_upgrade_unit_window_callback(struct widget * pWidget)134 static int ok_upgrade_unit_window_callback(struct widget *pWidget)
135 {
136   if (PRESSED_EVENT(Main.event)) {
137     int ut1 = MAX_ID - pWidget->ID;
138 
139     /* popdown upgrade dlg */
140     popdown_window_group_dialog(pUnits_Upg_Dlg->pBeginWidgetList,
141                                 pUnits_Upg_Dlg->pEndWidgetList);
142     FC_FREE(pUnits_Upg_Dlg);
143 
144     dsend_packet_unit_type_upgrade(&client.conn, ut1);
145   }
146 
147   return -1;
148 }
149 
150 /**************************************************************************
151   User interacted with Upgrade Obsolete button of the unit upgrade dialog.
152 **************************************************************************/
upgrade_unit_window_callback(struct widget * pWindow)153 static int upgrade_unit_window_callback(struct widget *pWindow)
154 {
155   if (PRESSED_EVENT(Main.event)) {
156     move_window_group(pUnits_Upg_Dlg->pBeginWidgetList, pWindow);
157   }
158 
159   return -1;
160 }
161 
162 /**************************************************************************
163   User interacted with Cancel button of the unit upgrade dialog.
164 **************************************************************************/
cancel_upgrade_unit_callback(struct widget * pWidget)165 static int cancel_upgrade_unit_callback(struct widget *pWidget)
166 {
167   if (PRESSED_EVENT(Main.event)) {
168     if (pUnits_Upg_Dlg) {
169       popdown_window_group_dialog(pUnits_Upg_Dlg->pBeginWidgetList,
170                                   pUnits_Upg_Dlg->pEndWidgetList);
171       FC_FREE(pUnits_Upg_Dlg);
172       flush_dirty();
173     }
174   }
175 
176   return -1;
177 }
178 
179 /**************************************************************************
180   Open dialog for upgrading units.
181 **************************************************************************/
popup_upgrade_unit_callback(struct widget * pWidget)182 static int popup_upgrade_unit_callback(struct widget *pWidget)
183 {
184   if (PRESSED_EVENT(Main.event)) {
185     struct unit_type *ut1;
186     struct unit_type *ut2;
187     int value;
188     char tBuf[128], cBuf[128];
189     struct widget *pBuf = NULL, *pWindow;
190     utf8_str *pstr;
191     SDL_Surface *pText;
192     SDL_Rect dst;
193     SDL_Rect area;
194 
195     ut1 = utype_by_number(MAX_ID - pWidget->ID);
196 
197     if (pUnits_Upg_Dlg) {
198       return 1;
199     }
200 
201     set_wstate(pWidget, FC_WS_NORMAL);
202     selected_widget = NULL;
203     widget_redraw(pWidget);
204     widget_mark_dirty(pWidget);
205 
206     pUnits_Upg_Dlg = fc_calloc(1, sizeof(struct SMALL_DLG));
207 
208     ut2 = can_upgrade_unittype(client.conn.playing, ut1);
209     value = unit_upgrade_price(client.conn.playing, ut1, ut2);
210 
211     fc_snprintf(tBuf, ARRAY_SIZE(tBuf), PL_("Treasury contains %d gold.",
212                                             "Treasury contains %d gold.",
213                                             client_player()->economic.gold),
214                 client_player()->economic.gold);
215 
216     fc_snprintf(cBuf, sizeof(cBuf),
217           /* TRANS: Last %s is pre-pluralised "Treasury contains %d gold." */
218           PL_("Upgrade as many %s to %s as possible for %d gold each?\n%s",
219               "Upgrade as many %s to %s as possible for %d gold each?\n%s",
220               value),
221           utype_name_translation(ut1),
222           utype_name_translation(ut2),
223           value, tBuf);
224 
225     pstr = create_utf8_from_char(_("Upgrade Obsolete Units"), adj_font(12));
226     pstr->style |= TTF_STYLE_BOLD;
227 
228     pWindow = create_window_skeleton(NULL, pstr, 0);
229 
230     pWindow->action = upgrade_unit_window_callback;
231     set_wstate(pWindow, FC_WS_NORMAL);
232 
233     add_to_gui_list(ID_WINDOW, pWindow);
234 
235     pUnits_Upg_Dlg->pEndWidgetList = pWindow;
236 
237     area = pWindow->area;
238 
239     /* ============================================================= */
240 
241     /* create text label */
242     pstr = create_utf8_from_char(cBuf, adj_font(10));
243     pstr->style |= (TTF_STYLE_BOLD|SF_CENTER);
244     pstr->fgcol = *get_theme_color(COLOR_THEME_UNITUPGRADE_TEXT);
245 
246     pText = create_text_surf_from_utf8(pstr);
247     FREEUTF8STR(pstr);
248 
249     area.h += (pText->h + adj_size(10));
250     area.w = MAX(area.w, pText->w + adj_size(20));
251 
252     /* cancel button */
253     pBuf = create_themeicon_button_from_chars(current_theme->CANCEL_Icon,
254                                               pWindow->dst, _("No"),
255                                               adj_font(12), 0);
256 
257     pBuf->action = cancel_upgrade_unit_callback;
258     set_wstate(pBuf, FC_WS_NORMAL);
259 
260     area.h += (pBuf->size.h + adj_size(20));
261 
262     add_to_gui_list(ID_BUTTON, pBuf);
263 
264     if (value <= client.conn.playing->economic.gold) {
265       pBuf = create_themeicon_button_from_chars(current_theme->OK_Icon, pWindow->dst,
266                                                 _("Yes"), adj_font(12), 0);
267 
268       pBuf->action = ok_upgrade_unit_window_callback;
269       set_wstate(pBuf, FC_WS_NORMAL);
270 
271       add_to_gui_list(pWidget->ID, pBuf);
272       pBuf->size.w = MAX(pBuf->size.w, pBuf->next->size.w);
273       pBuf->next->size.w = pBuf->size.w;
274       area.w = MAX(area.w, adj_size(30) + pBuf->size.w * 2);
275     } else {
276       area.w = MAX(area.w, pBuf->size.w + adj_size(20));
277     }
278     /* ============================================ */
279 
280     pUnits_Upg_Dlg->pBeginWidgetList = pBuf;
281 
282     resize_window(pWindow, NULL, get_theme_color(COLOR_THEME_BACKGROUND),
283                   (pWindow->size.w - pWindow->area.w) + area.w,
284                   (pWindow->size.h - pWindow->area.h) + area.h);
285 
286     widget_set_position(pWindow,
287                         pUnitsDlg->pEndWidgetList->size.x +
288                           (pUnitsDlg->pEndWidgetList->size.w - pWindow->size.w) / 2,
289                         pUnitsDlg->pEndWidgetList->size.y +
290                           (pUnitsDlg->pEndWidgetList->size.h - pWindow->size.h) / 2);
291 
292     /* setup rest of widgets */
293     /* label */
294     dst.x = area.x + (area.w - pText->w) / 2;
295     dst.y = area.y + adj_size(10);
296     alphablit(pText, NULL, pWindow->theme, &dst, 255);
297     FREESURFACE(pText);
298 
299     /* cancel button */
300     pBuf = pWindow->prev;
301     pBuf->size.y = area.y + area.h - pBuf->size.h - adj_size(10);
302 
303     if (value <= client.conn.playing->economic.gold) {
304       /* sell button */
305       pBuf = pBuf->prev;
306       pBuf->size.x = area.x + (area.w - (2 * pBuf->size.w + adj_size(10))) / 2;
307       pBuf->size.y = pBuf->next->size.y;
308 
309       /* cancel button */
310       pBuf->next->size.x = pBuf->size.x + pBuf->size.w + adj_size(10);
311     } else {
312       /* x position of cancel button */
313       pBuf->size.x = area.x + area.w - pBuf->size.w - adj_size(10);
314     }
315 
316     /* ================================================== */
317     /* redraw */
318     redraw_group(pUnits_Upg_Dlg->pBeginWidgetList, pWindow, 0);
319 
320     widget_mark_dirty(pWindow);
321     flush_dirty();
322   }
323 
324   return -1;
325 }
326 
327 /**************************************************************************
328   User interacted with units dialog Close Dialog button.
329 **************************************************************************/
exit_units_dlg_callback(struct widget * pWidget)330 static int exit_units_dlg_callback(struct widget *pWidget)
331 {
332   if (PRESSED_EVENT(Main.event)) {
333     if (pUnitsDlg) {
334       if (pUnits_Upg_Dlg) {
335          del_group_of_widgets_from_gui_list(pUnits_Upg_Dlg->pBeginWidgetList,
336                                             pUnits_Upg_Dlg->pEndWidgetList);
337          FC_FREE(pUnits_Upg_Dlg);
338       }
339       popdown_window_group_dialog(pUnitsDlg->pBeginWidgetList,
340                                   pUnitsDlg->pEndWidgetList);
341       FC_FREE(pUnitsDlg->pScroll);
342       FC_FREE(pUnitsDlg);
343       flush_dirty();
344     }
345   }
346 
347   return -1;
348 }
349 
350 /**************************************************************************
351   Rebuild the units report.
352 **************************************************************************/
real_activeunits_report_dialog_update(struct units_entry * units,struct units_entry * total)353 static void real_activeunits_report_dialog_update(struct units_entry *units,
354                                                   struct units_entry *total)
355 {
356   SDL_Color bg_color = {255, 255, 255, 136};
357   struct widget *pBuf = NULL;
358   struct widget *pWindow, *pLast;
359   utf8_str *pstr;
360   SDL_Surface *pText1, *pText2, *pText3 , *pText4, *pText5, *pLogo;
361   int w = 0 , count, ww, hh = 0, name_w = 0;
362   char cbuf[64];
363   SDL_Rect dst;
364   bool upgrade = FALSE;
365   SDL_Rect area;
366 
367   if (pUnitsDlg) {
368     popdown_window_group_dialog(pUnitsDlg->pBeginWidgetList,
369                                 pUnitsDlg->pEndWidgetList);
370   } else {
371     pUnitsDlg = fc_calloc(1, sizeof(struct ADVANCED_DLG));
372   }
373 
374   fc_snprintf(cbuf, sizeof(cbuf), _("active"));
375   pstr = create_utf8_from_char(cbuf, adj_font(10));
376   pstr->style |= SF_CENTER;
377   pText1 = create_text_surf_from_utf8(pstr);
378 
379   fc_snprintf(cbuf, sizeof(cbuf), _("under\nconstruction"));
380   copy_chars_to_utf8_str(pstr, cbuf);
381   pText2 = create_text_surf_from_utf8(pstr);
382 
383   fc_snprintf(cbuf, sizeof(cbuf), _("soonest\ncompletion"));
384   copy_chars_to_utf8_str(pstr, cbuf);
385   pText5 = create_text_surf_from_utf8(pstr);
386 
387   fc_snprintf(cbuf, sizeof(cbuf), _("Total"));
388   copy_chars_to_utf8_str(pstr, cbuf);
389   pText3 = create_text_surf_from_utf8(pstr);
390 
391   fc_snprintf(cbuf, sizeof(cbuf), _("Units"));
392   copy_chars_to_utf8_str(pstr, cbuf);
393   pText4 = create_text_surf_from_utf8(pstr);
394   name_w = pText4->w;
395   FREEUTF8STR(pstr);
396 
397   /* --------------- */
398   pstr = create_utf8_from_char(_("Units Report"), adj_font(12));
399   pstr->style |= TTF_STYLE_BOLD;
400 
401   pWindow = create_window_skeleton(NULL, pstr, 0);
402   set_wstate(pWindow, FC_WS_NORMAL);
403   pWindow->action = units_dialog_callback;
404 
405   add_to_gui_list(ID_UNITS_DIALOG_WINDOW, pWindow);
406 
407   pUnitsDlg->pEndWidgetList = pWindow;
408 
409   area = pWindow->area;
410 
411   /* ------------------------- */
412   /* exit button */
413   pBuf = create_themeicon(current_theme->Small_CANCEL_Icon, pWindow->dst,
414                           WF_WIDGET_HAS_INFO_LABEL | WF_RESTORE_BACKGROUND);
415   pBuf->info_label = create_utf8_from_char(_("Close Dialog (Esc)"), adj_font(12));
416   pBuf->action = exit_units_dlg_callback;
417   set_wstate(pBuf, FC_WS_NORMAL);
418   pBuf->key = SDLK_ESCAPE;
419 
420   add_to_gui_list(ID_BUTTON, pBuf);
421   /* ------------------------- */
422   /* totals */
423   fc_snprintf(cbuf, sizeof(cbuf), "%d", total->active_count);
424 
425   pstr = create_utf8_from_char(cbuf, adj_font(10));
426   pstr->style |= (TTF_STYLE_BOLD|SF_CENTER);
427 
428   pBuf = create_iconlabel(NULL, pWindow->dst, pstr,
429                           WF_RESTORE_BACKGROUND);
430 
431   area.h += pBuf->size.h;
432   pBuf->size.w = pText1->w + adj_size(6);
433   add_to_gui_list(ID_LABEL, pBuf);
434   /* ---------------------------------------------- */
435   fc_snprintf(cbuf, sizeof(cbuf), "%d", total->upkeep[O_SHIELD]);
436 
437   pstr = create_utf8_from_char(cbuf, adj_font(10));
438   pstr->style |= (TTF_STYLE_BOLD|SF_CENTER);
439 
440   pBuf = create_iconlabel(NULL, pWindow->dst, pstr, WF_RESTORE_BACKGROUND);
441 
442   pBuf->size.w = pText1->w;
443   add_to_gui_list(ID_LABEL, pBuf);
444   /* ---------------------------------------------- */
445   fc_snprintf(cbuf, sizeof(cbuf), "%d", total->upkeep[O_FOOD]);
446 
447   pstr = create_utf8_from_char(cbuf, adj_font(10));
448   pstr->style |= (TTF_STYLE_BOLD|SF_CENTER);
449 
450   pBuf = create_iconlabel(NULL, pWindow->dst, pstr, WF_RESTORE_BACKGROUND);
451 
452   pBuf->size.w = pText1->w;
453   add_to_gui_list(ID_LABEL, pBuf);
454   /* ---------------------------------------------- */
455   fc_snprintf(cbuf, sizeof(cbuf), "%d", total->upkeep[O_GOLD]);
456 
457   pstr = create_utf8_from_char(cbuf, adj_font(10));
458   pstr->style |= (TTF_STYLE_BOLD|SF_CENTER);
459 
460   pBuf = create_iconlabel(NULL, pWindow->dst, pstr, WF_RESTORE_BACKGROUND);
461 
462   pBuf->size.w = pText1->w;
463   add_to_gui_list(ID_LABEL, pBuf);
464   /* ---------------------------------------------- */
465   fc_snprintf(cbuf, sizeof(cbuf), "%d", total->building_count);
466 
467   pstr = create_utf8_from_char(cbuf, adj_font(10));
468   pstr->style |= (TTF_STYLE_BOLD|SF_CENTER);
469 
470   pBuf = create_iconlabel(NULL, pWindow->dst, pstr,
471                           WF_RESTORE_BACKGROUND);
472 
473   pBuf->size.w = pText2->w + adj_size(6);
474   add_to_gui_list(ID_LABEL, pBuf);
475 
476   /* ------------------------- */
477   pLast = pBuf;
478   count = 0;
479   unit_type_iterate(i) {
480     if ((units[utype_index(i)].active_count > 0)
481         || (units[utype_index(i)].building_count > 0)) {
482       upgrade = (can_upgrade_unittype(client.conn.playing, i) != NULL);
483 
484       /* unit type icon */
485       pBuf = create_iconlabel(adj_surf(get_unittype_surface(i, direction8_invalid())), pWindow->dst, NULL,
486                               WF_RESTORE_BACKGROUND | WF_FREE_THEME);
487       if (count > adj_size(72)) {
488         set_wflag(pBuf, WF_HIDDEN);
489       }
490       hh = pBuf->size.h;
491       add_to_gui_list(MAX_ID - utype_number(i), pBuf);
492 
493       /* unit type name */
494       pstr = create_utf8_from_char(utype_name_translation(i), adj_font(12));
495       pstr->style |= (TTF_STYLE_BOLD|SF_CENTER);
496       pBuf = create_iconlabel(NULL, pWindow->dst, pstr,
497                               (WF_RESTORE_BACKGROUND | WF_SELECT_WITHOUT_BAR));
498       if (upgrade) {
499         pBuf->string_utf8->fgcol = *get_theme_color(COLOR_THEME_UNITUPGRADE_TEXT);
500         pBuf->action = popup_upgrade_unit_callback;
501         set_wstate(pBuf, FC_WS_NORMAL);
502       } else {
503         pBuf->string_utf8->fgcol = *get_theme_color(COLOR_THEME_UNITSREP_TEXT);
504       }
505       pBuf->string_utf8->style &= ~SF_CENTER;
506       if (count > adj_size(72)) {
507         set_wflag(pBuf , WF_HIDDEN);
508       }
509       hh = MAX(hh, pBuf->size.h);
510       name_w = MAX(pBuf->size.w, name_w);
511       add_to_gui_list(MAX_ID - utype_number(i), pBuf);
512 
513       /* active */
514       fc_snprintf(cbuf, sizeof(cbuf), "%d", units[utype_index(i)].active_count);
515       pstr = create_utf8_from_char(cbuf, adj_font(10));
516       pstr->style |= SF_CENTER;
517       pBuf = create_iconlabel(NULL, pWindow->dst, pstr,
518                               WF_RESTORE_BACKGROUND);
519       if (count > adj_size(72)) {
520         set_wflag(pBuf, WF_HIDDEN);
521       }
522       hh = MAX(hh, pBuf->size.h);
523       pBuf->size.w = pText1->w + adj_size(6);
524       add_to_gui_list(MAX_ID - utype_number(i), pBuf);
525 
526       /* shield upkeep */
527       fc_snprintf(cbuf, sizeof(cbuf), "%d", units[utype_index(i)].upkeep[O_SHIELD]);
528       pstr = create_utf8_from_char(cbuf, adj_font(10));
529       pstr->style |= SF_CENTER;
530       pBuf = create_iconlabel(NULL, pWindow->dst, pstr,
531                               WF_RESTORE_BACKGROUND);
532       if (count > adj_size(72)) {
533         set_wflag(pBuf, WF_HIDDEN);
534       }
535       hh = MAX(hh, pBuf->size.h);
536       pBuf->size.w = pText1->w;
537       add_to_gui_list(MAX_ID - utype_number(i), pBuf);
538 
539       /* food upkeep */
540       fc_snprintf(cbuf, sizeof(cbuf), "%d", units[utype_index(i)].upkeep[O_FOOD]);
541       pstr = create_utf8_from_char(cbuf, adj_font(10));
542       pstr->style |= SF_CENTER;
543       pBuf = create_iconlabel(NULL, pWindow->dst, pstr,
544                               WF_RESTORE_BACKGROUND);
545       if (count > adj_size(72)) {
546         set_wflag(pBuf, WF_HIDDEN);
547       }
548 
549       hh = MAX(hh, pBuf->size.h);
550       pBuf->size.w = pText1->w;
551       add_to_gui_list(MAX_ID - utype_number(i), pBuf);
552 
553       /* gold upkeep */
554       fc_snprintf(cbuf, sizeof(cbuf), "%d", units[utype_index(i)].upkeep[O_GOLD]);
555       pstr = create_utf8_from_char(cbuf, adj_font(10));
556       pstr->style |= SF_CENTER;
557       pBuf = create_iconlabel(NULL, pWindow->dst, pstr,
558                               WF_RESTORE_BACKGROUND);
559       if (count > adj_size(72)) {
560         set_wflag(pBuf, WF_HIDDEN);
561       }
562 
563       hh = MAX(hh, pBuf->size.h);
564       pBuf->size.w = pText1->w;
565       add_to_gui_list(MAX_ID - utype_number(i), pBuf);
566 
567       /* building */
568       if (units[utype_index(i)].building_count > 0) {
569         fc_snprintf(cbuf, sizeof(cbuf), "%d", units[utype_index(i)].building_count);
570       } else {
571         fc_snprintf(cbuf, sizeof(cbuf), "--");
572       }
573       pstr = create_utf8_from_char(cbuf, adj_font(10));
574       pstr->style |= SF_CENTER;
575       pBuf = create_iconlabel(NULL, pWindow->dst, pstr,
576                               WF_RESTORE_BACKGROUND);
577       if (count > adj_size(72)) {
578         set_wflag(pBuf, WF_HIDDEN);
579       }
580       hh = MAX(hh, pBuf->size.h);
581       pBuf->size.w = pText2->w + adj_size(6);
582       add_to_gui_list(MAX_ID - utype_number(i), pBuf);
583 
584       /* soonest completion */
585       if (units[utype_index(i)].building_count > 0) {
586         fc_snprintf(cbuf, sizeof(cbuf), "%d %s", units[utype_index(i)].soonest_completions,
587                     PL_("turn", "turns", units[utype_index(i)].soonest_completions));
588       } else {
589         fc_snprintf(cbuf, sizeof(cbuf), "--");
590       }
591 
592       pstr = create_utf8_from_char(cbuf, adj_font(10));
593       pstr->style |= SF_CENTER;
594       pBuf = create_iconlabel(NULL, pWindow->dst, pstr,
595                               WF_RESTORE_BACKGROUND);
596 
597       if (count > adj_size(72)) {
598         set_wflag(pBuf, WF_HIDDEN);
599       }
600       hh = MAX(hh, pBuf->size.h);
601       pBuf->size.w = pText5->w + adj_size(6);
602       add_to_gui_list(MAX_ID - utype_number(i), pBuf);
603 
604       count += adj_size(8);
605       area.h += (hh/2);
606     }
607   } unit_type_iterate_end;
608 
609   pUnitsDlg->pBeginWidgetList = pBuf;
610   area.w = MAX(area.w, (tileset_full_tile_width(tileset) * 2 + name_w + adj_size(15))
611                + (adj_size(4) * pText1->w + adj_size(46)) + (pText2->w + adj_size(16))
612                + (pText5->w + adj_size(6)) + adj_size(2));
613   if (count > 0) {
614     pUnitsDlg->pEndActiveWidgetList = pLast->prev;
615     pUnitsDlg->pBeginActiveWidgetList = pUnitsDlg->pBeginWidgetList;
616     if (count > adj_size(80)) {
617       pUnitsDlg->pActiveWidgetList = pUnitsDlg->pEndActiveWidgetList;
618       if (pUnitsDlg->pScroll) {
619 	pUnitsDlg->pScroll->count = count;
620       }
621       ww = create_vertical_scrollbar(pUnitsDlg, 8, 10, TRUE, TRUE);
622       area.w += ww;
623       area.h = (hh + 9 * (hh/2) + adj_size(10));
624     } else {
625       area.h += hh/2;
626     }
627   } else {
628     area.h = adj_size(50);
629   }
630 
631   area.h += pText1->h + adj_size(10);
632   area.w += adj_size(2);
633 
634   pLogo = theme_get_background(theme, BACKGROUND_UNITSREP);
635   resize_window(pWindow, pLogo,	NULL,
636                 (pWindow->size.w - pWindow->area.w) + area.w,
637                 (pWindow->size.h - pWindow->area.h) + area.h);
638   FREESURFACE(pLogo);
639 
640 #if 0
641   pLogo = SDL_DisplayFormat(pWindow->theme);
642   FREESURFACE(pWindow->theme);
643   pWindow->theme = pLogo;
644   pLogo = NULL;
645 #endif /* 0 */
646 
647   area = pWindow->area;
648 
649   widget_set_position(pWindow,
650                       (main_window_width() - pWindow->size.w) / 2,
651                       (main_window_height() - pWindow->size.h) / 2);
652 
653   /* exit button */
654   pBuf = pWindow->prev;
655   pBuf->size.x = area.x + area.w - pBuf->size.w - 1;
656   pBuf->size.y = pWindow->size.y + adj_size(2);
657 
658   /* totals background and label */
659   dst.x = area.x + adj_size(2);
660   dst.y = area.y + area.h - (pText3->h + adj_size(2)) - adj_size(2);
661   dst.w = name_w + tileset_full_tile_width(tileset) * 2 + adj_size(5);
662   dst.h = pText3->h + adj_size(2);
663   fill_rect_alpha(pWindow->theme, &dst, &bg_color);
664 
665   create_frame(pWindow->theme,
666                dst.x, dst.y, dst.w, dst.h - 1,
667                get_theme_color(COLOR_THEME_UNITSREP_FRAME));
668 
669   dst.y += 1;
670   dst.x += ((name_w + tileset_full_tile_width(tileset) * 2 + adj_size(5)) - pText3->w) / 2;
671   alphablit(pText3, NULL, pWindow->theme, &dst, 255);
672   FREESURFACE(pText3);
673 
674   /* total active widget */
675   pBuf = pBuf->prev;
676   pBuf->size.x = area.x + name_w
677     + tileset_full_tile_width(tileset) * 2 + adj_size(17);
678   pBuf->size.y = dst.y;
679 
680   /* total shields cost widget */
681   pBuf = pBuf->prev;
682   pBuf->size.x = pBuf->next->size.x + pBuf->next->size.w + adj_size(10);
683   pBuf->size.y = dst.y;
684 
685   /* total food cost widget */
686   pBuf = pBuf->prev;
687   pBuf->size.x = pBuf->next->size.x + pBuf->next->size.w + adj_size(10);
688   pBuf->size.y = dst.y;
689 
690   /* total gold cost widget */
691   pBuf = pBuf->prev;
692   pBuf->size.x = pBuf->next->size.x + pBuf->next->size.w + adj_size(10);
693   pBuf->size.y = dst.y;
694 
695   /* total building count widget */
696   pBuf = pBuf->prev;
697   pBuf->size.x = pBuf->next->size.x + pBuf->next->size.w + adj_size(10);
698   pBuf->size.y = dst.y;
699 
700   /* units background and labels */
701   dst.x = area.x + adj_size(2);
702   dst.y = area.y + 1;
703   dst.w = name_w + tileset_full_tile_width(tileset) * 2 + adj_size(5);
704   dst.h = pText4->h + adj_size(2);
705   fill_rect_alpha(pWindow->theme, &dst, &bg_color);
706 
707   create_frame(pWindow->theme,
708                dst.x, dst.y, dst.w, dst.h - 1,
709                get_theme_color(COLOR_THEME_UNITSREP_FRAME));
710 
711   dst.y += 1;
712   dst.x += ((name_w + tileset_full_tile_width(tileset) * 2 + adj_size(5))- pText4->w) / 2;
713   alphablit(pText4, NULL, pWindow->theme, &dst, 255);
714   FREESURFACE(pText4);
715 
716   /* active count background and label */
717   dst.x = area.x + adj_size(2) + name_w + tileset_full_tile_width(tileset) * 2 + adj_size(15);
718   dst.y = area.y + 1;
719   dst.w = pText1->w + adj_size(6);
720   dst.h = area.h - adj_size(3);
721   fill_rect_alpha(pWindow->theme, &dst, &bg_color);
722 
723   create_frame(pWindow->theme,
724                dst.x, dst.y, dst.w, dst.h - 1,
725                get_theme_color(COLOR_THEME_UNITSREP_FRAME));
726 
727   dst.x += adj_size(3);
728   alphablit(pText1, NULL, pWindow->theme, &dst, 255);
729   ww = pText1->w;
730   hh = pText1->h;
731   FREESURFACE(pText1);
732 
733   /* shields cost background and label */
734   dst.x += (ww + adj_size(13));
735   w = dst.x;
736   dst.w = ww;
737   dst.h = area.h - adj_size(3);
738   fill_rect_alpha(pWindow->theme, &dst, &bg_color);
739 
740   create_frame(pWindow->theme,
741                dst.x, dst.y, dst.w, dst.h - 1,
742                get_theme_color(COLOR_THEME_UNITSREP_FRAME));
743 
744   dst.y = area.y + adj_size(3);
745   dst.x += ((ww - pIcons->pBIG_Shield->w) / 2);
746   alphablit(pIcons->pBIG_Shield, NULL, pWindow->theme, &dst, 255);
747 
748   /* food cost background and label */
749   dst.x = w + ww + adj_size(10);
750   w = dst.x;
751   dst.y = area.y + 1;
752   dst.w = ww;
753   dst.h = area.h - adj_size(3);
754   fill_rect_alpha(pWindow->theme, &dst, &bg_color);
755 
756   create_frame(pWindow->theme,
757                dst.x, dst.y, dst.w, dst.h - 1,
758                get_theme_color(COLOR_THEME_UNITSREP_FRAME));
759 
760   dst.y = area.y + adj_size(3);
761   dst.x += ((ww - pIcons->pBIG_Food->w) / 2);
762   alphablit(pIcons->pBIG_Food, NULL, pWindow->theme, &dst, 255);
763 
764   /* gold cost background and label */
765   dst.x = w + ww + adj_size(10);
766   w = dst.x;
767   dst.y = area.y + 1;
768   dst.w = ww;
769   dst.h = area.h - adj_size(3);
770   fill_rect_alpha(pWindow->theme, &dst, &bg_color);
771 
772   create_frame(pWindow->theme,
773                dst.x, dst.y, dst.w, dst.h - 1,
774                get_theme_color(COLOR_THEME_UNITSREP_FRAME));
775 
776   dst.y = area.y + adj_size(3);
777   dst.x += ((ww - pIcons->pBIG_Coin->w) / 2);
778   alphablit(pIcons->pBIG_Coin, NULL, pWindow->theme, &dst, 255);
779 
780   /* building count background and label */
781   dst.x = w + ww + adj_size(10);
782   dst.y = area.y + 1;
783   dst.w = pText2->w + adj_size(6);
784   ww = pText2->w + adj_size(6);
785   w = dst.x;
786   dst.h = area.h - adj_size(3);
787   fill_rect_alpha(pWindow->theme, &dst, &bg_color);
788 
789   create_frame(pWindow->theme,
790                dst.x, dst.y, dst.w, dst.h - 1,
791                get_theme_color(COLOR_THEME_UNITSREP_FRAME));
792 
793   dst.x += adj_size(3);
794   alphablit(pText2, NULL, pWindow->theme, &dst, 255);
795   FREESURFACE(pText2);
796 
797   /* building count background and label */
798   dst.x = w + ww + adj_size(10);
799   dst.y = area.y + 1;
800   dst.w = pText5->w + adj_size(6);
801   dst.h = area.h - adj_size(3);
802   fill_rect_alpha(pWindow->theme, &dst, &bg_color);
803 
804   create_frame(pWindow->theme,
805                dst.x, dst.y, dst.w, dst.h - 1,
806                get_theme_color(COLOR_THEME_UNITSREP_FRAME));
807 
808   dst.x += adj_size(3);
809   alphablit(pText5, NULL, pWindow->theme, &dst, 255);
810   FREESURFACE(pText5);
811 
812   if (count) {
813     int start_x = area.x + adj_size(2);
814     int start_y = area.y + hh + adj_size(3);
815     int mod = 0;
816 
817     pBuf = pBuf->prev;
818     while (TRUE) {
819       /* Unit type icon */
820       pBuf->size.x = start_x + (mod ? tileset_full_tile_width(tileset) : 0);
821       pBuf->size.y = start_y;
822       hh = pBuf->size.h;
823       mod ^= 1;
824 
825       /* Unit type name */
826       pBuf = pBuf->prev;
827       pBuf->size.w = name_w;
828       pBuf->size.x = start_x + tileset_full_tile_width(tileset) * 2 + adj_size(5);
829       pBuf->size.y = start_y + (hh - pBuf->size.h) / 2;
830 
831       /* Number active */
832       pBuf = pBuf->prev;
833       pBuf->size.x = pBuf->next->size.x + pBuf->next->size.w + adj_size(10);
834       pBuf->size.y = start_y + (hh - pBuf->size.h) / 2;
835 
836       /* Shield upkeep */
837       pBuf = pBuf->prev;
838       pBuf->size.x = pBuf->next->size.x + pBuf->next->size.w + adj_size(10);
839       pBuf->size.y = start_y + (hh - pBuf->size.h) / 2;
840 
841       /* Food upkeep */
842       pBuf = pBuf->prev;
843       pBuf->size.x = pBuf->next->size.x + pBuf->next->size.w + adj_size(10);
844       pBuf->size.y = start_y + (hh - pBuf->size.h) / 2;
845 
846       /* Gold upkeep */
847       pBuf = pBuf->prev;
848       pBuf->size.x = pBuf->next->size.x + pBuf->next->size.w + adj_size(10);
849       pBuf->size.y = start_y + (hh - pBuf->size.h) / 2;
850 
851       /* Number under construction */
852       pBuf = pBuf->prev;
853       pBuf->size.x = pBuf->next->size.x + pBuf->next->size.w + adj_size(10);
854       pBuf->size.y = start_y + (hh - pBuf->size.h) / 2;
855 
856       /* Soonest completion */
857       pBuf = pBuf->prev;
858       pBuf->size.x = pBuf->next->size.x + pBuf->next->size.w + adj_size(10);
859       pBuf->size.y = start_y + (hh - pBuf->size.h) / 2;
860 
861       start_y += (hh >> 1);
862       if (pBuf == pUnitsDlg->pBeginActiveWidgetList) {
863         break;
864       }
865       pBuf = pBuf->prev;
866     }
867 
868     if (pUnitsDlg->pScroll) {
869       setup_vertical_scrollbar_area(pUnitsDlg->pScroll,
870                                     area.x + area.w, area.y,
871                                     area.h, TRUE);
872     }
873 
874   }
875   /* ----------------------------------- */
876   redraw_group(pUnitsDlg->pBeginWidgetList, pWindow, 0);
877   widget_mark_dirty(pWindow);
878 
879   flush_dirty();
880 }
881 
882 /**************************************************************************
883   update the units report.
884 **************************************************************************/
real_units_report_dialog_update(void * unused)885 void real_units_report_dialog_update(void *unused)
886 {
887   if (pUnitsDlg) {
888     struct units_entry units[U_LAST];
889     struct units_entry units_total;
890     struct widget *pWidget, *pbuf;
891     bool is_in_list = FALSE;
892     char cbuf[32];
893     bool upgrade;
894     bool search_finished;
895 
896     get_units_report_data(units, &units_total);
897 
898     /* find if there are new units entry (if not then rebuild all) */
899     pWidget = pUnitsDlg->pEndActiveWidgetList; /* icon of first list entry */
900     unit_type_iterate(i) {
901       if ((units[utype_index(i)].active_count > 0)
902           || (units[utype_index(i)].building_count > 0)) {
903         is_in_list = FALSE;
904 
905         pbuf = pWidget; /* unit type icon */
906         while (pbuf) {
907           if ((MAX_ID - pbuf->ID) == utype_number(i)) {
908             is_in_list = TRUE;
909             pWidget = pbuf;
910             break;
911           }
912           if (pbuf->prev->prev->prev->prev->prev->prev->prev ==
913               pUnitsDlg->pBeginActiveWidgetList) {
914             break;
915           }
916 
917           /* first widget of next list entry */
918           pbuf = pbuf->prev->prev->prev->prev->prev->prev->prev->prev;
919         }
920 
921         if (!is_in_list) {
922           real_activeunits_report_dialog_update(units, &units_total);
923           return;
924         }
925       }
926     } unit_type_iterate_end;
927 
928     /* update list */
929     pWidget = pUnitsDlg->pEndActiveWidgetList;
930     unit_type_iterate(i) {
931       pbuf = pWidget; /* first widget (icon) of the first list entry */
932 
933       if ((units[utype_index(i)].active_count > 0) || (units[utype_index(i)].building_count > 0)) {
934         /* the player has at least one unit of this type */
935 
936         search_finished = FALSE;
937         while (!search_finished) {
938           if ((MAX_ID - pbuf->ID) == utype_number(i)) { /* list entry for this unit type found */
939 
940             upgrade = (can_upgrade_unittype(client.conn.playing, i) != NULL);
941 
942             pbuf = pbuf->prev; /* unit type name */
943             if (upgrade) {
944               pbuf->string_utf8->fgcol = *get_theme_color(COLOR_THEME_UNITUPGRADE_TEXT);
945               pbuf->action = popup_upgrade_unit_callback;
946               set_wstate(pbuf, FC_WS_NORMAL);
947             }
948 
949             pbuf = pbuf->prev; /* active */
950             fc_snprintf(cbuf, sizeof(cbuf), "%d", units[utype_index(i)].active_count);
951             copy_chars_to_utf8_str(pbuf->string_utf8, cbuf);
952 
953             pbuf = pbuf->prev; /* shield upkeep */
954             fc_snprintf(cbuf, sizeof(cbuf), "%d", units[utype_index(i)].upkeep[O_SHIELD]);
955             copy_chars_to_utf8_str(pbuf->string_utf8, cbuf);
956 
957             pbuf = pbuf->prev; /* food upkeep */
958             fc_snprintf(cbuf, sizeof(cbuf), "%d", units[utype_index(i)].upkeep[O_FOOD]);
959             copy_chars_to_utf8_str(pbuf->string_utf8, cbuf);
960 
961             pbuf = pbuf->prev; /* gold upkeep */
962             fc_snprintf(cbuf, sizeof(cbuf), "%d", units[utype_index(i)].upkeep[O_GOLD]);
963             copy_chars_to_utf8_str(pbuf->string_utf8, cbuf);
964 
965             pbuf = pbuf->prev; /* building */
966             if (units[utype_index(i)].building_count > 0) {
967               fc_snprintf(cbuf, sizeof(cbuf), "%d", units[utype_index(i)].building_count);
968             } else {
969               fc_snprintf(cbuf, sizeof(cbuf), "--");
970             }
971             copy_chars_to_utf8_str(pbuf->string_utf8, cbuf);
972 
973             pbuf = pbuf->prev; /* soonest completion */
974             if (units[utype_index(i)].building_count > 0) {
975               fc_snprintf(cbuf, sizeof(cbuf), "%d %s", units[utype_index(i)].soonest_completions,
976                           PL_("turn", "turns", units[utype_index(i)].soonest_completions));
977             } else {
978               fc_snprintf(cbuf, sizeof(cbuf), "--");
979             }
980             copy_chars_to_utf8_str(pbuf->string_utf8, cbuf);
981 
982             pWidget = pbuf->prev; /* icon of next unit type */
983 
984             search_finished = TRUE;
985 
986           } else { /* list entry for this unit type not found yet */
987 
988             /* search it */
989             pbuf = pWidget->next;
990             do {
991               del_widget_from_vertical_scroll_widget_list(pUnitsDlg, pbuf->prev);
992             } while (((MAX_ID - pbuf->prev->ID) != utype_number(i))
993                      && (pbuf->prev != pUnitsDlg->pBeginActiveWidgetList));
994 
995             if (pbuf->prev == pUnitsDlg->pBeginActiveWidgetList) {
996               /* list entry not found - can this really happen? */
997               del_widget_from_vertical_scroll_widget_list(pUnitsDlg, pbuf->prev);
998               pWidget = pbuf->prev; /* pUnitsDlg->pBeginActiveWidgetList */
999               search_finished = TRUE;
1000             } else {
1001               /* found it */
1002               pbuf = pbuf->prev; /* first widget (icon) of list entry */
1003             }
1004           }
1005         }
1006       } else { /* player has no unit of this type */
1007         if (pbuf && pbuf->next != pUnitsDlg->pBeginActiveWidgetList) {
1008           if (utype_number(i) < (MAX_ID - pbuf->ID)) {
1009             continue;
1010           } else {
1011             pbuf = pbuf->next;
1012             do {
1013               del_widget_from_vertical_scroll_widget_list(pUnitsDlg,
1014                                                           pbuf->prev);
1015             } while (((MAX_ID - pbuf->prev->ID) == utype_number(i))
1016                      && (pbuf->prev != pUnitsDlg->pBeginActiveWidgetList));
1017             if (pbuf->prev == pUnitsDlg->pBeginActiveWidgetList) {
1018               del_widget_from_vertical_scroll_widget_list(pUnitsDlg,
1019                                                           pbuf->prev);
1020             }
1021             pWidget = pbuf->prev;
1022           }
1023         }
1024       }
1025     } unit_type_iterate_end;
1026 
1027     /* -------------------------------------- */
1028 
1029     /* total active */
1030     pbuf = pUnitsDlg->pEndWidgetList->prev->prev;
1031     fc_snprintf(cbuf, sizeof(cbuf), "%d", units_total.active_count);
1032     copy_chars_to_utf8_str(pbuf->string_utf8, cbuf);
1033 
1034     /* total shields cost */
1035     pbuf = pbuf->prev;
1036     fc_snprintf(cbuf, sizeof(cbuf), "%d", units_total.upkeep[O_SHIELD]);
1037     copy_chars_to_utf8_str(pbuf->string_utf8, cbuf);
1038 
1039     /* total food cost widget */
1040     pbuf = pbuf->prev;
1041     fc_snprintf(cbuf, sizeof(cbuf), "%d", units_total.upkeep[O_FOOD]);
1042     copy_chars_to_utf8_str(pbuf->string_utf8, cbuf);
1043 
1044     /* total gold cost widget */
1045     pbuf = pbuf->prev;
1046     fc_snprintf(cbuf, sizeof(cbuf), "%d", units_total.upkeep[O_GOLD]);
1047     copy_chars_to_utf8_str(pbuf->string_utf8, cbuf);
1048 
1049     /* total building count */
1050     pbuf = pbuf->prev;
1051     fc_snprintf(cbuf, sizeof(cbuf), "%d", units_total.building_count);
1052     copy_chars_to_utf8_str(pbuf->string_utf8, cbuf);
1053 
1054     /* -------------------------------------- */
1055     redraw_group(pUnitsDlg->pBeginWidgetList, pUnitsDlg->pEndWidgetList, 0);
1056     widget_mark_dirty(pUnitsDlg->pEndWidgetList);
1057 
1058     flush_dirty();
1059   }
1060 }
1061 
1062 /**************************************************************************
1063   Popup (or raise) the units report (F2).  It may or may not be modal.
1064 **************************************************************************/
units_report_dialog_popup(bool make_modal)1065 void units_report_dialog_popup(bool make_modal)
1066 {
1067   struct units_entry units[U_LAST];
1068   struct units_entry units_total;
1069 
1070   if (pUnitsDlg) {
1071     return;
1072   }
1073 
1074   get_units_report_data(units, &units_total);
1075   real_activeunits_report_dialog_update(units, &units_total);
1076 }
1077 
1078 /**************************************************************************
1079   Popdown the units report.
1080 **************************************************************************/
units_report_dialog_popdown(void)1081 void units_report_dialog_popdown(void)
1082 {
1083   if (pUnitsDlg) {
1084     if (pUnits_Upg_Dlg) {
1085       del_group_of_widgets_from_gui_list(pUnits_Upg_Dlg->pBeginWidgetList,
1086                                          pUnits_Upg_Dlg->pEndWidgetList);
1087       FC_FREE(pUnits_Upg_Dlg);
1088     }
1089     popdown_window_group_dialog(pUnitsDlg->pBeginWidgetList,
1090                                 pUnitsDlg->pEndWidgetList);
1091     FC_FREE(pUnitsDlg->pScroll);
1092     FC_FREE(pUnitsDlg);
1093   }
1094 }
1095 
1096 /* ===================================================================== */
1097 /* ======================== Economy Report ============================= */
1098 /* ===================================================================== */
1099 static struct ADVANCED_DLG *pEconomyDlg = NULL;
1100 static struct SMALL_DLG *pEconomy_Sell_Dlg = NULL;
1101 
1102 struct rates_move {
1103   int min, max, tax, x, gov_max;
1104   int *src_rate, *dst_rate;
1105   struct widget *pHoriz_Src, *pHoriz_Dst;
1106   struct widget *pLabel_Src, *pLabel_Dst;
1107 };
1108 
1109 /**************************************************************************
1110   User interacted with Economy Report window.
1111 **************************************************************************/
economy_dialog_callback(struct widget * pWindow)1112 static int economy_dialog_callback(struct widget *pWindow)
1113 {
1114   if (PRESSED_EVENT(Main.event)) {
1115     move_window_group(pEconomyDlg->pBeginWidgetList, pWindow);
1116   }
1117 
1118   return -1;
1119 }
1120 
1121 /**************************************************************************
1122   User interacted with Economy dialog Close Dialog button.
1123 **************************************************************************/
exit_economy_dialog_callback(struct widget * pWidget)1124 static int exit_economy_dialog_callback(struct widget *pWidget)
1125 {
1126   if (PRESSED_EVENT(Main.event)) {
1127     if (pEconomyDlg) {
1128       if (pEconomy_Sell_Dlg) {
1129         del_group_of_widgets_from_gui_list(pEconomy_Sell_Dlg->pBeginWidgetList,
1130                                            pEconomy_Sell_Dlg->pEndWidgetList);
1131         FC_FREE(pEconomy_Sell_Dlg);
1132       }
1133       popdown_window_group_dialog(pEconomyDlg->pBeginWidgetList,
1134                                   pEconomyDlg->pEndWidgetList);
1135       FC_FREE(pEconomyDlg->pScroll);
1136       FC_FREE(pEconomyDlg);
1137       set_wstate(get_tax_rates_widget(), FC_WS_NORMAL);
1138       widget_redraw(get_tax_rates_widget());
1139       widget_mark_dirty(get_tax_rates_widget());
1140       flush_dirty();
1141     }
1142   }
1143 
1144   return -1;
1145 }
1146 
1147 /**************************************************************************
1148   Toggle Rates dialog locking checkbox.
1149 **************************************************************************/
toggle_block_callback(struct widget * pCheckBox)1150 static int toggle_block_callback(struct widget *pCheckBox)
1151 {
1152   if (PRESSED_EVENT(Main.event)) {
1153     switch (pCheckBox->ID) {
1154     case ID_CHANGE_TAXRATE_DLG_LUX_BLOCK_CHECKBOX:
1155       SDL_Client_Flags ^= CF_CHANGE_TAXRATE_LUX_BLOCK;
1156       return -1;
1157 
1158     case ID_CHANGE_TAXRATE_DLG_SCI_BLOCK_CHECKBOX:
1159       SDL_Client_Flags ^= CF_CHANGE_TAXRATE_SCI_BLOCK;
1160       return -1;
1161 
1162     default:
1163       return -1;
1164     }
1165   }
1166 
1167   return -1;
1168 }
1169 
1170 /**************************************************************************
1171   User released mouse button while adjusting rates.
1172 **************************************************************************/
report_scroll_mouse_button_up(SDL_MouseButtonEvent * pButtonEvent,void * pData)1173 static Uint16 report_scroll_mouse_button_up(SDL_MouseButtonEvent *pButtonEvent,
1174                                             void *pData)
1175 {
1176   return (Uint16)ID_SCROLLBAR;
1177 }
1178 
1179 /**************************************************************************
1180   User moved a mouse while adjusting rates.
1181 **************************************************************************/
report_scroll_mouse_motion_handler(SDL_MouseMotionEvent * pMotionEvent,void * pData)1182 static Uint16 report_scroll_mouse_motion_handler(SDL_MouseMotionEvent *pMotionEvent,
1183                                                  void *pData)
1184 {
1185   struct rates_move *pMotion = (struct rates_move *)pData;
1186   struct widget *pTax_Label = pEconomyDlg->pEndWidgetList->prev->prev;
1187   struct widget *pbuf = NULL;
1188   char cbuf[8];
1189   int dir, inc, x, *buf_rate = NULL;
1190 
1191   pMotionEvent->x -= pMotion->pHoriz_Src->dst->dest_rect.x;
1192 
1193   if ((abs(pMotionEvent->x - pMotion->x) > 7)
1194       && (pMotionEvent->x >= pMotion->min)
1195       && (pMotionEvent->x <= pMotion->max)) {
1196 
1197     /* set up directions */
1198     if (pMotionEvent->xrel > 0) {
1199       dir = 15;
1200       inc = 10;
1201     } else {
1202       dir = -15;
1203       inc = -10;
1204     }
1205 
1206     /* make checks */
1207     x = pMotion->pHoriz_Src->size.x;
1208     if (((x + dir) <= pMotion->max) && ((x + dir) >= pMotion->min)) {
1209       /* src in range */
1210       if (pMotion->pHoriz_Dst) {
1211         x = pMotion->pHoriz_Dst->size.x;
1212 	if (((x + (-1 * dir)) > pMotion->max) || ((x + (-1 * dir)) < pMotion->min)) {
1213 	  /* dst out of range */
1214 	  if (pMotion->tax + (-1 * inc) <= pMotion->gov_max
1215               && pMotion->tax + (-1 * inc) >= 0) {
1216             /* tax in range */
1217             pbuf = pMotion->pHoriz_Dst;
1218             pMotion->pHoriz_Dst = NULL;
1219             buf_rate = pMotion->dst_rate;
1220             pMotion->dst_rate = &pMotion->tax;
1221             pMotion->pLabel_Dst = pTax_Label;
1222           } else {
1223             pMotion->x = pMotion->pHoriz_Src->size.x;
1224             return ID_ERROR;
1225           }
1226 	}
1227       } else {
1228         if (pMotion->tax + (-1 * inc) > pMotion->gov_max
1229             || pMotion->tax + (-1 * inc) < 0) {
1230           pMotion->x = pMotion->pHoriz_Src->size.x;
1231           return ID_ERROR;
1232         }
1233       }
1234 
1235       /* undraw scrollbars */
1236       widget_undraw(pMotion->pHoriz_Src);
1237       widget_mark_dirty(pMotion->pHoriz_Src);
1238 
1239       if (pMotion->pHoriz_Dst) {
1240         widget_undraw(pMotion->pHoriz_Dst);
1241         widget_mark_dirty(pMotion->pHoriz_Dst);
1242       }
1243 
1244       pMotion->pHoriz_Src->size.x += dir;
1245       if (pMotion->pHoriz_Dst) {
1246         pMotion->pHoriz_Dst->size.x -= dir;
1247       }
1248 
1249       *pMotion->src_rate += inc;
1250       *pMotion->dst_rate -= inc;
1251 
1252       fc_snprintf(cbuf, sizeof(cbuf), "%d%%", *pMotion->src_rate);
1253       copy_chars_to_utf8_str(pMotion->pLabel_Src->string_utf8, cbuf);
1254       fc_snprintf(cbuf, sizeof(cbuf), "%d%%", *pMotion->dst_rate);
1255       copy_chars_to_utf8_str(pMotion->pLabel_Dst->string_utf8, cbuf);
1256 
1257       /* redraw label */
1258       widget_redraw(pMotion->pLabel_Src);
1259       widget_mark_dirty(pMotion->pLabel_Src);
1260 
1261       widget_redraw(pMotion->pLabel_Dst);
1262       widget_mark_dirty(pMotion->pLabel_Dst);
1263 
1264       /* redraw scroolbar */
1265       if (get_wflags(pMotion->pHoriz_Src) & WF_RESTORE_BACKGROUND) {
1266         refresh_widget_background(pMotion->pHoriz_Src);
1267       }
1268       widget_redraw(pMotion->pHoriz_Src);
1269       widget_mark_dirty(pMotion->pHoriz_Src);
1270 
1271       if (pMotion->pHoriz_Dst) {
1272         if (get_wflags(pMotion->pHoriz_Dst) & WF_RESTORE_BACKGROUND) {
1273           refresh_widget_background(pMotion->pHoriz_Dst);
1274         }
1275         widget_redraw(pMotion->pHoriz_Dst);
1276         widget_mark_dirty(pMotion->pHoriz_Dst);
1277       }
1278 
1279       flush_dirty();
1280 
1281       if (pbuf != NULL) {
1282         pMotion->pHoriz_Dst = pbuf;
1283         pMotion->pLabel_Dst = pMotion->pHoriz_Dst->prev;
1284         pMotion->dst_rate = buf_rate;
1285         pbuf = NULL;
1286       }
1287 
1288       pMotion->x = pMotion->pHoriz_Src->size.x;
1289     }
1290   } /* if */
1291 
1292   return ID_ERROR;
1293 }
1294 
1295 
1296 /**************************************************************************
1297   Handle Rates sliders.
1298 **************************************************************************/
horiz_taxrate_callback(struct widget * pHoriz_Src)1299 static int horiz_taxrate_callback(struct widget *pHoriz_Src)
1300 {
1301   if (PRESSED_EVENT(Main.event)) {
1302     struct rates_move pMotion;
1303 
1304     pMotion.pHoriz_Src = pHoriz_Src;
1305     pMotion.pLabel_Src = pHoriz_Src->prev;
1306 
1307     switch (pHoriz_Src->ID) {
1308       case ID_CHANGE_TAXRATE_DLG_LUX_SCROLLBAR:
1309         if (SDL_Client_Flags & CF_CHANGE_TAXRATE_LUX_BLOCK) {
1310           goto END;
1311         }
1312         pMotion.src_rate = (int *)pHoriz_Src->data.ptr;
1313         pMotion.pHoriz_Dst = pHoriz_Src->prev->prev->prev; /* sci */
1314         pMotion.dst_rate = (int *)pMotion.pHoriz_Dst->data.ptr;
1315         pMotion.tax = 100 - *pMotion.src_rate - *pMotion.dst_rate;
1316         if ((SDL_Client_Flags & CF_CHANGE_TAXRATE_SCI_BLOCK)) {
1317           if (pMotion.tax <= get_player_bonus(client.conn.playing, EFT_MAX_RATES)) {
1318             pMotion.pHoriz_Dst = NULL;	/* tax */
1319             pMotion.dst_rate = &pMotion.tax;
1320           } else {
1321             goto END;	/* all blocked */
1322           }
1323         }
1324 
1325       break;
1326 
1327       case ID_CHANGE_TAXRATE_DLG_SCI_SCROLLBAR:
1328         if ((SDL_Client_Flags & CF_CHANGE_TAXRATE_SCI_BLOCK)) {
1329           goto END;
1330         }
1331         pMotion.src_rate = (int *)pHoriz_Src->data.ptr;
1332         pMotion.pHoriz_Dst = pHoriz_Src->next->next->next; /* lux */
1333         pMotion.dst_rate = (int *)pMotion.pHoriz_Dst->data.ptr;
1334         pMotion.tax = 100 - *pMotion.src_rate - *pMotion.dst_rate;
1335         if (SDL_Client_Flags & CF_CHANGE_TAXRATE_LUX_BLOCK) {
1336           if (pMotion.tax <= get_player_bonus(client.conn.playing, EFT_MAX_RATES)) {
1337             /* tax */
1338             pMotion.pHoriz_Dst = NULL;
1339             pMotion.dst_rate = &pMotion.tax;
1340           } else {
1341             goto END;	/* all blocked */
1342           }
1343         }
1344 
1345       break;
1346 
1347       default:
1348         return -1;
1349     }
1350 
1351     if (pMotion.pHoriz_Dst) {
1352       pMotion.pLabel_Dst = pMotion.pHoriz_Dst->prev;
1353     } else {
1354       /* tax label */
1355       pMotion.pLabel_Dst = pEconomyDlg->pEndWidgetList->prev->prev;
1356     }
1357 
1358     pMotion.min = pHoriz_Src->next->size.x + pHoriz_Src->next->size.w + adj_size(2);
1359     pMotion.gov_max = get_player_bonus(client.conn.playing, EFT_MAX_RATES);
1360     pMotion.max = pMotion.min + pMotion.gov_max * 1.5;
1361     pMotion.x = pHoriz_Src->size.x;
1362 
1363     MOVE_STEP_Y = 0;
1364     /* Filter mouse motion events */
1365     SDL_SetEventFilter(FilterMouseMotionEvents, NULL);
1366     gui_event_loop((void *)(&pMotion), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1367                    report_scroll_mouse_button_up,
1368                    report_scroll_mouse_motion_handler);
1369     /* Turn off Filter mouse motion events */
1370     SDL_SetEventFilter(NULL, NULL);
1371     MOVE_STEP_Y = DEFAULT_MOVE_STEP;
1372 
1373 END:
1374     unselect_widget_action();
1375     selected_widget = pHoriz_Src;
1376     set_wstate(pHoriz_Src, FC_WS_SELECTED);
1377     widget_redraw(pHoriz_Src);
1378     widget_flush(pHoriz_Src);
1379   }
1380 
1381   return -1;
1382 }
1383 
1384 /**************************************************************************
1385   User interacted with Update button of the Rates.
1386 **************************************************************************/
apply_taxrates_callback(struct widget * pButton)1387 static int apply_taxrates_callback(struct widget *pButton)
1388 {
1389   if (PRESSED_EVENT(Main.event)) {
1390     struct widget *pBuf;
1391     int science, luxury, tax;
1392 
1393     if (C_S_RUNNING != client_state()) {
1394       return -1;
1395     }
1396 
1397     /* Science Scrollbar */
1398     pBuf = pButton->next->next;
1399     science = *(int *)pBuf->data.ptr;
1400 
1401     /* Luxuries Scrollbar */
1402     pBuf = pBuf->next->next->next;
1403     luxury = *(int *)pBuf->data.ptr;
1404 
1405     /* Tax */
1406     tax = 100 - luxury - science;
1407 
1408     if (tax != client.conn.playing->economic.tax
1409         || science != client.conn.playing->economic.science
1410         || luxury != client.conn.playing->economic.luxury) {
1411       dsend_packet_player_rates(&client.conn, tax, luxury, science);
1412     }
1413 
1414     widget_redraw(pButton);
1415     widget_flush(pButton);
1416   }
1417 
1418   return -1;
1419 }
1420 
1421 /**************************************************************************
1422   Set economy dialog widgets enabled.
1423 **************************************************************************/
enable_economy_dlg(void)1424 static void enable_economy_dlg(void)
1425 {
1426   /* lux lock */
1427   struct widget *pBuf = pEconomyDlg->pEndWidgetList->prev->prev->prev->prev->prev->prev;
1428 
1429   set_wstate(pBuf, FC_WS_NORMAL);
1430 
1431   /* lux scrollbar */
1432   pBuf = pBuf->prev;
1433   set_wstate(pBuf, FC_WS_NORMAL);
1434 
1435   /* sci lock */
1436   pBuf = pBuf->prev->prev;
1437   set_wstate(pBuf, FC_WS_NORMAL);
1438 
1439   /* sci scrollbar */
1440   pBuf = pBuf->prev;
1441   set_wstate(pBuf, FC_WS_NORMAL);
1442 
1443   /* update button */
1444   pBuf = pBuf->prev->prev;
1445   set_wstate(pBuf, FC_WS_NORMAL);
1446 
1447   /* cancel button */
1448   pBuf = pBuf->prev;
1449   set_wstate(pBuf, FC_WS_NORMAL);
1450 
1451   set_group_state(pEconomyDlg->pBeginActiveWidgetList,
1452                   pEconomyDlg->pEndActiveWidgetList, FC_WS_NORMAL);
1453   if (pEconomyDlg->pScroll && pEconomyDlg->pActiveWidgetList) {
1454     set_wstate(pEconomyDlg->pScroll->pUp_Left_Button, FC_WS_NORMAL);
1455     set_wstate(pEconomyDlg->pScroll->pDown_Right_Button, FC_WS_NORMAL);
1456     set_wstate(pEconomyDlg->pScroll->pScrollBar, FC_WS_NORMAL);
1457   }
1458 }
1459 
1460 /**************************************************************************
1461   Set economy dialog widgets disabled.
1462 **************************************************************************/
disable_economy_dlg(void)1463 static void disable_economy_dlg(void)
1464 {
1465   /* lux lock */
1466   struct widget *pBuf = pEconomyDlg->pEndWidgetList->prev->prev->prev->prev->prev->prev;
1467 
1468   set_wstate(pBuf, FC_WS_DISABLED);
1469 
1470   /* lux scrollbar */
1471   pBuf = pBuf->prev;
1472   set_wstate(pBuf, FC_WS_DISABLED);
1473 
1474   /* sci lock */
1475   pBuf = pBuf->prev->prev;
1476   set_wstate(pBuf, FC_WS_DISABLED);
1477 
1478   /* sci scrollbar */
1479   pBuf = pBuf->prev;
1480   set_wstate(pBuf, FC_WS_DISABLED);
1481 
1482   /* update button */
1483   pBuf = pBuf->prev->prev;
1484   set_wstate(pBuf, FC_WS_DISABLED);
1485 
1486   /* cancel button */
1487   pBuf = pBuf->prev;
1488   set_wstate(pBuf, FC_WS_DISABLED);
1489 
1490   set_group_state(pEconomyDlg->pBeginActiveWidgetList,
1491                   pEconomyDlg->pEndActiveWidgetList, FC_WS_DISABLED);
1492   if (pEconomyDlg->pScroll && pEconomyDlg->pActiveWidgetList) {
1493     set_wstate(pEconomyDlg->pScroll->pUp_Left_Button, FC_WS_DISABLED);
1494     set_wstate(pEconomyDlg->pScroll->pDown_Right_Button, FC_WS_DISABLED);
1495     set_wstate(pEconomyDlg->pScroll->pScrollBar, FC_WS_DISABLED);
1496   }
1497 }
1498 
1499 /* --------------------------------------------------------------- */
1500 
1501 /**************************************************************************
1502   User interacted with Yes button of the improvement selling dialog.
1503 **************************************************************************/
ok_sell_impr_callback(struct widget * pWidget)1504 static int ok_sell_impr_callback(struct widget *pWidget)
1505 {
1506   if (PRESSED_EVENT(Main.event)) {
1507     int imp, total_count, count = 0;
1508     struct widget *pImpr = (struct widget *)pWidget->data.ptr;
1509 
1510     imp = pImpr->data.cont->id0;
1511     total_count = pImpr->data.cont->id1;
1512 
1513     /* popdown sell dlg */
1514     popdown_window_group_dialog(pEconomy_Sell_Dlg->pBeginWidgetList,
1515                                 pEconomy_Sell_Dlg->pEndWidgetList);
1516     FC_FREE(pEconomy_Sell_Dlg);
1517     enable_economy_dlg();
1518 
1519     /* send sell */
1520     city_list_iterate(client.conn.playing->cities, pCity) {
1521       if (!pCity->did_sell && city_has_building(pCity, improvement_by_number(imp))){
1522         count++;
1523 
1524         city_sell_improvement(pCity, imp);
1525       }
1526     } city_list_iterate_end;
1527 
1528     if (count == total_count) {
1529       del_widget_from_vertical_scroll_widget_list(pEconomyDlg, pImpr);
1530     }
1531   }
1532 
1533   return -1;
1534 }
1535 
1536 /**************************************************************************
1537   User interacted with the improvement selling window.
1538 **************************************************************************/
sell_impr_window_callback(struct widget * pWindow)1539 static int sell_impr_window_callback(struct widget *pWindow)
1540 {
1541   if (PRESSED_EVENT(Main.event)) {
1542     move_window_group(pEconomy_Sell_Dlg->pBeginWidgetList, pWindow);
1543   }
1544 
1545   return -1;
1546 }
1547 
1548 /**************************************************************************
1549   User interacted with Cancel button of the improvement selling dialog.
1550 **************************************************************************/
cancel_sell_impr_callback(struct widget * pWidget)1551 static int cancel_sell_impr_callback(struct widget *pWidget)
1552 {
1553   if (PRESSED_EVENT(Main.event)) {
1554     if (pEconomy_Sell_Dlg) {
1555       popdown_window_group_dialog(pEconomy_Sell_Dlg->pBeginWidgetList,
1556                                   pEconomy_Sell_Dlg->pEndWidgetList);
1557       FC_FREE(pEconomy_Sell_Dlg);
1558       enable_economy_dlg();
1559       flush_dirty();
1560     }
1561   }
1562 
1563   return -1;
1564 }
1565 
1566 /**************************************************************************
1567   Open improvement selling dialog.
1568 **************************************************************************/
popup_sell_impr_callback(struct widget * pWidget)1569 static int popup_sell_impr_callback(struct widget *pWidget)
1570 {
1571   if (PRESSED_EVENT(Main.event)) {
1572     int imp, total_count ,count = 0, gold = 0;
1573     int value;
1574     char cBuf[128];
1575     struct widget *pBuf = NULL, *pWindow;
1576     utf8_str *pstr;
1577     SDL_Surface *pText;
1578     SDL_Rect dst;
1579     SDL_Rect area;
1580 
1581     if (pEconomy_Sell_Dlg) {
1582       return 1;
1583     }
1584 
1585     set_wstate(pWidget, FC_WS_NORMAL);
1586     selected_widget = NULL;
1587     widget_redraw(pWidget);
1588     widget_mark_dirty(pWidget);
1589 
1590     pEconomy_Sell_Dlg = fc_calloc(1, sizeof(struct SMALL_DLG));
1591 
1592     imp = pWidget->data.cont->id0;
1593     total_count = pWidget->data.cont->id1;
1594     value = impr_sell_gold(improvement_by_number(imp));
1595 
1596     city_list_iterate(client.conn.playing->cities, pCity) {
1597       if (!pCity->did_sell && city_has_building(pCity, improvement_by_number(imp))) {
1598         count++;
1599         gold += value;
1600       }
1601     } city_list_iterate_end;
1602 
1603     if (count > 0) {
1604       fc_snprintf(cBuf, sizeof(cBuf),
1605                   _("We have %d of %s\n(total value is : %d)\n"
1606                     "We can sell %d of them for %d gold."),
1607                   total_count,
1608                   improvement_name_translation(improvement_by_number(imp)),
1609                   total_count * value, count, gold);
1610     } else {
1611       fc_snprintf(cBuf, sizeof(cBuf),
1612                   _("We can't sell any %s in this turn."),
1613                   improvement_name_translation(improvement_by_number(imp)));
1614     }
1615 
1616     pstr = create_utf8_from_char(_("Sell It?"), adj_font(12));
1617     pstr->style |= TTF_STYLE_BOLD;
1618 
1619     pWindow = create_window_skeleton(NULL, pstr, 0);
1620 
1621     pWindow->action = sell_impr_window_callback;
1622     set_wstate(pWindow, FC_WS_NORMAL);
1623 
1624     pEconomy_Sell_Dlg->pEndWidgetList = pWindow;
1625 
1626     add_to_gui_list(ID_WINDOW, pWindow);
1627 
1628     area = pWindow->area;
1629 
1630     /* ============================================================= */
1631 
1632     /* create text label */
1633     pstr = create_utf8_from_char(cBuf, adj_font(10));
1634     pstr->style |= (TTF_STYLE_BOLD|SF_CENTER);
1635     pstr->fgcol = *get_theme_color(COLOR_THEME_SELLIMPR_TEXT);
1636 
1637     pText = create_text_surf_from_utf8(pstr);
1638     FREEUTF8STR(pstr);
1639 
1640     area.w = MAX(area.w, pText->w + adj_size(20));
1641     area.h += (pText->h + adj_size(10));
1642 
1643     /* cancel button */
1644     pBuf = create_themeicon_button_from_chars(current_theme->CANCEL_Icon,
1645                                               pWindow->dst, _("No"),
1646                                               adj_font(12), 0);
1647 
1648     pBuf->action = cancel_sell_impr_callback;
1649     set_wstate(pBuf, FC_WS_NORMAL);
1650 
1651     area.h += (pBuf->size.h + adj_size(20));
1652 
1653     add_to_gui_list(ID_BUTTON, pBuf);
1654 
1655     if (count > 0) {
1656       pBuf = create_themeicon_button_from_chars(current_theme->OK_Icon, pWindow->dst,
1657                                                 _("Sell"), adj_font(12), 0);
1658 
1659       pBuf->action = ok_sell_impr_callback;
1660       set_wstate(pBuf, FC_WS_NORMAL);
1661       pBuf->data.ptr = (void *)pWidget;
1662 
1663       add_to_gui_list(ID_BUTTON, pBuf);
1664       pBuf->size.w = MAX(pBuf->size.w, pBuf->next->size.w);
1665       pBuf->next->size.w = pBuf->size.w;
1666       area.w = MAX(area.w, adj_size(30) + pBuf->size.w * 2);
1667     } else {
1668       area.w = MAX(area.w, pBuf->size.w + adj_size(20));
1669     }
1670     /* ============================================ */
1671 
1672     pEconomy_Sell_Dlg->pBeginWidgetList = pBuf;
1673 
1674     resize_window(pWindow, NULL, get_theme_color(COLOR_THEME_BACKGROUND),
1675                   (pWindow->size.w - pWindow->area.w) + area.w,
1676                   (pWindow->size.h - pWindow->area.h) + area.h);
1677 
1678     area = pWindow->area;
1679 
1680     widget_set_position(pWindow,
1681                         pEconomyDlg->pEndWidgetList->size.x +
1682                           (pEconomyDlg->pEndWidgetList->size.w - pWindow->size.w) / 2,
1683                         pEconomyDlg->pEndWidgetList->size.y +
1684                           (pEconomyDlg->pEndWidgetList->size.h - pWindow->size.h) / 2);
1685 
1686     /* setup rest of widgets */
1687     /* label */
1688     dst.x = area.x + (area.w - pText->w) / 2;
1689     dst.y = area.y + adj_size(10);
1690     alphablit(pText, NULL, pWindow->theme, &dst, 255);
1691     FREESURFACE(pText);
1692 
1693     /* cancel button */
1694     pBuf = pWindow->prev;
1695     pBuf->size.y = area.y + area.h - pBuf->size.h - adj_size(10);
1696 
1697     if (count > 0) {
1698       /* sell button */
1699       pBuf = pBuf->prev;
1700       pBuf->size.x = area.x + (area.w - (2 * pBuf->size.w + adj_size(10))) / 2;
1701       pBuf->size.y = pBuf->next->size.y;
1702 
1703       /* cancel button */
1704       pBuf->next->size.x = pBuf->size.x + pBuf->size.w + adj_size(10);
1705     } else {
1706       /* x position of cancel button */
1707       pBuf->size.x = area.x + area.w - adj_size(10) - pBuf->size.w;
1708     }
1709 
1710     /* ================================================== */
1711     /* redraw */
1712     redraw_group(pEconomy_Sell_Dlg->pBeginWidgetList, pWindow, 0);
1713     disable_economy_dlg();
1714 
1715     widget_mark_dirty(pWindow);
1716     flush_dirty();
1717   }
1718 
1719   return -1;
1720 }
1721 
1722 /**************************************************************************
1723   Update the economy report.
1724 **************************************************************************/
real_economy_report_dialog_update(void * unused)1725 void real_economy_report_dialog_update(void *unused)
1726 {
1727   if (pEconomyDlg) {
1728     struct widget *pbuf = pEconomyDlg->pEndWidgetList;
1729     int tax, total, entries_used = 0;
1730     char cbuf[128];
1731     struct improvement_entry entries[B_LAST];
1732 
1733     get_economy_report_data(entries, &entries_used, &total, &tax);
1734 
1735     /* tresure */
1736     pbuf = pbuf->prev;
1737     fc_snprintf(cbuf, sizeof(cbuf), "%d", client.conn.playing->economic.gold);
1738     copy_chars_to_utf8_str(pbuf->string_utf8, cbuf);
1739     remake_label_size(pbuf);
1740 
1741     /* Icome */
1742     pbuf = pbuf->prev->prev;
1743     fc_snprintf(cbuf, sizeof(cbuf), "%d", tax);
1744     copy_chars_to_utf8_str(pbuf->string_utf8, cbuf);
1745     remake_label_size(pbuf);
1746 
1747     /* Cost */
1748     pbuf = pbuf->prev;
1749     fc_snprintf(cbuf, sizeof(cbuf), "%d", total);
1750     copy_chars_to_utf8_str(pbuf->string_utf8, cbuf);
1751     remake_label_size(pbuf);
1752 
1753     /* Netto */
1754     pbuf = pbuf->prev;
1755     fc_snprintf(cbuf, sizeof(cbuf), "%d", tax - total);
1756     copy_chars_to_utf8_str(pbuf->string_utf8, cbuf);
1757     remake_label_size(pbuf);
1758     if (tax - total < 0) {
1759       pbuf->string_utf8->fgcol = *get_theme_color(COLOR_THEME_ECONOMYDLG_NEG_TEXT);
1760     } else {
1761       pbuf->string_utf8->fgcol = *get_theme_color(COLOR_THEME_ECONOMYDLG_TEXT);
1762     }
1763 
1764     /* ---------------- */
1765     redraw_group(pEconomyDlg->pBeginWidgetList, pEconomyDlg->pEndWidgetList, 0);
1766     widget_flush(pEconomyDlg->pEndWidgetList);
1767   }
1768 }
1769 
1770 /**************************************************************************
1771   Popdown the economy report.
1772 **************************************************************************/
economy_report_dialog_popdown(void)1773 void economy_report_dialog_popdown(void)
1774 {
1775   if (pEconomyDlg) {
1776     if (pEconomy_Sell_Dlg) {
1777        del_group_of_widgets_from_gui_list(pEconomy_Sell_Dlg->pBeginWidgetList,
1778                                           pEconomy_Sell_Dlg->pEndWidgetList);
1779        FC_FREE(pEconomy_Sell_Dlg);
1780     }
1781     popdown_window_group_dialog(pEconomyDlg->pBeginWidgetList,
1782                                 pEconomyDlg->pEndWidgetList);
1783     FC_FREE(pEconomyDlg->pScroll);
1784     FC_FREE(pEconomyDlg);
1785     set_wstate(get_tax_rates_widget(), FC_WS_NORMAL);
1786     widget_redraw(get_tax_rates_widget());
1787     widget_mark_dirty(get_tax_rates_widget());
1788   }
1789 }
1790 
1791 #define TARGETS_ROW     2
1792 #define TARGETS_COL     4
1793 
1794 /**************************************************************************
1795   Popup (or raise) the economy report (F5).  It may or may not be modal.
1796 **************************************************************************/
economy_report_dialog_popup(bool make_modal)1797 void economy_report_dialog_popup(bool make_modal)
1798 {
1799   SDL_Color bg_color = {255,255,255,128};
1800   SDL_Color bg_color2 = {255,255,255,136};
1801   SDL_Color bg_color3 = {255,255,255,64};
1802   struct widget *pBuf;
1803   struct widget *pWindow , *pLast;
1804   utf8_str *pstr, *pstr2;
1805   SDL_Surface *pSurf, *pText_Name, *pText, *pZoom;
1806   SDL_Surface *pBackground;
1807   int i, count , h = 0;
1808   int w = 0; /* left column values */
1809   int w2 = 0; /* right column: lock + scrollbar + ... */
1810   int w3 = 0; /* left column text without values */
1811   int tax, total, entries_used = 0;
1812   char cbuf[128];
1813   struct improvement_entry entries[B_LAST];
1814   SDL_Rect dst;
1815   SDL_Rect area;
1816   struct government *pGov = government_of_player(client.conn.playing);
1817   SDL_Surface *pTreasuryText;
1818   SDL_Surface *pTaxRateText;
1819   SDL_Surface *pTotalIncomeText;
1820   SDL_Surface *pTotalCostText;
1821   SDL_Surface *pNetIncomeText;
1822   SDL_Surface *pMaxRateText;
1823 
1824   if (pEconomyDlg) {
1825     return;
1826   }
1827 
1828   /* disable "Economy" button */
1829   pBuf = get_tax_rates_widget();
1830   set_wstate(pBuf, FC_WS_DISABLED);
1831   widget_redraw(pBuf);
1832   widget_mark_dirty(pBuf);
1833 
1834   pEconomyDlg = fc_calloc(1, sizeof(struct ADVANCED_DLG));
1835 
1836   get_economy_report_data(entries, &entries_used, &total, &tax);
1837 
1838   /* --------------- */
1839   pstr = create_utf8_from_char(_("Economy Report"), adj_font(12));
1840   pstr->style |= TTF_STYLE_BOLD;
1841 
1842   pWindow = create_window_skeleton(NULL, pstr, 0);
1843   pEconomyDlg->pEndWidgetList = pWindow;
1844   set_wstate(pWindow, FC_WS_NORMAL);
1845   pWindow->action = economy_dialog_callback;
1846 
1847   add_to_gui_list(ID_ECONOMY_DIALOG_WINDOW, pWindow);
1848 
1849   area = pWindow->area;
1850 
1851   /* ------------------------- */
1852 
1853   /* "Treasury" text surface */
1854   fc_snprintf(cbuf, sizeof(cbuf), _("Treasury: "));
1855   pstr2 = create_utf8_from_char(cbuf, adj_font(12));
1856   pstr2->style |= TTF_STYLE_BOLD;
1857   pTreasuryText = create_text_surf_from_utf8(pstr2);
1858   w3 = MAX(w3, pTreasuryText->w);
1859 
1860   /* "Treasury" value label*/
1861   fc_snprintf(cbuf, sizeof(cbuf), "%d", client.conn.playing->economic.gold);
1862   pstr = create_utf8_from_char(cbuf, adj_font(12));
1863   pstr->style |= (TTF_STYLE_BOLD|SF_CENTER);
1864 
1865   pBuf = create_iconlabel(pIcons->pBIG_Coin, pWindow->dst, pstr,
1866                           (WF_RESTORE_BACKGROUND|WF_ICON_CENTER_RIGHT));
1867 
1868   add_to_gui_list(ID_LABEL, pBuf);
1869 
1870   w = MAX(w, pBuf->size.w);
1871   h += pBuf->size.h;
1872 
1873   /* "Tax Rate" text surface */
1874   fc_snprintf(cbuf, sizeof(cbuf), _("Tax Rate: "));
1875   copy_chars_to_utf8_str(pstr2, cbuf);
1876   pTaxRateText = create_text_surf_from_utf8(pstr2);
1877   w3 = MAX(w3, pTaxRateText->w);
1878 
1879   /* "Tax Rate" value label */
1880   /* it is important to leave 1 space at ending of this string */
1881   fc_snprintf(cbuf, sizeof(cbuf), "%d%% ", client.conn.playing->economic.tax);
1882   pstr = create_utf8_from_char(cbuf, adj_font(12));
1883   pstr->style |= (TTF_STYLE_BOLD|SF_CENTER);
1884 
1885   pBuf = create_iconlabel(NULL, pWindow->dst, pstr, WF_RESTORE_BACKGROUND);
1886 
1887   add_to_gui_list(ID_LABEL, pBuf);
1888 
1889   w = MAX(w, pBuf->size.w + pBuf->next->size.w);
1890   h += pBuf->size.h;
1891 
1892   /* "Total Income" text surface */
1893   fc_snprintf(cbuf, sizeof(cbuf), _("Total Income: "));
1894   copy_chars_to_utf8_str(pstr2, cbuf);
1895   pTotalIncomeText = create_text_surf_from_utf8(pstr2);
1896   w3 = MAX(w3, pTotalIncomeText->w);
1897 
1898   /* "Total Icome" value label */
1899   fc_snprintf(cbuf, sizeof(cbuf), "%d", tax);
1900   pstr = create_utf8_from_char(cbuf, adj_font(12));
1901   pstr->style |= TTF_STYLE_BOLD;
1902 
1903   pBuf = create_iconlabel(NULL, pWindow->dst, pstr, WF_RESTORE_BACKGROUND);
1904 
1905   add_to_gui_list(ID_LABEL, pBuf);
1906 
1907   w = MAX(w, pBuf->size.w);
1908   h += pBuf->size.h;
1909 
1910   /* "Total Cost" text surface */
1911   fc_snprintf(cbuf, sizeof(cbuf), _("Total Cost: "));
1912   copy_chars_to_utf8_str(pstr2, cbuf);
1913   pTotalCostText = create_text_surf_from_utf8(pstr2);
1914 
1915   /* "Total Cost" value label */
1916   fc_snprintf(cbuf, sizeof(cbuf), "%d", total);
1917   pstr = create_utf8_from_char(cbuf, adj_font(12));
1918   pstr->style |= TTF_STYLE_BOLD;
1919 
1920   pBuf = create_iconlabel(NULL, pWindow->dst, pstr, WF_RESTORE_BACKGROUND);
1921 
1922   add_to_gui_list(ID_LABEL, pBuf);
1923 
1924   w = MAX(w, pBuf->size.w);
1925   h += pBuf->size.h;
1926 
1927   /* "Net Income" text surface */
1928   fc_snprintf(cbuf, sizeof(cbuf), _("Net Income: "));
1929   copy_chars_to_utf8_str(pstr2, cbuf);
1930   pNetIncomeText = create_text_surf_from_utf8(pstr2);
1931   w3 = MAX(w3, pNetIncomeText->w);
1932 
1933   /* "Net Icome" value label */
1934   fc_snprintf(cbuf, sizeof(cbuf), "%d", tax - total);
1935   pstr = create_utf8_from_char(cbuf, adj_font(12));
1936   pstr->style |= (TTF_STYLE_BOLD|SF_CENTER);
1937 
1938   if (tax - total < 0) {
1939     pstr->fgcol = *get_theme_color(COLOR_THEME_ECONOMYDLG_NEG_TEXT);
1940   }
1941 
1942   pBuf = create_iconlabel(NULL, pWindow->dst, pstr, WF_RESTORE_BACKGROUND);
1943 
1944   add_to_gui_list(ID_LABEL, pBuf);
1945 
1946   w = MAX(w, pBuf->size.w);
1947   h += pBuf->size.h;
1948 
1949   /* gov and taxrate */
1950   fc_snprintf(cbuf, sizeof(cbuf), _("%s max rate : %d%%"),
1951               government_name_translation(pGov),
1952               get_player_bonus(client.conn.playing, EFT_MAX_RATES));
1953   copy_chars_to_utf8_str(pstr2, cbuf);
1954   pMaxRateText = create_text_surf_from_utf8(pstr2);
1955 
1956   FREEUTF8STR(pstr2);
1957 
1958   /* ------------------------- */
1959   /* lux rate */
1960 
1961   /* lux rate lock */
1962   fc_snprintf(cbuf, sizeof(cbuf), _("Lock"));
1963   pstr = create_utf8_from_char(cbuf, adj_font(10));
1964   pstr->style |= TTF_STYLE_BOLD;
1965 
1966   pBuf = create_checkbox(pWindow->dst,
1967                          SDL_Client_Flags & CF_CHANGE_TAXRATE_LUX_BLOCK,
1968                          WF_RESTORE_BACKGROUND | WF_WIDGET_HAS_INFO_LABEL);
1969   set_new_checkbox_theme(pBuf, current_theme->LOCK_Icon, current_theme->UNLOCK_Icon);
1970   pBuf->info_label = pstr;
1971   pBuf->action = toggle_block_callback;
1972   set_wstate(pBuf, FC_WS_NORMAL);
1973 
1974   add_to_gui_list(ID_CHANGE_TAXRATE_DLG_LUX_BLOCK_CHECKBOX, pBuf);
1975 
1976   w2 = adj_size(10) + pBuf->size.w;
1977 
1978   /* lux rate slider */
1979   pBuf = create_horizontal(current_theme->Horiz, pWindow->dst, adj_size(30),
1980                            (WF_FREE_DATA | WF_RESTORE_BACKGROUND));
1981 
1982   pBuf->action = horiz_taxrate_callback;
1983   pBuf->data.ptr = fc_calloc(1, sizeof(int));
1984   *(int *)pBuf->data.ptr = client.conn.playing->economic.luxury;
1985   set_wstate(pBuf, FC_WS_NORMAL);
1986 
1987   add_to_gui_list(ID_CHANGE_TAXRATE_DLG_LUX_SCROLLBAR, pBuf);
1988 
1989   w2 += adj_size(184);
1990 
1991   /* lux rate iconlabel */
1992 
1993   /* it is important to leave 1 space at ending of this string */
1994   fc_snprintf(cbuf, sizeof(cbuf), "%d%% ", client.conn.playing->economic.luxury);
1995   pstr = create_utf8_from_char(cbuf, adj_font(11));
1996   pstr->style |= TTF_STYLE_BOLD;
1997 
1998   pBuf = create_iconlabel(pIcons->pBIG_Luxury, pWindow->dst, pstr,
1999                           WF_RESTORE_BACKGROUND);
2000   add_to_gui_list(ID_CHANGE_TAXRATE_DLG_LUX_LABEL, pBuf);
2001 
2002   w2 += (adj_size(5) + pBuf->size.w + adj_size(10));
2003 
2004   /* ------------------------- */
2005   /* science rate */
2006 
2007   /* science rate lock */
2008   fc_snprintf(cbuf, sizeof(cbuf), _("Lock"));
2009   pstr = create_utf8_from_char(cbuf, adj_font(10));
2010   pstr->style |= TTF_STYLE_BOLD;
2011 
2012   pBuf = create_checkbox(pWindow->dst,
2013                          SDL_Client_Flags & CF_CHANGE_TAXRATE_SCI_BLOCK,
2014                          WF_RESTORE_BACKGROUND | WF_WIDGET_HAS_INFO_LABEL);
2015 
2016   set_new_checkbox_theme(pBuf, current_theme->LOCK_Icon, current_theme->UNLOCK_Icon);
2017 
2018   pBuf->info_label = pstr;
2019   pBuf->action = toggle_block_callback;
2020   set_wstate(pBuf, FC_WS_NORMAL);
2021 
2022   add_to_gui_list(ID_CHANGE_TAXRATE_DLG_SCI_BLOCK_CHECKBOX, pBuf);
2023 
2024   /* science rate slider */
2025   pBuf = create_horizontal(current_theme->Horiz, pWindow->dst, adj_size(30),
2026                            (WF_FREE_DATA | WF_RESTORE_BACKGROUND));
2027 
2028   pBuf->action = horiz_taxrate_callback;
2029   pBuf->data.ptr = fc_calloc(1, sizeof(int));
2030   *(int *)pBuf->data.ptr = client.conn.playing->economic.science;
2031 
2032   set_wstate(pBuf, FC_WS_NORMAL);
2033 
2034   add_to_gui_list(ID_CHANGE_TAXRATE_DLG_SCI_SCROLLBAR, pBuf);
2035 
2036   /* science rate iconlabel */
2037   /* it is important to leave 1 space at ending of this string */
2038   fc_snprintf(cbuf, sizeof(cbuf), "%d%% ", client.conn.playing->economic.science);
2039   pstr = create_utf8_from_char(cbuf, adj_font(11));
2040   pstr->style |= TTF_STYLE_BOLD;
2041 
2042   pBuf = create_iconlabel(pIcons->pBIG_Colb, pWindow->dst, pstr,
2043                           WF_RESTORE_BACKGROUND);
2044 
2045   add_to_gui_list(ID_CHANGE_TAXRATE_DLG_SCI_LABEL, pBuf);
2046 
2047   /* ---- */
2048 
2049   fc_snprintf(cbuf, sizeof(cbuf), _("Update"));
2050   pstr = create_utf8_from_char(cbuf, adj_font(12));
2051   pBuf = create_themeicon_button(current_theme->Small_OK_Icon, pWindow->dst, pstr, 0);
2052   pBuf->action = apply_taxrates_callback;
2053   set_wstate(pBuf, FC_WS_NORMAL);
2054 
2055   add_to_gui_list(ID_CHANGE_TAXRATE_DLG_OK_BUTTON, pBuf);
2056 
2057   /* ---- */
2058 
2059   fc_snprintf(cbuf, sizeof(cbuf), _("Close Dialog (Esc)"));
2060   pstr = create_utf8_from_char(cbuf, adj_font(12));
2061   pBuf = create_themeicon(current_theme->Small_CANCEL_Icon, pWindow->dst,
2062                           WF_WIDGET_HAS_INFO_LABEL | WF_RESTORE_BACKGROUND);
2063   pBuf->info_label = pstr;
2064   pBuf->action = exit_economy_dialog_callback;
2065   set_wstate(pBuf, FC_WS_NORMAL);
2066   pBuf->key = SDLK_ESCAPE;
2067 
2068   add_to_gui_list(ID_CHANGE_TAXRATE_DLG_CANCEL_BUTTON, pBuf);
2069 
2070   h += adj_size(5);
2071 
2072   /* ------------------------- */
2073   pLast = pBuf;
2074   if (entries_used > 0) {
2075 
2076     /* Create Imprv Background Icon */
2077     pBackground = create_surf(adj_size(116), adj_size(116), SDL_SWSURFACE);
2078 
2079     SDL_FillRect(pBackground, NULL, map_rgba(pBackground->format, bg_color));
2080 
2081     create_frame(pBackground,
2082                  0, 0, pBackground->w - 1, pBackground->h - 1,
2083                  get_theme_color(COLOR_THEME_ECONOMYDLG_FRAME));
2084 
2085     pstr = create_utf8_str(NULL, 0, adj_font(10));
2086     pstr->style |= (SF_CENTER|TTF_STYLE_BOLD);
2087     pstr->bgcol = (SDL_Color) {0, 0, 0, 0};
2088 
2089     for (i = 0; i < entries_used; i++) {
2090       struct improvement_entry *p = &entries[i];
2091       struct impr_type *pImprove = p->type;
2092 
2093       pSurf = crop_rect_from_surface(pBackground, NULL);
2094 
2095       fc_snprintf(cbuf, sizeof(cbuf), "%s", improvement_name_translation(pImprove));
2096 
2097       copy_chars_to_utf8_str(pstr, cbuf);
2098       pstr->style |= TTF_STYLE_BOLD;
2099       pText_Name = create_text_surf_smaller_than_w(pstr, pSurf->w - adj_size(4));
2100 
2101       fc_snprintf(cbuf, sizeof(cbuf), "%s %d\n%s %d",
2102                   _("Built"), p->count, _("U Total"),p->total_cost);
2103       copy_chars_to_utf8_str(pstr, cbuf);
2104       pstr->style &= ~TTF_STYLE_BOLD;
2105 
2106       pText = create_text_surf_from_utf8(pstr);
2107 
2108       /*-----------------*/
2109 
2110       pZoom = get_building_surface(pImprove);
2111       pZoom = zoomSurface(pZoom, DEFAULT_ZOOM * ((float)54 / pZoom->w), DEFAULT_ZOOM * ((float)54 / pZoom->w), 1);
2112 
2113       dst.x = (pSurf->w - pZoom->w) / 2;
2114       dst.y = (pSurf->h / 2 - pZoom->h) / 2;
2115       alphablit(pZoom, NULL, pSurf, &dst, 255);
2116       dst.y += pZoom->h;
2117       FREESURFACE(pZoom);
2118 
2119       dst.x = (pSurf->w - pText_Name->w)/2;
2120       dst.y += ((pSurf->h - dst.y) -
2121                 (pText_Name->h + (pIcons->pBIG_Coin->h + 2) + pText->h)) / 2;
2122       alphablit(pText_Name, NULL, pSurf, &dst, 255);
2123 
2124       dst.y += pText_Name->h;
2125       if (p->cost) {
2126         dst.x = (pSurf->w - p->cost * (pIcons->pBIG_Coin->w + 1))/2;
2127         for (count = 0; count < p->cost; count++) {
2128           alphablit(pIcons->pBIG_Coin, NULL, pSurf, &dst, 255);
2129           dst.x += pIcons->pBIG_Coin->w + 1;
2130         }
2131       } else {
2132 
2133         if (!is_wonder(pImprove)) {
2134           copy_chars_to_utf8_str(pstr, _("Nation"));
2135 	} else {
2136           copy_chars_to_utf8_str(pstr, _("Wonder"));
2137 	}
2138         /*pstr->style &= ~TTF_STYLE_BOLD;*/
2139 
2140         pZoom = create_text_surf_from_utf8(pstr);
2141 
2142         dst.x = (pSurf->w - pZoom->w) / 2;
2143         alphablit(pZoom, NULL, pSurf, &dst, 255);
2144         FREESURFACE(pZoom);
2145       }
2146 
2147       dst.y += (pIcons->pBIG_Coin->h + adj_size(2));
2148       dst.x = (pSurf->w - pText->w) / 2;
2149       alphablit(pText, NULL, pSurf, &dst, 255);
2150 
2151       FREESURFACE(pText);
2152       FREESURFACE(pText_Name);
2153 
2154       pBuf = create_icon2(pSurf, pWindow->dst,
2155                           (WF_RESTORE_BACKGROUND|WF_FREE_THEME|WF_FREE_DATA));
2156 
2157       set_wstate(pBuf, FC_WS_NORMAL);
2158 
2159       pBuf->data.cont = fc_calloc(1, sizeof(struct CONTAINER));
2160       pBuf->data.cont->id0 = improvement_number(p->type);
2161       pBuf->data.cont->id1 = p->count;
2162       pBuf->action = popup_sell_impr_callback;
2163 
2164       add_to_gui_list(MAX_ID - i, pBuf);
2165 
2166       if (i > (TARGETS_ROW * TARGETS_COL - 1)) {
2167         set_wflag(pBuf, WF_HIDDEN);
2168       }
2169     }
2170 
2171     FREEUTF8STR(pstr);
2172     FREESURFACE(pBackground);
2173 
2174     pEconomyDlg->pEndActiveWidgetList = pLast->prev;
2175     pEconomyDlg->pBeginWidgetList = pBuf;
2176     pEconomyDlg->pBeginActiveWidgetList = pEconomyDlg->pBeginWidgetList;
2177 
2178     if (entries_used > (TARGETS_ROW * TARGETS_COL)) {
2179       pEconomyDlg->pActiveWidgetList = pEconomyDlg->pEndActiveWidgetList;
2180       count = create_vertical_scrollbar(pEconomyDlg,
2181                                         TARGETS_COL, TARGETS_ROW, TRUE, TRUE);
2182       h += (TARGETS_ROW * pBuf->size.h + adj_size(10));
2183     } else {
2184       count = 0;
2185       if (entries_used > TARGETS_COL) {
2186         h += pBuf->size.h;
2187       }
2188       h += (adj_size(10) + pBuf->size.h);
2189     }
2190     count = TARGETS_COL * pBuf->size.w + count;
2191   } else {
2192     pEconomyDlg->pBeginWidgetList = pBuf;
2193     h += adj_size(10);
2194     count = 0;
2195   }
2196 
2197   area.w = MAX(area.w, MAX(adj_size(10) + w3 + w + w2, count));
2198   area.h = h;
2199 
2200   pBackground = theme_get_background(theme, BACKGROUND_ECONOMYDLG);
2201   if (resize_window(pWindow, pBackground, NULL,
2202                     (pWindow->size.w - pWindow->area.w) + area.w,
2203                     (pWindow->size.h - pWindow->area.h) + area.h)) {
2204     FREESURFACE(pBackground);
2205   }
2206 
2207   area = pWindow->area;
2208 
2209   widget_set_position(pWindow,
2210                       (main_window_width() - pWindow->size.w) / 2,
2211                       (main_window_height() - pWindow->size.h) / 2);
2212 
2213   /* "Treasury" value label */
2214   pBuf = pWindow->prev;
2215   pBuf->size.x = area.x + adj_size(10) + pTreasuryText->w;
2216   pBuf->size.y = area.y + adj_size(5);
2217 
2218   w = pTreasuryText->w + pBuf->size.w;
2219   h = pBuf->size.h;
2220 
2221   /* "Tax Rate" value label */
2222   pBuf = pBuf->prev;
2223   pBuf->size.x = area.x + adj_size(10) + pTaxRateText->w;
2224   pBuf->size.y = pBuf->next->size.y + pBuf->next->size.h;
2225 
2226   w = MAX(w, pTaxRateText->w + pBuf->size.w);
2227   h += pBuf->size.h;
2228 
2229   /* "Total Income" value label */
2230   pBuf = pBuf->prev;
2231   pBuf->size.x = area.x + adj_size(10) + pTotalIncomeText->w;
2232   pBuf->size.y = pBuf->next->size.y + pBuf->next->size.h;
2233 
2234   w = MAX(w, pTotalIncomeText->w + pBuf->size.w);
2235   h += pBuf->size.h;
2236 
2237   /* "Total Cost" value label */
2238   pBuf = pBuf->prev;
2239   pBuf->size.x = area.x + adj_size(10) + pTotalCostText->w;
2240   pBuf->size.y = pBuf->next->size.y + pBuf->next->size.h;
2241 
2242   w = MAX(w, pTotalCostText->w + pBuf->size.w);
2243   h += pBuf->size.h;
2244 
2245   /* "Net Income" value label */
2246   pBuf = pBuf->prev;
2247   pBuf->size.x = area.x + adj_size(10) + pNetIncomeText->w;
2248   pBuf->size.y = pBuf->next->size.y + pBuf->next->size.h;
2249 
2250   w = MAX(w, pNetIncomeText->w + pBuf->size.w);
2251   h += pBuf->size.h;
2252 
2253   /* Backgrounds */
2254   dst.x = area.x;
2255   dst.y = area.y;
2256   dst.w = area.w;
2257   dst.h = h + adj_size(15);
2258   h = dst.h;
2259 
2260   fill_rect_alpha(pWindow->theme, &dst, &bg_color2);
2261 
2262   create_frame(pWindow->theme,
2263                dst.x, dst.y, dst.w - 1, dst.h - 1,
2264                get_theme_color(COLOR_THEME_ECONOMYDLG_FRAME));
2265 
2266   /* draw statical strings */
2267   dst.x = area.x + adj_size(10);
2268   dst.y = area.y + adj_size(5);
2269 
2270   /* "Treasury */
2271   alphablit(pTreasuryText, NULL, pWindow->theme, &dst, 255);
2272   dst.y += pTreasuryText->h;
2273   FREESURFACE(pTreasuryText);
2274 
2275   /* Tax Rate */
2276   alphablit(pTaxRateText, NULL, pWindow->theme, &dst, 255);
2277   dst.y += pTaxRateText->h;
2278   FREESURFACE(pTaxRateText);
2279 
2280   /* Total Income */
2281   alphablit(pTotalIncomeText, NULL, pWindow->theme, &dst, 255);
2282   dst.y += pTotalIncomeText->h;
2283   FREESURFACE(pTotalIncomeText);
2284 
2285   /* Total Cost */
2286   alphablit(pTotalCostText, NULL, pWindow->theme, &dst, 255);
2287   dst.y += pTotalCostText->h;
2288   FREESURFACE(pTotalCostText);
2289 
2290   /* Net Income */
2291   alphablit(pNetIncomeText, NULL, pWindow->theme, &dst, 255);
2292   dst.y += pNetIncomeText->h;
2293   FREESURFACE(pNetIncomeText);
2294 
2295   /* gov and taxrate */
2296   dst.x = area.x + adj_size(10) + w + ((area.w - (w + adj_size(10)) - pMaxRateText->w) / 2);
2297   dst.y = area.y + adj_size(5);
2298 
2299   alphablit(pMaxRateText, NULL, pWindow->theme, &dst, 255);
2300   dst.y += (pMaxRateText->h + 1);
2301   FREESURFACE(pMaxRateText);
2302 
2303   /* Luxuries Horizontal Scrollbar Background */
2304   dst.x = area.x + adj_size(10) + w + (area.w - (w + adj_size(10)) - adj_size(184)) / 2;
2305   dst.w = adj_size(184);
2306   dst.h = current_theme->Horiz->h - adj_size(2);
2307 
2308   fill_rect_alpha(pWindow->theme, &dst, &bg_color3);
2309 
2310   create_frame(pWindow->theme,
2311                dst.x, dst.y, dst.w - 1, dst.h - 1,
2312                get_theme_color(COLOR_THEME_ECONOMYDLG_FRAME));
2313 
2314   /* lock icon */
2315   pBuf = pBuf->prev;
2316   pBuf->size.x = dst.x - pBuf->size.w;
2317   pBuf->size.y = dst.y - adj_size(2);
2318 
2319   /* lux scrollbar */
2320   pBuf = pBuf->prev;
2321   pBuf->size.x = dst.x + adj_size(2) + (client.conn.playing->economic.luxury * 3) / 2;
2322   pBuf->size.y = dst.y -1;
2323 
2324   /* lux rate */
2325   pBuf = pBuf->prev;
2326   pBuf->size.x = dst.x + dst.w + adj_size(5);
2327   pBuf->size.y = dst.y + 1;
2328 
2329   /* Science Horizontal Scrollbar Background */
2330   dst.y += current_theme->Horiz->h + 1;
2331   fill_rect_alpha(pWindow->theme, &dst, &bg_color3);
2332 
2333   create_frame(pWindow->theme,
2334                dst.x, dst.y, dst.w - 1, dst.h - 1,
2335                get_theme_color(COLOR_THEME_ECONOMYDLG_FRAME));
2336 
2337   /* science lock icon */
2338   pBuf = pBuf->prev;
2339   pBuf->size.x = dst.x - pBuf->size.w;
2340   pBuf->size.y = dst.y - adj_size(2);
2341 
2342   /* science scrollbar */
2343   pBuf = pBuf->prev;
2344   pBuf->size.x = dst.x + adj_size(2) + (client.conn.playing->economic.science * 3) / 2;
2345   pBuf->size.y = dst.y -1;
2346 
2347   /* science rate */
2348   pBuf = pBuf->prev;
2349   pBuf->size.x = dst.x + dst.w + adj_size(5);
2350   pBuf->size.y = dst.y + 1;
2351 
2352   /* update */
2353   pBuf = pBuf->prev;
2354   pBuf->size.x = dst.x + (dst.w - pBuf->size.w) / 2;
2355   pBuf->size.y = dst.y + dst.h + adj_size(3);
2356 
2357   /* cancel */
2358   pBuf = pBuf->prev;
2359   pBuf->size.x = area.x + area.w - pBuf->size.w - 1;
2360   pBuf->size.y = pWindow->size.y + adj_size(2);
2361   /* ------------------------------- */
2362 
2363   if (entries_used > 0) {
2364     setup_vertical_widgets_position(TARGETS_COL,
2365                                     area.x,
2366                                     area.y + h,
2367                                     0, 0, pEconomyDlg->pBeginActiveWidgetList,
2368                                     pEconomyDlg->pEndActiveWidgetList);
2369     if (pEconomyDlg->pScroll) {
2370       setup_vertical_scrollbar_area(pEconomyDlg->pScroll,
2371                                     area.x + area.w - 1,
2372                                     area.y + h,
2373                                     area.h - h - 1, TRUE);
2374     }
2375   }
2376 
2377   /* ------------------------ */
2378   redraw_group(pEconomyDlg->pBeginWidgetList, pWindow, 0);
2379   widget_mark_dirty(pWindow);
2380   flush_dirty();
2381 }
2382 
2383 /* ===================================================================== */
2384 /* ======================== Science Report ============================= */
2385 /* ===================================================================== */
2386 static struct SMALL_DLG *pScienceDlg = NULL;
2387 
2388 static struct ADVANCED_DLG *pChangeTechDlg = NULL;
2389 
2390 /**************************************************************************
2391   Create icon surface for a tech.
2392 **************************************************************************/
create_select_tech_icon(utf8_str * pstr,Tech_type_id tech_id,enum tech_info_mode mode)2393 SDL_Surface *create_select_tech_icon(utf8_str *pstr, Tech_type_id tech_id,
2394                                      enum tech_info_mode mode)
2395 {
2396   struct unit_type *pUnit = NULL;
2397   SDL_Surface *pSurf, *pText, *pTmp, *pTmp2;
2398   SDL_Surface *Surf_Array[10], **pBuf_Array;
2399   SDL_Rect dst;
2400   SDL_Color color;
2401   int w, h;
2402 
2403   color = *get_tech_color(tech_id);
2404   switch (mode)
2405   {
2406   case SMALL_MODE:
2407     h = adj_size(40);
2408     w = adj_size(135);
2409     break;
2410   case MED_MODE:
2411     color = *get_theme_color(COLOR_THEME_SCIENCEDLG_MED_TECHICON_BG);
2412     fc__fallthrough; /* No break, continue to setting default h & w */
2413   default:
2414     h = adj_size(200);
2415     w = adj_size(100);
2416     break;
2417   }
2418 
2419   pText = create_text_surf_smaller_than_w(pstr, adj_size(100 - 4));
2420 
2421   /* create label surface */
2422   pSurf = create_surf(w, h, SDL_SWSURFACE);
2423 
2424   if (tech_id == research_get(client_player())->researching) {
2425     color.a = 180;
2426   } else {
2427     color.a = 128;
2428   }
2429 
2430   SDL_FillRect(pSurf, NULL, map_rgba(pSurf->format, color));
2431 
2432   create_frame(pSurf,
2433                0,0, pSurf->w - 1, pSurf->h - 1,
2434                get_theme_color(COLOR_THEME_SCIENCEDLG_FRAME));
2435 
2436   pTmp = get_tech_icon(tech_id);
2437 
2438   if (mode == SMALL_MODE) {
2439     /* draw name tech text */
2440     dst.x = adj_size(35) + (pSurf->w - pText->w - adj_size(35)) / 2;
2441     dst.y = (pSurf->h - pText->h) / 2;
2442     alphablit(pText, NULL, pSurf, &dst, 255);
2443     FREESURFACE(pText);
2444 
2445     /* draw tech icon */
2446     pText = ResizeSurface(pTmp, adj_size(25), adj_size(25), 1);
2447     dst.x = (adj_size(35) - pText->w) / 2;
2448     dst.y = (pSurf->h - pText->h) / 2;
2449     alphablit(pText, NULL, pSurf, &dst, 255);
2450     FREESURFACE(pText);
2451 
2452   } else {
2453 
2454     /* draw name tech text */
2455     dst.x = (pSurf->w - pText->w) / 2;
2456     dst.y = adj_size(20);
2457     alphablit(pText, NULL, pSurf, &dst, 255);
2458     dst.y += pText->h + adj_size(10);
2459     FREESURFACE(pText);
2460 
2461     /* draw tech icon */
2462     dst.x = (pSurf->w - pTmp->w) / 2;
2463     alphablit(pTmp, NULL, pSurf, &dst, 255);
2464     dst.y += pTmp->w + adj_size(10);
2465 
2466     /* fill array with iprvm. icons */
2467     w = 0;
2468     improvement_iterate(pImprove) {
2469       requirement_vector_iterate(&pImprove->reqs, preq) {
2470         if (VUT_ADVANCE == preq->source.kind
2471             && advance_number(preq->source.value.advance) == tech_id) {
2472           pTmp2 = get_building_surface(pImprove);
2473           Surf_Array[w++] = zoomSurface(pTmp2, DEFAULT_ZOOM * ((float)36 / pTmp2->w), DEFAULT_ZOOM * ((float)36 / pTmp2->w), 1);
2474         }
2475       } requirement_vector_iterate_end;
2476     } improvement_iterate_end;
2477 
2478     if (w) {
2479       if (w >= 2) {
2480         dst.x = (pSurf->w - 2 * Surf_Array[0]->w) / 2;
2481       } else {
2482         dst.x = (pSurf->w - Surf_Array[0]->w) / 2;
2483       }
2484 
2485       /* draw iprvm. icons */
2486       pBuf_Array = Surf_Array;
2487       h = 0;
2488       while (w) {
2489         alphablit(*pBuf_Array, NULL, pSurf, &dst, 255);
2490         dst.x += (*pBuf_Array)->w;
2491         w--;
2492         h++;
2493         if (!(h % 2)) {
2494           if (w >= 2) {
2495             dst.x = (pSurf->w - 2 * (*pBuf_Array)->w) / 2;
2496           } else {
2497             dst.x = (pSurf->w - (*pBuf_Array)->w) / 2;
2498           }
2499           dst.y += (*pBuf_Array)->h;
2500           h = 0;
2501         } /* h == 2 */
2502         pBuf_Array++;
2503       }	/* while */
2504       dst.y += Surf_Array[0]->h + adj_size(5);
2505     } /* if (w) */
2506   /* -------------------------------------------------------- */
2507     w = 0;
2508     unit_type_iterate(un) {
2509       pUnit = un;
2510       if (advance_number(pUnit->require_advance) == tech_id) {
2511         Surf_Array[w++] = adj_surf(get_unittype_surface(un, direction8_invalid()));
2512       }
2513     } unit_type_iterate_end;
2514 
2515     if (w) {
2516       if (w < 2) {
2517         /* w == 1 */
2518         if (Surf_Array[0]->w > 64) {
2519           float zoom = DEFAULT_ZOOM * (64.0 / Surf_Array[0]->w);
2520           SDL_Surface *zoomed = zoomSurface(Surf_Array[0], zoom, zoom, 1);
2521 
2522           dst.x = (pSurf->w - zoomed->w) / 2;
2523           alphablit(zoomed, NULL, pSurf, &dst, 255);
2524           FREESURFACE(zoomed);
2525         } else {
2526           dst.x = (pSurf->w - Surf_Array[0]->w) / 2;
2527           alphablit(Surf_Array[0], NULL, pSurf, &dst, 255);
2528         }
2529       } else {
2530         float zoom;
2531 
2532         if (w > 2) {
2533           zoom = DEFAULT_ZOOM * (38.0 / Surf_Array[0]->w);
2534         } else {
2535           zoom = DEFAULT_ZOOM * (45.0 / Surf_Array[0]->w);
2536         }
2537         dst.x = (pSurf->w - (Surf_Array[0]->w * 2) * zoom - 2) / 2;
2538         pBuf_Array = Surf_Array;
2539         h = 0;
2540         while (w) {
2541           SDL_Surface *zoomed = zoomSurface((*pBuf_Array), zoom, zoom, 1);
2542 
2543           alphablit(zoomed, NULL, pSurf, &dst, 255);
2544           dst.x += zoomed->w + 2;
2545           w--;
2546           h++;
2547           if (!(h % 2)) {
2548             if (w >= 2) {
2549               dst.x = (pSurf->w - 2 * zoomed->w - 2 ) / 2;
2550             } else {
2551               dst.x = (pSurf->w - zoomed->w) / 2;
2552             }
2553             dst.y += zoomed->h + 2;
2554             h = 0;
2555           } /* h == 2 */
2556           pBuf_Array++;
2557           FREESURFACE(zoomed);
2558         } /* while */
2559       } /* w > 1 */
2560     } /* if (w) */
2561   }
2562 
2563   FREESURFACE(pTmp);
2564 
2565   return pSurf;
2566 }
2567 
2568 /**************************************************************************
2569   enable science dialog group ( without window )
2570 **************************************************************************/
enable_science_dialog(void)2571 static void enable_science_dialog(void)
2572 {
2573   set_group_state(pScienceDlg->pBeginWidgetList,
2574                   pScienceDlg->pEndWidgetList->prev, FC_WS_NORMAL);
2575 }
2576 
2577 /**************************************************************************
2578   disable science dialog group ( without window )
2579 **************************************************************************/
disable_science_dialog(void)2580 static void disable_science_dialog(void)
2581 {
2582   set_group_state(pScienceDlg->pBeginWidgetList,
2583                   pScienceDlg->pEndWidgetList->prev, FC_WS_DISABLED);
2584 }
2585 
2586 /**************************************************************************
2587   Update the science report.
2588 **************************************************************************/
real_science_report_dialog_update(void * unused)2589 void real_science_report_dialog_update(void *unused)
2590 {
2591   SDL_Color bg_color = {255, 255, 255, 136};
2592 
2593   if (pScienceDlg) {
2594     const struct research *presearch = research_get(client_player());
2595     char cBuf[128];
2596     utf8_str *pStr;
2597     SDL_Surface *pSurf;
2598     SDL_Surface *pColb_Surface = pIcons->pBIG_Colb;
2599     int step, i, cost;
2600     SDL_Rect dest;
2601     struct unit_type *pUnit;
2602     struct widget *pChangeResearchButton;
2603     struct widget *pChangeResearchGoalButton;
2604     SDL_Rect area;
2605     struct widget *pWindow = pScienceDlg->pEndWidgetList;
2606 
2607     area = pWindow->area;
2608     pChangeResearchButton = pWindow->prev;
2609     pChangeResearchGoalButton = pWindow->prev->prev;
2610 
2611     if (A_UNSET != presearch->researching) {
2612       cost = presearch->client.researching_cost;
2613     } else {
2614       cost = 0;
2615     }
2616 
2617     /* update current research icons */
2618     FREESURFACE(pChangeResearchButton->theme);
2619     pChangeResearchButton->theme = get_tech_icon(presearch->researching);
2620     FREESURFACE(pChangeResearchGoalButton->theme);
2621     pChangeResearchGoalButton->theme = get_tech_icon(presearch->tech_goal);
2622 
2623     /* redraw Window */
2624     widget_redraw(pWindow);
2625 
2626     /* ------------------------------------- */
2627 
2628     /* research progress text */
2629     pStr = create_utf8_from_char(science_dialog_text(), adj_font(12));
2630     pStr->style |= SF_CENTER;
2631     pStr->fgcol = *get_theme_color(COLOR_THEME_SCIENCEDLG_TEXT);
2632 
2633     pSurf = create_text_surf_from_utf8(pStr);
2634 
2635     dest.x = area.x + (area.w - pSurf->w) / 2;
2636     dest.y = area.y + adj_size(2);
2637     alphablit(pSurf, NULL, pWindow->dst->surface, &dest, 255);
2638 
2639     dest.y += pSurf->h + adj_size(4);
2640 
2641     FREESURFACE(pSurf);
2642 
2643     dest.x = area.x + adj_size(16);
2644 
2645     /* separator */
2646     create_line(pWindow->dst->surface,
2647                 dest.x, dest.y, (area.x + area.w - adj_size(16)), dest.y,
2648                 get_theme_color(COLOR_THEME_SCIENCEDLG_FRAME));
2649 
2650     dest.y += adj_size(6);
2651 
2652     widget_set_position(pChangeResearchButton, dest.x, dest.y + adj_size(18));
2653 
2654     /* current research text */
2655     fc_snprintf(cBuf, sizeof(cBuf), "%s: %s",
2656                 research_advance_name_translation(presearch,
2657                                                   presearch->researching),
2658                 get_science_target_text(NULL));
2659 
2660     copy_chars_to_utf8_str(pStr, cBuf);
2661 
2662     pSurf = create_text_surf_from_utf8(pStr);
2663 
2664     dest.x = pChangeResearchButton->size.x + pChangeResearchButton->size.w + adj_size(10);
2665 
2666     alphablit(pSurf, NULL, pWindow->dst->surface, &dest, 255);
2667 
2668     dest.y += pSurf->h + adj_size(4);
2669 
2670     FREESURFACE(pSurf);
2671 
2672     /* progress bar */
2673     if (cost > 0) {
2674       int cost_div_safe = cost - 1;
2675 
2676       cost_div_safe = (cost_div_safe != 0 ? cost_div_safe : 1);
2677       dest.w = cost * pColb_Surface->w;
2678       step = pColb_Surface->w;
2679       if (dest.w > (area.w - dest.x - adj_size(16))) {
2680         dest.w = (area.w - dest.x - adj_size(16));
2681         step = ((area.w - dest.x - adj_size(16)) - pColb_Surface->w) / cost_div_safe;
2682 
2683         if (step == 0) {
2684           step = 1;
2685         }
2686       }
2687 
2688       dest.h = pColb_Surface->h + adj_size(4);
2689       fill_rect_alpha(pWindow->dst->surface, &dest, &bg_color);
2690 
2691       create_frame(pWindow->dst->surface,
2692                    dest.x - 1, dest.y - 1, dest.w, dest.h,
2693                    get_theme_color(COLOR_THEME_SCIENCEDLG_FRAME));
2694 
2695       if (cost > adj_size(286)) {
2696         cost = adj_size(286) * ((float) presearch->bulbs_researched / cost);
2697       } else {
2698         cost = (float) cost * ((float) presearch->bulbs_researched / cost);
2699       }
2700 
2701       dest.y += adj_size(2);
2702       for (i = 0; i < cost; i++) {
2703         alphablit(pColb_Surface, NULL, pWindow->dst->surface, &dest, 255);
2704         dest.x += step;
2705       }
2706     }
2707 
2708     /* improvement icons */
2709 
2710     dest.y += dest.h + adj_size(4);
2711     dest.x = pChangeResearchButton->size.x + pChangeResearchButton->size.w + adj_size(10);
2712 
2713     /* buildings */
2714     improvement_iterate(pImprove) {
2715       requirement_vector_iterate(&pImprove->reqs, preq) {
2716         if (VUT_ADVANCE == preq->source.kind
2717             && (advance_number(preq->source.value.advance)
2718                 == presearch->researching)) {
2719           pSurf = adj_surf(get_building_surface(pImprove));
2720           alphablit(pSurf, NULL, pWindow->dst->surface, &dest, 255);
2721           dest.x += pSurf->w + 1;
2722         }
2723       } requirement_vector_iterate_end;
2724     } improvement_iterate_end;
2725 
2726     dest.x += adj_size(5);
2727 
2728     /* units */
2729     unit_type_iterate(un) {
2730       pUnit = un;
2731       if (advance_number(pUnit->require_advance) == presearch->researching) {
2732         SDL_Surface *surf = get_unittype_surface(un, direction8_invalid());
2733         int w = surf->w;
2734 
2735 	if (w > 64) {
2736           float zoom = DEFAULT_ZOOM * (64.0 / w);
2737 
2738           pSurf = zoomSurface(surf, zoom, zoom, 1);
2739           alphablit(pSurf, NULL, pWindow->dst->surface, &dest, 255);
2740           dest.x += pSurf->w + adj_size(2);
2741           FREESURFACE(pSurf);
2742         } else {
2743           pSurf = adj_surf(surf);
2744           alphablit(pSurf, NULL, pWindow->dst->surface, &dest, 255);
2745           dest.x += pSurf->w + adj_size(2);
2746         }
2747       }
2748     } unit_type_iterate_end;
2749 
2750     /* -------------------------------- */
2751     /* draw separator line */
2752     dest.x = area.x + adj_size(16);
2753     dest.y += adj_size(48) + adj_size(6);
2754 
2755     create_line(pWindow->dst->surface,
2756                 dest.x, dest.y, (area.x + area.w - adj_size(16)), dest.y,
2757                 get_theme_color(COLOR_THEME_SCIENCEDLG_FRAME));
2758 
2759     dest.x = pChangeResearchButton->size.x;
2760     dest.y += adj_size(6);
2761 
2762     widget_set_position(pChangeResearchGoalButton, dest.x, dest.y + adj_size(16));
2763 
2764     /* -------------------------------- */
2765 
2766     /* Goals */
2767     if (A_UNSET != presearch->tech_goal) {
2768       /* current goal text */
2769       copy_chars_to_utf8_str(pStr, research_advance_name_translation
2770                              (presearch, presearch->tech_goal));
2771       pSurf = create_text_surf_from_utf8(pStr);
2772 
2773       dest.x = pChangeResearchGoalButton->size.x + pChangeResearchGoalButton->size.w + adj_size(10);
2774       alphablit(pSurf, NULL, pWindow->dst->surface, &dest, 255);
2775 
2776       dest.y += pSurf->h;
2777 
2778       FREESURFACE(pSurf);
2779 
2780       copy_chars_to_utf8_str(pStr, get_science_goal_text
2781                              (presearch->tech_goal));
2782       pSurf = create_text_surf_from_utf8(pStr);
2783 
2784       dest.x = pChangeResearchGoalButton->size.x + pChangeResearchGoalButton->size.w + adj_size(10);
2785       alphablit(pSurf, NULL, pWindow->dst->surface, &dest, 255);
2786 
2787       dest.y += pSurf->h + adj_size(6);
2788 
2789       FREESURFACE(pSurf);
2790 
2791       /* buildings */
2792       improvement_iterate(pImprove) {
2793         requirement_vector_iterate(&pImprove->reqs, preq) {
2794           if (VUT_ADVANCE == preq->source.kind
2795               && (advance_number(preq->source.value.advance)
2796                   == presearch->tech_goal)) {
2797             pSurf = adj_surf(get_building_surface(pImprove));
2798             alphablit(pSurf, NULL, pWindow->dst->surface, &dest, 255);
2799             dest.x += pSurf->w + 1;
2800           }
2801         } requirement_vector_iterate_end;
2802       } improvement_iterate_end;
2803 
2804       dest.x += adj_size(6);
2805 
2806       /* units */
2807       unit_type_iterate(un) {
2808         pUnit = un;
2809         if (advance_number(pUnit->require_advance) == presearch->tech_goal) {
2810           SDL_Surface *surf = get_unittype_surface(un, direction8_invalid());
2811           int w = surf->w;
2812 
2813           if (w > 64) {
2814             float zoom = DEFAULT_ZOOM * (64.0 / w);
2815 
2816             pSurf = zoomSurface(surf, zoom, zoom, 1);
2817             alphablit(pSurf, NULL, pWindow->dst->surface, &dest, 255);
2818             dest.x += pSurf->w + adj_size(2);
2819             FREESURFACE(pSurf);
2820           } else {
2821             pSurf = adj_surf(surf);
2822             alphablit(pSurf, NULL, pWindow->dst->surface, &dest, 255);
2823             dest.x += pSurf->w + adj_size(2);
2824           }
2825         }
2826       } unit_type_iterate_end;
2827     }
2828 
2829     /* -------------------------------- */
2830     widget_mark_dirty(pWindow);
2831     redraw_group(pScienceDlg->pBeginWidgetList, pWindow->prev, 1);
2832     flush_dirty();
2833 
2834     FREEUTF8STR(pStr);
2835   }
2836 }
2837 
2838 /**************************************************************************
2839   Close science report dialog.
2840 **************************************************************************/
science_report_dialog_popdown(void)2841 static void science_report_dialog_popdown(void)
2842 {
2843   if (pScienceDlg) {
2844     popdown_window_group_dialog(pScienceDlg->pBeginWidgetList,
2845                                 pScienceDlg->pEndWidgetList);
2846     FC_FREE(pScienceDlg);
2847     set_wstate(get_research_widget(), FC_WS_NORMAL);
2848     widget_redraw(get_research_widget());
2849     widget_mark_dirty(get_research_widget());
2850     flush_dirty();
2851   }
2852 }
2853 
2854 /**************************************************************************
2855   Close research target changing dialog.
2856 **************************************************************************/
exit_change_tech_dlg_callback(struct widget * pWidget)2857 static int exit_change_tech_dlg_callback(struct widget *pWidget)
2858 {
2859   if (PRESSED_EVENT(Main.event)) {
2860     if (pChangeTechDlg) {
2861       popdown_window_group_dialog(pChangeTechDlg->pBeginWidgetList,
2862                                   pChangeTechDlg->pEndWidgetList);
2863       FC_FREE(pChangeTechDlg->pScroll);
2864       FC_FREE(pChangeTechDlg);
2865       enable_science_dialog();
2866       if (pWidget) {
2867         flush_dirty();
2868       }
2869     }
2870   }
2871 
2872   return -1;
2873 }
2874 
2875 /**************************************************************************
2876   User interacted with button of specific Tech.
2877 **************************************************************************/
change_research_callback(struct widget * pWidget)2878 static int change_research_callback(struct widget *pWidget)
2879 {
2880   if (PRESSED_EVENT(Main.event)) {
2881     dsend_packet_player_research(&client.conn, (MAX_ID - pWidget->ID));
2882     exit_change_tech_dlg_callback(NULL);
2883   } else if (Main.event.button.button == SDL_BUTTON_MIDDLE) {
2884     popup_tech_info((MAX_ID - pWidget->ID));
2885   }
2886 
2887   return -1;
2888 }
2889 
2890 /**************************************************************************
2891   This function is used by change research and change goals dlgs.
2892 **************************************************************************/
change_research_goal_dialog_callback(struct widget * pWindow)2893 static int change_research_goal_dialog_callback(struct widget *pWindow)
2894 {
2895   if (PRESSED_EVENT(Main.event)) {
2896     if (select_window_group_dialog(pChangeTechDlg->pBeginWidgetList, pWindow)) {
2897       widget_flush(pWindow);
2898     }
2899   }
2900 
2901   return -1;
2902 }
2903 
2904 /**************************************************************************
2905   Popup dialog to change current research.
2906 **************************************************************************/
popup_change_research_dialog(void)2907 static void popup_change_research_dialog(void)
2908 {
2909   const struct research *presearch = research_get(client_player());
2910   struct widget *pBuf = NULL;
2911   struct widget *pWindow;
2912   utf8_str *pstr;
2913   SDL_Surface *pSurf;
2914   int max_col, max_row, col, i, count = 0, h;
2915   SDL_Rect area;
2916 
2917   if (is_future_tech(presearch->researching)) {
2918     return;
2919   }
2920 
2921   advance_index_iterate(A_FIRST, aidx) {
2922     if (!research_invention_gettable(presearch, aidx, FALSE)) {
2923       continue;
2924     }
2925     count++;
2926   } advance_index_iterate_end;
2927 
2928   if (count < 2) {
2929     return;
2930   }
2931 
2932   pChangeTechDlg = fc_calloc(1, sizeof(struct ADVANCED_DLG));
2933 
2934   pstr = create_utf8_from_char(_("What should we focus on now?"), adj_font(12));
2935   pstr->style |= TTF_STYLE_BOLD;
2936 
2937   pWindow = create_window_skeleton(NULL, pstr, 0);
2938   pChangeTechDlg->pEndWidgetList = pWindow;
2939   set_wstate(pWindow, FC_WS_NORMAL);
2940   pWindow->action = change_research_goal_dialog_callback;
2941 
2942   add_to_gui_list(ID_SCIENCE_DLG_CHANGE_REASARCH_WINDOW, pWindow);
2943 
2944   area = pWindow->area;
2945 
2946   /* ------------------------- */
2947   /* exit button */
2948   pBuf = create_themeicon(current_theme->Small_CANCEL_Icon, pWindow->dst,
2949                           WF_WIDGET_HAS_INFO_LABEL | WF_RESTORE_BACKGROUND);
2950   pBuf->info_label = create_utf8_from_char(_("Close Dialog (Esc)"),
2951                                            adj_font(12));
2952   area.w += pBuf->size.w + adj_size(10);
2953   pBuf->action = exit_change_tech_dlg_callback;
2954   set_wstate(pBuf, FC_WS_NORMAL);
2955   pBuf->key = SDLK_ESCAPE;
2956 
2957   add_to_gui_list(ID_TERRAIN_ADV_DLG_EXIT_BUTTON, pBuf);
2958 
2959   /* ------------------------- */
2960   /* max col - 104 is select tech widget width */
2961   max_col = (main_window_width() - (pWindow->size.w - pWindow->area.w) - adj_size(2)) / adj_size(104);
2962   /* max row - 204 is select tech widget height */
2963   max_row = (main_window_height() - (pWindow->size.h - pWindow->area.h) - adj_size(2)) / adj_size(204);
2964 
2965   /* make space on screen for scrollbar */
2966   if (max_col * max_row < count) {
2967     max_col--;
2968   }
2969 
2970   if (count < max_col + 1) {
2971     col = count;
2972   } else {
2973     if (count < max_col + 3) {
2974       col = max_col - 2;
2975     } else {
2976       if (count < max_col + 5) {
2977         col = max_col - 1;
2978       } else {
2979         col = max_col;
2980       }
2981     }
2982   }
2983 
2984   pstr = create_utf8_str(NULL, 0, adj_font(10));
2985   pstr->style |= (TTF_STYLE_BOLD | SF_CENTER);
2986 
2987   count = 0;
2988   h = col * max_row;
2989   advance_index_iterate(A_FIRST, aidx) {
2990     if (!research_invention_gettable(presearch, aidx, FALSE)) {
2991       continue;
2992     }
2993 
2994     count++;
2995 
2996     copy_chars_to_utf8_str(pstr, advance_name_translation(advance_by_number(aidx)));
2997     pSurf = create_select_tech_icon(pstr, aidx, MED_MODE);
2998     pBuf = create_icon2(pSurf, pWindow->dst,
2999                         WF_FREE_THEME | WF_RESTORE_BACKGROUND);
3000 
3001     set_wstate(pBuf, FC_WS_NORMAL);
3002     pBuf->action = change_research_callback;
3003 
3004     add_to_gui_list(MAX_ID - aidx, pBuf);
3005 
3006     if (count > h) {
3007       set_wflag(pBuf, WF_HIDDEN);
3008     }
3009   } advance_index_iterate_end;
3010 
3011   FREEUTF8STR(pstr);
3012 
3013   pChangeTechDlg->pBeginWidgetList = pBuf;
3014   pChangeTechDlg->pBeginActiveWidgetList = pChangeTechDlg->pBeginWidgetList;
3015   pChangeTechDlg->pEndActiveWidgetList = pChangeTechDlg->pEndWidgetList->prev->prev;
3016 
3017   /* -------------------------------------------------------------- */
3018 
3019   i = 0;
3020   if (count > col) {
3021     count = (count + (col - 1)) / col;
3022     if (count > max_row) {
3023       pChangeTechDlg->pActiveWidgetList = pChangeTechDlg->pEndActiveWidgetList;
3024       count = max_row;
3025       i = create_vertical_scrollbar(pChangeTechDlg, col, count, TRUE, TRUE);
3026     }
3027   } else {
3028     count = 1;
3029   }
3030 
3031   disable_science_dialog();
3032 
3033   area.w = MAX(area.w, (col * pBuf->size.w + adj_size(2) + i));
3034   area.h = MAX(area.h, count * pBuf->size.h + adj_size(2));
3035 
3036   /* alloca window theme and win background buffer */
3037   pSurf = theme_get_background(theme, BACKGROUND_CHANGERESEARCHDLG);
3038   resize_window(pWindow, pSurf, NULL,
3039                 (pWindow->size.w - pWindow->area.w) + area.w,
3040                 (pWindow->size.h - pWindow->area.h) + area.h);
3041   FREESURFACE(pSurf);
3042 
3043   area = pWindow->area;
3044 
3045   widget_set_position(pWindow,
3046                       (main_window_width() - pWindow->size.w) / 2,
3047                       (main_window_height() - pWindow->size.h) / 2);
3048 
3049   /* exit button */
3050   pBuf = pWindow->prev;
3051   pBuf->size.x = area.x + area.w - pBuf->size.w - 1;
3052   pBuf->size.y = pWindow->size.y + adj_size(2);
3053 
3054   setup_vertical_widgets_position(col, area.x + 1,
3055                                   area.y, 0, 0,
3056                                   pChangeTechDlg->pBeginActiveWidgetList,
3057                                   pChangeTechDlg->pEndActiveWidgetList);
3058 
3059   if (pChangeTechDlg->pScroll) {
3060     setup_vertical_scrollbar_area(pChangeTechDlg->pScroll,
3061                                   area.x + area.w, area.y,
3062                                   area.h, TRUE);
3063   }
3064 
3065   redraw_group(pChangeTechDlg->pBeginWidgetList, pWindow, FALSE);
3066 
3067   widget_flush(pWindow);
3068 }
3069 
3070 /**************************************************************************
3071   User chose spesic tech as research goal.
3072 **************************************************************************/
change_research_goal_callback(struct widget * pWidget)3073 static int change_research_goal_callback(struct widget *pWidget)
3074 {
3075   if (PRESSED_EVENT(Main.event)) {
3076     dsend_packet_player_tech_goal(&client.conn, (MAX_ID - pWidget->ID));
3077 
3078     exit_change_tech_dlg_callback(NULL);
3079 
3080     /* Following is to make the menu go back to the current goal;
3081      * there may be a better way to do this?  --dwp */
3082     real_science_report_dialog_update(NULL);
3083   } else if (Main.event.button.button == SDL_BUTTON_MIDDLE) {
3084     popup_tech_info((MAX_ID - pWidget->ID));
3085   }
3086 
3087   return -1;
3088 }
3089 
3090 /**************************************************************************
3091   Popup dialog to change research goal.
3092 **************************************************************************/
popup_change_research_goal_dialog(void)3093 static void popup_change_research_goal_dialog(void)
3094 {
3095   const struct research *presearch = research_get(client_player());
3096   struct widget *pBuf = NULL;
3097   struct widget *pWindow;
3098   utf8_str *pstr;
3099   SDL_Surface *pSurf;
3100   char cBuf[128];
3101   int max_col, max_row, col, i, count = 0, h , num;
3102   SDL_Rect area;
3103 
3104   /* collect all techs which are reachable in under 11 steps
3105    * hist will hold afterwards the techid of the current choice
3106    */
3107   advance_index_iterate(A_FIRST, aidx) {
3108     if (research_invention_reachable(presearch, aidx)
3109         && TECH_KNOWN != research_invention_state(presearch, aidx)
3110         && (11 > research_goal_unknown_techs(presearch, aidx)
3111             || aidx == presearch->tech_goal)) {
3112       count++;
3113     }
3114   } advance_index_iterate_end;
3115 
3116   if (count < 1) {
3117     return;
3118   }
3119 
3120   pChangeTechDlg = fc_calloc(1, sizeof(struct ADVANCED_DLG));
3121 
3122   pstr = create_utf8_from_char(_("Select target :"), adj_font(12));
3123   pstr->style |= TTF_STYLE_BOLD;
3124 
3125   pWindow = create_window_skeleton(NULL, pstr, 0);
3126   pChangeTechDlg->pEndWidgetList = pWindow;
3127   set_wstate(pWindow, FC_WS_NORMAL);
3128   pWindow->action = change_research_goal_dialog_callback;
3129 
3130   add_to_gui_list(ID_SCIENCE_DLG_CHANGE_GOAL_WINDOW, pWindow);
3131 
3132   area = pWindow->area;
3133 
3134   /* ------------------------- */
3135   /* exit button */
3136   pBuf = create_themeicon(current_theme->Small_CANCEL_Icon, pWindow->dst,
3137                           WF_WIDGET_HAS_INFO_LABEL | WF_RESTORE_BACKGROUND);
3138   pBuf->info_label = create_utf8_from_char(_("Close Dialog (Esc)"),
3139                                            adj_font(12));
3140   area.w += pBuf->size.w + adj_size(10);
3141   pBuf->action = exit_change_tech_dlg_callback;
3142   set_wstate(pBuf, FC_WS_NORMAL);
3143   pBuf->key = SDLK_ESCAPE;
3144 
3145   add_to_gui_list(ID_SCIENCE_DLG_CHANGE_GOAL_CANCEL_BUTTON, pBuf);
3146 
3147   /* ------------------------- */
3148   /* max col - 104 is goal tech widget width */
3149   max_col = (main_window_width() - (pWindow->size.w - pWindow->area.w) - adj_size(2)) / adj_size(104);
3150 
3151   /* max row - 204 is goal tech widget height */
3152   max_row = (main_window_height() - (pWindow->size.h - pWindow->area.h) - adj_size(2)) / adj_size(204);
3153 
3154   /* make space on screen for scrollbar */
3155   if (max_col * max_row < count) {
3156     max_col--;
3157   }
3158 
3159   if (count < max_col + 1) {
3160     col = count;
3161   } else {
3162     if (count < max_col + 3) {
3163       col = max_col - 2;
3164     } else {
3165       if (count < max_col + 5) {
3166         col = max_col - 1;
3167       } else {
3168         col = max_col;
3169       }
3170     }
3171   }
3172 
3173   pstr = create_utf8_str(NULL, 0, adj_font(10));
3174   pstr->style |= (TTF_STYLE_BOLD | SF_CENTER);
3175 
3176   /* collect all techs which are reachable in under 11 steps
3177    * hist will hold afterwards the techid of the current choice
3178    */
3179   count = 0;
3180   h = col * max_row;
3181   advance_index_iterate(A_FIRST, aidx) {
3182     if (research_invention_reachable(presearch, aidx)
3183         && TECH_KNOWN != research_invention_state(presearch, aidx)
3184         && (11 > (num = research_goal_unknown_techs(presearch, aidx))
3185             || aidx == presearch->tech_goal)) {
3186 
3187       count++;
3188       fc_snprintf(cBuf, sizeof(cBuf), "%s\n%d %s",
3189                   advance_name_translation(advance_by_number(aidx)),
3190                   num,
3191                   PL_("step", "steps", num));
3192       copy_chars_to_utf8_str(pstr, cBuf);
3193       pSurf = create_select_tech_icon(pstr, aidx, FULL_MODE);
3194       pBuf = create_icon2(pSurf, pWindow->dst,
3195                           WF_FREE_THEME | WF_RESTORE_BACKGROUND);
3196 
3197       set_wstate(pBuf, FC_WS_NORMAL);
3198       pBuf->action = change_research_goal_callback;
3199 
3200       add_to_gui_list(MAX_ID - aidx, pBuf);
3201 
3202       if (count > h) {
3203         set_wflag(pBuf, WF_HIDDEN);
3204       }
3205     }
3206   } advance_index_iterate_end;
3207 
3208   FREEUTF8STR(pstr);
3209 
3210   pChangeTechDlg->pBeginWidgetList = pBuf;
3211   pChangeTechDlg->pBeginActiveWidgetList = pChangeTechDlg->pBeginWidgetList;
3212   pChangeTechDlg->pEndActiveWidgetList = pChangeTechDlg->pEndWidgetList->prev->prev;
3213 
3214   /* -------------------------------------------------------------- */
3215 
3216   i = 0;
3217   if (count > col) {
3218     count = (count + (col-1)) / col;
3219     if (count > max_row) {
3220       pChangeTechDlg->pActiveWidgetList = pChangeTechDlg->pEndActiveWidgetList;
3221       count = max_row;
3222       i = create_vertical_scrollbar(pChangeTechDlg, col, count, TRUE, TRUE);
3223     }
3224   } else {
3225     count = 1;
3226   }
3227 
3228   disable_science_dialog();
3229 
3230   area.w = MAX(area.w, (col * pBuf->size.w + adj_size(2) + i));
3231   area.h = MAX(area.h, count * pBuf->size.h + adj_size(2));
3232 
3233   /* alloca window theme and win background buffer */
3234   pSurf = theme_get_background(theme, BACKGROUND_CHANGERESEARCHDLG);
3235   resize_window(pWindow, pSurf, NULL,
3236                 (pWindow->size.w - pWindow->area.w) + area.w,
3237                 (pWindow->size.h - pWindow->area.h) + area.h);
3238   FREESURFACE(pSurf);
3239 
3240   area = pWindow->area;
3241 
3242   widget_set_position(pWindow,
3243                       (main_window_width() - pWindow->size.w) / 2,
3244                       (main_window_height() - pWindow->size.h) / 2);
3245 
3246   /* exit button */
3247   pBuf = pWindow->prev;
3248   pBuf->size.x = area.x + area.w - pBuf->size.w - 1;
3249   pBuf->size.y = pWindow->size.y + adj_size(2);
3250 
3251   setup_vertical_widgets_position(col, area.x + 1,
3252                                   area.y, 0, 0,
3253                                   pChangeTechDlg->pBeginActiveWidgetList,
3254                                   pChangeTechDlg->pEndActiveWidgetList);
3255 
3256   if (pChangeTechDlg->pScroll) {
3257     setup_vertical_scrollbar_area(pChangeTechDlg->pScroll,
3258                                   area.x + area.w, area.y,
3259                                   area.h, TRUE);
3260   }
3261 
3262   redraw_group(pChangeTechDlg->pBeginWidgetList, pWindow, FALSE);
3263 
3264   widget_flush(pWindow);
3265 }
3266 
3267 /**************************************************************************
3268   User interacted with science dialog window.
3269 **************************************************************************/
science_dialog_callback(struct widget * pWindow)3270 static int science_dialog_callback(struct widget *pWindow)
3271 {
3272   if (PRESSED_EVENT(Main.event)) {
3273     if (!pChangeTechDlg) {
3274       if (select_window_group_dialog(pScienceDlg->pBeginWidgetList, pWindow)) {
3275         widget_flush(pWindow);
3276       }
3277       if (move_window_group_dialog(pScienceDlg->pBeginWidgetList, pWindow)) {
3278         real_science_report_dialog_update(NULL);
3279       }
3280     }
3281   }
3282 
3283   return -1;
3284 }
3285 
3286 /**************************************************************************
3287   Open research target changing dialog.
3288 **************************************************************************/
popup_change_research_dialog_callback(struct widget * pWidget)3289 static int popup_change_research_dialog_callback(struct widget *pWidget)
3290 {
3291   if (PRESSED_EVENT(Main.event)) {
3292     set_wstate(pWidget, FC_WS_NORMAL);
3293     selected_widget = NULL;
3294     widget_redraw(pWidget);
3295     widget_flush(pWidget);
3296 
3297     popup_change_research_dialog();
3298   }
3299   return -1;
3300 }
3301 
3302 /**************************************************************************
3303   Open research goal changing dialog.
3304 **************************************************************************/
popup_change_research_goal_dialog_callback(struct widget * pWidget)3305 static int popup_change_research_goal_dialog_callback(struct widget *pWidget)
3306 {
3307   if (PRESSED_EVENT(Main.event)) {
3308     set_wstate(pWidget, FC_WS_NORMAL);
3309     selected_widget = NULL;
3310     widget_redraw(pWidget);
3311     widget_flush(pWidget);
3312 
3313     popup_change_research_goal_dialog();
3314   }
3315   return -1;
3316 }
3317 
3318 /**************************************************************************
3319   Close science dialog.
3320 **************************************************************************/
popdown_science_dialog_callback(struct widget * pWidget)3321 static int popdown_science_dialog_callback(struct widget *pWidget)
3322 {
3323   if (PRESSED_EVENT(Main.event)) {
3324     science_report_dialog_popdown();
3325   }
3326 
3327   return -1;
3328 }
3329 
3330 /**************************************************************************
3331   Popup (or raise) the science report(F6).  It may or may not be modal.
3332 **************************************************************************/
science_report_dialog_popup(bool raise)3333 void science_report_dialog_popup(bool raise)
3334 {
3335   const struct research *presearch;
3336   struct widget *pWidget, *pWindow;
3337   struct widget *pChangeResearchButton;
3338   struct widget *pChangeResearchGoalButton;
3339   struct widget *pExitButton;
3340   utf8_str *pstr;
3341   SDL_Surface *pBackground, *pTechIcon;
3342   int count;
3343   SDL_Rect area;
3344 
3345   if (pScienceDlg) {
3346     return;
3347   }
3348 
3349   presearch = research_get(client_player());
3350 
3351   /* disable research button */
3352   pWidget = get_research_widget();
3353   set_wstate(pWidget, FC_WS_DISABLED);
3354   widget_redraw(pWidget);
3355   widget_mark_dirty(pWidget);
3356 
3357   pScienceDlg = fc_calloc(1, sizeof(struct SMALL_DLG));
3358 
3359   /* TRANS: Research report title */
3360   pstr = create_utf8_from_char(_("Research"), adj_font(12));
3361   pstr->style |= TTF_STYLE_BOLD;
3362 
3363 #ifdef SMALL_SCREEN
3364   pWindow = create_window(NULL, pstr, 200, 132, 0);
3365 #else  /* SMALL_SCREEN */
3366   pWindow = create_window(NULL, pstr, adj_size(400), adj_size(246), 0);
3367 #endif /* SMALL_SCREEN */
3368   set_wstate(pWindow, FC_WS_NORMAL);
3369   pWindow->action = science_dialog_callback;
3370 
3371   pScienceDlg->pEndWidgetList = pWindow;
3372 
3373   pBackground = theme_get_background(theme, BACKGROUND_SCIENCEDLG);
3374   pWindow->theme = ResizeSurface(pBackground, pWindow->size.w, pWindow->size.h, 1);
3375   FREESURFACE(pBackground);
3376 
3377   area = pWindow->area;
3378 
3379   widget_set_position(pWindow,
3380                       (main_window_width() - pWindow->size.w) / 2,
3381                       (main_window_height() - pWindow->size.h) / 2);
3382 
3383   add_to_gui_list(ID_SCIENCE_DLG_WINDOW, pWindow);
3384 
3385   /* count number of researchable techs */
3386   count = 0;
3387   advance_index_iterate(A_FIRST, i) {
3388     if (research_invention_reachable(presearch, i)
3389         && TECH_KNOWN != research_invention_state(presearch, i)) {
3390       count++;
3391     }
3392   } advance_index_iterate_end;
3393 
3394   /* current research icon */
3395   pTechIcon = get_tech_icon(presearch->researching);
3396   pChangeResearchButton = create_icon2(pTechIcon, pWindow->dst, WF_RESTORE_BACKGROUND | WF_FREE_THEME);
3397 
3398   pChangeResearchButton->action = popup_change_research_dialog_callback;
3399   if (count > 0) {
3400     set_wstate(pChangeResearchButton, FC_WS_NORMAL);
3401   }
3402 
3403   add_to_gui_list(ID_SCIENCE_DLG_CHANGE_REASARCH_BUTTON, pChangeResearchButton);
3404 
3405   /* current research goal icon */
3406   pTechIcon = get_tech_icon(presearch->tech_goal);
3407   pChangeResearchGoalButton = create_icon2(pTechIcon, pWindow->dst, WF_RESTORE_BACKGROUND | WF_FREE_THEME);
3408 
3409   pChangeResearchGoalButton->action = popup_change_research_goal_dialog_callback;
3410   if (count > 0) {
3411     set_wstate(pChangeResearchGoalButton, FC_WS_NORMAL);
3412   }
3413 
3414   add_to_gui_list(ID_SCIENCE_DLG_CHANGE_GOAL_BUTTON, pChangeResearchGoalButton);
3415 
3416   /* ------ */
3417   /* exit button */
3418   pExitButton = create_themeicon(current_theme->Small_CANCEL_Icon, pWindow->dst,
3419                                  WF_WIDGET_HAS_INFO_LABEL
3420                                  | WF_RESTORE_BACKGROUND);
3421   pExitButton->info_label = create_utf8_from_char(_("Close Dialog (Esc)"),
3422                                                   adj_font(12));
3423   pExitButton->action = popdown_science_dialog_callback;
3424   set_wstate(pExitButton, FC_WS_NORMAL);
3425   pExitButton->key = SDLK_ESCAPE;
3426 
3427   add_to_gui_list(ID_SCIENCE_CANCEL_DLG_BUTTON, pExitButton);
3428 
3429   widget_set_position(pExitButton,
3430                       area.x + area.w - pExitButton->size.w - adj_size(1),
3431                       pWindow->size.y + adj_size(2));
3432 
3433   /* ======================== */
3434   pScienceDlg->pBeginWidgetList = pExitButton;
3435 
3436   real_science_report_dialog_update(NULL);
3437 }
3438 
3439 /**************************************************************************
3440   Popdown all the science reports (report, change tech, change goals).
3441 **************************************************************************/
science_report_dialogs_popdown_all(void)3442 void science_report_dialogs_popdown_all(void)
3443 {
3444   if (pChangeTechDlg) {
3445     popdown_window_group_dialog(pChangeTechDlg->pBeginWidgetList,
3446                                 pChangeTechDlg->pEndWidgetList);
3447     FC_FREE(pChangeTechDlg->pScroll);
3448     FC_FREE(pChangeTechDlg);
3449   }
3450   if (pScienceDlg) {
3451     popdown_window_group_dialog(pScienceDlg->pBeginWidgetList,
3452                                 pScienceDlg->pEndWidgetList);
3453     FC_FREE(pScienceDlg);
3454     set_wstate(get_research_widget(), FC_WS_NORMAL);
3455     widget_redraw(get_research_widget());
3456     widget_mark_dirty(get_research_widget());
3457   }
3458 }
3459 
3460 /****************************************************************************
3461   Resize and redraw the requirement tree.
3462 ****************************************************************************/
science_report_dialog_redraw(void)3463 void science_report_dialog_redraw(void)
3464 {
3465   /* No requirement tree yet. */
3466 }
3467 
3468 /* ===================================================================== */
3469 /* ======================== Endgame Report ============================= */
3470 /* ===================================================================== */
3471 
3472 static char eg_buffer[150 * MAX_NUM_PLAYERS];
3473 static int eg_player_count = 0;
3474 static int eg_players_received = 0;
3475 
3476 /****************************************************************
3477   Show a dialog with player statistics at endgame.
3478   TODO: Display all statistics in packet_endgame_report.
3479 *****************************************************************/
endgame_report_dialog_start(const struct packet_endgame_report * packet)3480 void endgame_report_dialog_start(const struct packet_endgame_report *packet)
3481 {
3482   eg_buffer[0] = '\0';
3483   eg_player_count = packet->player_num;
3484   eg_players_received = 0;
3485 }
3486 
3487 /****************************************************************
3488   Received endgame report information about single player
3489 *****************************************************************/
endgame_report_dialog_player(const struct packet_endgame_player * packet)3490 void endgame_report_dialog_player(const struct packet_endgame_player *packet)
3491 {
3492   const struct player *pplayer = player_by_number(packet->player_id);
3493 
3494   eg_players_received++;
3495 
3496   cat_snprintf(eg_buffer, sizeof(eg_buffer),
3497                PL_("%2d: The %s ruler %s scored %d point\n",
3498                    "%2d: The %s ruler %s scored %d points\n",
3499                    packet->score),
3500                eg_players_received, nation_adjective_for_player(pplayer),
3501                player_name(pplayer), packet->score);
3502 
3503   if (eg_players_received == eg_player_count) {
3504     popup_notify_dialog(_("Final Report:"),
3505                         _("The Greatest Civilizations in the world."),
3506                         eg_buffer);
3507   }
3508 }
3509