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)
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 ***********************************************************************/
15 #include <fc_config.h>
21 #include <math.h> /* sqrt */
34 #include "government.h"
36 #include "specialist.h"
44 #include "client_main.h"
50 /* client/gui-gtk-4.0 */
54 #include "gui_stuff.h"
58 #define TECH_TREE_DEPTH 20
63 static GtkWidget
*help_dialog_shell
;
64 static GtkWidget
*help_view_sw
;
66 static GtkWidget
*help_view
;
68 static GtkWidget
*help_frame
;
69 static GtkTextBuffer
*help_text
;
70 static GtkWidget
*help_text_sw
;
71 static GtkWidget
*help_vbox
;
72 static GtkWidget
*help_tile
;
73 static GtkWidget
*help_box
;
74 static GtkWidget
*help_itable
;
75 static GtkWidget
*help_wtable
;
76 static GtkWidget
*help_utable
;
77 static GtkWidget
*help_ttable
;
78 static GtkWidget
*help_etable
;
79 static GtkWidget
*help_tree
;
80 static GtkTreeStore
*tstore
;
82 static GtkWidget
*help_tree_sw
;
83 static GtkWidget
*help_tree_expand
;
84 static GtkWidget
*help_tree_collapse
;
85 static GtkWidget
*help_tree_buttons_hbox
;
86 static GtkWidget
*help_ilabel
[6];
87 static GtkWidget
*help_wlabel
[6];
88 static GtkWidget
*help_ulabel
[5][5];
89 static GtkWidget
*help_tlabel
[4][5];
90 static GtkWidget
*help_elabel
[6];
92 static bool help_advances
[A_LAST
];
94 static GPtrArray
*help_history
;
95 static int help_history_pos
;
98 static const char *help_ilabel_name
[6] =
99 { N_("Cost:"), NULL
, N_("Upkeep:"), NULL
, N_("Requirement:"), NULL
};
101 static const char *help_wlabel_name
[6] =
102 { N_("Cost:"), NULL
, N_("Requirement:"), NULL
, N_("Obsolete by:"), NULL
};
104 static const char *help_ulabel_name
[5][5] =
106 { N_("Cost:"), NULL
, NULL
, N_("Attack:"), NULL
},
107 { N_("Defense:"), NULL
, NULL
, N_("Move:") , NULL
},
108 { N_("FirePower:"), NULL
, NULL
, N_("Hitpoints:"), NULL
},
109 { N_("Basic Upkeep:"), NULL
, NULL
, N_("Vision:"), NULL
},
110 { N_("Requirement:"), NULL
, NULL
, N_("Obsolete by:"), NULL
}
113 static const char *help_tlabel_name
[4][5] =
115 { N_("Move/Defense:"), NULL
, NULL
, N_("Food/Res/Trade:"), NULL
},
116 { N_("Resources:"), NULL
, NULL
, NULL
, NULL
},
117 { N_("Irrig. Rslt/Time:"), NULL
, NULL
, N_("Mine Rslt/Time:"), NULL
},
118 { N_("Trans. Rslt/Time:"), NULL
, NULL
, NULL
, NULL
}
121 static const char *help_elabel_name
[6] =
122 /* TRANS: Label for build cost for extras in help. Will be followed by
123 * something like "3 MP" (where MP = Movement Points) */
124 { N_("Build:"), NULL
,
125 /* TRANS: Extra conflicts in help. Will be followed by a list of extras
126 * that can't be built on the same tile as this one. */
127 N_("Conflicts with:"), NULL
,
128 /* TRANS: Extra bonus in help. Will be followed by food/production/trade
129 * stats like "0/0/+1", "0/+50%/0" */
130 N_("Bonus (F/P/T):"), NULL
};
132 #define REQ_LABEL_NONE _("?tech:None")
133 #define REQ_LABEL_NEVER _("(Never)")
135 static void create_help_dialog(void);
136 static void help_update_dialog(const struct help_item
*pitem
);
137 static void create_help_page(enum help_page_type type
);
139 static void select_help_item_string(const char *item
,
140 enum help_page_type htype
);
141 static void help_command_update(void);
142 static void help_command_callback(GtkWidget
*w
, gint response_id
);
144 /****************************************************************
145 Set topic specific title for help_frame
146 *****************************************************************/
147 static void set_title_topic(char *topic
)
149 if (strcmp(topic
, _(HELP_ABOUT_ITEM
)) == 0) {
150 gtk_frame_set_label(GTK_FRAME(help_frame
), freeciv_name_version());
152 gtk_frame_set_label(GTK_FRAME(help_frame
), topic
);
157 /****************************************************************
159 *****************************************************************/
160 void popdown_help_dialog(void)
162 if (help_dialog_shell
) {
163 gtk_widget_destroy(help_dialog_shell
);
167 /****************************************************************
168 Popup help dialog for given item of given type.
169 *****************************************************************/
170 void popup_help_dialog_typed(const char *item
, enum help_page_type htype
)
172 if (!help_dialog_shell
) {
173 create_help_dialog();
174 set_relative_window_position(GTK_WINDOW(toplevel
),
175 GTK_WINDOW(help_dialog_shell
), 10, 10);
177 gtk_window_present(GTK_WINDOW(help_dialog_shell
));
179 select_help_item_string(item
, htype
);
182 /****************************************************************
183 Not sure if this should call Q_(item) as it does, or whether all
184 callers of this function should do so themselves... --dwp
185 *****************************************************************/
186 void popup_help_dialog_string(const char *item
)
188 popup_help_dialog_typed(Q_(item
), HELP_ANY
);
191 /**************************************************************************
192 Called by help_update_tech and itself
193 Creates a node in the given tree for the given tech, and creates child
194 nodes for any children it has up to levels deep. These are then expanded
195 if they are less than expanded_levels deep. Avoids generating redundant
196 subtrees, so that if Literacy occurs twice in a tech tree, only the first
197 will have children. Color codes the node based on when it will be
198 discovered: red >2 turns, yellow 1 turn, green 0 turns (discovered).
199 **************************************************************************/
200 static void create_tech_tree(int tech
, int levels
, GtkTreeIter
*parent
)
202 const struct research
*presearch
;
207 GValue value
= { 0, };
209 if (advance_required(tech
, AR_ONE
) == A_LAST
210 && advance_required(tech
, AR_TWO
) == A_LAST
) {
211 bg
= COLOR_REQTREE_UNKNOWN
;
213 gtk_tree_store_append(tstore
, &l
, parent
);
214 help_advances
[tech
] = TRUE
;
216 g_value_init(&value
, G_TYPE_STRING
);
217 g_value_set_static_string(&value
, _("Removed"));
218 gtk_tree_store_set_value(tstore
, &l
, 0, &value
);
219 g_value_unset(&value
);
221 gtk_tree_store_set(tstore
, &l
,
224 3, &get_color(tileset
, bg
)->color
229 presearch
= research_get(client_player());
231 bg
= COLOR_REQTREE_BACKGROUND
;
232 switch (research_invention_state(presearch
, tech
)) {
234 bg
= COLOR_REQTREE_UNKNOWN
;
237 bg
= COLOR_REQTREE_KNOWN
;
239 case TECH_PREREQS_KNOWN
:
240 bg
= COLOR_REQTREE_PREREQS_KNOWN
;
243 turns_to_tech
= research_goal_unknown_techs(presearch
, tech
);
245 /* l is the original in the tree. */
246 original
= !help_advances
[tech
];
248 gtk_tree_store_append(tstore
, &l
, parent
);
249 help_advances
[tech
] = TRUE
;
251 g_value_init(&value
, G_TYPE_STRING
);
252 g_value_set_static_string(&value
,
253 research_advance_name_translation(presearch
,
255 gtk_tree_store_set_value(tstore
, &l
, 0, &value
);
256 g_value_unset(&value
);
258 gtk_tree_store_set(tstore
, &l
,
261 3, &get_color(tileset
, bg
)->color
,
268 /* only add children to orginals */
269 if (advance_required(tech
, AR_ONE
) != A_NONE
)
270 create_tech_tree(advance_required(tech
, AR_ONE
), levels
, &l
);
271 if (advance_required(tech
, AR_TWO
) != A_NONE
)
272 create_tech_tree(advance_required(tech
, AR_TWO
), levels
, &l
);
277 /**************************************************************************
278 Selects the help page for the tech in the tree that was double clicked.
279 **************************************************************************/
280 static void help_tech_tree_activated_callback(GtkTreeView
*view
,
282 GtkTreeViewColumn
*col
,
288 gtk_tree_model_get_iter(GTK_TREE_MODEL(tstore
), &it
, path
);
289 gtk_tree_model_get(GTK_TREE_MODEL(tstore
), &it
, 2, &tech
, -1);
290 select_help_item_string(advance_name_translation(advance_by_number(tech
)),
294 /**************************************************************************
295 Called when "Expand All" button is clicked
296 **************************************************************************/
297 static void help_tech_tree_expand_callback(GtkWidget
*w
, gpointer data
)
299 gtk_tree_view_expand_all(GTK_TREE_VIEW(data
));
302 /**************************************************************************
303 Called when "Collapse All" button is clicked
304 **************************************************************************/
305 static void help_tech_tree_collapse_callback(GtkWidget
*w
, gpointer data
)
307 gtk_tree_view_collapse_all(GTK_TREE_VIEW(data
));
310 /**************************************************************************
312 **************************************************************************/
313 static void help_hyperlink_callback(GtkWidget
*w
)
316 enum help_page_type type
;
318 s
=gtk_label_get_text(GTK_LABEL(w
));
319 type
=GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(w
), "page_type"));
321 /* FIXME: May be able to skip, or may need to modify, advances[A_NONE]
322 below, depending on which i18n is done elsewhere.
324 if (strcmp(s
, REQ_LABEL_NEVER
) != 0
325 && strcmp(s
, skip_intl_qualifier_prefix(REQ_LABEL_NONE
)) != 0
326 && strcmp(s
, advance_name_translation(advance_by_number(A_NONE
))) != 0)
327 select_help_item_string(s
, type
);
330 /**************************************************************************
331 Create new hyperlink button
332 **************************************************************************/
333 static GtkWidget
*help_hyperlink_new(GtkWidget
*label
, enum help_page_type type
)
337 button
= gtk_button_new();
338 gtk_button_set_relief(GTK_BUTTON(button
), GTK_RELIEF_NONE
);
339 gtk_widget_set_halign(label
, GTK_ALIGN_CENTER
);
340 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
341 gtk_widget_set_name(label
, "help_link");
342 gtk_container_add(GTK_CONTAINER(button
), label
);
343 gtk_widget_show(button
);
344 g_signal_connect_swapped(button
, "clicked",
345 G_CALLBACK(help_hyperlink_callback
), label
);
346 g_object_set_data(G_OBJECT(label
), "page_type", GUINT_TO_POINTER(type
));
350 /**************************************************************************
351 Create new hyperlink button with text
352 **************************************************************************/
353 static GtkWidget
*help_slink_new(const gchar
*txt
, enum help_page_type type
)
355 GtkWidget
*button
, *label
;
357 label
= gtk_label_new(txt
);
358 gtk_widget_set_halign(label
, GTK_ALIGN_CENTER
);
359 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
360 button
= help_hyperlink_new(label
, type
);
365 /**************************************************************************
367 **************************************************************************/
368 static void help_box_hide(void)
370 gtk_widget_hide(help_box
);
372 gtk_widget_hide(help_tile
);
374 gtk_widget_hide(help_itable
);
375 gtk_widget_hide(help_wtable
);
376 gtk_widget_hide(help_utable
);
377 gtk_widget_hide(help_ttable
);
378 gtk_widget_hide(help_etable
);
380 gtk_widget_hide(help_tile
); /* FIXME: twice? */
382 gtk_widget_hide(help_vbox
);
383 gtk_widget_hide(help_text_sw
);
385 gtk_widget_hide(help_tree_sw
);
386 gtk_widget_hide(help_tree_buttons_hbox
);
389 /**************************************************************************
390 Completely destory help dialog
391 **************************************************************************/
392 static void help_destroy_callback(GtkWidget
*w
, gpointer data
)
394 g_ptr_array_free(help_history
, TRUE
);
395 help_dialog_shell
= NULL
;
398 /**************************************************************************
399 New topic activated from help dialog
400 **************************************************************************/
401 static void activated_topic(GtkTreeView
*view
, gpointer data
)
404 GtkTreeViewColumn
*col
;
407 struct help_item
*pitem
;
409 model
= gtk_tree_view_get_model(view
);
411 gtk_tree_view_get_cursor(view
, &path
, &col
);
412 gtk_tree_model_get_iter(model
, &it
, path
);
413 gtk_tree_path_free(path
);
419 gtk_tree_model_get(model
, &it
, 1, &pitem
, -1);
421 if (help_history_pos
>= 0 &&
422 g_ptr_array_index(help_history
, help_history_pos
) == (gpointer
) pitem
) {
426 help_update_dialog(pitem
);
428 /* add to history. */
429 if (help_history_pos
< help_history
->len
- 1) {
430 g_ptr_array_set_size(help_history
, help_history_pos
+ 1);
434 g_ptr_array_add(help_history
, (gpointer
)pitem
);
435 help_command_update();
438 /**************************************************************************
440 **************************************************************************/
441 static void create_help_dialog(void)
447 GtkCellRenderer
*rend
;
448 GtkTreeViewColumn
*col
;
451 GtkTreeSelection
*selection
;
453 help_history
= g_ptr_array_new();
454 help_history_pos
= -1;
456 help_dialog_shell
= gtk_dialog_new_with_buttons(_("Freeciv Help Browser"),
466 setup_dialog(help_dialog_shell
, toplevel
);
467 gtk_dialog_set_default_response(GTK_DIALOG(help_dialog_shell
),
469 gtk_widget_set_name(help_dialog_shell
, "Freeciv");
471 g_signal_connect(help_dialog_shell
, "response",
472 G_CALLBACK(help_command_callback
), NULL
);
473 g_signal_connect(help_dialog_shell
, "destroy",
474 G_CALLBACK(help_destroy_callback
), NULL
);
476 hbox
= gtk_grid_new();
477 gtk_grid_set_column_spacing(GTK_GRID(hbox
), 5);
478 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(help_dialog_shell
))), hbox
);
479 gtk_widget_show(hbox
);
481 /* build tree store. */
482 store
= gtk_tree_store_new(2, G_TYPE_STRING
, G_TYPE_POINTER
);
484 array
= g_array_new(FALSE
, FALSE
, sizeof(GtkTreeIter
));
485 help_items_iterate(pitem
) {
486 GtkTreeIter
*it
, *parent
;
490 for (s
= pitem
->topic
; *s
== ' '; s
++) {
493 depth
= s
- pitem
->topic
;
495 array
= g_array_set_size(array
, depth
+1);
498 parent
= &g_array_index(array
, GtkTreeIter
, depth
-1);
503 it
= &g_array_index(array
, GtkTreeIter
, depth
);
504 gtk_tree_store_append(store
, it
, parent
);
506 gtk_tree_store_set(store
, it
, 0, pitem
->topic
, 1, pitem
, -1);
507 } help_items_iterate_end
;
510 /* create tree view. */
511 help_view
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(store
));
512 g_object_unref(store
);
513 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(help_view
));
514 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(help_view
), FALSE
);
516 g_signal_connect(help_view
, "cursor-changed",
517 G_CALLBACK(activated_topic
), NULL
);
519 selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(help_view
));
520 gtk_tree_selection_set_mode(selection
, GTK_SELECTION_BROWSE
);
522 rend
= gtk_cell_renderer_text_new();
523 col
= gtk_tree_view_column_new_with_attributes(NULL
, rend
, "text", 0, NULL
);
524 gtk_tree_view_append_column(GTK_TREE_VIEW(help_view
), col
);
526 help_view_sw
= gtk_scrolled_window_new(NULL
, NULL
);
527 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(help_view_sw
),
528 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
529 gtk_widget_set_size_request(help_view_sw
, 190, -1);
530 gtk_container_add(GTK_CONTAINER(help_view_sw
), help_view
);
531 gtk_widget_show(help_view
);
532 gtk_container_add(GTK_CONTAINER(hbox
), help_view_sw
);
533 gtk_widget_show(help_view_sw
);
535 help_frame
= gtk_frame_new("");
536 gtk_container_add(GTK_CONTAINER(hbox
), help_frame
);
537 gtk_widget_set_size_request(help_frame
, 520, 350);
538 gtk_widget_show(help_frame
);
540 help_box
= gtk_grid_new();
541 gtk_grid_set_row_spacing(GTK_GRID(help_box
), 5);
542 gtk_orientable_set_orientation(GTK_ORIENTABLE(help_box
),
543 GTK_ORIENTATION_VERTICAL
);
544 gtk_container_add(GTK_CONTAINER(help_frame
), help_box
);
546 help_tile
= gtk_image_new();
547 gtk_container_add(GTK_CONTAINER(help_box
), help_tile
);
549 help_itable
= gtk_grid_new();
550 gtk_container_add(GTK_CONTAINER(help_box
), help_itable
);
552 for (i
= 0; i
< 6; i
++) {
554 gtk_label_new(help_ilabel_name
[i
] ? _(help_ilabel_name
[i
]) : "");
555 gtk_widget_set_hexpand(help_ilabel
[i
], TRUE
);
558 button
= help_hyperlink_new(help_ilabel
[i
], HELP_TECH
);
559 gtk_grid_attach(GTK_GRID(help_itable
), button
, i
, 0, 1, 1);
561 gtk_grid_attach(GTK_GRID(help_itable
), help_ilabel
[i
], i
, 0, 1, 1);
562 gtk_widget_set_name(help_ilabel
[i
], "help_label");
564 gtk_widget_show(help_ilabel
[i
]);
567 help_wtable
= gtk_grid_new();
568 gtk_container_add(GTK_CONTAINER(help_box
), help_wtable
);
570 for (i
= 0; i
< 6; i
++) {
572 gtk_label_new(help_wlabel_name
[i
] ? _(help_wlabel_name
[i
]) : "");
573 gtk_widget_set_hexpand(help_wlabel
[i
], TRUE
);
575 if (i
== 3 || i
== 5) {
576 button
= help_hyperlink_new(help_wlabel
[i
], HELP_TECH
);
577 gtk_grid_attach(GTK_GRID(help_wtable
), button
, i
, 0, 1, 1);
579 gtk_grid_attach(GTK_GRID(help_wtable
), help_wlabel
[i
], i
, 0, 1, 1);
580 gtk_widget_set_name(help_wlabel
[i
], "help_label");
582 gtk_widget_show(help_wlabel
[i
]);
586 help_utable
= gtk_grid_new();
587 gtk_container_add(GTK_CONTAINER(help_box
), help_utable
);
589 for (i
= 0; i
< 5; i
++) {
590 for (j
= 0; j
< 5; j
++) {
592 gtk_label_new(help_ulabel_name
[j
][i
] ? _(help_ulabel_name
[j
][i
]) : "");
593 gtk_widget_set_hexpand(help_ulabel
[j
][i
], TRUE
);
595 if (j
== 4 && (i
== 1 || i
== 4)) {
597 button
= help_hyperlink_new(help_ulabel
[j
][i
], HELP_TECH
);
599 button
= help_hyperlink_new(help_ulabel
[j
][i
], HELP_UNIT
);
602 gtk_grid_attach(GTK_GRID(help_utable
), button
, i
, j
, 1, 1);
604 gtk_grid_attach(GTK_GRID(help_utable
), help_ulabel
[j
][i
],
606 gtk_widget_set_name(help_ulabel
[j
][i
], "help_label");
608 gtk_widget_show(help_ulabel
[j
][i
]);
612 help_ttable
= gtk_grid_new();
613 gtk_container_add(GTK_CONTAINER(help_box
), help_ttable
);
615 for (j
= 0; j
< 4; j
++) {
616 for (i
= 0; i
< 5; i
++) {
618 gtk_label_new(help_tlabel_name
[j
][i
] ? _(help_tlabel_name
[j
][i
]) : "");
619 gtk_widget_set_hexpand(help_tlabel
[j
][i
], TRUE
);
620 gtk_widget_set_name(help_tlabel
[j
][i
], "help_label");
622 /* Ugly (but these numbers are hardcoded in help_update_terrain() too) */
623 if (j
== 1 && i
== 1) {
624 /* Extra wide cell for terrain specials */
625 gtk_grid_attach(GTK_GRID(help_ttable
), help_tlabel
[j
][i
],
627 gtk_widget_show(help_tlabel
[j
][i
]);
628 break; /* skip rest of row */
630 gtk_grid_attach(GTK_GRID(help_ttable
), help_tlabel
[j
][i
],
632 gtk_widget_show(help_tlabel
[j
][i
]);
637 help_etable
= gtk_grid_new();
638 gtk_container_add(GTK_CONTAINER(help_box
), help_etable
);
640 for (i
= 0; i
< 6; i
++) {
642 gtk_label_new(help_elabel_name
[i
] ? _(help_elabel_name
[i
]) : "");
643 gtk_widget_set_hexpand(help_elabel
[i
], TRUE
);
644 gtk_grid_attach(GTK_GRID(help_etable
), help_elabel
[i
], i
% 4, i
/ 4, 1, 1);
645 gtk_widget_set_name(help_elabel
[i
], "help_label");
646 gtk_widget_show(help_elabel
[i
]);
649 help_vbox
= gtk_grid_new();
650 gtk_grid_set_row_spacing(GTK_GRID(help_vbox
), 1);
651 gtk_orientable_set_orientation(GTK_ORIENTABLE(help_vbox
),
652 GTK_ORIENTATION_VERTICAL
);
653 gtk_widget_set_margin_start(help_vbox
, 5);
654 gtk_widget_set_margin_end(help_vbox
, 5);
655 gtk_widget_set_margin_top(help_vbox
, 5);
656 gtk_widget_set_margin_bottom(help_vbox
, 5);
657 gtk_container_add(GTK_CONTAINER(help_box
), help_vbox
);
659 text
= gtk_text_view_new();
660 gtk_widget_set_hexpand(text
, TRUE
);
661 gtk_widget_set_vexpand(text
, TRUE
);
662 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(text
), FALSE
);
663 gtk_text_view_set_editable(GTK_TEXT_VIEW(text
), FALSE
);
664 gtk_widget_set_margin_start(text
, 5);
665 gtk_widget_set_margin_end(text
, 5);
666 gtk_widget_set_margin_top(text
, 5);
667 gtk_widget_set_margin_bottom(text
, 5);
668 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text
), GTK_WRAP_WORD
);
669 gtk_widget_set_name(text
, "help_text");
670 help_text
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(text
));
671 gtk_widget_show(text
);
673 help_text_sw
= gtk_scrolled_window_new(NULL
, NULL
);
674 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(help_text_sw
),
675 GTK_POLICY_AUTOMATIC
, GTK_POLICY_ALWAYS
);
676 gtk_container_add(GTK_CONTAINER(help_text_sw
), text
);
677 gtk_container_add(GTK_CONTAINER(help_box
), help_text_sw
);
679 /* build tech store. */
680 tstore
= gtk_tree_store_new(4,
681 G_TYPE_STRING
, /* tech name */
682 G_TYPE_INT
, /* turns to tech */
683 G_TYPE_INT
, /* tech id */
684 GDK_TYPE_RGBA
); /* color */
685 help_tree
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(tstore
));
686 gtk_widget_set_hexpand(help_tree
, TRUE
);
687 gtk_widget_set_vexpand(help_tree
, TRUE
);
688 g_object_unref(tstore
);
689 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(help_tree
), FALSE
);
691 g_signal_connect(help_tree
, "row_activated",
692 G_CALLBACK(help_tech_tree_activated_callback
), NULL
);
695 col
= gtk_tree_view_column_new();
697 rend
= gtk_cell_renderer_text_new();
698 g_object_set(rend
, "weight", "bold", NULL
);
699 gtk_tree_view_column_pack_start(col
, rend
, TRUE
);
700 gtk_tree_view_column_set_attributes(col
, rend
,
702 "background-rgba", 3,
704 rend
= gtk_cell_renderer_text_new();
705 g_object_set(rend
, "weight", "bold", "xalign", 1.0, NULL
);
706 gtk_tree_view_column_pack_start(col
, rend
, FALSE
);
707 gtk_tree_view_column_set_attributes(col
, rend
,
709 "background-rgba", 3,
712 gtk_tree_view_append_column(GTK_TREE_VIEW(help_tree
), col
);
715 help_tree_sw
= gtk_scrolled_window_new(NULL
, NULL
);
716 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(help_tree_sw
),
717 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
718 gtk_container_add(GTK_CONTAINER(help_tree_sw
), help_tree
);
719 gtk_widget_show(help_tree
);
720 gtk_container_add(GTK_CONTAINER(help_box
), help_tree_sw
);
723 gtk_button_new_with_label(_("Expand All"));
724 help_tree_collapse
= gtk_button_new_with_label(_("Collapse All"));
726 g_signal_connect(help_tree_expand
, "clicked",
727 G_CALLBACK(help_tech_tree_expand_callback
), help_tree
);
728 g_signal_connect(help_tree_collapse
, "clicked",
729 G_CALLBACK(help_tech_tree_collapse_callback
), help_tree
);
731 help_tree_buttons_hbox
= gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL
);
732 gtk_container_add(GTK_CONTAINER(help_tree_buttons_hbox
), help_tree_expand
);
733 gtk_container_add(GTK_CONTAINER(help_tree_buttons_hbox
), help_tree_collapse
);
734 gtk_container_add(GTK_CONTAINER(help_box
), help_tree_buttons_hbox
);
735 gtk_widget_show(help_tree_buttons_hbox
);
737 create_help_page(HELP_TEXT
);
740 /**************************************************************************
741 Create page for help type
742 **************************************************************************/
743 static void create_help_page(enum help_page_type type
)
747 /**************************************************************************
748 Set sprite to show for current help item.
749 **************************************************************************/
750 static void set_help_tile_from_sprite(struct sprite
*spr
)
756 gtk_image_set_from_surface(GTK_IMAGE(help_tile
), spr
->surface
);
757 gtk_widget_show(help_tile
);
760 /**************************************************************************
761 Set sprite to show for current terrain.
762 **************************************************************************/
763 static void set_help_tile_from_terrain(struct terrain
*pterr
)
765 struct canvas canvas
= FC_STATIC_CANVAS_INIT
;
769 canvas
.surface
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32
,
770 tileset_tile_width(tileset
),
771 tileset_tile_height(tileset
));
773 cr
= cairo_create(canvas
.surface
);
774 cairo_set_operator(cr
, CAIRO_OPERATOR_CLEAR
);
778 for (i
= 0; i
< 3; i
++) {
779 struct drawn_sprite sprs
[80];
780 int count
= fill_basic_terrain_layer_sprite_array(tileset
, sprs
,
783 put_drawn_sprites(&canvas
, 1.0, 0, 0, count
, sprs
, FALSE
);
786 gtk_image_set_from_surface(GTK_IMAGE(help_tile
), canvas
.surface
);
787 gtk_widget_show(help_tile
);
788 cairo_surface_destroy(canvas
.surface
);
791 /**************************************************************************
792 Display updated help about improvement
793 **************************************************************************/
794 static void help_update_improvement(const struct help_item
*pitem
,
798 struct impr_type
*imp
= improvement_by_translated_name(title
);
800 create_help_page(HELP_IMPROVEMENT
);
802 if (imp
&& !is_great_wonder(imp
)) {
803 const char *req
= skip_intl_qualifier_prefix(REQ_LABEL_NONE
);
806 sprintf(buf
, "%d", impr_build_shield_cost(imp
));
807 gtk_label_set_text(GTK_LABEL(help_ilabel
[1]), buf
);
808 sprintf(buf
, "%d", imp
->upkeep
);
809 gtk_label_set_text(GTK_LABEL(help_ilabel
[3]), buf
);
811 /* FIXME: this should show ranges, negated reqs, and all the
813 * Currently it's limited to 1 req but this code is partially prepared
814 * to be extended. Remember MAX_NUM_REQS is a compile-time
816 requirement_vector_iterate(&imp
->reqs
, preq
) {
817 if (!preq
->present
) {
820 req
= universal_name_translation(&preq
->source
, req_buf
, sizeof(req_buf
));
822 } requirement_vector_iterate_end
;
823 gtk_label_set_text(GTK_LABEL(help_ilabel
[5]), req
);
824 /* create_tech_tree(help_improvement_tree, 0, imp->tech_req, 3);*/
826 gtk_label_set_text(GTK_LABEL(help_ilabel
[1]), "0");
827 gtk_label_set_text(GTK_LABEL(help_ilabel
[3]), "0");
828 gtk_label_set_text(GTK_LABEL(help_ilabel
[5]), REQ_LABEL_NEVER
);
829 /* create_tech_tree(help_improvement_tree, 0, advance_count(), 3);*/
832 set_help_tile_from_sprite(get_building_sprite(tileset
, imp
));
834 gtk_widget_show(help_itable
);
836 helptext_building(buf
, sizeof(buf
), client
.conn
.playing
, pitem
->text
, imp
);
837 gtk_text_buffer_set_text(help_text
, buf
, -1);
838 gtk_widget_show(help_text_sw
);
841 /**************************************************************************
842 Display updated help about wonder
843 **************************************************************************/
844 static void help_update_wonder(const struct help_item
*pitem
,
848 struct impr_type
*imp
= improvement_by_translated_name(title
);
850 create_help_page(HELP_WONDER
);
852 if (imp
&& is_great_wonder(imp
)) {
856 sprintf(buf
, "%d", impr_build_shield_cost(imp
));
857 gtk_label_set_text(GTK_LABEL(help_wlabel
[1]), buf
);
859 /* FIXME: this should show ranges, negated reqs, and all the
861 * Currently it's limited to 1 req but this code is partially prepared
862 * to be extended. Remember MAX_NUM_REQS is a compile-time
865 requirement_vector_iterate(&imp
->reqs
, preq
) {
866 if (!preq
->present
) {
869 gtk_label_set_text(GTK_LABEL(help_wlabel
[3 + i
]),
870 universal_name_translation(&preq
->source
,
871 req_buf
, sizeof(req_buf
)));
874 } requirement_vector_iterate_end
;
875 gtk_label_set_text(GTK_LABEL(help_wlabel
[5]), REQ_LABEL_NEVER
);
876 requirement_vector_iterate(&imp
->obsolete_by
, pobs
) {
877 if (pobs
->source
.kind
== VUT_ADVANCE
) {
878 gtk_label_set_text(GTK_LABEL(help_wlabel
[5]),
879 advance_name_translation
880 (pobs
->source
.value
.advance
));
883 } requirement_vector_iterate_end
;
884 /* create_tech_tree(help_improvement_tree, 0, imp->tech_req, 3);*/
886 /* can't find wonder */
887 gtk_label_set_text(GTK_LABEL(help_wlabel
[1]), "0");
888 gtk_label_set_text(GTK_LABEL(help_wlabel
[3]), REQ_LABEL_NEVER
);
889 gtk_label_set_text(GTK_LABEL(help_wlabel
[5]), skip_intl_qualifier_prefix(REQ_LABEL_NONE
));
890 /* create_tech_tree(help_improvement_tree, 0, advance_count(), 3); */
893 set_help_tile_from_sprite(get_building_sprite(tileset
, imp
));
895 gtk_widget_show(help_wtable
);
897 helptext_building(buf
, sizeof(buf
), client
.conn
.playing
, pitem
->text
, imp
);
898 gtk_text_buffer_set_text(help_text
, buf
, -1);
899 gtk_widget_show(help_text_sw
);
902 /**************************************************************************
903 Display updated help about unit type
904 **************************************************************************/
905 static void help_update_unit_type(const struct help_item
*pitem
,
909 struct unit_type
*utype
= unit_type_by_translated_name(title
);
911 create_help_page(HELP_UNIT
);
914 sprintf(buf
, "%d", utype_build_shield_cost(utype
));
915 gtk_label_set_text(GTK_LABEL(help_ulabel
[0][1]), buf
);
916 sprintf(buf
, "%d", utype
->attack_strength
);
917 gtk_label_set_text(GTK_LABEL(help_ulabel
[0][4]), buf
);
918 sprintf(buf
, "%d", utype
->defense_strength
);
919 gtk_label_set_text(GTK_LABEL(help_ulabel
[1][1]), buf
);
920 sprintf(buf
, "%s", move_points_text(utype
->move_rate
, TRUE
));
921 gtk_label_set_text(GTK_LABEL(help_ulabel
[1][4]), buf
);
922 sprintf(buf
, "%d", utype
->firepower
);
923 gtk_label_set_text(GTK_LABEL(help_ulabel
[2][1]), buf
);
924 sprintf(buf
, "%d", utype
->hp
);
925 gtk_label_set_text(GTK_LABEL(help_ulabel
[2][4]), buf
);
926 gtk_label_set_text(GTK_LABEL(help_ulabel
[3][1]),
927 helptext_unit_upkeep_str(utype
));
928 sprintf(buf
, "%d", (int)sqrt((double)utype
->vision_radius_sq
));
929 gtk_label_set_text(GTK_LABEL(help_ulabel
[3][4]), buf
);
930 if (A_NEVER
== utype
->require_advance
) {
931 gtk_label_set_text(GTK_LABEL(help_ulabel
[4][1]), REQ_LABEL_NEVER
);
933 gtk_label_set_text(GTK_LABEL(help_ulabel
[4][1]),
934 advance_name_translation(utype
->require_advance
));
936 /* create_tech_tree(help_improvement_tree, 0, advance_number(utype->require_advance), 3);*/
937 if (U_NOT_OBSOLETED
== utype
->obsoleted_by
) {
938 gtk_label_set_text(GTK_LABEL(help_ulabel
[4][4]), skip_intl_qualifier_prefix(REQ_LABEL_NONE
));
940 gtk_label_set_text(GTK_LABEL(help_ulabel
[4][4]),
941 utype_name_translation(utype
->obsoleted_by
));
944 helptext_unit(buf
, sizeof(buf
), client
.conn
.playing
, pitem
->text
, utype
);
946 gtk_text_buffer_set_text(help_text
, buf
, -1);
947 gtk_widget_show(help_text_sw
);
949 set_help_tile_from_sprite(get_unittype_sprite(tileset
, utype
,
950 direction8_invalid()));
952 gtk_label_set_text(GTK_LABEL(help_ulabel
[0][1]), "0");
953 gtk_label_set_text(GTK_LABEL(help_ulabel
[0][4]), "0");
954 gtk_label_set_text(GTK_LABEL(help_ulabel
[1][1]), "0");
955 gtk_label_set_text(GTK_LABEL(help_ulabel
[1][4]), "0");
956 gtk_label_set_text(GTK_LABEL(help_ulabel
[2][1]), "0");
957 gtk_label_set_text(GTK_LABEL(help_ulabel
[2][4]), "0");
958 gtk_label_set_text(GTK_LABEL(help_ulabel
[3][1]), "0");
959 gtk_label_set_text(GTK_LABEL(help_ulabel
[3][4]), "0");
961 gtk_label_set_text(GTK_LABEL(help_ulabel
[4][1]), REQ_LABEL_NEVER
);
962 /* create_tech_tree(help_improvement_tree, 0, A_LAST, 3);*/
963 gtk_label_set_text(GTK_LABEL(help_ulabel
[4][4]), skip_intl_qualifier_prefix(REQ_LABEL_NONE
));
965 gtk_text_buffer_set_text(help_text
, buf
, -1);
966 gtk_widget_show(help_text_sw
);
968 gtk_widget_show(help_utable
);
971 /**************************************************************************
972 Cut str to at max len bytes in a utf8 friendly way
973 **************************************************************************/
974 static char *fc_chomp(char *str
, size_t len
)
982 for (i
= g_utf8_find_prev_char(str
, i
);
983 (i
&& g_unichar_isspace(g_utf8_get_char(i
)));
984 i
= g_utf8_find_prev_char(str
, i
)) {
990 /**************************************************************************
991 Display updated help about tech
992 **************************************************************************/
993 static void help_update_tech(const struct help_item
*pitem
, char *title
)
998 struct advance
*padvance
= advance_by_translated_name(title
);
1000 create_help_page(HELP_TECH
);
1002 if (padvance
&& !is_future_tech(i
= advance_number(padvance
))) {
1006 gtk_container_foreach(GTK_CONTAINER(help_vbox
), (GtkCallback
)gtk_widget_destroy
, NULL
);
1008 for (j
= 0; j
< ARRAY_SIZE(help_advances
); j
++) {
1009 help_advances
[j
] = FALSE
;
1011 gtk_tree_store_clear(tstore
);
1012 create_tech_tree(i
, TECH_TREE_DEPTH
, NULL
);
1013 gtk_widget_show(help_tree_sw
);
1014 gtk_widget_show(help_tree_buttons_hbox
);
1016 helptext_advance(buf
, sizeof(buf
), client
.conn
.playing
, pitem
->text
, i
);
1020 set_help_tile_from_sprite(get_tech_sprite(tileset
, i
));
1022 w
= gtk_text_view_new();
1023 gtk_widget_set_hexpand(w
, TRUE
);
1024 gtk_widget_set_vexpand(w
, TRUE
);
1025 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(w
), FALSE
);
1026 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(w
), GTK_WRAP_WORD
);
1027 gtk_widget_set_name(w
, "help_text");
1028 gtk_widget_set_margin_start(w
, 5);
1029 gtk_widget_set_margin_end(w
, 5);
1030 gtk_widget_set_margin_top(w
, 5);
1031 gtk_widget_set_margin_bottom(w
, 5);
1032 gtk_text_view_set_editable(GTK_TEXT_VIEW(w
), FALSE
);
1033 gtk_container_add(GTK_CONTAINER(help_vbox
), w
);
1036 txt
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(w
));
1038 gtk_text_buffer_set_text(txt
, buf
, -1);
1041 w
= gtk_separator_new(GTK_ORIENTATION_HORIZONTAL
);
1042 g_object_set(w
, "margin", 5, NULL
);
1043 gtk_widget_set_hexpand(w
, TRUE
);
1044 gtk_widget_set_vexpand(w
, TRUE
);
1045 gtk_container_add(GTK_CONTAINER(help_vbox
), w
);
1048 governments_iterate(pgov
) {
1049 /* FIXME: need a more general mechanism for this, since this
1050 * helptext needs to be shown in all possible req source types. */
1051 requirement_vector_iterate(&pgov
->reqs
, preq
) {
1052 if (VUT_ADVANCE
== preq
->source
.kind
1053 && preq
->source
.value
.advance
== padvance
) {
1054 hbox
= gtk_grid_new();
1055 gtk_container_add(GTK_CONTAINER(help_vbox
), hbox
);
1056 w
= gtk_label_new(_("Allows"));
1057 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1058 w
= help_slink_new(government_name_translation(pgov
),
1060 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1061 gtk_widget_show(hbox
);
1063 } requirement_vector_iterate_end
;
1064 } governments_iterate_end
;
1066 improvement_iterate(pimprove
) {
1067 requirement_vector_iterate(&pimprove
->reqs
, preq
) {
1068 if (VUT_ADVANCE
== preq
->source
.kind
1069 && preq
->source
.value
.advance
== padvance
) {
1070 hbox
= gtk_grid_new();
1071 gtk_container_add(GTK_CONTAINER(help_vbox
), hbox
);
1072 w
= gtk_label_new(_("Allows"));
1073 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1074 w
= help_slink_new(improvement_name_translation(pimprove
),
1075 is_great_wonder(pimprove
)
1077 : HELP_IMPROVEMENT
);
1078 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1079 gtk_widget_show(hbox
);
1081 } requirement_vector_iterate_end
;
1082 requirement_vector_iterate(&pimprove
->obsolete_by
, pobs
) {
1083 if (pobs
->source
.kind
== VUT_ADVANCE
1084 && pobs
->source
.value
.advance
== padvance
) {
1085 hbox
= gtk_grid_new();
1086 gtk_container_add(GTK_CONTAINER(help_vbox
), hbox
);
1087 w
= gtk_label_new(_("Obsoletes"));
1088 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1089 w
= help_slink_new(improvement_name_translation(pimprove
),
1090 is_great_wonder(pimprove
)
1092 : HELP_IMPROVEMENT
);
1093 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1094 gtk_widget_show(hbox
);
1096 } requirement_vector_iterate_end
;
1097 } improvement_iterate_end
;
1099 unit_type_iterate(punittype
) {
1100 if (padvance
!= punittype
->require_advance
) {
1103 hbox
= gtk_grid_new();
1104 gtk_container_add(GTK_CONTAINER(help_vbox
), hbox
);
1105 w
= gtk_label_new(_("Allows"));
1106 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1107 w
= help_slink_new(utype_name_translation(punittype
), HELP_UNIT
);
1108 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1109 gtk_widget_show(hbox
);
1110 } unit_type_iterate_end
;
1112 advance_iterate(A_NONE
, ptest
) {
1113 if (padvance
== advance_requires(ptest
, AR_ONE
)) {
1114 if (advance_by_number(A_NONE
) == advance_requires(ptest
, AR_TWO
)) {
1115 hbox
= gtk_grid_new();
1116 gtk_container_add(GTK_CONTAINER(help_vbox
), hbox
);
1117 w
= gtk_label_new(_("Allows"));
1118 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1119 w
= help_slink_new(advance_name_translation(ptest
), HELP_TECH
);
1120 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1121 gtk_widget_show(hbox
);
1123 hbox
= gtk_grid_new();
1124 gtk_container_add(GTK_CONTAINER(help_vbox
), hbox
);
1125 w
= gtk_label_new(_("Allows"));
1126 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1127 w
= help_slink_new(advance_name_translation(ptest
), HELP_TECH
);
1128 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1129 w
= gtk_label_new(_("with"));
1130 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1131 w
= help_slink_new(advance_name_translation(advance_requires(ptest
, AR_TWO
)),
1133 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1134 w
= gtk_label_new(Q_("?techhelp:"));
1135 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1136 gtk_widget_show(hbox
);
1139 if (padvance
== advance_requires(ptest
, AR_TWO
)) {
1140 hbox
= gtk_grid_new();
1141 gtk_container_add(GTK_CONTAINER(help_vbox
), hbox
);
1142 w
= gtk_label_new(_("Allows"));
1143 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1144 w
= help_slink_new(advance_name_translation(ptest
), HELP_TECH
);
1145 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1146 w
= gtk_label_new(_("with"));
1147 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1148 w
= help_slink_new(advance_name_translation(advance_requires(ptest
, AR_ONE
)),
1150 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1151 w
= gtk_label_new(Q_("?techhelp:"));
1152 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1153 gtk_widget_show(hbox
);
1155 } advance_iterate_end
;
1156 gtk_widget_show(help_vbox
);
1160 /**************************************************************************
1161 Create widgets about all extras of one cause activity to the terrain.
1162 **************************************************************************/
1163 static void help_extras_of_act_for_terrain(struct terrain
*pterr
,
1164 enum unit_activity act
,
1167 enum extra_cause cause
= activity_to_extra_cause(act
);
1169 extra_type_by_cause_iterate(cause
, pextra
) {
1170 if (pextra
->buildable
1171 && requirement_fulfilled_by_terrain(pterr
, &(pextra
->reqs
))) {
1177 hbox
= gtk_grid_new();
1178 gtk_container_add(GTK_CONTAINER(help_vbox
), hbox
);
1179 w
= gtk_label_new(label
);
1180 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1181 w
= help_slink_new(extra_name_translation(pextra
), HELP_EXTRA
);
1182 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1184 btime
= terrain_extra_build_time(pterr
, act
, pextra
);
1185 fc_snprintf(buffer
, sizeof(buffer
), PL_("%d turn", "%d turns", btime
), btime
);
1186 w
= gtk_label_new(buffer
);
1187 gtk_container_add(GTK_CONTAINER(hbox
), w
);
1189 gtk_widget_show(hbox
);
1191 } extra_type_by_cause_iterate_end
;
1194 /**************************************************************************
1195 Display updated help about terrain
1196 **************************************************************************/
1197 static void help_update_terrain(const struct help_item
*pitem
,
1201 struct terrain
*pterrain
= terrain_by_translated_name(title
);
1203 create_help_page(HELP_TERRAIN
);
1206 struct universal for_terr
= { .kind
= VUT_TERRAIN
, .value
= { .terrain
= pterrain
}};
1208 set_help_tile_from_terrain(pterrain
);
1211 /* 25 => "1.25"; 50 => "1.5"; 100 => "2.0" */
1212 int defbonus
= pterrain
->defense_bonus
+ 100;
1213 int frac
= defbonus
% 100;
1215 if ((frac
% 10) == 0) {
1218 sprintf(buf
, "%d/%d.%d",
1219 pterrain
->movement_cost
, defbonus
/ 100, frac
);
1221 gtk_label_set_text(GTK_LABEL(help_tlabel
[0][1]), buf
);
1223 sprintf(buf
, "%d/%d/%d",
1224 pterrain
->output
[O_FOOD
],
1225 pterrain
->output
[O_SHIELD
],
1226 pterrain
->output
[O_TRADE
]);
1227 gtk_label_set_text(GTK_LABEL(help_tlabel
[0][4]), buf
);
1230 if (*(pterrain
->resources
)) {
1231 struct extra_type
**r
;
1233 for (r
= pterrain
->resources
; *r
; r
++) {
1234 /* TRANS: " Whales (2/1/2)," */
1235 sprintf (buf
+ strlen (buf
), " %s (%d/%d/%d),",
1236 extra_name_translation(*r
),
1237 pterrain
->output
[O_FOOD
] + (*r
)->data
.resource
->output
[O_FOOD
],
1238 pterrain
->output
[O_SHIELD
] + (*r
)->data
.resource
->output
[O_SHIELD
],
1239 pterrain
->output
[O_TRADE
] + (*r
)->data
.resource
->output
[O_TRADE
]);
1241 buf
[strlen (buf
) - 1] = '.';
1243 /* TRANS: "Resources: (none)" */
1244 sprintf (buf
+ strlen (buf
), _("(none)"));
1246 gtk_label_set_text(GTK_LABEL(help_tlabel
[1][1]), buf
);
1248 strcpy(buf
, _("n/a"));
1249 if (pterrain
->irrigation_result
!= pterrain
&& pterrain
->irrigation_result
!= T_NONE
1250 && effect_cumulative_max(EFT_IRRIG_TF_POSSIBLE
, &for_terr
) > 0) {
1251 sprintf(buf
, "%s / %d",
1252 terrain_name_translation(pterrain
->irrigation_result
),
1253 pterrain
->irrigation_time
);
1255 gtk_label_set_text(GTK_LABEL(help_tlabel
[2][1]), buf
);
1257 strcpy(buf
, _("n/a"));
1258 if (pterrain
->mining_result
!= pterrain
&& pterrain
->mining_result
!= T_NONE
1259 && effect_cumulative_max(EFT_MINING_TF_POSSIBLE
, &for_terr
) > 0) {
1260 sprintf(buf
, "%s / %d",
1261 terrain_name_translation(pterrain
->mining_result
),
1262 pterrain
->mining_time
);
1264 gtk_label_set_text(GTK_LABEL(help_tlabel
[2][4]), buf
);
1267 if (pterrain
->transform_result
!= T_NONE
1268 && effect_cumulative_max(EFT_TRANSFORM_POSSIBLE
, &for_terr
) > 0) {
1269 sprintf(buf
, "%s / %d",
1270 terrain_name_translation(pterrain
->transform_result
),
1271 pterrain
->transform_time
);
1273 gtk_label_set_text(GTK_LABEL(help_tlabel
[3][1]), buf
);
1275 gtk_container_foreach(GTK_CONTAINER(help_vbox
), (GtkCallback
)gtk_widget_destroy
, NULL
);
1276 if (pterrain
->irrigation_result
== pterrain
1277 && effect_cumulative_max(EFT_IRRIG_POSSIBLE
, &for_terr
) > 0) {
1278 help_extras_of_act_for_terrain(pterrain
, ACTIVITY_IRRIGATE
, _("Build as irrigation"));
1280 if (pterrain
->mining_result
== pterrain
1281 && effect_cumulative_max(EFT_MINING_POSSIBLE
, &for_terr
) > 0) {
1282 help_extras_of_act_for_terrain(pterrain
, ACTIVITY_MINE
, _("Build as mine"));
1284 help_extras_of_act_for_terrain(pterrain
, ACTIVITY_GEN_ROAD
, _("Build as road"));
1285 help_extras_of_act_for_terrain(pterrain
, ACTIVITY_BASE
, _("Build as base"));
1286 gtk_widget_show(help_vbox
);
1289 helptext_terrain(buf
, sizeof(buf
), client
.conn
.playing
, pitem
->text
, pterrain
);
1291 gtk_text_buffer_set_text(help_text
, buf
, -1);
1292 gtk_widget_show(help_text_sw
);
1294 gtk_widget_show(help_ttable
);
1297 /**************************************************************************
1298 Help page for extras.
1299 **************************************************************************/
1300 static void help_update_extra(const struct help_item
*pitem
, char *title
)
1303 struct extra_type
*pextra
= extra_type_by_translated_name(title
);
1305 create_help_page(HELP_EXTRA
);
1308 if (pextra
== NULL
) {
1309 strcat(buf
, pitem
->text
);
1311 struct road_type
*proad
= extra_road_get(pextra
);
1312 bool is_resource
= is_extra_caused_by(pextra
, EC_RESOURCE
);
1315 if (pextra
->buildable
) {
1316 if (pextra
->build_time
!= 0) {
1317 /* TRANS: "MP" = movement points */
1318 sprintf(buf
, _("%d MP"), pextra
->build_time
);
1320 /* TRANS: Build time depends on terrain. */
1321 sprintf(buf
, _("Terrain specific"));
1326 gtk_label_set_text(GTK_LABEL(help_elabel
[1]), buf
);
1327 /* Conflicting extras */
1330 /* TRANS: (Resource extra) Conflicts with: */
1331 strcat(buf
, _("Other Resources"));
1333 extra_type_iterate(pextra2
) {
1334 if (!can_extras_coexist(pextra
, pextra2
)
1335 && (!is_resource
|| !is_extra_caused_by(pextra2
, EC_RESOURCE
))) {
1336 if (buf
[0] != '\0') {
1339 strcat(buf
, extra_name_translation(pextra2
));
1341 } extra_type_iterate_end
;
1342 /* TRANS: "Conflicts with: (none)" (extras) */
1343 gtk_label_set_text(GTK_LABEL(help_elabel
[3]), buf
[0] ? buf
: _("(none)"));
1346 if (proad
!= NULL
) {
1347 const char *bonus
= NULL
;
1349 output_type_iterate(o
) {
1350 if (proad
->tile_incr
[o
] > 0) {
1351 /* TRANS: Road bonus depends on terrain. */
1352 bonus
= _("Terrain specific");
1355 } output_type_iterate_end
;
1357 bonus
= helptext_road_bonus_str(NULL
, proad
);
1360 /* TRANS: No output bonus from a road */
1361 bonus
= Q_("?bonus:None");
1363 gtk_label_set_text(GTK_LABEL(help_elabel
[5]), bonus
);
1365 gtk_label_set_text(GTK_LABEL(help_elabel
[5]), Q_("?bonus:None"));
1368 helptext_extra(buf
, sizeof(buf
), client
.conn
.playing
, pitem
->text
, pextra
);
1370 gtk_widget_show(help_etable
);
1372 gtk_text_buffer_set_text(help_text
, buf
, -1);
1373 gtk_widget_show(help_text_sw
);
1376 /**************************************************************************
1377 This is currently just a text page, with special text:
1378 **************************************************************************/
1379 static void help_update_goods(const struct help_item
*pitem
,
1383 struct goods_type
*pgood
= goods_by_translated_name(title
);
1385 create_help_page(HELP_GOODS
);
1388 strcat(buf
, pitem
->text
);
1390 helptext_goods(buf
, sizeof(buf
), client
.conn
.playing
, pitem
->text
,
1393 create_help_page(HELP_GOODS
);
1394 gtk_text_buffer_set_text(help_text
, buf
, -1);
1395 gtk_widget_show(help_text_sw
);
1398 /**************************************************************************
1399 This is currently just a text page, with special text:
1400 **************************************************************************/
1401 static void help_update_specialist(const struct help_item
*pitem
,
1405 struct specialist
*pspec
= specialist_by_translated_name(title
);
1408 strcat(buf
, pitem
->text
);
1410 helptext_specialist(buf
, sizeof(buf
), client
.conn
.playing
, pitem
->text
,
1413 create_help_page(HELP_TEXT
);
1414 gtk_text_buffer_set_text(help_text
, buf
, -1);
1415 gtk_widget_show(help_text_sw
);
1418 /**************************************************************************
1419 This is currently just a text page, with special text:
1420 **************************************************************************/
1421 static void help_update_government(const struct help_item
*pitem
,
1425 struct government
*gov
= government_by_translated_name(title
);
1428 strcat(buf
, pitem
->text
);
1430 helptext_government(buf
, sizeof(buf
), client
.conn
.playing
, pitem
->text
, gov
);
1432 create_help_page(HELP_TEXT
);
1433 gtk_text_buffer_set_text(help_text
, buf
, -1);
1434 gtk_widget_show(help_text_sw
);
1437 /**************************************************************************
1438 This is currently just a text page, with special text
1439 **************************************************************************/
1440 static void help_update_nation(const struct help_item
*pitem
, char *title
,
1441 struct nation_type
*pnation
)
1446 strcat(buf
, pitem
->text
);
1448 helptext_nation(buf
, sizeof(buf
), pnation
, pitem
->text
);
1450 create_help_page(HELP_TEXT
);
1451 gtk_text_buffer_set_text(help_text
, buf
, -1);
1452 gtk_widget_show(help_text_sw
);
1455 /**************************************************************************
1456 Display updated help dialog
1457 **************************************************************************/
1458 static void help_update_dialog(const struct help_item
*pitem
)
1462 /* figure out what kind of item is required for pitem ingo */
1464 for (top
= pitem
->topic
; *top
== ' '; top
++) {
1469 gtk_text_buffer_set_text(help_text
, "", -1);
1471 switch(pitem
->type
) {
1472 case HELP_IMPROVEMENT
:
1473 help_update_improvement(pitem
, top
);
1476 help_update_wonder(pitem
, top
);
1479 help_update_unit_type(pitem
, top
);
1482 help_update_tech(pitem
, top
);
1485 help_update_terrain(pitem
, top
);
1488 help_update_extra(pitem
, top
);
1491 help_update_goods(pitem
, top
);
1493 case HELP_SPECIALIST
:
1494 help_update_specialist(pitem
, top
);
1496 case HELP_GOVERNMENT
:
1497 help_update_government(pitem
, top
);
1500 help_update_nation(pitem
, top
, nation_by_translated_plural(top
));
1504 /* it was a pure text item */
1505 create_help_page(HELP_TEXT
);
1507 gtk_text_buffer_set_text(help_text
, pitem
->text
, -1);
1508 gtk_widget_show(help_text_sw
);
1511 set_title_topic(pitem
->topic
);
1513 gtk_widget_show(help_box
);
1516 /**************************************************************************
1517 Add item at path to selection and scroll to its cell
1518 **************************************************************************/
1519 static void help_item_zoom(GtkTreePath
*path
)
1521 GtkTreeModel
*model
;
1522 GtkTreeIter it
, child
, item
;
1523 GtkTreeSelection
*selection
;
1525 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(help_view
));
1526 gtk_tree_model_get_iter(model
, &item
, path
);
1528 for (child
=item
; gtk_tree_model_iter_parent(model
, &it
, &child
); child
=it
) {
1529 GtkTreePath
*it_path
;
1531 it_path
= gtk_tree_model_get_path(model
, &it
);
1532 gtk_tree_view_expand_row(GTK_TREE_VIEW(help_view
), it_path
, TRUE
);
1533 gtk_tree_path_free(it_path
);
1536 selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(help_view
));
1537 gtk_tree_selection_select_iter(selection
, &item
);
1538 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(help_view
), path
, NULL
,
1542 /****************************************************************
1543 Return path to help item.
1544 *****************************************************************/
1545 static GtkTreePath
*help_item_path(const struct help_item
*pitem
)
1550 path
= gtk_tree_path_new_first();
1552 help_items_iterate(pitem2
) {
1556 for (s
= pitem2
->topic
; *s
== ' '; s
++) {
1559 depth
= s
- pitem2
->topic
+ 1;
1561 while (depth
< gtk_tree_path_get_depth(path
)) {
1562 gtk_tree_path_up(path
);
1563 gtk_tree_path_next(path
);
1566 while (depth
> gtk_tree_path_get_depth(path
)) {
1567 gtk_tree_path_down(path
);
1572 gtk_tree_path_next(path
);
1575 if (pitem
== pitem2
)
1579 } help_items_iterate_end
;
1584 /****************************************************************
1585 Add item to selection
1586 *****************************************************************/
1587 static void select_help_item_string(const char *item
, enum help_page_type htype
)
1589 const struct help_item
*pitem
;
1592 GtkTreeViewColumn
*col
;
1594 if (!(pitem
= get_help_item_spec(item
, htype
, &idx
))) {
1598 path
= help_item_path(pitem
);
1599 help_item_zoom(path
);
1601 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(help_view
), 0);
1602 gtk_tree_view_set_cursor(GTK_TREE_VIEW(help_view
), path
, col
, FALSE
);
1603 gtk_tree_path_free(path
);
1606 /**************************************************************************
1607 Set sensitivity of help dialog response buttons.
1608 **************************************************************************/
1609 static void help_command_update(void)
1611 GtkDialog
*dialog
= GTK_DIALOG(help_dialog_shell
);
1613 if (help_history_pos
< 0) {
1614 gtk_dialog_set_response_sensitive(dialog
, 1, FALSE
);
1615 gtk_dialog_set_response_sensitive(dialog
, 2, FALSE
);
1617 gtk_dialog_set_response_sensitive(dialog
, 1, TRUE
);
1618 gtk_dialog_set_response_sensitive(dialog
, 2, TRUE
);
1620 if (help_history_pos
== 0) {
1621 gtk_dialog_set_response_sensitive(dialog
, 1, FALSE
);
1623 if (help_history_pos
>= help_history
->len
- 1) {
1624 gtk_dialog_set_response_sensitive(dialog
, 2, FALSE
);
1629 /**************************************************************************
1630 User gave response to help dialog
1631 **************************************************************************/
1632 static void help_command_callback(GtkWidget
*w
, gint response_id
)
1635 const struct help_item
*pitem
;
1637 if (response_id
== 1) {
1638 if (help_history_pos
> 0) {
1641 pitem
= g_ptr_array_index(help_history
, help_history_pos
);
1642 path
= help_item_path(pitem
);
1643 help_item_zoom(path
);
1644 help_update_dialog(pitem
);
1645 help_command_update();
1647 } else if (response_id
== 2) {
1648 if (help_history_pos
< help_history
->len
- 1) {
1651 pitem
= g_ptr_array_index(help_history
, help_history_pos
);
1652 path
= help_item_path(pitem
);
1653 help_item_zoom(path
);
1654 help_update_dialog(pitem
);
1655 help_command_update();
1658 gtk_widget_destroy(help_dialog_shell
);