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