1 /***********************************************************************
2  Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 ***********************************************************************/
13 
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17 
18 /* SDL */
19 #include <SDL/SDL.h>
20 
21 /* utility */
22 #include "fcintl.h"
23 #include "log.h"
24 
25 /* common */
26 #include "game.h"
27 #include "government.h"
28 #include "movement.h"
29 
30 /* client */
31 #include "client_main.h"
32 #include "helpdata.h"
33 
34 /* gui-sdl */
35 #include "colors.h"
36 #include "graphics.h"
37 #include "gui_id.h"
38 #include "gui_main.h"
39 #include "gui_tilespec.h"
40 #include "mapview.h"
41 #include "repodlgs.h"
42 #include "sprite.h"
43 #include "themespec.h"
44 #include "widget.h"
45 
46 #include "helpdlg.h"
47 
48 static struct ADVANCED_DLG *pHelpDlg = NULL;
49 
50 struct TECHS_BUTTONS {
51   struct widget *pTargets[6], *pSub_Targets[6];
52   struct widget *pRequirementButton[2], *pSub_Req[4];
53   struct widget *pDock;
54   bool show_tree;
55   bool show_full_tree;
56 };
57 
58 struct UNITS_BUTTONS {
59   struct widget *pObsoleteByButton;
60   struct widget *pRequirementButton;
61   struct widget *pDock;
62 };
63 
64 enum help_page_type current_help_dlg = HELP_LAST;
65 
66 static const int bufsz = 8192;
67 
68 static int change_tech_callback(struct widget *pWidget);
69 
70 /**************************************************************************
71   Open Help Browser without any specific topic in mind
72 **************************************************************************/
popup_help_browser(void)73 void popup_help_browser(void)
74 {
75   popup_tech_info(A_NONE);
76 }
77 
78 /**************************************************************************
79   Popup the help dialog to get help on the given string topic.  Note that
80   the topic may appear in multiple sections of the help (it may be both
81   an improvement and a unit, for example).
82 
83   The string will be untranslated.
84 **************************************************************************/
popup_help_dialog_string(const char * item)85 void popup_help_dialog_string(const char *item)
86 {
87   popup_help_dialog_typed(Q_(item), HELP_ANY);
88 }
89 
90 /**************************************************************************
91   Popup the help dialog to display help on the given string topic from
92   the given section.
93 
94   The string will be translated.
95 **************************************************************************/
popup_help_dialog_typed(const char * item,enum help_page_type eHPT)96 void popup_help_dialog_typed(const char *item, enum help_page_type eHPT)
97 {
98   log_debug("popup_help_dialog_typed : PORT ME");
99 }
100 
101 /**************************************************************************
102   Close the help dialog.
103 **************************************************************************/
popdown_help_dialog(void)104 void popdown_help_dialog(void)
105 {
106   if (pHelpDlg)
107   {
108     popdown_window_group_dialog(pHelpDlg->pBeginWidgetList,
109                                            pHelpDlg->pEndWidgetList);
110     FC_FREE(pHelpDlg->pScroll);
111     FC_FREE(pHelpDlg);
112     current_help_dlg = HELP_LAST;
113   }
114 }
115 
116 /**************************************************************************
117   User interacted with help dialog window
118 **************************************************************************/
help_dlg_window_callback(struct widget * pWindow)119 static int help_dlg_window_callback(struct widget *pWindow)
120 {
121   return -1;
122 }
123 
124 /**************************************************************************
125   User requested closing of the help dialog
126 **************************************************************************/
exit_help_dlg_callback(struct widget * pWidget)127 static int exit_help_dlg_callback(struct widget *pWidget)
128 {
129   if (Main.event.button.button == SDL_BUTTON_LEFT) {
130     popdown_help_dialog();
131     flush_dirty();
132   }
133 
134   return -1;
135 }
136 
137 /**************************************************************************
138   User requested new government help
139 **************************************************************************/
change_gov_callback(struct widget * pWidget)140 static int change_gov_callback(struct widget *pWidget)
141 {
142   if (Main.event.button.button == SDL_BUTTON_LEFT) {
143     popup_gov_info(MAX_ID - pWidget->ID);
144   }
145   return -1;
146 }
147 
148 /**************************************************************************
149   Show government info
150 **************************************************************************/
popup_gov_info(int gov)151 void popup_gov_info(int gov)
152 {
153 }
154 
155 /**************************************************************************
156   User requested new improvement help
157 **************************************************************************/
change_impr_callback(struct widget * pWidget)158 static int change_impr_callback(struct widget *pWidget)
159 {
160   if (Main.event.button.button == SDL_BUTTON_LEFT) {
161     popup_impr_info(MAX_ID - pWidget->ID);
162   }
163 
164   return -1;
165 }
166 
167 /**************************************************************************
168   Refresh improvement help dialog
169 **************************************************************************/
redraw_impr_info_dlg(void)170 static void redraw_impr_info_dlg(void)
171 {
172   SDL_Color bg_color = {255, 255, 255, 64};
173 
174   struct widget *pWindow = pHelpDlg->pEndWidgetList;
175   struct UNITS_BUTTONS *pStore = (struct UNITS_BUTTONS *)pWindow->data.ptr;
176   SDL_Rect dst;
177 
178   redraw_group(pWindow->prev, pWindow, FALSE);
179 
180   dst.x = pStore->pDock->prev->size.x - adj_size(10);
181   dst.y = pStore->pDock->prev->size.y - adj_size(10);
182   dst.w = pWindow->size.w - (dst.x - pWindow->size.x) - adj_size(10);
183   dst.h = pWindow->size.h - (dst.y - pWindow->size.y) - adj_size(10);
184 
185   SDL_FillRectAlpha(pWindow->dst->surface, &dst, &bg_color);
186   putframe(pWindow->dst->surface,
187            dst.x, dst.y, dst.x + dst.w, dst.y + dst.h,
188            get_theme_color(COLOR_THEME_HELPDLG_FRAME));
189 
190   /*------------------------------------- */
191   redraw_group(pHelpDlg->pBeginWidgetList, pWindow->prev->prev, FALSE);
192   widget_flush(pWindow);
193 }
194 
195 /**************************************************************************
196   Show improvement info
197 **************************************************************************/
popup_impr_info(Impr_type_id impr)198 void popup_impr_info(Impr_type_id impr)
199 {
200   SDL_Color bg_color = {255, 255, 255, 128};
201 
202   struct widget *pWindow;
203   struct UNITS_BUTTONS *pStore;
204 
205   struct widget *pCloseButton = NULL;
206   struct widget *pListToggleButton = NULL;
207   struct widget *pImprovementButton = NULL;
208   struct widget *pImprNameLabel = NULL;
209   struct widget *pCostLabel = NULL;
210   struct widget *pUpkeepLabel = NULL;
211   struct widget *pRequirementLabel = NULL;
212   struct widget *pRequirementLabel2 = NULL;
213   struct widget *pObsoleteByLabel = NULL;
214   struct widget *pObsoleteByLabel2 = NULL;
215   struct widget *pHelptextLabel = NULL;
216 
217   struct widget *pDock;
218   SDL_String16 *pTitle, *pStr;
219   SDL_Surface *pSurf;
220   int h, start_x, start_y, impr_type_count;
221   bool created, text = FALSE;
222   int scrollbar_width = 0;
223   struct impr_type *pImpr_type;
224   char buffer[64000];
225   SDL_Rect area;
226   struct advance *obsTech = NULL;
227 
228   if(current_help_dlg != HELP_IMPROVEMENT) {
229     popdown_help_dialog();
230   }
231 
232   if (!pHelpDlg) {
233     SDL_Surface *pBackgroundTmpl, *pBackground, *pText, *pIcon;
234     SDL_Rect dst;
235 
236     current_help_dlg = HELP_IMPROVEMENT;
237     created = TRUE;
238 
239     /* create dialog */
240     pHelpDlg = fc_calloc(1, sizeof(struct ADVANCED_DLG));
241     pStore = fc_calloc(1, sizeof(struct UNITS_BUTTONS));
242 
243     /* create window */
244     pTitle = create_str16_from_char(_("Help : Improvements"), adj_font(12));
245     pTitle->style |= TTF_STYLE_BOLD;
246 
247     pWindow = create_window_skeleton(NULL, pTitle, WF_FREE_DATA);
248     pWindow->action = help_dlg_window_callback;
249     set_wstate(pWindow , FC_WS_NORMAL);
250     pWindow->data.ptr = (void *)pStore;
251     add_to_gui_list(ID_WINDOW, pWindow);
252 
253     pHelpDlg->pEndWidgetList = pWindow;
254 
255     area = pWindow->area;
256     /* ------------------ */
257 
258     /* close button */
259     pCloseButton = create_themeicon(current_theme->Small_CANCEL_Icon, pWindow->dst,
260                                     WF_WIDGET_HAS_INFO_LABEL
261                                     | WF_RESTORE_BACKGROUND);
262     pCloseButton->info_label =
263         create_str16_from_char(_("Close Dialog (Esc)"), adj_font(12));
264     pCloseButton->action = exit_help_dlg_callback;
265     set_wstate(pCloseButton, FC_WS_NORMAL);
266     pCloseButton->key = SDLK_ESCAPE;
267 
268     add_to_gui_list(ID_BUTTON, pCloseButton);
269 
270     /* ------------------ */
271     pDock = pCloseButton;
272 
273     pStr = create_string16(NULL, 0, adj_font(10));
274     pStr->style |= (TTF_STYLE_BOLD | SF_CENTER);
275 
276     /* background template for entries in scroll list */
277     pBackgroundTmpl = create_surf_alpha(adj_size(135), adj_size(40), SDL_SWSURFACE);
278     SDL_FillRect(pBackgroundTmpl, NULL, map_rgba(pBackgroundTmpl->format, bg_color));
279     putframe(pBackgroundTmpl,
280              0, 0, pBackgroundTmpl->w - 1, pBackgroundTmpl->h - 1,
281              get_theme_color(COLOR_THEME_HELPDLG_FRAME));
282 
283     impr_type_count = 0;
284     improvement_iterate(pImprove) {
285 
286       /* copy background surface */
287       pBackground = SDL_DisplayFormatAlpha(pBackgroundTmpl);
288 
289       /* blit improvement name */
290       copy_chars_to_string16(pStr, improvement_name_translation(pImprove));
291       pText = create_text_surf_smaller_that_w(pStr, adj_size(100 - 4));
292       dst.x = adj_size(40) + (pBackground->w - pText->w - adj_size(40)) / 2;
293       dst.y = (pBackground->h - pText->h) / 2;
294       alphablit(pText, NULL, pBackground, &dst);
295       FREESURFACE(pText);
296 
297       /* blit improvement icon */
298       pIcon = ResizeSurfaceBox(get_building_surface(pImprove),
299                                adj_size(36), adj_size(36), 1, TRUE, TRUE);
300       dst.x = adj_size(5);
301       dst.y = (pBackground->h - pIcon->h) / 2;
302       alphablit(pIcon, NULL, pBackground, &dst);
303       FREESURFACE(pIcon);
304 
305       pImprovementButton = create_icon2(pBackground, pWindow->dst,
306                                         WF_FREE_THEME | WF_RESTORE_BACKGROUND);
307 
308       set_wstate(pImprovementButton, FC_WS_NORMAL);
309       pImprovementButton->action = change_impr_callback;
310       add_to_gui_list(MAX_ID - improvement_number(pImprove), pImprovementButton);
311 
312       if (impr_type_count++ >= 10) {
313         set_wflag(pImprovementButton, WF_HIDDEN);
314       }
315 
316     } improvement_iterate_end;
317 
318     FREESURFACE(pBackgroundTmpl);
319 
320     pHelpDlg->pEndActiveWidgetList = pDock->prev;
321     pHelpDlg->pBeginWidgetList = pImprovementButton ? pImprovementButton : pCloseButton;
322     pHelpDlg->pBeginActiveWidgetList = pHelpDlg->pBeginWidgetList;
323 
324     if (impr_type_count > 10) {
325       pHelpDlg->pActiveWidgetList = pHelpDlg->pEndActiveWidgetList;
326       scrollbar_width = create_vertical_scrollbar(pHelpDlg, 1, 10, TRUE, TRUE);
327     }
328 
329     /* toggle techs list button */
330     pListToggleButton = create_themeicon_button_from_chars(current_theme->UP_Icon,
331                                                            pWindow->dst,
332                                                            _("Improvements"),
333                                                            adj_font(10), 0);
334 #if 0
335    pListToggleButton->action = toggle_full_tree_mode_in_help_dlg_callback;
336    if (pStore->show_tree) {
337       set_wstate(pListToggleButton, FC_WS_NORMAL);
338    }
339 #endif
340 
341     widget_resize(pListToggleButton, adj_size(160), adj_size(15));
342     pListToggleButton->string16->fgcol = *get_theme_color(COLOR_THEME_HELPDLG_TEXT);
343 
344     add_to_gui_list(ID_BUTTON, pListToggleButton);
345 
346     pDock = pListToggleButton;
347     pStore->pDock = pDock;
348   } else {
349     created = FALSE;
350     scrollbar_width = (pHelpDlg->pScroll ? pHelpDlg->pScroll->pUp_Left_Button->size.w : 0);
351     pWindow = pHelpDlg->pEndWidgetList;
352     pStore = (struct UNITS_BUTTONS *)pWindow->data.ptr;
353     pDock = pStore->pDock;
354 
355     area = pWindow->area;
356 
357     /* delete any previous list entries */
358     if (pDock != pHelpDlg->pBeginWidgetList) {
359       del_group_of_widgets_from_gui_list(pHelpDlg->pBeginWidgetList,
360                                          pDock->prev);
361       pHelpDlg->pBeginWidgetList = pDock;
362     }
363   }
364 
365   pImpr_type = improvement_by_number(impr);
366 
367   pSurf = get_building_surface(pImpr_type);
368   pImprNameLabel = create_iconlabel_from_chars(
369                      ResizeSurfaceBox(pSurf, adj_size(64), adj_size(48), 1, TRUE, TRUE),
370                      pWindow->dst, city_improvement_name_translation(NULL, pImpr_type),
371                      adj_font(24), WF_FREE_THEME);
372 
373   pImprNameLabel->ID = ID_LABEL;
374   DownAdd(pImprNameLabel, pDock);
375   pDock = pImprNameLabel;
376 
377   if (!improvement_has_flag(pImpr_type, IF_GOLD)) {
378     sprintf(buffer, "%s %d", _("Cost:"), impr_build_shield_cost(pImpr_type));
379     pCostLabel = create_iconlabel_from_chars(NULL, pWindow->dst,
380                                              buffer, adj_font(12), 0);
381     pCostLabel->ID = ID_LABEL;
382     DownAdd(pCostLabel, pDock);
383     pDock = pCostLabel;
384 
385     if (!is_wonder(pImpr_type)) {
386       sprintf(buffer, "%s %d", _("Upkeep:"), pImpr_type->upkeep);
387       pUpkeepLabel = create_iconlabel_from_chars(NULL, pWindow->dst,
388                                                  buffer, adj_font(12), 0);
389       pUpkeepLabel->ID = ID_LABEL;
390       DownAdd(pUpkeepLabel, pDock);
391       pDock = pUpkeepLabel;
392     }
393   }
394 
395   /* requirement */
396   pRequirementLabel = create_iconlabel_from_chars(NULL, pWindow->dst,
397                                                   _("Requirement:"),
398                                                   adj_font(12), 0);
399   pRequirementLabel->ID = ID_LABEL;
400   DownAdd(pRequirementLabel, pDock);
401   pDock = pRequirementLabel;
402 
403   if (requirement_vector_size(&pImpr_type->reqs) == 0) {
404     pRequirementLabel2 = create_iconlabel_from_chars(NULL, pWindow->dst,
405                                                      Q_("?req:None"),
406                                                      adj_font(12), 0);
407     pRequirementLabel2->ID = ID_LABEL;
408   } else {
409     /* FIXME: this should show ranges, negated reqs, and all the
410      * MAX_NUM_REQS reqs.
411      * Currently it's limited to 1 req. Remember MAX_NUM_REQS is a compile-time
412      * definition. */
413     requirement_vector_iterate(&pImpr_type->reqs, preq) {
414       if (!preq->present) {
415         continue;
416       }
417       pRequirementLabel2 = create_iconlabel_from_chars(NULL, pWindow->dst,
418                              universal_name_translation(&preq->source, buffer, sizeof(buffer)),
419                              adj_font(12), WF_RESTORE_BACKGROUND);
420       if (preq->source.kind != VUT_ADVANCE) {
421         break; /* FIXME */
422       }
423       pRequirementLabel2->ID = MAX_ID - advance_number(preq->source.value.advance);
424       pRequirementLabel2->string16->fgcol = *get_tech_color(advance_number(preq->source.value.advance));
425       pRequirementLabel2->action = change_tech_callback;
426       set_wstate(pRequirementLabel2, FC_WS_NORMAL);
427       break;
428     } requirement_vector_iterate_end;
429   }
430   DownAdd(pRequirementLabel2, pDock);
431   pDock = pRequirementLabel2;
432   pStore->pRequirementButton = pRequirementLabel2;
433 
434   /* obsolete by */
435   pObsoleteByLabel = create_iconlabel_from_chars(NULL, pWindow->dst,
436                                                  _("Obsolete by:"),
437                                                  adj_font(12), 0);
438   pObsoleteByLabel->ID = ID_LABEL;
439   DownAdd(pObsoleteByLabel, pDock);
440   pDock = pObsoleteByLabel;
441 
442 
443   requirement_vector_iterate(&pImpr_type->obsolete_by, pobs) {
444     if (pobs->source.kind == VUT_ADVANCE) {
445       obsTech = pobs->source.value.advance;
446       break;
447     }
448   } requirement_vector_iterate_end;
449   if (obsTech == NULL) {
450     pObsoleteByLabel2 = create_iconlabel_from_chars(NULL, pWindow->dst,
451                                                     _("Never"), adj_font(12), 0);
452     pObsoleteByLabel2->ID = ID_LABEL;
453   } else {
454     pObsoleteByLabel2 = create_iconlabel_from_chars(NULL, pWindow->dst,
455                                                     advance_name_translation(obsTech),
456                                                     adj_font(12), WF_RESTORE_BACKGROUND);
457     pObsoleteByLabel2->ID = MAX_ID - advance_number(obsTech);
458     pObsoleteByLabel2->string16->fgcol = *get_tech_color(advance_number(obsTech));
459     pObsoleteByLabel2->action = change_tech_callback;
460     set_wstate(pObsoleteByLabel2, FC_WS_NORMAL);
461   }
462   DownAdd(pObsoleteByLabel2, pDock);
463   pDock = pObsoleteByLabel2;
464   pStore->pObsoleteByButton = pObsoleteByLabel2;
465 
466   /* helptext */
467   start_x = (area.x + 1 + scrollbar_width + pHelpDlg->pEndActiveWidgetList->size.w + adj_size(20));
468 
469   buffer[0] = '\0';
470   helptext_building(buffer, sizeof(buffer), client.conn.playing, NULL, pImpr_type);
471   if (buffer[0] != '\0') {
472     SDL_String16 *bstr = create_str16_from_char(buffer, adj_font(12));
473 
474     convert_string_to_const_surface_width(bstr, adj_size(640) - start_x - adj_size(20));
475     pHelptextLabel = create_iconlabel(NULL, pWindow->dst, bstr, 0);
476     pHelptextLabel->ID = ID_LABEL;
477     DownAdd(pHelptextLabel, pDock);
478     pDock = pHelptextLabel;
479     text = TRUE;
480   }
481 
482   pHelpDlg->pBeginWidgetList = pHelptextLabel ? pHelptextLabel : pObsoleteByLabel2;
483 
484   /* --------------------------------------------------------- */
485   if (created) {
486 
487     pSurf = theme_get_background(theme, BACKGROUND_HELPDLG);
488     if (resize_window(pWindow, pSurf, NULL, adj_size(640), adj_size(480))) {
489       FREESURFACE(pSurf);
490     }
491 
492     area = pWindow->area;
493 
494     widget_set_position(pWindow,
495                         (Main.screen->w - pWindow->size.w) / 2,
496                         (Main.screen->h - pWindow->size.h) / 2);
497 
498     /* exit button */
499     pCloseButton = pWindow->prev;
500     widget_set_position(pCloseButton,
501                         area.x + area.w - pCloseButton->size.w - 1,
502                         pWindow->size.y + adj_size(2));
503 
504     /* list toggle button */
505     pListToggleButton = pStore->pDock;
506     widget_set_position(pListToggleButton, area.x, area.y);
507 
508     /* list entries */
509     h = setup_vertical_widgets_position(1, area.x + scrollbar_width,
510                                            area.y + pListToggleButton->size.h, 0, 0,
511                                            pHelpDlg->pBeginActiveWidgetList,
512                                            pHelpDlg->pEndActiveWidgetList);
513 
514     /* scrollbar */
515     if (pHelpDlg->pScroll) {
516       setup_vertical_scrollbar_area(pHelpDlg->pScroll,
517                                     area.x, area.y + pListToggleButton->size.h,
518                                     h, FALSE);
519     }
520   }
521 
522   pImprNameLabel = pStore->pDock->prev;
523   widget_set_position(pImprNameLabel, start_x, area.y + adj_size(16));
524 
525   start_y = pImprNameLabel->size.y + pImprNameLabel->size.h + adj_size(10);
526 
527   if (!improvement_has_flag(pImpr_type, IF_GOLD)) {
528     pCostLabel = pImprNameLabel->prev;
529     widget_set_position(pCostLabel, start_x, start_y);
530     if (!is_wonder(pImpr_type)) {
531       pUpkeepLabel = pCostLabel->prev;
532       widget_set_position(pUpkeepLabel,
533                           pCostLabel->size.x + pCostLabel->size.w + adj_size(20),
534                           start_y);
535     }
536     start_y += pCostLabel->size.h;
537   }
538 
539   pRequirementLabel = pStore->pRequirementButton->next;
540   widget_set_position(pRequirementLabel, start_x, start_y);
541 
542   pRequirementLabel2 = pStore->pRequirementButton;
543   widget_set_position(pRequirementLabel2,
544                       pRequirementLabel->size.x + pRequirementLabel->size.w + adj_size(5),
545                       start_y);
546 
547   if (pStore->pObsoleteByButton) {
548     pObsoleteByLabel = pStore->pObsoleteByButton->next;
549     widget_set_position(pObsoleteByLabel,
550                         pRequirementLabel2->size.x + pRequirementLabel2->size.w + adj_size(10),
551                         start_y);
552 
553     pObsoleteByLabel2 = pStore->pObsoleteByButton;
554     widget_set_position(pObsoleteByLabel2,
555                         pObsoleteByLabel->size.x + pObsoleteByLabel->size.w + adj_size(5),
556                         start_y);
557 
558     start_y += pObsoleteByLabel2->size.h;
559   }
560 
561   start_y += adj_size(30);
562 
563   if (text) {
564     widget_set_position(pHelptextLabel, start_x, start_y);
565   }
566 
567   redraw_impr_info_dlg();
568 }
569 
570 /**************************************************************************
571   User requested new unit help
572 **************************************************************************/
change_unit_callback(struct widget * pWidget)573 static int change_unit_callback(struct widget *pWidget)
574 {
575   if (Main.event.button.button == SDL_BUTTON_LEFT) {
576     popup_unit_info(MAX_ID - pWidget->ID);
577   }
578   return -1;
579 }
580 
581 /**************************************************************************
582   Refresh unit help dialog
583 **************************************************************************/
redraw_unit_info_dlg(void)584 static void redraw_unit_info_dlg(void)
585 {
586   SDL_Color bg_color = {255, 255, 255, 64};
587 
588   struct widget *pWindow = pHelpDlg->pEndWidgetList;
589   struct UNITS_BUTTONS *pStore = (struct UNITS_BUTTONS *)pWindow->data.ptr;
590   SDL_Rect dst;
591 
592   redraw_group(pWindow->prev, pWindow, FALSE);
593 
594   dst.x = pStore->pDock->prev->size.x - adj_size(10);
595   dst.y = pStore->pDock->prev->size.y - adj_size(10);
596   dst.w = pWindow->size.w - (dst.x - pWindow->size.x) - adj_size(10);
597   dst.h = pWindow->size.h - (dst.y - pWindow->size.y) - adj_size(10);
598 
599   SDL_FillRectAlpha(pWindow->dst->surface, &dst, &bg_color);
600   putframe(pWindow->dst->surface,
601            dst.x, dst.y, dst.x + dst.w, dst.y + dst.h,
602            get_theme_color(COLOR_THEME_HELPDLG_FRAME));
603 
604   /*------------------------------------- */
605   redraw_group(pHelpDlg->pBeginWidgetList, pWindow->prev->prev, FALSE);
606   widget_flush(pWindow);
607 }
608 
609 /**************************************************************************
610   Show unit type info
611 **************************************************************************/
popup_unit_info(Unit_type_id type_id)612 void popup_unit_info(Unit_type_id type_id)
613 {
614   SDL_Color bg_color = {255, 255, 255, 128};
615 
616   struct widget *pWindow;
617   struct UNITS_BUTTONS *pStore;
618 
619   struct widget *pCloseButton = NULL;
620   struct widget *pListToggleButton = NULL;
621   struct widget *pUnitButton = NULL;
622   struct widget *pUnitNameLabel = NULL;
623   struct widget *pUnitInfoLabel = NULL;
624   struct widget *pRequirementLabel = NULL;
625   struct widget *pRequirementLabel2 = NULL;
626   struct widget *pObsoleteByLabel = NULL;
627   struct widget *pObsoleteByLabel2 = NULL;
628   struct widget *pHelptextLabel = NULL;
629 
630   struct widget *pDock;
631   SDL_String16 *pTitle, *pStr;
632   SDL_Surface *pSurf;
633   int h, start_x, start_y, utype_count;
634   bool created, text = FALSE;
635   int scrollbar_width = 0;
636   struct unit_type *pUnitType;
637   char buffer[bufsz];
638   SDL_Rect area;
639 
640   if (current_help_dlg != HELP_UNIT) {
641     popdown_help_dialog();
642   }
643 
644   /* create new dialog if it doesn't exist yet */
645   if (!pHelpDlg) {
646     SDL_Surface *pBackgroundTmpl, *pBackground, *pText, *pIcon;
647     SDL_Rect dst;
648 
649     current_help_dlg = HELP_UNIT;
650     created = TRUE;
651 
652     /* create dialog */
653     pHelpDlg = fc_calloc(1, sizeof(struct ADVANCED_DLG));
654     pStore = fc_calloc(1, sizeof(struct UNITS_BUTTONS));
655 
656     /* create window */
657     pTitle = create_str16_from_char(_("Help : Units"), adj_font(12));
658     pTitle->style |= TTF_STYLE_BOLD;
659 
660     pWindow = create_window_skeleton(NULL, pTitle, WF_FREE_DATA);
661     pWindow->action = help_dlg_window_callback;
662     set_wstate(pWindow , FC_WS_NORMAL);
663     pWindow->data.ptr = (void *)pStore;
664     add_to_gui_list(ID_WINDOW, pWindow);
665 
666     pHelpDlg->pEndWidgetList = pWindow;
667 
668     area = pWindow->area;
669 
670     /* ------------------ */
671 
672     /* close button */
673     pCloseButton = create_themeicon(current_theme->Small_CANCEL_Icon, pWindow->dst,
674                                     WF_WIDGET_HAS_INFO_LABEL
675                                     | WF_RESTORE_BACKGROUND);
676     pCloseButton->info_label =
677         create_str16_from_char(_("Close Dialog (Esc)"), adj_font(12));
678     pCloseButton->action = exit_help_dlg_callback;
679     set_wstate(pCloseButton, FC_WS_NORMAL);
680     pCloseButton->key = SDLK_ESCAPE;
681 
682     add_to_gui_list(ID_BUTTON, pCloseButton);
683 
684     /* ------------------ */
685     pDock = pCloseButton;
686 
687     /* --- create scrollable unit list on the left side ---*/
688 
689     pStr = create_string16(NULL, 0, adj_font(10));
690     pStr->style |= (TTF_STYLE_BOLD | SF_CENTER);
691 
692     /* background template for entries in scroll list */
693     pBackgroundTmpl = create_surf_alpha(adj_size(135), adj_size(40), SDL_SWSURFACE);
694     SDL_FillRect(pBackgroundTmpl, NULL, map_rgba(pBackgroundTmpl->format, bg_color));
695     putframe(pBackgroundTmpl,
696              0, 0, pBackgroundTmpl->w - 1, pBackgroundTmpl->h - 1,
697              get_theme_color(COLOR_THEME_HELPDLG_FRAME));
698 
699     utype_count = 0;
700     unit_type_iterate(ut) {
701 
702       /* copy background surface */
703       pBackground = SDL_DisplayFormatAlpha(pBackgroundTmpl);
704 
705       /* blit unit name */
706       copy_chars_to_string16(pStr, utype_name_translation(ut));
707       pText = create_text_surf_smaller_that_w(pStr, adj_size(100 - 4));
708       dst.x = adj_size(35) + (pBackground->w - pText->w - adj_size(35)) / 2;
709       dst.y = (pBackground->h - pText->h) / 2;
710       alphablit(pText, NULL, pBackground, &dst);
711       FREESURFACE(pText);
712 
713       /* blit unit icon */
714       pIcon = ResizeSurfaceBox(get_unittype_surface(ut, direction8_invalid()),
715                                adj_size(36), adj_size(36), 1, TRUE, TRUE);
716       dst.x = (adj_size(35) - pIcon->w) / 2;
717       dst.y = (pBackground->h - pIcon->h) / 2;
718       alphablit(pIcon, NULL, pBackground, &dst);
719       FREESURFACE(pIcon);
720 
721       pUnitButton = create_icon2(pBackground, pWindow->dst,
722                                  WF_FREE_THEME | WF_RESTORE_BACKGROUND);
723 
724       set_wstate(pUnitButton, FC_WS_NORMAL);
725       pUnitButton->action = change_unit_callback;
726       add_to_gui_list(MAX_ID - utype_number(ut), pUnitButton);
727 
728       if (utype_count++ >= 10) {
729         set_wflag(pUnitButton, WF_HIDDEN);
730       }
731 
732     } unit_type_iterate_end;
733 
734     FREESURFACE(pBackgroundTmpl);
735 
736     pHelpDlg->pEndActiveWidgetList = pDock->prev;
737     pHelpDlg->pBeginWidgetList = pUnitButton ? pUnitButton : pCloseButton;
738     pHelpDlg->pBeginActiveWidgetList = pHelpDlg->pBeginWidgetList;
739 
740     if (utype_count > 10) {
741       pHelpDlg->pActiveWidgetList = pHelpDlg->pEndActiveWidgetList;
742       scrollbar_width = create_vertical_scrollbar(pHelpDlg, 1, 10, TRUE, TRUE);
743     }
744 
745     /* toggle techs list button */
746     pListToggleButton = create_themeicon_button_from_chars(current_theme->UP_Icon,
747                           pWindow->dst,  _("Units"), adj_font(10), 0);
748 #if 0
749     pListToggleButton->action = toggle_full_tree_mode_in_help_dlg_callback;
750     if (pStore->show_tree) {
751       set_wstate(pListToggleButton, FC_WS_NORMAL);
752     }
753 #endif
754 
755     widget_resize(pListToggleButton, adj_size(160), adj_size(15));
756     pListToggleButton->string16->fgcol = *get_theme_color(COLOR_THEME_HELPDLG_TEXT);
757 
758     add_to_gui_list(ID_BUTTON, pListToggleButton);
759 
760     pDock = pListToggleButton;
761     pStore->pDock = pDock;
762   } else {
763     created = FALSE;
764     scrollbar_width = (pHelpDlg->pScroll ? pHelpDlg->pScroll->pUp_Left_Button->size.w : 0);
765     pWindow = pHelpDlg->pEndWidgetList;
766     pStore = (struct UNITS_BUTTONS *)pWindow->data.ptr;
767     pDock = pStore->pDock;
768 
769     area = pWindow->area;
770 
771     /* delete any previous list entries */
772     if (pDock != pHelpDlg->pBeginWidgetList) {
773       del_group_of_widgets_from_gui_list(pHelpDlg->pBeginWidgetList,
774                                          pDock->prev);
775       pHelpDlg->pBeginWidgetList = pDock;
776     }
777   }
778 
779   pUnitType = utype_by_number(type_id);
780   pUnitNameLabel= create_iconlabel_from_chars(
781                 adj_surf(get_unittype_surface(pUnitType, direction8_invalid())),
782                 pWindow->dst, utype_name_translation(pUnitType),
783                 adj_font(24), WF_FREE_THEME);
784 
785   pUnitNameLabel->ID = ID_LABEL;
786   DownAdd(pUnitNameLabel, pDock);
787   pDock = pUnitNameLabel;
788 
789 
790   {
791     char buf[2048];
792 
793     fc_snprintf(buf, sizeof(buf), "%s %d %s",
794               _("Cost:"), utype_build_shield_cost(pUnitType),
795               PL_("shield", "shields", utype_build_shield_cost(pUnitType)));
796 
797     if(pUnitType->pop_cost)
798     {
799       cat_snprintf(buf, sizeof(buf), " %d %s",
800           pUnitType->pop_cost, PL_("citizen", "citizens", pUnitType->pop_cost));
801     }
802 
803     cat_snprintf(buf, sizeof(buf), "      %s",  _("Upkeep:"));
804 
805     if (pUnitType->upkeep[O_SHIELD]) {
806       cat_snprintf(buf, sizeof(buf), " %d %s",
807                    pUnitType->upkeep[O_SHIELD], PL_("shield", "shields",
808                                                     pUnitType->upkeep[O_SHIELD]));
809     }
810     if (pUnitType->upkeep[O_FOOD]) {
811       cat_snprintf(buf, sizeof(buf), " %d %s",
812                    pUnitType->upkeep[O_FOOD], PL_("food", "foods",
813                                                   pUnitType->upkeep[O_FOOD]));
814     }
815     if (pUnitType->upkeep[O_GOLD]) {
816       cat_snprintf(buf, sizeof(buf), " %d %s",
817                    pUnitType->upkeep[O_GOLD], PL_("gold", "golds",
818                                                   pUnitType->upkeep[O_GOLD]));
819     }
820     if (pUnitType->happy_cost) {
821       cat_snprintf(buf, sizeof(buf), " %d %s",
822                    pUnitType->happy_cost, PL_("citizen", "citizens",
823                                               pUnitType->happy_cost));
824     }
825 
826     cat_snprintf(buf, sizeof(buf), "\n%s %d %s %d %s %s\n%s %d %s %d %s %d",
827               _("Attack:"), pUnitType->attack_strength,
828               _("Defense:"), pUnitType->defense_strength,
829               _("Move:"), move_points_text(pUnitType->move_rate, TRUE),
830               _("Vision:"), pUnitType->vision_radius_sq,
831               _("FirePower:"), pUnitType->firepower,
832               _("Hitpoints:"), pUnitType->hp);
833 
834     pUnitInfoLabel = create_iconlabel_from_chars(NULL, pWindow->dst, buf,
835                                                  adj_font(12), 0);
836     pUnitInfoLabel->ID = ID_LABEL;
837     DownAdd(pUnitInfoLabel, pDock);
838     pDock = pUnitInfoLabel;
839   }
840 
841   /* requirement */
842   pRequirementLabel = create_iconlabel_from_chars(NULL, pWindow->dst,
843                                                   _("Requirement:"),
844                                                   adj_font(12), 0);
845   pRequirementLabel->ID = ID_LABEL;
846   DownAdd(pRequirementLabel, pDock);
847   pDock = pRequirementLabel;
848 
849   if (A_NEVER == pUnitType->require_advance
850       || advance_by_number(A_NONE) == pUnitType->require_advance) {
851     pRequirementLabel2 = create_iconlabel_from_chars(NULL, pWindow->dst,
852                                                      Q_("?tech:None"), adj_font(12), 0);
853     pRequirementLabel2->ID = ID_LABEL;
854   } else {
855     pRequirementLabel2 = create_iconlabel_from_chars(NULL, pWindow->dst,
856           advance_name_translation(pUnitType->require_advance),
857           adj_font(12),
858                           WF_RESTORE_BACKGROUND);
859     pRequirementLabel2->ID = MAX_ID - advance_number(pUnitType->require_advance);
860     pRequirementLabel2->string16->fgcol = *get_tech_color(advance_number(pUnitType->require_advance));
861     pRequirementLabel2->action = change_tech_callback;
862     set_wstate(pRequirementLabel2, FC_WS_NORMAL);
863   }
864   DownAdd(pRequirementLabel2, pDock);
865   pDock = pRequirementLabel2;
866   pStore->pRequirementButton = pRequirementLabel2;
867 
868   /* obsolete by */
869   pObsoleteByLabel = create_iconlabel_from_chars(NULL, pWindow->dst,
870                                                  _("Obsolete by:"),
871                                                  adj_font(12), 0);
872   pObsoleteByLabel->ID = ID_LABEL;
873   DownAdd(pObsoleteByLabel, pDock);
874   pDock = pObsoleteByLabel;
875 
876   if (pUnitType->obsoleted_by == U_NOT_OBSOLETED) {
877     pObsoleteByLabel2 = create_iconlabel_from_chars(NULL, pWindow->dst,
878                                                     Q_("?utype:None"),
879                                                     adj_font(12), 0);
880     pObsoleteByLabel2->ID = ID_LABEL;
881   } else {
882     struct unit_type *utype = pUnitType->obsoleted_by;
883 
884     pObsoleteByLabel2 = create_iconlabel_from_chars(NULL, pWindow->dst,
885                                                     utype_name_translation(utype),
886                                                     adj_font(12),
887                                                     WF_RESTORE_BACKGROUND);
888     pObsoleteByLabel2->string16->fgcol = *get_tech_color(advance_number(utype->require_advance));
889     pObsoleteByLabel2->ID = MAX_ID - utype_number(pUnitType->obsoleted_by);
890     pObsoleteByLabel2->action = change_unit_callback;
891     set_wstate(pObsoleteByLabel2, FC_WS_NORMAL);
892   }
893   DownAdd(pObsoleteByLabel2, pDock);
894   pDock = pObsoleteByLabel2;
895   pStore->pObsoleteByButton = pObsoleteByLabel2;
896 
897   /* helptext */
898   start_x = (area.x + 1 + scrollbar_width + pHelpDlg->pActiveWidgetList->size.w + adj_size(20));
899 
900   buffer[0] = '\0';
901   helptext_unit(buffer, sizeof(buffer), client.conn.playing, "", utype_by_number(type_id));
902   if (buffer[0] != '\0') {
903     SDL_String16 *ustr = create_str16_from_char(buffer, adj_font(12));
904 
905     convert_string_to_const_surface_width(ustr, adj_size(640) - start_x - adj_size(20));
906     pHelptextLabel = create_iconlabel(NULL, pWindow->dst, ustr, 0);
907     pHelptextLabel->ID = ID_LABEL;
908     DownAdd(pHelptextLabel, pDock);
909     pDock = pHelptextLabel;
910     text = TRUE;
911   }
912 
913   pHelpDlg->pBeginWidgetList = pHelptextLabel ? pHelptextLabel : pObsoleteByLabel2;
914 
915   /* --------------------------------------------------------- */
916   if (created) {
917 
918     pSurf = theme_get_background(theme, BACKGROUND_HELPDLG);
919     if (resize_window(pWindow, pSurf, NULL, adj_size(640), adj_size(480))) {
920       FREESURFACE(pSurf);
921     }
922 
923     area = pWindow->area;
924 
925     widget_set_position(pWindow,
926                         (Main.screen->w - pWindow->size.w) / 2,
927                         (Main.screen->h - pWindow->size.h) / 2);
928 
929     /* exit button */
930     pCloseButton = pWindow->prev;
931     widget_set_position(pCloseButton,
932                         area.x + area.w - pCloseButton->size.w - 1,
933                         pWindow->size.y + adj_size(2));
934 
935     /* list toggle button */
936     pListToggleButton = pStore->pDock;
937     widget_set_position(pListToggleButton, area.x, area.y);
938 
939     /* list entries */
940     h = setup_vertical_widgets_position(1, area.x + scrollbar_width,
941                                            area.y + pListToggleButton->size.h, 0, 0,
942                                            pHelpDlg->pBeginActiveWidgetList,
943                                            pHelpDlg->pEndActiveWidgetList);
944 
945     /* scrollbar */
946     if (pHelpDlg->pScroll) {
947       setup_vertical_scrollbar_area(pHelpDlg->pScroll,
948                                     area.x, area.y + pListToggleButton->size.h,
949                                     h, FALSE);
950     }
951   }
952 
953   pUnitNameLabel = pStore->pDock->prev;
954   widget_set_position(pUnitNameLabel, start_x, area.y + adj_size(16));
955 
956   start_y = pUnitNameLabel->size.y + pUnitNameLabel->size.h + adj_size(10);
957 
958   pUnitInfoLabel = pUnitNameLabel->prev;
959   widget_set_position(pUnitInfoLabel, start_x, start_y);
960 
961   start_y += pUnitInfoLabel->size.h;
962 
963   pRequirementLabel = pStore->pRequirementButton->next;
964   widget_set_position(pRequirementLabel, start_x, start_y);
965 
966   pRequirementLabel2 = pStore->pRequirementButton;
967   widget_set_position(pRequirementLabel2,
968                       pRequirementLabel->size.x + pRequirementLabel->size.w + adj_size(5),
969                       start_y);
970 
971   pObsoleteByLabel = pStore->pObsoleteByButton->next;
972   widget_set_position(pObsoleteByLabel,
973                       pRequirementLabel2->size.x + pRequirementLabel2->size.w + adj_size(10),
974                       start_y);
975 
976   pObsoleteByLabel2 = pStore->pObsoleteByButton;
977   widget_set_position(pObsoleteByLabel2,
978                       pObsoleteByLabel->size.x + pObsoleteByLabel->size.w + adj_size(5),
979                       start_y);
980 
981   start_y += pObsoleteByLabel2->size.h + adj_size(20);
982 
983   if (text) {
984     pHelptextLabel = pStore->pObsoleteByButton->prev;
985     widget_set_position(pHelptextLabel, start_x, start_y);
986   }
987 
988   redraw_unit_info_dlg();
989 }
990 
991 /* =============================================== */
992 /* ==================== Tech Tree ================ */
993 /* =============================================== */
994 
995 /**************************************************************************
996   User requested new tech help
997 **************************************************************************/
change_tech_callback(struct widget * pWidget)998 static int change_tech_callback(struct widget *pWidget)
999 {
1000   if (Main.event.button.button == SDL_BUTTON_LEFT) {
1001     popup_tech_info(MAX_ID - pWidget->ID);
1002   }
1003   return -1;
1004 }
1005 
1006 /**************************************************************************
1007   User requested new tech tree
1008 **************************************************************************/
show_tech_tree_callback(struct widget * pWidget)1009 static int show_tech_tree_callback(struct widget *pWidget)
1010 {
1011   if (Main.event.button.button == SDL_BUTTON_LEFT) {
1012     struct TECHS_BUTTONS *pStore = (struct TECHS_BUTTONS *)pHelpDlg->pEndWidgetList->data.ptr;
1013 
1014     pStore->show_tree = !pStore->show_tree;
1015     if (!pStore->show_tree) {
1016       pStore->show_full_tree = FALSE;
1017       pStore->pDock->theme2 = current_theme->UP_Icon;
1018     }
1019     popup_tech_info(MAX_ID - pStore->pDock->prev->ID);
1020   }
1021   return -1;
1022 }
1023 
1024 /**************************************************************************
1025   Refresh tech help dialog
1026 **************************************************************************/
redraw_tech_info_dlg(void)1027 static void redraw_tech_info_dlg(void)
1028 {
1029   SDL_Color bg_color = {255, 255, 255, 64};
1030 
1031   struct widget *pWindow = pHelpDlg->pEndWidgetList;
1032   struct TECHS_BUTTONS *pStore = (struct TECHS_BUTTONS *)pWindow->data.ptr;
1033   SDL_Surface *pText0, *pText1 = NULL;
1034   SDL_String16 *pStr;
1035   SDL_Rect dst;
1036 
1037   redraw_group(pWindow->prev, pWindow, FALSE);
1038 
1039   dst.x = pStore->pDock->prev->prev->size.x - adj_size(10);
1040   dst.y = pStore->pDock->prev->prev->size.y - adj_size(10);
1041   dst.w = pWindow->size.w - (dst.x - pWindow->size.x) - adj_size(10);
1042   dst.h = pWindow->size.h - (dst.y - pWindow->size.y) - adj_size(10);
1043 
1044   SDL_FillRectAlpha(pWindow->dst->surface, &dst, &bg_color);
1045   putframe(pWindow->dst->surface,
1046            dst.x, dst.y, dst.x + dst.w, dst.y + dst.h,
1047            get_theme_color(COLOR_THEME_HELPDLG_FRAME));
1048 
1049   /* -------------------------- */
1050   pStr = create_str16_from_char(_("Allows"), adj_font(14));
1051   pStr->style |= TTF_STYLE_BOLD;
1052 
1053   pText0 = create_text_surf_from_str16(pStr);
1054   dst.x = pStore->pDock->prev->prev->size.x;
1055   if (pStore->pTargets[0]) {
1056     dst.y = pStore->pTargets[0]->size.y - pText0->h;
1057   } else {
1058     dst.y = pStore->pDock->prev->prev->size.y
1059               + pStore->pDock->prev->prev->size.h + adj_size(10);
1060   }
1061 
1062   alphablit(pText0, NULL, pWindow->dst->surface, &dst);
1063   FREESURFACE(pText0);
1064 
1065   if (pStore->pSub_Targets[0]) {
1066     int i;
1067 
1068     change_ptsize16(pStr, adj_font(12));
1069 
1070     copy_chars_to_string16(pStr, _("( with "));
1071     pText0 = create_text_surf_from_str16(pStr);
1072 
1073     copy_chars_to_string16(pStr, _(" )"));
1074     pText1 = create_text_surf_from_str16(pStr);
1075     i = 0;
1076     while (i < 6 && pStore->pSub_Targets[i]) {
1077       dst.x = pStore->pSub_Targets[i]->size.x - pText0->w;
1078       dst.y = pStore->pSub_Targets[i]->size.y;
1079 
1080       alphablit(pText0, NULL, pWindow->dst->surface, &dst);
1081       dst.x = pStore->pSub_Targets[i]->size.x + pStore->pSub_Targets[i]->size.w;
1082       dst.y = pStore->pSub_Targets[i]->size.y;
1083 
1084       alphablit(pText1, NULL, pWindow->dst->surface, &dst);
1085       i++;
1086     }
1087 
1088     FREESURFACE(pText0);
1089     FREESURFACE(pText1);
1090   }
1091   FREESTRING16(pStr);
1092 
1093   redraw_group(pHelpDlg->pBeginWidgetList, pWindow->prev->prev, FALSE);
1094   widget_flush(pWindow);
1095 }
1096 
1097 /**************************************************************************
1098   Create tech info widgets
1099 **************************************************************************/
create_tech_info(Tech_type_id tech,int width,struct widget * pWindow,struct TECHS_BUTTONS * pStore)1100 static struct widget *create_tech_info(Tech_type_id tech, int width,
1101                                        struct widget *pWindow,
1102                                        struct TECHS_BUTTONS *pStore)
1103 {
1104   struct widget *pWidget;
1105   struct widget *pLast, *pBudynki;
1106   struct widget *pDock = pStore->pDock;
1107   int i, targets_count,sub_targets_count, max_width = 0;
1108   int start_x, start_y, imp_count, unit_count, flags_count, gov_count;
1109   char buffer[bufsz];
1110   SDL_Surface *pSurf;
1111 
1112   start_x = (pWindow->area.x + adj_size(1) + width + pHelpDlg->pActiveWidgetList->size.w + adj_size(20));
1113 
1114   /* tech tree icon */
1115   pWidget = create_icon2(current_theme->Tech_Tree_Icon, pWindow->dst,
1116                          WF_RESTORE_BACKGROUND);
1117 
1118   set_wstate(pWidget, FC_WS_NORMAL);
1119   pWidget->action = show_tech_tree_callback;
1120   pWidget->ID = MAX_ID - tech;
1121   DownAdd(pWidget, pDock);
1122   pDock = pWidget;
1123 
1124   /* tech name (heading) */
1125   pWidget= create_iconlabel_from_chars(get_tech_icon(tech),
1126                     pWindow->dst,
1127                     advance_name_translation(advance_by_number(tech)),
1128                     adj_font(24),
1129                     WF_FREE_THEME);
1130 
1131   pWidget->ID = ID_LABEL;
1132   DownAdd(pWidget, pDock);
1133   pDock = pWidget;
1134 
1135   /* target techs */
1136   targets_count = 0;
1137   advance_index_iterate(A_FIRST, aidx) {
1138     if ((targets_count < 6)
1139         && (advance_required(aidx, AR_ONE) == tech
1140             || advance_required(aidx, AR_TWO) == tech)) {
1141       pWidget= create_iconlabel_from_chars(NULL, pWindow->dst,
1142               advance_name_translation(advance_by_number(aidx)),
1143               adj_font(12),
1144               WF_RESTORE_BACKGROUND);
1145       pWidget->string16->fgcol = *get_tech_color(aidx);
1146       max_width = MAX(max_width, pWidget->size.w);
1147       set_wstate(pWidget, FC_WS_NORMAL);
1148       pWidget->action = change_tech_callback;
1149       pWidget->ID = MAX_ID - aidx;
1150       DownAdd(pWidget, pDock);
1151       pDock = pWidget;
1152       pStore->pTargets[targets_count++] = pWidget;
1153     }
1154   } advance_index_iterate_end;
1155   if (targets_count < 6) {
1156     pStore->pTargets[targets_count] = NULL;
1157   }
1158 
1159   sub_targets_count = 0;
1160   if (targets_count > 0) {
1161     int sub_tech;
1162 
1163     for(i = 0; i < targets_count; i++) {
1164       sub_tech = MAX_ID - pStore->pTargets[i]->ID;
1165       if (advance_required(sub_tech, AR_ONE) == tech
1166           && advance_required(sub_tech, AR_TWO) != A_NONE) {
1167         sub_tech = advance_required(sub_tech, AR_TWO);
1168       } else if (advance_required(sub_tech, AR_TWO) == tech
1169                  && advance_required(sub_tech, AR_ONE) != A_NONE) {
1170         sub_tech = advance_required(sub_tech, AR_ONE);
1171       } else {
1172         continue;
1173       }
1174       pWidget= create_iconlabel_from_chars(NULL, pWindow->dst,
1175               advance_name_translation(advance_by_number(sub_tech)),
1176               adj_font(12),
1177               WF_RESTORE_BACKGROUND);
1178       pWidget->string16->fgcol = *get_tech_color(sub_tech);
1179       set_wstate(pWidget, FC_WS_NORMAL);
1180       pWidget->action = change_tech_callback;
1181       pWidget->ID = MAX_ID - sub_tech;
1182       DownAdd(pWidget, pDock);
1183       pDock = pWidget;
1184       pStore->pSub_Targets[sub_targets_count++] = pWidget;
1185     }
1186   }
1187   if (sub_targets_count < 6) {
1188     pStore->pSub_Targets[sub_targets_count] = NULL;
1189   }
1190 
1191   /* fill array with iprvm. icons */
1192   pBudynki = pWidget;
1193 
1194   /* target governments */
1195   gov_count = 0;
1196   governments_iterate(gov) {
1197     requirement_vector_iterate(&(gov->reqs), preq) {
1198       if (VUT_ADVANCE == preq->source.kind
1199           && advance_number(preq->source.value.advance) == tech) {
1200 
1201         pWidget = create_iconlabel_from_chars(adj_surf(get_government_surface(gov)),
1202                 pWindow->dst,
1203                 government_name_translation(gov),
1204                 adj_font(14),
1205                 WF_RESTORE_BACKGROUND|WF_SELLECT_WITHOUT_BAR | WF_FREE_THEME);
1206         set_wstate(pWidget, FC_WS_NORMAL);
1207         pWidget->action = change_gov_callback;
1208         pWidget->ID = MAX_ID - government_index(gov);
1209         DownAdd(pWidget, pDock);
1210         pDock = pWidget;
1211         gov_count++;
1212       }
1213     } requirement_vector_iterate_end;
1214   } governments_iterate_end;
1215 
1216   /* target improvements */
1217   imp_count = 0;
1218   improvement_iterate(pimprove) {
1219     if (valid_improvement(pimprove)) {
1220       /* FIXME: this should show ranges and all the MAX_NUM_REQS reqs.
1221        * Currently it's limited to 1 req. Remember MAX_NUM_REQS is a compile-time
1222        * definition. */
1223       requirement_vector_iterate(&(pimprove->reqs), preq) {
1224         if (VUT_ADVANCE == preq->source.kind
1225             && advance_number(preq->source.value.advance) == tech) {
1226           pSurf = get_building_surface(pimprove);
1227           pWidget = create_iconlabel_from_chars(
1228                   ResizeSurfaceBox(pSurf, adj_size(48), adj_size(48), 1, TRUE, TRUE),
1229                   pWindow->dst,
1230                   improvement_name_translation(pimprove),
1231                   adj_font(14),
1232                   WF_RESTORE_BACKGROUND|WF_SELLECT_WITHOUT_BAR);
1233           set_wstate(pWidget, FC_WS_NORMAL);
1234           if (is_wonder(pimprove)) {
1235             pWidget->string16->fgcol = *get_theme_color(COLOR_THEME_CITYDLG_LUX);
1236           }
1237           pWidget->action = change_impr_callback;
1238           pWidget->ID = MAX_ID - improvement_number(pimprove);
1239           DownAdd(pWidget, pDock);
1240           pDock = pWidget;
1241           imp_count++;
1242         }
1243 
1244         break;
1245       } requirement_vector_iterate_end;
1246     }
1247   } improvement_iterate_end;
1248 
1249   unit_count = 0;
1250   unit_type_iterate(un) {
1251     struct unit_type *pUnitType = un;
1252 
1253     if (advance_number(pUnitType->require_advance) == tech) {
1254       pWidget = create_iconlabel_from_chars(
1255                                    ResizeSurfaceBox(get_unittype_surface(un, direction8_invalid()),
1256                                    adj_size(48), adj_size(48), 1, TRUE, TRUE),
1257                   pWindow->dst, utype_name_translation(pUnitType), adj_font(14),
1258                   (WF_FREE_THEME|WF_RESTORE_BACKGROUND|WF_SELLECT_WITHOUT_BAR));
1259       set_wstate(pWidget, FC_WS_NORMAL);
1260       pWidget->action = change_unit_callback;
1261       pWidget->ID = MAX_ID - utype_number(un);
1262       DownAdd(pWidget, pDock);
1263       pDock = pWidget;
1264       unit_count++;
1265     }
1266   } unit_type_iterate_end;
1267 
1268   buffer[0] = '\0';
1269   if (tech != A_NONE) {
1270     helptext_advance(buffer, sizeof(buffer), client.conn.playing, "", tech);
1271   }
1272   if (buffer[0] != '\0') {
1273     SDL_String16 *pStr = create_str16_from_char(buffer, adj_font(12));
1274 
1275     convert_string_to_const_surface_width(pStr, adj_size(640) - start_x - adj_size(20));
1276     pWidget = create_iconlabel(NULL, pWindow->dst, pStr, 0);
1277     pWidget->ID = ID_LABEL;
1278     DownAdd(pWidget, pDock);
1279     pDock = pWidget;
1280     flags_count = 1;
1281   } else {
1282     flags_count = 0;
1283   }
1284 
1285   pLast = pWidget;
1286   /* --------------------------------------------- */
1287 
1288   /* tree button */
1289   pWidget = pStore->pDock->prev;
1290   pWidget->size.x = pWindow->area.x + pWindow->area.w - pWidget->size.w - adj_size(17);
1291   pWidget->size.y = pWindow->area.y + adj_size(16);
1292 
1293   /* Tech label */
1294   pWidget = pWidget->prev;
1295   pWidget->size.x = start_x;
1296   pWidget->size.y = pWindow->area.y + adj_size(16);
1297   start_y = pWidget->size.y + pWidget->size.h + adj_size(30);
1298 
1299   if (targets_count) {
1300     int j, t0, t1;
1301 
1302     i = 0;
1303     j = 0;
1304     t1 = MAX_ID - pStore->pSub_Targets[j]->ID;
1305     while (i < 6 && pStore->pTargets[i]) {
1306       pStore->pTargets[i]->size.x = pWindow->size.x + start_x;
1307       pStore->pTargets[i]->size.y = start_y;
1308 
1309       if (pStore->pSub_Targets[j]) {
1310         t0 = MAX_ID - pStore->pTargets[i]->ID;
1311         t1 = MAX_ID - pStore->pSub_Targets[j]->ID;
1312         if (advance_required(t0, AR_ONE) == t1
1313             || advance_required(t0, AR_TWO) == t1) {
1314           pStore->pSub_Targets[j]->size.x = pWindow->size.x + start_x + max_width + 60;
1315           pStore->pSub_Targets[j]->size.y = pStore->pTargets[i]->size.y;
1316           j++;
1317         }
1318       }
1319 
1320       start_y += pStore->pTargets[i]->size.h;
1321       i++;
1322     }
1323 
1324     start_y += adj_size(10);
1325   }
1326   pWidget = NULL;
1327 
1328   if (gov_count) {
1329     pWidget = pBudynki->prev;
1330     while (gov_count-- && pWidget) {
1331       pWidget->size.x = pWindow->size.x + start_x;
1332       pWidget->size.y = start_y;
1333       start_y += pWidget->size.h + adj_size(2);
1334       pWidget = pWidget->prev;
1335     }
1336   }
1337 
1338   if (imp_count) {
1339     if (!pWidget) {
1340       pWidget = pBudynki->prev;
1341     }
1342     while (imp_count-- && pWidget) {
1343       pWidget->size.x = pWindow->size.x + start_x;
1344       pWidget->size.y = start_y;
1345       start_y += pWidget->size.h + adj_size(2);
1346       pWidget = pWidget->prev;
1347     }
1348   }
1349 
1350   if (unit_count) {
1351     if (!pWidget) {
1352       pWidget = pBudynki->prev;
1353     }
1354     while (unit_count-- && pWidget) {
1355       pWidget->size.x = pWindow->size.x + start_x;
1356       pWidget->size.y = start_y;
1357       start_y += pWidget->size.h + adj_size(2);
1358       pWidget = pWidget->prev;
1359     }
1360   }
1361 
1362   if (flags_count) {
1363     if (!pWidget) {
1364       pWidget = pBudynki->prev;
1365     }
1366     while (flags_count-- && pWidget) {
1367       pWidget->size.x = pWindow->size.x + start_x;
1368       pWidget->size.y = start_y;
1369       start_y += pWidget->size.h + adj_size(2);
1370       pWidget = pWidget->prev;
1371     }
1372   }
1373 
1374   return pLast;
1375 }
1376 
1377 /**************************************************************************
1378   Refresh tech tree dialog
1379 **************************************************************************/
redraw_tech_tree_dlg(void)1380 static void redraw_tech_tree_dlg(void)
1381 {
1382   SDL_Color *line_color = get_theme_color(COLOR_THEME_HELPDLG_LINE);
1383   SDL_Color bg_color = {255, 255, 255, 64};
1384 
1385   struct widget *pWindow = pHelpDlg->pEndWidgetList;
1386   struct widget *pSub0, *pSub1;
1387   struct TECHS_BUTTONS *pStore = (struct TECHS_BUTTONS *)pWindow->data.ptr;
1388   struct widget *pTech = pStore->pDock->prev;
1389   int i,j, tech, count, step, mod;
1390   SDL_Rect dst;
1391 
1392   /* Redraw Window with exit button */
1393   redraw_group(pWindow->prev, pWindow, FALSE);
1394 
1395   dst.x = pWindow->area.x + pWindow->area.w - adj_size(459) - adj_size(7);
1396   dst.y = pWindow->area.y + adj_size(6);
1397   dst.w = pWindow->area.w - (dst.x - pWindow->area.x) - adj_size(10);
1398   dst.h = pWindow->area.h - (dst.y - pWindow->area.y) - adj_size(10);
1399 
1400   SDL_FillRectAlpha(pWindow->dst->surface, &dst, &bg_color);
1401   putframe(pWindow->dst->surface,
1402            dst.x, dst.y, dst.x + dst.w, dst.y + dst.h,
1403            get_theme_color(COLOR_THEME_HELPDLG_FRAME));
1404 
1405   /* Draw Req arrows */
1406   i = 0;
1407   while (i < 4 && pStore->pSub_Req[i]) {
1408     i++;
1409   }
1410   count = i;
1411 
1412   i = 0;
1413   while (i < 2 && pStore->pRequirementButton[i]) {
1414     tech = MAX_ID - pStore->pRequirementButton[i]->ID;
1415 
1416     /*find Sub_Req's */
1417     if (i) {
1418       pSub0 = NULL;
1419       for (j = count - 1; j >= 0; j--) {
1420         if (MAX_ID - pStore->pSub_Req[j]->ID == advance_required(tech, AR_ONE)) {
1421           pSub0 = pStore->pSub_Req[j];
1422           break;
1423         }
1424       }
1425 
1426       pSub1 = NULL;
1427       for(j = count - 1; j >= 0; j--) {
1428         if (MAX_ID - pStore->pSub_Req[j]->ID == advance_required(tech, AR_TWO)) {
1429           pSub1 = pStore->pSub_Req[j];
1430           break;
1431         }
1432       }
1433     } else {
1434       pSub0 = NULL;
1435       for(j = 0; j < 4 && pStore->pSub_Req[j]; j++) {
1436         if (MAX_ID - pStore->pSub_Req[j]->ID == advance_required(tech, AR_ONE)) {
1437           pSub0 = pStore->pSub_Req[j];
1438           break;
1439         }
1440       }
1441 
1442       pSub1 = NULL;
1443       for(j = 0; j < 4 && pStore->pSub_Req[j]; j++) {
1444         if (MAX_ID - pStore->pSub_Req[j]->ID == advance_required(tech, AR_TWO)) {
1445           pSub1 = pStore->pSub_Req[j];
1446           break;
1447         }
1448       }
1449     }
1450 
1451     /* draw main Arrow */
1452     putline(pStore->pRequirementButton[i]->dst->surface,
1453         pStore->pRequirementButton[i]->size.x + pStore->pRequirementButton[i]->size.w,
1454         pStore->pRequirementButton[i]->size.y + pStore->pRequirementButton[i]->size.h / 2,
1455         pTech->size.x,
1456         pStore->pRequirementButton[i]->size.y + pStore->pRequirementButton[i]->size.h / 2,
1457         line_color);
1458 
1459     /* Draw Sub_Req arrows */
1460     if (pSub0 || pSub1) {
1461       putline(pStore->pRequirementButton[i]->dst->surface,
1462         pStore->pRequirementButton[i]->size.x - adj_size(10),
1463         pStore->pRequirementButton[i]->size.y + pStore->pRequirementButton[i]->size.h / 2,
1464         pStore->pRequirementButton[i]->size.x ,
1465         pStore->pRequirementButton[i]->size.y + pStore->pRequirementButton[i]->size.h / 2,
1466         line_color);
1467     }
1468 
1469     if (pSub0) {
1470       putline(pStore->pRequirementButton[i]->dst->surface,
1471         pStore->pRequirementButton[i]->size.x - adj_size(10),
1472         pSub0->size.y + pSub0->size.h / 2,
1473         pStore->pRequirementButton[i]->size.x - adj_size(10),
1474         pStore->pRequirementButton[i]->size.y + pStore->pRequirementButton[i]->size.h / 2,
1475         line_color);
1476       putline(pStore->pRequirementButton[i]->dst->surface,
1477         pSub0->size.x + pSub0->size.w,
1478         pSub0->size.y + pSub0->size.h / 2,
1479         pStore->pRequirementButton[i]->size.x - adj_size(10),
1480         pSub0->size.y + pSub0->size.h / 2,
1481         line_color);
1482     }
1483 
1484     if (pSub1) {
1485       putline(pStore->pRequirementButton[i]->dst->surface,
1486         pStore->pRequirementButton[i]->size.x - adj_size(10),
1487         pSub1->size.y + pSub1->size.h / 2,
1488         pStore->pRequirementButton[i]->size.x - adj_size(10),
1489         pStore->pRequirementButton[i]->size.y + pStore->pRequirementButton[i]->size.h / 2,
1490         line_color);
1491       putline(pStore->pRequirementButton[i]->dst->surface,
1492         pSub1->size.x + pSub1->size.w,
1493         pSub1->size.y + pSub1->size.h / 2,
1494         pStore->pRequirementButton[i]->size.x - adj_size(10),
1495         pSub1->size.y + pSub1->size.h / 2,
1496         line_color);
1497     }
1498     i++;
1499   }
1500 
1501   i = 0;
1502   while (i < 6 && pStore->pTargets[i]) {
1503     i++;
1504   }
1505   count = i;
1506 
1507   if (count > 4) {
1508     mod = 3;
1509   } else {
1510     mod = 2;
1511   }
1512 
1513   for (i = 0; i< count; i++) {
1514     tech = MAX_ID - pStore->pTargets[i]->ID;
1515     step = pTech->size.h / (count + 1);
1516 
1517     switch ((i % mod)) {
1518     case 2:
1519       line_color = get_theme_color(COLOR_THEME_HELPDLG_LINE2);
1520       break;
1521     case 1:
1522       line_color = get_theme_color(COLOR_THEME_HELPDLG_LINE3);
1523       break;
1524     default:
1525       line_color = get_theme_color(COLOR_THEME_HELPDLG_LINE);
1526       break;
1527     }
1528 
1529     /*find Sub_Req's */
1530     if (advance_required(tech, AR_ONE) == MAX_ID - pTech->ID) {
1531       pSub0 = pTech;
1532     } else {
1533       pSub0 = NULL;
1534       for (j = 0; j < 6 && pStore->pSub_Targets[j]; j++) {
1535         if (MAX_ID - pStore->pSub_Targets[j]->ID == advance_required(tech, AR_ONE)) {
1536           pSub0 = pStore->pSub_Targets[j];
1537           break;
1538         }
1539       }
1540     }
1541 
1542     if (advance_required(tech, AR_TWO) == MAX_ID - pTech->ID) {
1543       pSub1 = pTech;
1544     } else {
1545       pSub1 = NULL;
1546       for (j = 0; j < 6 && pStore->pSub_Targets[j]; j++) {
1547         if (MAX_ID - pStore->pSub_Targets[j]->ID == advance_required(tech, AR_TWO)) {
1548           pSub1 = pStore->pSub_Targets[j];
1549           break;
1550         }
1551       }
1552     }
1553 
1554     /* Draw Sub_Targets arrows */
1555     if (pSub0 || pSub1) {
1556       putline(pStore->pTargets[i]->dst->surface,
1557         pStore->pTargets[i]->size.x - ((i % mod) + 1) * 6,
1558         pStore->pTargets[i]->size.y + pStore->pTargets[i]->size.h / 2,
1559         pStore->pTargets[i]->size.x ,
1560         pStore->pTargets[i]->size.y + pStore->pTargets[i]->size.h / 2,
1561         line_color);
1562     }
1563 
1564     if (pSub0) {
1565       int y;
1566 
1567       if (pSub0 == pTech) {
1568         y = pSub0->size.y + step * (i + 1);
1569       } else {
1570         y = pSub0->size.y + pSub0->size.h / 2;
1571       }
1572 
1573       putline(pStore->pTargets[i]->dst->surface,
1574         pStore->pTargets[i]->size.x - ((i % mod) + 1) * 6,
1575         y,
1576         pStore->pTargets[i]->size.x - ((i % mod) + 1) * 6,
1577         pStore->pTargets[i]->size.y + pStore->pTargets[i]->size.h / 2,
1578         line_color);
1579       putline(pStore->pTargets[i]->dst->surface,
1580         pSub0->size.x + pSub0->size.w,
1581         y,
1582         pStore->pTargets[i]->size.x - ((i % mod) + 1) * 6,
1583         y,
1584         line_color);
1585     }
1586 
1587     if (pSub1) {
1588       int y;
1589 
1590       if (pSub1 == pTech) {
1591         y = pSub1->size.y + step * (i + 1);
1592       } else {
1593         y = pSub1->size.y + pSub1->size.h / 2;
1594       }
1595       putline(pStore->pTargets[i]->dst->surface,
1596         pStore->pTargets[i]->size.x - ((i % mod) + 1) * 6,
1597         y,
1598         pStore->pTargets[i]->size.x - ((i % mod) + 1) * 6,
1599         pStore->pTargets[i]->size.y + pStore->pTargets[i]->size.h / 2,
1600         line_color);
1601       putline(pStore->pTargets[i]->dst->surface,
1602         pSub1->size.x + pSub1->size.w,
1603         y,
1604         pStore->pTargets[i]->size.x - ((i % mod) + 1) * 6,
1605         y,
1606         line_color);
1607     }
1608   }
1609 
1610   /* Redraw rest */
1611   redraw_group(pHelpDlg->pBeginWidgetList, pWindow->prev->prev, FALSE);
1612 
1613   widget_flush(pWindow);
1614 }
1615 
1616 /**************************************************************************
1617   User requested toggling between full tech tree and single tech
1618 **************************************************************************/
toggle_full_tree_mode_in_help_dlg_callback(struct widget * pWidget)1619 static int toggle_full_tree_mode_in_help_dlg_callback(struct widget *pWidget)
1620 {
1621   if (Main.event.button.button == SDL_BUTTON_LEFT) {
1622     struct TECHS_BUTTONS *pStore = (struct TECHS_BUTTONS *)pHelpDlg->pEndWidgetList->data.ptr;
1623 
1624     if (pStore->show_full_tree) {
1625       pWidget->theme2 = current_theme->UP_Icon;
1626     } else {
1627       pWidget->theme2 = current_theme->DOWN_Icon;
1628     }
1629     pStore->show_full_tree = !pStore->show_full_tree;
1630     popup_tech_info(MAX_ID - pStore->pDock->prev->ID);
1631   }
1632 
1633   return -1;
1634 }
1635 
1636 /**************************************************************************
1637   Create tech tree widgets
1638 **************************************************************************/
create_tech_tree(Tech_type_id tech,int width,struct widget * pWindow,struct TECHS_BUTTONS * pStore)1639 static struct widget *create_tech_tree(Tech_type_id tech, int width,
1640                                        struct widget *pWindow,
1641                                        struct TECHS_BUTTONS *pStore)
1642 {
1643   int i, w, h, req_count , targets_count, sub_req_count, sub_targets_count;
1644   struct widget *pWidget;
1645   struct widget *pTech;
1646   SDL_String16 *pStr;
1647   SDL_Surface *pSurf;
1648   struct widget *pDock = pStore->pDock;
1649 
1650   pStr = create_string16(NULL, 0, adj_font(10));
1651   pStr->style |= (TTF_STYLE_BOLD | SF_CENTER);
1652 
1653   copy_chars_to_string16(pStr, advance_name_translation(advance_by_number(tech)));
1654   pSurf = create_sellect_tech_icon(pStr, tech, FULL_MODE);
1655   pWidget = create_icon2(pSurf, pWindow->dst,
1656                 WF_FREE_THEME | WF_RESTORE_BACKGROUND);
1657 
1658   set_wstate(pWidget, FC_WS_NORMAL);
1659   pWidget->action = show_tech_tree_callback;
1660   pWidget->ID = MAX_ID - tech;
1661   DownAdd(pWidget, pDock);
1662   pTech = pWidget;
1663   pDock = pWidget;
1664 
1665   req_count  = 0;
1666   for (i = AR_ONE; i <= AR_TWO; i++) {
1667     Tech_type_id ar = advance_required(tech, i);
1668     struct advance *vap = valid_advance_by_number(ar);
1669 
1670     if (NULL != vap && A_NONE != ar) {
1671       copy_chars_to_string16(pStr, advance_name_translation(vap));
1672       pSurf = create_sellect_tech_icon(pStr, ar, SMALL_MODE);
1673       pWidget = create_icon2(pSurf, pWindow->dst,
1674                 WF_FREE_THEME | WF_RESTORE_BACKGROUND);
1675       set_wstate(pWidget, FC_WS_NORMAL);
1676       pWidget->action = change_tech_callback;
1677       pWidget->ID = MAX_ID - ar;
1678       DownAdd(pWidget, pDock);
1679       pDock = pWidget;
1680       pStore->pRequirementButton[i] = pWidget;
1681       req_count++;
1682     } else {
1683       pStore->pRequirementButton[i] = NULL;
1684     }
1685   }
1686 
1687   sub_req_count = 0;
1688 
1689   if (pStore->show_full_tree && req_count) {
1690     int j, sub_tech;
1691 
1692     for (j = 0; j < req_count; j++) {
1693       sub_tech = MAX_ID - pStore->pRequirementButton[j]->ID;
1694       for (i = AR_ONE; i <= AR_TWO; i++) {
1695         Tech_type_id ar = advance_required(sub_tech, i);
1696         struct advance *vap = valid_advance_by_number(ar);
1697 
1698         if (NULL != vap && A_NONE != ar) {
1699           copy_chars_to_string16(pStr, advance_name_translation(vap));
1700           pSurf = create_sellect_tech_icon(pStr, ar, SMALL_MODE);
1701           pWidget = create_icon2(pSurf, pWindow->dst,
1702                 WF_FREE_THEME | WF_RESTORE_BACKGROUND);
1703           set_wstate(pWidget, FC_WS_NORMAL);
1704           pWidget->action = change_tech_callback;
1705           pWidget->ID = MAX_ID - ar;
1706           DownAdd(pWidget, pDock);
1707           pDock = pWidget;
1708           pStore->pSub_Req[sub_req_count++] = pWidget;
1709         }
1710       }
1711     }
1712   }
1713 
1714   if (sub_req_count < 4) {
1715     pStore->pSub_Req[sub_req_count] = NULL;
1716   }
1717 
1718   targets_count = 0;
1719   advance_index_iterate(A_FIRST, aidx) {
1720     if ((targets_count < 6)
1721         && (advance_required(aidx, AR_ONE) == tech
1722             || advance_required(aidx, AR_TWO) == tech)) {
1723       copy_chars_to_string16(pStr, advance_name_translation(advance_by_number(aidx)));
1724       pSurf = create_sellect_tech_icon(pStr, aidx, SMALL_MODE);
1725       pWidget = create_icon2(pSurf, pWindow->dst,
1726                 WF_FREE_THEME | WF_RESTORE_BACKGROUND);
1727 
1728       set_wstate(pWidget, FC_WS_NORMAL);
1729       pWidget->action = change_tech_callback;
1730       pWidget->ID = MAX_ID - aidx;
1731       DownAdd(pWidget, pDock);
1732       pDock = pWidget;
1733       pStore->pTargets[targets_count++] = pWidget;
1734     }
1735   } advance_index_iterate_end;
1736   if (targets_count < 6) {
1737     pStore->pTargets[targets_count] = NULL;
1738   }
1739 
1740   sub_targets_count = 0;
1741   if (targets_count) {
1742     int sub_tech;
1743 
1744     for (i = 0; i < targets_count; i++) {
1745       sub_tech = MAX_ID - pStore->pTargets[i]->ID;
1746       if (advance_required(sub_tech, AR_ONE) == tech
1747           && advance_required(sub_tech, AR_TWO) != A_NONE) {
1748         sub_tech = advance_required(sub_tech, AR_TWO);
1749       } else if (advance_required(sub_tech, AR_TWO) == tech
1750                  && advance_required(sub_tech, AR_ONE) != A_NONE) {
1751         sub_tech = advance_required(sub_tech, AR_ONE);
1752       } else {
1753         continue;
1754       }
1755 
1756       copy_chars_to_string16(pStr, advance_name_translation(advance_by_number(sub_tech)));
1757       pSurf = create_sellect_tech_icon(pStr, sub_tech, SMALL_MODE);
1758       pWidget = create_icon2(pSurf, pWindow->dst,
1759         WF_FREE_THEME | WF_RESTORE_BACKGROUND);
1760       set_wstate(pWidget, FC_WS_NORMAL);
1761       pWidget->action = change_tech_callback;
1762       pWidget->ID = MAX_ID - sub_tech;
1763       DownAdd(pWidget, pDock);
1764       pDock = pWidget;
1765       pStore->pSub_Targets[sub_targets_count++] = pWidget;
1766     }
1767   }
1768   if (sub_targets_count < 6) {
1769     pStore->pSub_Targets[sub_targets_count] = NULL;
1770   }
1771 
1772   FREESTRING16(pStr);
1773 
1774   /* ------------------------------------------ */
1775   if (sub_req_count) {
1776     w = (adj_size(20) + pStore->pSub_Req[0]->size.w) * 2;
1777     w += (pWindow->size.w - (20 + pStore->pSub_Req[0]->size.w + w + pTech->size.w)) / 2;
1778   } else {
1779     if (req_count) {
1780       w = (pWindow->area.x + 1 + width + pStore->pRequirementButton[0]->size.w * 2 + adj_size(20));
1781       w += (pWindow->size.w - ((adj_size(20) + pStore->pRequirementButton[0]->size.w) + w + pTech->size.w)) / 2;
1782     } else {
1783       w = (pWindow->size.w - pTech->size.w) / 2;
1784     }
1785   }
1786 
1787   pTech->size.x = pWindow->size.x + w;
1788   pTech->size.y = pWindow->area.y + (pWindow->area.h - pTech->size.h) / 2;
1789 
1790   if (req_count) {
1791     h = (req_count == 1 ? pStore->pRequirementButton[0]->size.h :
1792         req_count * (pStore->pRequirementButton[0]->size.h + adj_size(80)) - adj_size(80));
1793     h = pTech->size.y + (pTech->size.h - h) / 2;
1794     for(i =0; i <req_count; i++) {
1795       pStore->pRequirementButton[i]->size.x = pTech->size.x - adj_size(20) - pStore->pRequirementButton[i]->size.w;
1796       pStore->pRequirementButton[i]->size.y = h;
1797       h += (pStore->pRequirementButton[i]->size.h + adj_size(80));
1798     }
1799   }
1800 
1801   if (sub_req_count) {
1802     h = (sub_req_count == 1 ? pStore->pSub_Req[0]->size.h :
1803          sub_req_count * (pStore->pSub_Req[0]->size.h + adj_size(20)) - adj_size(20));
1804     h = pTech->size.y + (pTech->size.h - h) / 2;
1805     for (i = 0; i < sub_req_count; i++) {
1806       pStore->pSub_Req[i]->size.x = pTech->size.x - (adj_size(20) + pStore->pSub_Req[i]->size.w) * 2;
1807       pStore->pSub_Req[i]->size.y = h;
1808       h += (pStore->pSub_Req[i]->size.h + adj_size(20));
1809     }
1810   }
1811 
1812   if (targets_count) {
1813     h = (targets_count == 1 ? pStore->pTargets[0]->size.h :
1814      targets_count * (pStore->pTargets[0]->size.h + adj_size(20)) - adj_size(20));
1815     h = pTech->size.y + (pTech->size.h - h) / 2;
1816     for (i = 0; i < targets_count; i++) {
1817       pStore->pTargets[i]->size.x = pTech->size.x + pTech->size.w + adj_size(20);
1818       pStore->pTargets[i]->size.y = h;
1819       h += (pStore->pTargets[i]->size.h + adj_size(20));
1820     }
1821   }
1822 
1823   if (sub_targets_count) {
1824     if (sub_targets_count < 3) {
1825       pStore->pSub_Targets[0]->size.x = pTech->size.x + pTech->size.w - pStore->pSub_Targets[0]->size.w;
1826       pStore->pSub_Targets[0]->size.y = pTech->size.y - pStore->pSub_Targets[0]->size.h - adj_size(10);
1827       if (pStore->pSub_Targets[1]) {
1828         pStore->pSub_Targets[1]->size.x = pTech->size.x + pTech->size.w - pStore->pSub_Targets[1]->size.w;
1829         pStore->pSub_Targets[1]->size.y = pTech->size.y + pTech->size.h + adj_size(10);
1830       }
1831     }
1832     else
1833     {
1834       if (sub_targets_count < 5) {
1835         for (i = 0; i < MIN(sub_targets_count, 4); i++) {
1836           pStore->pSub_Targets[i]->size.x = pTech->size.x + pTech->size.w - pStore->pSub_Targets[i]->size.w;
1837           if (i < 2) {
1838             pStore->pSub_Targets[i]->size.y = pTech->size.y - (pStore->pSub_Targets[i]->size.h + adj_size(5)) * ( 2 - i );
1839           } else {
1840             pStore->pSub_Targets[i]->size.y = pTech->size.y + pTech->size.h + adj_size(5)  + (pStore->pSub_Targets[i]->size.h + adj_size(5)) * ( i - 2 );
1841           }
1842         }
1843       } else {
1844         h = (pStore->pSub_Targets[0]->size.h + adj_size(6));
1845         for (i = 0; i < MIN(sub_targets_count, 6); i++) {
1846           switch(i) {
1847           case 0:
1848             pStore->pSub_Targets[i]->size.x = pTech->size.x + pTech->size.w - pStore->pSub_Targets[i]->size.w;
1849             pStore->pSub_Targets[i]->size.y = pTech->size.y - h * 2;
1850             break;
1851           case 1:
1852             pStore->pSub_Targets[i]->size.x = pTech->size.x + pTech->size.w - pStore->pSub_Targets[i]->size.w * 2 - adj_size(10);
1853             pStore->pSub_Targets[i]->size.y = pTech->size.y - h - h / 2;
1854             break;
1855           case 2:
1856             pStore->pSub_Targets[i]->size.x = pTech->size.x + pTech->size.w - pStore->pSub_Targets[i]->size.w;
1857             pStore->pSub_Targets[i]->size.y = pTech->size.y - h;
1858             break;
1859           case 3:
1860             pStore->pSub_Targets[i]->size.x = pTech->size.x + pTech->size.w - pStore->pSub_Targets[i]->size.w;
1861             pStore->pSub_Targets[i]->size.y = pTech->size.y + pTech->size.h + adj_size(6);
1862             break;
1863           case 4:
1864             pStore->pSub_Targets[i]->size.x = pTech->size.x + pTech->size.w - pStore->pSub_Targets[i]->size.w;
1865             pStore->pSub_Targets[i]->size.y = pTech->size.y + pTech->size.h + adj_size(6) + h;
1866             break;
1867           default:
1868             pStore->pSub_Targets[i]->size.x = pTech->size.x + pTech->size.w - pStore->pSub_Targets[i]->size.w * 2 - adj_size(10);
1869             pStore->pSub_Targets[i]->size.y = pTech->size.y + pTech->size.h + adj_size(6) + h / 2 ;
1870             break;
1871           }
1872         }
1873       }
1874     }
1875   }
1876 
1877   return pWidget;
1878 }
1879 
1880 /**************************************************************************
1881   Show tech info
1882 **************************************************************************/
popup_tech_info(Tech_type_id tech)1883 void popup_tech_info(Tech_type_id tech)
1884 {
1885   struct widget *pWindow;
1886   struct TECHS_BUTTONS *pStore;
1887 
1888   struct widget *pCloseButton = NULL;
1889   struct widget *pAdvanceLabel = NULL;
1890   struct widget *pListToggleButton = NULL;
1891 
1892   struct widget *pDock;
1893   SDL_String16 *pTitle, *pStr;
1894   SDL_Surface *pSurf;
1895   int h, tech_count;
1896   bool created;
1897   int scrollbar_width = 0;
1898   SDL_Rect area;
1899 
1900   if (current_help_dlg != HELP_TECH) {
1901     popdown_help_dialog();
1902   }
1903 
1904   /* create new dialog if it doesn't exist yet */
1905   if (!pHelpDlg) {
1906     current_help_dlg = HELP_TECH;
1907     created = TRUE;
1908 
1909     /* create dialog */
1910     pHelpDlg = fc_calloc(1, sizeof(struct ADVANCED_DLG));
1911     pStore = fc_calloc(1, sizeof(struct TECHS_BUTTONS));
1912 
1913     pStore->show_tree = FALSE;
1914     pStore->show_full_tree = FALSE;
1915 
1916     /* create window */
1917     pTitle = create_str16_from_char(_("Help : Advances Tree"), adj_font(12));
1918     pTitle->style |= TTF_STYLE_BOLD;
1919 
1920     pWindow = create_window_skeleton(NULL, pTitle, WF_FREE_DATA);
1921     pWindow->data.ptr = (void *)pStore;
1922     pWindow->action = help_dlg_window_callback;
1923     set_wstate(pWindow , FC_WS_NORMAL);
1924 
1925     add_to_gui_list(ID_WINDOW, pWindow);
1926 
1927     pHelpDlg->pEndWidgetList = pWindow;
1928 
1929     area = pWindow->area;
1930 
1931     /* ------------------ */
1932 
1933     /* close button */
1934     pCloseButton = create_themeicon(current_theme->Small_CANCEL_Icon, pWindow->dst,
1935                                     WF_WIDGET_HAS_INFO_LABEL
1936                                     | WF_RESTORE_BACKGROUND);
1937     pCloseButton->info_label =
1938         create_str16_from_char(_("Close Dialog (Esc)"), adj_font(12));
1939     pCloseButton->action = exit_help_dlg_callback;
1940     set_wstate(pCloseButton, FC_WS_NORMAL);
1941     pCloseButton->key = SDLK_ESCAPE;
1942 
1943     add_to_gui_list(ID_BUTTON, pCloseButton);
1944 
1945     /* ------------------ */
1946     pDock = pCloseButton;
1947 
1948     /* --- create scrollable advance list on the left side ---*/
1949     pStr = create_string16(NULL, 0, adj_font(10));
1950     pStr->style |= (TTF_STYLE_BOLD | SF_CENTER);
1951 
1952     tech_count = 0;
1953     advance_index_iterate(A_FIRST, i) {
1954       struct advance *vap = valid_advance_by_number(i);;
1955 
1956       if (vap) {
1957         copy_chars_to_string16(pStr, advance_name_translation(vap));
1958         pSurf = create_sellect_tech_icon(pStr, i, SMALL_MODE);
1959         pAdvanceLabel = create_icon2(pSurf, pWindow->dst,
1960                                      WF_FREE_THEME | WF_RESTORE_BACKGROUND);
1961 
1962         set_wstate(pAdvanceLabel, FC_WS_NORMAL);
1963         pAdvanceLabel->action = change_tech_callback;
1964         add_to_gui_list(MAX_ID - i, pAdvanceLabel);
1965 
1966         if (tech_count++ >= 10) {
1967           set_wflag(pAdvanceLabel, WF_HIDDEN);
1968         }
1969       }
1970     } advance_index_iterate_end;
1971 
1972     FREESTRING16(pStr);
1973 
1974     pHelpDlg->pEndActiveWidgetList = pDock->prev;
1975     pHelpDlg->pBeginWidgetList = pAdvanceLabel ? pAdvanceLabel : pCloseButton;
1976     pHelpDlg->pBeginActiveWidgetList = pHelpDlg->pBeginWidgetList;
1977 
1978     if (tech_count > 10) {
1979       pHelpDlg->pActiveWidgetList = pHelpDlg->pEndActiveWidgetList;
1980       scrollbar_width = create_vertical_scrollbar(pHelpDlg, 1, 10, TRUE, TRUE);
1981     }
1982 
1983     /* toggle techs list button */
1984     pListToggleButton = create_themeicon_button_from_chars(current_theme->UP_Icon,
1985                                                            pWindow->dst,
1986                                                            _("Advances"),
1987                                                            adj_font(10), 0);
1988     pListToggleButton->action = toggle_full_tree_mode_in_help_dlg_callback;
1989     if (pStore->show_tree) {
1990       set_wstate(pListToggleButton, FC_WS_NORMAL);
1991     }
1992     widget_resize(pListToggleButton, adj_size(160), adj_size(15));
1993     pListToggleButton->string16->fgcol = *get_theme_color(COLOR_THEME_HELPDLG_TEXT);
1994 
1995     add_to_gui_list(ID_BUTTON, pListToggleButton);
1996 
1997     pDock = pListToggleButton;
1998     pStore->pDock = pDock;
1999   } else {
2000     created = FALSE;
2001     scrollbar_width = (pHelpDlg->pScroll ? pHelpDlg->pScroll->pUp_Left_Button->size.w: 0);
2002     pWindow = pHelpDlg->pEndWidgetList;
2003     pStore = (struct TECHS_BUTTONS *)pWindow->data.ptr;
2004     pDock = pStore->pDock;
2005 
2006     area = pWindow->area;
2007 
2008     /* delete any previous list entries */
2009     if (pDock != pHelpDlg->pBeginWidgetList) {
2010       del_group_of_widgets_from_gui_list(pHelpDlg->pBeginWidgetList, pDock->prev);
2011       pHelpDlg->pBeginWidgetList = pDock;
2012     }
2013 
2014     /* show/hide techs list */
2015     pListToggleButton = pDock;
2016 
2017     if (pStore->show_tree) {
2018       set_wstate(pListToggleButton, FC_WS_NORMAL);
2019     } else {
2020       set_wstate(pListToggleButton, FC_WS_DISABLED);
2021     }
2022 
2023     if (pStore->show_full_tree) {
2024       /* all entries are visible without scrolling */
2025       hide_group(pHelpDlg->pBeginActiveWidgetList,
2026                  pHelpDlg->pEndActiveWidgetList);
2027       hide_scrollbar(pHelpDlg->pScroll);
2028     } else {
2029       int count = pHelpDlg->pScroll->active;
2030 
2031       pAdvanceLabel = pHelpDlg->pActiveWidgetList;
2032       while (pAdvanceLabel && count--) {
2033         pAdvanceLabel = pAdvanceLabel->prev;
2034       }
2035       pAdvanceLabel = pAdvanceLabel->next;
2036       show_group(pAdvanceLabel, pHelpDlg->pActiveWidgetList);
2037       show_scrollbar(pHelpDlg->pScroll);
2038     }
2039   }
2040 
2041   /* --------------------------------------------------------- */
2042   if (created) {
2043 
2044     pSurf = theme_get_background(theme, BACKGROUND_HELPDLG);
2045     if (resize_window(pWindow, pSurf, NULL, adj_size(640), adj_size(480))) {
2046       FREESURFACE(pSurf);
2047     }
2048 
2049     area = pWindow->area;
2050 
2051     widget_set_position(pWindow,
2052                         (Main.screen->w - pWindow->size.w) / 2,
2053                         (Main.screen->h - pWindow->size.h) / 2);
2054 
2055     /* exit button */
2056     pCloseButton = pWindow->prev;
2057     widget_set_position(pCloseButton,
2058                         area.x + area.w - pCloseButton->size.w - 1,
2059                         pWindow->size.y + adj_size(2));
2060 
2061     /* list toggle button */
2062     pListToggleButton = pStore->pDock;
2063     widget_set_position(pListToggleButton, area.x, area.y);
2064 
2065     /* list entries */
2066     h = setup_vertical_widgets_position(1, area.x + scrollbar_width,
2067                                         area.y + pListToggleButton->size.h, 0, 0,
2068                                         pHelpDlg->pBeginActiveWidgetList,
2069                                         pHelpDlg->pEndActiveWidgetList);
2070     /* scrollbar */
2071     if (pHelpDlg->pScroll) {
2072       setup_vertical_scrollbar_area(pHelpDlg->pScroll,
2073                                     area.x, area.y + pListToggleButton->size.h,
2074                                     h, FALSE);
2075     }
2076   }
2077 
2078   if (pStore->show_tree) {
2079     pHelpDlg->pBeginWidgetList = create_tech_tree(tech, scrollbar_width, pWindow, pStore);
2080     redraw_tech_tree_dlg();
2081   } else {
2082     pHelpDlg->pBeginWidgetList = create_tech_info(tech, scrollbar_width, pWindow, pStore);
2083     redraw_tech_info_dlg();
2084   }
2085 }
2086