Freeciv-3.1
Loading...
Searching...
No Matches
dialogs.c
Go to the documentation of this file.
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#include <stdarg.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22
23#include <gtk/gtk.h>
24#include <gdk/gdkkeysyms.h>
25
26/* utility */
27#include "astring.h"
28#include "bitvector.h"
29#include "fcintl.h"
30#include "log.h"
31#include "mem.h"
32#include "rand.h"
33#include "support.h"
34
35/* common */
36#include "game.h"
37#include "government.h"
38#include "map.h"
39#include "packets.h"
40#include "player.h"
41
42/* client */
43#include "client_main.h"
44#include "climisc.h"
45#include "connectdlg_common.h"
46#include "control.h"
47#include "helpdata.h" /* for helptext_nation() */
48#include "goto.h"
49#include "options.h"
50#include "packhand.h"
51#include "text.h"
52#include "tilespec.h"
53
54/* client/gui-gtk-3.0 */
55#include "chatline.h"
56#include "choice_dialog.h"
57#include "citydlg.h"
58#include "editprop.h"
59#include "graphics.h"
60#include "gui_main.h"
61#include "gui_stuff.h"
62#include "mapview.h"
63#include "plrdlg.h"
64#include "wldlg.h"
65#include "unitselect.h"
66#include "unitselextradlg.h"
67
68#include "dialogs.h"
69
70/******************************************************************/
71static GtkWidget *races_shell;
72static GtkWidget *nationsets_chooser;
74/* One entry per nation group, plus one at the end for 'all nations' */
76static GtkWidget *races_notebook;
77static GtkWidget *races_properties;
78static GtkWidget *races_leader;
79static GtkWidget *races_sex[2];
80static GtkWidget *races_style_list;
81static GtkTextBuffer *races_text;
82
83static void create_races_dialog(struct player *pplayer);
84static void races_response(GtkWidget *w, gint response, gpointer data);
85static void races_nation_callback(GtkTreeSelection *select, gpointer data);
86static void races_leader_callback(void);
87static void races_sex_callback(GtkWidget *w, gpointer data);
88static void races_style_callback(GtkTreeSelection *select, gpointer data);
89static gboolean races_selection_func(GtkTreeSelection *select,
90 GtkTreeModel *model, GtkTreePath *path,
91 gboolean selected, gpointer data);
92
93static int selected_nation;
94static int selected_sex;
95static int selected_style;
96
98
99/**********************************************************************/
102void popup_notify_dialog(const char *caption, const char *headline,
103 const char *lines)
104{
105 static struct gui_dialog *shell;
106 GtkWidget *vbox, *label, *headline_label, *sw;
107
108 gui_dialog_new(&shell, GTK_NOTEBOOK(bottom_notebook), NULL, TRUE);
110
111 gui_dialog_add_button(shell, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
112 gui_dialog_set_default_response(shell, GTK_RESPONSE_CLOSE);
113
114 vbox = gtk_grid_new();
115 gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox),
116 GTK_ORIENTATION_VERTICAL);
117 gtk_grid_set_row_spacing(GTK_GRID(vbox), 2);
118 gtk_container_add(GTK_CONTAINER(shell->vbox), vbox);
119
120 headline_label = gtk_label_new(headline);
121 gtk_container_add(GTK_CONTAINER(vbox), headline_label);
122 gtk_widget_set_name(headline_label, "notify_label");
123
124 gtk_label_set_justify(GTK_LABEL(headline_label), GTK_JUSTIFY_LEFT);
125 gtk_widget_set_halign(headline_label, GTK_ALIGN_START);
126 gtk_widget_set_valign(headline_label, GTK_ALIGN_START);
127
128 sw = gtk_scrolled_window_new(NULL, NULL);
129 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
130 GTK_SHADOW_ETCHED_IN);
131 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
132 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
133 label = gtk_label_new(lines);
134 gtk_widget_set_hexpand(label, TRUE);
135 gtk_widget_set_vexpand(label, TRUE);
136 gtk_container_add(GTK_CONTAINER(sw), label);
137
138 gtk_widget_set_name(label, "notify_label");
139 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
140 gtk_widget_set_halign(label, GTK_ALIGN_START);
141 gtk_widget_set_valign(label, GTK_ALIGN_START);
142
143 gtk_container_add(GTK_CONTAINER(vbox), sw);
144
146
149
150 shell = NULL;
151}
152
153/**********************************************************************/
157static void notify_goto_response(GtkWidget *w, gint response)
158{
159 struct city *pcity = NULL;
160 struct tile *ptile = g_object_get_data(G_OBJECT(w), "tile");
161
162 switch (response) {
163 case 1:
165 break;
166 case 2:
167 pcity = tile_city(ptile);
168
171 }
172
173 if (pcity) {
174 popup_city_dialog(pcity);
175 }
176 break;
177 }
178 gtk_widget_destroy(w);
179}
180
181/**********************************************************************/
184static void notify_connect_msg_response(GtkWidget *w, gint response)
185{
186 gtk_widget_destroy(w);
187}
188
189/**********************************************************************/
194void popup_notify_goto_dialog(const char *headline, const char *lines,
195 const struct text_tag_list *tags,
196 struct tile *ptile)
197{
198 GtkWidget *shell, *label, *goto_command, *popcity_command;
199
200 shell = gtk_dialog_new();
201 gtk_window_set_title(GTK_WINDOW(shell), headline);
203 gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_CLOSE);
204 gtk_window_set_position(GTK_WINDOW(shell), GTK_WIN_POS_CENTER_ON_PARENT);
205
206 label = gtk_label_new(lines);
207 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(shell))), label);
208 gtk_widget_show(label);
209
210 goto_command = gtk_stockbutton_new(GTK_STOCK_JUMP_TO,
211 _("Goto _Location"));
212 gtk_dialog_add_action_widget(GTK_DIALOG(shell), goto_command, 1);
213 gtk_widget_show(goto_command);
214
215 popcity_command = gtk_stockbutton_new(GTK_STOCK_ZOOM_IN,
216 _("I_nspect City"));
217 gtk_dialog_add_action_widget(GTK_DIALOG(shell), popcity_command, 2);
218 gtk_widget_show(popcity_command);
219
220 gtk_dialog_add_button(GTK_DIALOG(shell), GTK_STOCK_CLOSE,
221 GTK_RESPONSE_CLOSE);
222
223 if (!ptile) {
224 gtk_widget_set_sensitive(goto_command, FALSE);
225 gtk_widget_set_sensitive(popcity_command, FALSE);
226 } else {
227 struct city *pcity;
228
229 pcity = tile_city(ptile);
230 gtk_widget_set_sensitive(popcity_command,
231 (NULL != pcity && city_owner(pcity) == client.conn.playing));
232 }
233
234 g_object_set_data(G_OBJECT(shell), "tile", ptile);
235
236 g_signal_connect(shell, "response", G_CALLBACK(notify_goto_response), NULL);
237 gtk_widget_show(shell);
238}
239
240/**********************************************************************/
243void popup_connect_msg(const char *headline, const char *message)
244{
245 GtkWidget *shell, *label;
246
247 shell = gtk_dialog_new();
248 gtk_window_set_title(GTK_WINDOW(shell), headline);
250 gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_CLOSE);
251 gtk_window_set_position(GTK_WINDOW(shell), GTK_WIN_POS_CENTER_ON_PARENT);
252
253 label = gtk_label_new(message);
254 gtk_label_set_selectable(GTK_LABEL(label), 1);
255
256 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(shell))), label);
257 gtk_widget_show(label);
258
259 gtk_dialog_add_button(GTK_DIALOG(shell), GTK_STOCK_CLOSE,
260 GTK_RESPONSE_CLOSE);
261
262 g_signal_connect(shell, "response", G_CALLBACK(notify_connect_msg_response),
263 NULL);
264 gtk_widget_show(shell);
265}
266
267/**********************************************************************/
270static void revolution_response(GtkWidget *w, gint response, gpointer data)
271{
272 struct government *government = data;
273
274 if (response == GTK_RESPONSE_YES) {
275 if (!government) {
277 } else {
279 }
280 }
281 if (w) {
282 gtk_widget_destroy(w);
283 }
284}
285
286/**********************************************************************/
290{
291 static GtkWidget *shell = NULL;
292
294 if (!shell) {
295 shell = gtk_message_dialog_new(NULL,
296 0,
297 GTK_MESSAGE_WARNING,
298 GTK_BUTTONS_YES_NO,
299 _("You say you wanna revolution?"));
300 gtk_window_set_title(GTK_WINDOW(shell), _("Revolution!"));
302
303 g_signal_connect(shell, "destroy",
304 G_CALLBACK(gtk_widget_destroyed), &shell);
305 }
306 g_signal_connect(shell, "response",
307 G_CALLBACK(revolution_response), government);
308
309 gtk_window_present(GTK_WINDOW(shell));
310 } else {
311 revolution_response(shell, GTK_RESPONSE_YES, government);
312 }
313}
314
315/**********************************************************************/
318static void pillage_callback(GtkWidget *dlg, gint arg)
319{
321
322 if (arg == GTK_RESPONSE_YES) {
323 int au_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dlg),
324 "actor"));
325 struct unit *actor = game_unit_by_number(au_id);
326
327 int tgt_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dlg),
328 "target"));
329 struct extra_type *tgt_extra = extra_by_number(tgt_id);
330
331 if (actor && tgt_extra) {
333 tgt_extra);
334 }
335 }
336
337 gtk_widget_destroy(dlg);
338}
339
340/**********************************************************************/
343void popup_pillage_dialog(struct unit *punit, bv_extras extras)
344{
346 /* Possibly legal target extras. */
347 bv_extras alternative;
348 /* Selected by default. */
349 struct extra_type *preferred_tgt;
350 /* Current target to check. */
351 struct extra_type *tgt;
352
354
355 BV_CLR_ALL(alternative);
356 preferred_tgt = get_preferred_pillage(extras);
357
358 while ((tgt = get_preferred_pillage(extras))) {
359 int what;
360
361 what = extra_index(tgt);
362 BV_CLR(extras, what);
363 BV_SET(alternative, what);
364 }
365
366 select_tgt_extra(punit, unit_tile(punit), alternative, preferred_tgt,
367 /* TRANS: Pillage dialog title. */
368 _("What To Pillage"),
369 /* TRANS: Pillage dialog actor text. */
370 _("Looking for target extra:"),
371 /* TRANS: Pillage dialog target text. */
372 _("Select what to pillage:"),
373 /* TRANS: Pillage dialog do button text. */
374 _("Pillage"), G_CALLBACK(pillage_callback));
375 }
376}
377
378/**********************************************************************/
383{
385}
386
387/**********************************************************************/
395
396/**************************************************************************
397 NATION SELECTION DIALOG
398**************************************************************************/
399/**********************************************************************/
404static GtkTreePath *path_to_nation_on_list(Nation_type_id nation,
405 GtkTreeView *list)
406{
407 if (nation == -1 || list == NULL) {
408 return NULL;
409 } else {
410 GtkTreeModel *model = gtk_tree_view_get_model(list);
411 GtkTreeIter iter;
412 GtkTreePath *path = NULL;
413 gtk_tree_model_get_iter_first(model, &iter);
414 do {
415 int nation_of_row;
416 gtk_tree_model_get(model, &iter, 0, &nation_of_row, -1);
417 if (nation == nation_of_row) {
418 path = gtk_tree_model_get_path(model, &iter);
419 break;
420 }
421 } while (gtk_tree_model_iter_next(model, &iter));
422 return path;
423 }
424}
425
426/**********************************************************************/
432static void select_nation_on_tab(GtkWidget *tab_list, int nation)
433{
434 /* tab_list is a GtkTreeView (not its enclosing GtkScrolledWindow). */
435 GtkTreeView *list = GTK_TREE_VIEW(tab_list);
436 GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
437 GtkTreePath *path = path_to_nation_on_list(nation, list);
438
439 /* Suppress normal effects of selection change to avoid loops. */
440 g_signal_handlers_block_by_func(select, races_nation_callback, NULL);
441 if (path) {
442 /* Found nation on this list. */
443 /* Avoid disturbing tabs that already have the correct selection. */
444 if (!gtk_tree_selection_path_is_selected(select, path)) {
445 /* Set cursor -- this will cause the nation to be selected */
446 gtk_tree_view_set_cursor(list, path, NULL, FALSE);
447 /* Make sure selected nation is visible in list */
448 gtk_tree_view_scroll_to_cell(list, path, NULL, FALSE, 0, 0);
449 }
450 } else {
451 /* Either no nation was selected, or the nation is not mentioned in
452 * this tab. Either way we want to end up with no selection. */
453 GtkTreePath *cursorpath;
454
455 /* If there is no cursor, Gtk tends to focus and select the first row
456 * at the first opportunity, disturbing any existing state. We want to
457 * allow the no-rows-selected state, so detect this case and defuse
458 * it by setting a cursor. */
459 gtk_tree_view_get_cursor(list, &cursorpath, NULL);
460 /* Set the cursor in the case above, or if there was a previous
461 * selection */
462 if (!cursorpath || gtk_tree_selection_get_selected(select, NULL, NULL)) {
463 cursorpath = gtk_tree_path_new_first();
464 gtk_tree_view_set_cursor(list, cursorpath, NULL, FALSE);
465 }
466 gtk_tree_selection_unselect_all(select);
467 gtk_tree_path_free(cursorpath);
468 }
469 gtk_tree_path_free(path);
470 /* Re-enable selection change side-effects */
471 g_signal_handlers_unblock_by_func(select, races_nation_callback, NULL);
472}
473
474/**********************************************************************/
477static void sync_tabs_to_nation(int nation)
478{
479 /* Ensure that all tabs are in sync with the new selection */
480 int i;
481
482 for (i = 0; i <= nation_group_count(); i++) {
483 if (races_nation_list[i]) {
485 }
486 }
487}
488
489/**********************************************************************/
493static void populate_leader_list(void)
494{
495 int i;
496 GtkListStore *model =
497 GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(races_leader)));
498
499 i = 0;
500 gtk_list_store_clear(model);
501 if (selected_nation >= 0) {
503 (selected_nation)), pleader) {
504 const char *leader_name = nation_leader_name(pleader);
505 GtkTreeIter iter; /* unused */
506
507 gtk_list_store_insert_with_values(model, &iter, i, 0, leader_name, -1);
508 i++;
510 }
511}
512
513/**********************************************************************/
519static void select_nation(int nation,
520 const char *leadername, bool is_male,
521 int style_id)
522{
523 selected_nation = nation;
524
525 /* Refresh the available leaders. */
527
528 if (selected_nation != -1) {
529
530 /* Select leader name and sex. */
531 if (leadername) {
532 gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(races_leader))),
533 leadername);
534 /* Assume is_male is valid too. */
535 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(races_sex[is_male]),
536 TRUE);
537 } else {
538 int idx = fc_rand(nation_leader_list_size(
540
541 gtk_combo_box_set_active(GTK_COMBO_BOX(races_leader), idx);
542 /* This also updates the leader sex, eventually. */
543 }
544
545 /* Select the appropriate city style entry. */
546 {
547 int i;
548 int j = 0;
549 GtkTreePath *path;
550
551 styles_iterate(pstyle) {
552 i = basic_city_style_for_style(pstyle);
553
554 if (i >= 0 && i < style_id) {
555 j++;
556 } else {
557 break;
558 }
560
561 path = gtk_tree_path_new();
562 gtk_tree_path_append_index(path, j);
563 gtk_tree_view_set_cursor(GTK_TREE_VIEW(races_style_list), path,
564 NULL, FALSE);
565 gtk_tree_path_free(path);
566 }
567
568 /* Update nation description. */
569 {
570 char buf[4096];
571
572 helptext_nation(buf, sizeof(buf),
574 gtk_text_buffer_set_text(races_text, buf, -1);
575 }
576
577 gtk_widget_set_sensitive(races_properties, TRUE);
578 /* Once we've made a nation selection, allow user to ok */
579 gtk_dialog_set_response_sensitive(GTK_DIALOG(races_shell),
580 GTK_RESPONSE_ACCEPT, TRUE);
581 } else {
582 /* No nation selected. Blank properties and make controls insensitive. */
583 /* Leader name */
584 gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(races_leader))),
585 "");
586 /* Leader sex (*shrug*) */
587 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(races_sex[0]), TRUE);
588 /* City style */
589 {
590 GtkTreeSelection* select
591 = gtk_tree_view_get_selection(GTK_TREE_VIEW(races_style_list));
592
593 gtk_tree_selection_unselect_all(select);
594 }
595 /* Nation description */
596 gtk_text_buffer_set_text(races_text, "", 0);
597
598 gtk_widget_set_sensitive(races_properties, FALSE);
599 /* Don't allow OK without a selection
600 * (user can still do "Random Nation") */
601 gtk_dialog_set_response_sensitive(GTK_DIALOG(races_shell),
602 GTK_RESPONSE_ACCEPT, FALSE);
603 }
604
605 /* Update notebook to reflect the current selection */
607}
608
609/**********************************************************************/
615static GtkWidget* create_list_of_nations_in_group(struct nation_group* group,
616 int index)
617{
618 GtkWidget *sw = NULL;
619 GtkListStore *store = NULL;
620 GtkWidget *list = NULL;
621
622 /* Populate nation list store. */
623 nations_iterate(pnation) {
624 bool used;
625 GdkPixbuf *img;
626 GtkTreeIter it;
627 GValue value = { 0, };
628
629 if (!is_nation_playable(pnation) || !is_nation_pickable(pnation)) {
630 continue;
631 }
632
633 if (NULL != group && !nation_is_in_group(pnation, group)) {
634 continue;
635 }
636
637 /* Only create tab on demand -- we don't want it if there aren't any
638 * currently pickable nations in this group. */
639 if (sw == NULL) {
640 GtkTreeSelection *select;
641 GtkCellRenderer *render;
642 GtkTreeViewColumn *column;
643
644 store = gtk_list_store_new(4, G_TYPE_INT, G_TYPE_BOOLEAN,
645 GDK_TYPE_PIXBUF, G_TYPE_STRING);
646 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store),
647 3, GTK_SORT_ASCENDING);
648
649 list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
650 gtk_widget_set_hexpand(list, TRUE);
651 gtk_widget_set_vexpand(list, TRUE);
652 gtk_tree_view_set_search_column(GTK_TREE_VIEW(list), 3);
653 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), FALSE);
654 g_object_unref(store);
655
656 select = gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
657 g_signal_connect(select, "changed", G_CALLBACK(races_nation_callback),
658 NULL);
659 gtk_tree_selection_set_select_function(select, races_selection_func,
660 NULL, NULL);
661
662 sw = gtk_scrolled_window_new(NULL, NULL);
663 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
664 GTK_SHADOW_ETCHED_IN);
665 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
666 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
667 gtk_container_add(GTK_CONTAINER(sw), list);
668
669 render = gtk_cell_renderer_pixbuf_new();
670 column = gtk_tree_view_column_new_with_attributes("Flag", render,
671 "pixbuf", 2, NULL);
672 gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
673 render = gtk_cell_renderer_text_new();
674 column = gtk_tree_view_column_new_with_attributes("Nation", render,
675 "text", 3, "strikethrough", 1, NULL);
676 gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
677 }
678
679 gtk_list_store_append(store, &it);
680
681 used = (pnation->player != NULL && pnation->player != races_player);
682 gtk_list_store_set(store, &it, 0, nation_number(pnation), 1, used, -1);
683 img = get_flag(pnation);
684 if (img != NULL) {
685 gtk_list_store_set(store, &it, 2, img, -1);
686 g_object_unref(img);
687 }
688
689 g_value_init(&value, G_TYPE_STRING);
690 g_value_set_static_string(&value, nation_adjective_translation(pnation));
691 gtk_list_store_set_value(store, &it, 3, &value);
692 g_value_unset(&value);
694
695 races_nation_list[index] = list;
696 return sw;
697}
698
699/**********************************************************************/
703{
704 GtkWidget *nation_list;
705 GtkWidget *group_name_label;
706 int i;
707
708 for (i = 0; i < nation_group_count(); i++) {
709 struct nation_group* group = (nation_group_by_number(i));
710
711 if (is_nation_group_hidden(group)) {
712 races_nation_list[i] = NULL;
713 continue;
714 }
715 nation_list = create_list_of_nations_in_group(group, i);
716 if (nation_list) {
717 group_name_label = gtk_label_new(nation_group_name_translation(group));
718 gtk_notebook_append_page(GTK_NOTEBOOK(races_notebook), nation_list,
719 group_name_label);
720 }
721 }
722
724 /* Even this list can be empty if there are no pickable nations (due to
725 * a combination of start position and nationset restrictions). */
726 if (nation_list) {
727 group_name_label = gtk_label_new(_("All"));
728 gtk_notebook_append_page(GTK_NOTEBOOK(races_notebook), nation_list,
729 group_name_label);
730 }
731}
732
733/**********************************************************************/
737void races_update_pickable(bool nationset_change)
738{
739 int tab, groupidx;
740
741 if (!races_shell) {
742 return;
743 }
744
745 /* Save selected tab */
746 tab = gtk_notebook_get_current_page(GTK_NOTEBOOK(races_notebook));
747 if (tab != -1) {
748 int i = 0;
749
750 groupidx = 0;
751 /* Turn tab index into a nation group index (they're not always equal,
752 * as some groups may not currently have tabs). */
753 do {
754 while (groupidx <= nation_group_count()
755 && races_nation_list[groupidx] == NULL) {
756 groupidx++;
757 }
758 fc_assert_action(groupidx <= nation_group_count(), break);
759 /* Nation group 'groupidx' is what's displayed on the i'th tab */
760 if (i == tab) {
761 break;
762 }
763 i++;
764 groupidx++;
765 } while (TRUE);
766 } else {
767 /* No tabs currently */
768 groupidx = -1;
769 }
770
771 /* selected_nation already contains currently selected nation; however,
772 * it may no longer be a valid choice */
773 if (selected_nation != -1
775 select_nation(-1, NULL, FALSE, 0);
776 }
777
778 /* Delete all list stores, treeviews, tabs */
779 while (gtk_notebook_get_n_pages(GTK_NOTEBOOK(races_notebook)) > 0) {
780 gtk_notebook_remove_page(GTK_NOTEBOOK(races_notebook), -1);
781 }
782
783 /* (Re)create all of them */
785
786 /* Can't set current tab before child widget is visible */
787 gtk_widget_show_all(GTK_WIDGET(races_notebook));
788
789 /* Restore selected tab */
790 if (groupidx != -1 && races_nation_list[groupidx] != NULL) {
791 int i;
792
793 tab = 0;
794 for (i = 0; i < groupidx; i++) {
795 if (races_nation_list[i] != NULL) {
796 tab++;
797 }
798 }
799 gtk_notebook_set_current_page(GTK_NOTEBOOK(races_notebook), tab);
800 }
801
802 /* Restore selected nation */
804}
805
806/**********************************************************************/
809void nationset_sync_to_server(const char *nationset)
810{
811 if (nationsets_chooser) {
812 struct nation_set *set = nation_set_by_setting_value(nationset);
813
814 gtk_combo_box_set_active(GTK_COMBO_BOX(nationsets_chooser),
815 nation_set_index(set));
816 }
817}
818
819/**********************************************************************/
822static void nationset_callback(GtkComboBox *b, gpointer data)
823{
824 GtkTreeIter iter;
825 if (gtk_combo_box_get_active_iter(b, &iter)) {
826 struct option *poption = optset_option_by_name(server_optset, "nationset");
827 gchar *rule_name;
828
829 gtk_tree_model_get(gtk_combo_box_get_model(b), &iter,
830 0, &rule_name, -1);
831 /* Suppress propagation of an option value equivalent to the current
832 * server state, after canonicalisation, to avoid loops from
833 * nationset_sync_to_server().
834 * (HACK: relies on local Gtk "changed" signal getting here before
835 * server response.) */
837 != nation_set_by_rule_name(rule_name)) {
838 option_str_set(poption, rule_name);
839 }
840 FC_FREE(rule_name);
841 }
842}
843
844/**********************************************************************/
847static void create_races_dialog(struct player *pplayer)
848{
849 GtkWidget *shell;
850 GtkWidget *cmd;
851 GtkWidget *hbox, *table;
852 GtkWidget *frame, *label, *combo;
853 GtkWidget *text;
854 GtkWidget *notebook;
855 GtkWidget *sw;
856 GtkWidget *list;
857 GtkListStore *store;
858 GtkCellRenderer *render;
859 GtkTreeViewColumn *column;
860 int i;
861 char *title;
862
863 /* Init. */
864 selected_nation = -1;
865
866 if (C_S_RUNNING == client_state()) {
867 title = _("Edit Nation");
868 } else if (NULL != pplayer && pplayer == client.conn.playing) {
869 title = _("What Nation Will You Be?");
870 } else {
871 title = _("Pick Nation");
872 }
873
874 shell = gtk_dialog_new_with_buttons(title,
875 NULL,
876 0,
877 GTK_STOCK_CANCEL,
878 GTK_RESPONSE_CANCEL,
879 _("_Random Nation"),
880 GTK_RESPONSE_NO, /* arbitrary */
881 GTK_STOCK_OK,
882 GTK_RESPONSE_ACCEPT,
883 NULL);
885 races_player = pplayer;
887
888 gtk_window_set_position(GTK_WINDOW(shell), GTK_WIN_POS_CENTER_ON_PARENT);
889 gtk_window_set_default_size(GTK_WINDOW(shell), -1, 590);
890
891 frame = gtk_frame_new(_("Select a nation"));
892 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(shell))), frame);
893
894 hbox = gtk_grid_new();
895 gtk_grid_set_column_spacing(GTK_GRID(hbox), 18);
896 gtk_container_set_border_width(GTK_CONTAINER(hbox), 3);
897 gtk_container_add(GTK_CONTAINER(frame), hbox);
898
899 /* Left side: nation list */
900 {
901 GtkWidget* nation_selection_list = gtk_grid_new();
902
903 nationsets_chooser = NULL;
904
905 gtk_grid_set_row_spacing(GTK_GRID(nation_selection_list), 2);
906
907 /* Nationset selector dropdown */
908 /* Only present this if there is more than one choice.
909 * (If ruleset is changed, possibly changing the number of available sets
910 * and invalidating this decision, then dialog will be popped down.) */
911 if (nation_set_count() > 1) {
912 GtkListStore *sets_model = gtk_list_store_new(4, G_TYPE_STRING,
913 G_TYPE_STRING,
914 G_TYPE_STRING,
915 G_TYPE_STRING);
916 GtkCellRenderer *renderer;
917
918 nation_sets_iterate(pset) {
919 /* Index in list store must match nation_set_index(). */
920 gchar *escaped;
921 struct astring s = ASTRING_INIT;
922 int num_nations = 0;
923 nations_iterate(pnation) {
924 if (is_nation_playable(pnation) && nation_is_in_set(pnation, pset)) {
925 num_nations++;
926 }
928 escaped = g_markup_escape_text(nation_set_name_translation(pset), -1);
929 /* TRANS: nation set name followed by number of playable nations;
930 * <b> and </b> are Pango markup and should be left alone */
931 astr_set(&s, PL_("<b>%s</b> (%d nation)",
932 "<b>%s</b> (%d nations)", num_nations),
933 escaped, num_nations);
934 g_free(escaped);
935 if (strlen(nation_set_description(pset)) > 0) {
936 /* While in principle it would be better to get Gtk to wrap the
937 * drop-down (e.g. via "wrap-width" property), there's no way
938 * to specify the indentation we want. So we do it ourselves. */
939 char *desc = fc_strdup(_(nation_set_description(pset)));
940 char *p = desc;
941
942 fc_break_lines(desc, 70);
943 astr_add(&s, "\n");
944 while (*p) {
945 int len = strcspn(p, "\n");
946
947 if (p[len] == '\n') {
948 len++;
949 }
950 escaped = g_markup_escape_text(p, len);
951 astr_add(&s, "\t%s", escaped);
952 g_free(escaped);
953 p += len;
954 }
955 FC_FREE(desc);
956 }
957 gtk_list_store_insert_with_values(sets_model, NULL, -1,
958 0, nation_set_rule_name(pset),
959 1, astr_str(&s),
961 -1);
962 astr_free(&s);
964
965 /* We want a combo box where the button displays just the set name,
966 * but the dropdown displays the expanded description. */
968 = gtk_combo_box_new_with_model_and_entry(GTK_TREE_MODEL(sets_model));
969 g_object_unref(G_OBJECT(sets_model));
970 {
971 /* Do our best to turn the text-entry widget into something more
972 * like a cell-view: disable editing, and focusing (which removes
973 * the caret). */
974 GtkWidget *entry = gtk_bin_get_child(GTK_BIN(nationsets_chooser));
975
976 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
977 gtk_widget_set_can_focus(entry, FALSE);
978 }
979 /* The entry displays the set name. */
980 gtk_combo_box_set_entry_text_column(GTK_COMBO_BOX(nationsets_chooser),
981 2);
982 /* The dropdown displays the marked-up description. */
983 renderer = gtk_cell_renderer_text_new();
984 gtk_cell_layout_clear(GTK_CELL_LAYOUT(nationsets_chooser));
985 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(nationsets_chooser),
986 renderer, TRUE);
987 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(nationsets_chooser),
988 renderer, "markup", 1, NULL);
989 g_signal_connect(nationsets_chooser, "destroy",
990 G_CALLBACK(gtk_widget_destroyed), &nationsets_chooser);
991 g_signal_connect(nationsets_chooser, "changed",
992 G_CALLBACK(nationset_callback), NULL);
993 {
994 /* Populate initially from client's view of server setting */
996 "nationset");
997
998 if (poption) {
1000 }
1001 }
1002
1003 label = g_object_new(GTK_TYPE_LABEL,
1004 "use-underline", TRUE,
1005 "label", _("_Nation Set:"),
1006 "xalign", 0.0,
1007 "yalign", 0.5,
1008 NULL);
1009 gtk_label_set_mnemonic_widget(GTK_LABEL(label), nationsets_chooser);
1010
1011 gtk_widget_set_hexpand(nationsets_chooser, TRUE);
1012 gtk_grid_attach(GTK_GRID(nation_selection_list), label,
1013 0, 0, 1, 1);
1014 gtk_grid_attach(GTK_GRID(nation_selection_list), nationsets_chooser,
1015 1, 0, 1, 1);
1016 }
1017
1018 races_notebook = gtk_notebook_new();
1019 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(races_notebook), GTK_POS_LEFT);
1020 gtk_grid_attach(GTK_GRID(nation_selection_list), races_notebook,
1021 0, 2, 2, 1);
1022
1023 /* Suppress notebook tabs if there will be only one ("All") */
1024 {
1025 bool show_groups = FALSE;
1026
1027 nation_groups_iterate(pgroup) {
1028 if (!is_nation_group_hidden(pgroup)) {
1029 show_groups = TRUE;
1030 break;
1031 }
1033 if (!show_groups) {
1034 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(races_notebook), FALSE);
1035 } else {
1036 label = g_object_new(GTK_TYPE_LABEL,
1037 "use-underline", TRUE,
1038 "label", _("Nation _Groups:"),
1039 "xalign", 0.0,
1040 "yalign", 0.5,
1041 NULL);
1042 gtk_label_set_mnemonic_widget(GTK_LABEL(label), races_notebook);
1043 gtk_grid_attach(GTK_GRID(nation_selection_list), label,
1044 0, 1, 2, 1);
1045 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(races_notebook), TRUE);
1046 }
1047 }
1048
1049 /* Populate treeview */
1051
1052 gtk_container_add(GTK_CONTAINER(hbox), nation_selection_list);
1053 }
1054
1055 /* Right side. */
1056 notebook = gtk_notebook_new();
1057 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_BOTTOM);
1058 gtk_container_add(GTK_CONTAINER(hbox), notebook);
1059
1060 /* Properties pane. */
1061 label = gtk_label_new_with_mnemonic(_("_Properties"));
1062
1063 races_properties = table = gtk_grid_new();
1064 g_signal_connect(table, "destroy",
1065 G_CALLBACK(gtk_widget_destroyed), &races_properties);
1066 g_object_set(table, "margin", 6, NULL);
1067 gtk_grid_set_row_spacing(GTK_GRID(table), 2);
1068 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), table, label);
1069
1070 /* Leader. */
1071 {
1072 GtkListStore *model = gtk_list_store_new(1, G_TYPE_STRING);
1073
1074 combo = gtk_combo_box_new_with_model_and_entry(GTK_TREE_MODEL(model));
1075 gtk_combo_box_set_entry_text_column(GTK_COMBO_BOX(combo), 0);
1076 g_object_unref(G_OBJECT(model));
1077 }
1078 races_leader = combo;
1079 label = g_object_new(GTK_TYPE_LABEL,
1080 "use-underline", TRUE,
1081 "mnemonic-widget", GTK_COMBO_BOX(combo),
1082 "label", _("_Leader:"),
1083 "xalign", 0.0,
1084 "yalign", 0.5,
1085 NULL);
1086 gtk_widget_set_margin_bottom(label, 6);
1087 gtk_widget_set_margin_right(label, 12);
1088 gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 2);
1089 gtk_grid_attach(GTK_GRID(table), combo, 1, 0, 2, 1);
1090
1091 cmd = gtk_radio_button_new_with_mnemonic(NULL, _("_Female"));
1092 gtk_widget_set_margin_bottom(cmd, 6);
1093 races_sex[0] = cmd;
1094 gtk_grid_attach(GTK_GRID(table), cmd, 1, 1, 1, 1);
1095
1096 cmd = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(cmd),
1097 _("_Male"));
1098 gtk_widget_set_margin_bottom(cmd, 6);
1099 races_sex[1] = cmd;
1100 gtk_grid_attach(GTK_GRID(table), cmd, 2, 1, 1, 1);
1101
1102 /* City style. */
1103 store = gtk_list_store_new(3, G_TYPE_INT,
1104 GDK_TYPE_PIXBUF, G_TYPE_STRING);
1105
1106 list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1107 gtk_widget_set_hexpand(list, TRUE);
1108 gtk_widget_set_vexpand(list, TRUE);
1110 g_object_unref(store);
1111 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), FALSE);
1112 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(list)), "changed",
1113 G_CALLBACK(races_style_callback), NULL);
1114
1115 sw = gtk_scrolled_window_new(NULL, NULL);
1116 gtk_widget_set_margin_top(sw, 6);
1117 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
1118 GTK_SHADOW_ETCHED_IN);
1119 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1120 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1121 gtk_container_add(GTK_CONTAINER(sw), list);
1122 gtk_grid_attach(GTK_GRID(table), sw, 1, 2, 2, 2);
1123
1124 label = g_object_new(GTK_TYPE_LABEL,
1125 "use-underline", TRUE,
1126 "mnemonic-widget", list,
1127 "label", _("City _Styles:"),
1128 "xalign", 0.0,
1129 "yalign", 0.5,
1130 NULL);
1131 gtk_widget_set_margin_top(label, 6);
1132 gtk_widget_set_margin_right(label, 12);
1133 gtk_grid_attach(GTK_GRID(table), label, 0, 2, 1, 1);
1134
1135 render = gtk_cell_renderer_pixbuf_new();
1136 column = gtk_tree_view_column_new_with_attributes(NULL, render,
1137 "pixbuf", 1, NULL);
1138 gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
1139 render = gtk_cell_renderer_text_new();
1140 column = gtk_tree_view_column_new_with_attributes(NULL, render,
1141 "text", 2, NULL);
1142 gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
1143
1144 /* Populate style store. */
1145 styles_iterate(pstyle) {
1146 GdkPixbuf *img;
1147 struct sprite *s;
1148 GtkTreeIter it;
1149
1150 i = basic_city_style_for_style(pstyle);
1151
1152 if (i >= 0) {
1153 gtk_list_store_append(store, &it);
1154
1157 free_sprite(s);
1158 gtk_list_store_set(store, &it, 0, i, 1, img, 2,
1160 g_object_unref(img);
1161 }
1163
1164 /* Legend pane. */
1165 label = gtk_label_new_with_mnemonic(_("_Description"));
1166
1167 text = gtk_text_view_new();
1168 g_object_set(text, "margin", 6, NULL);
1169 gtk_widget_set_hexpand(text, TRUE);
1170 gtk_widget_set_vexpand(text, TRUE);
1171 races_text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text));
1172 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD);
1173 gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);
1174 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(text), FALSE);
1175 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text), 6);
1176 gtk_text_view_set_right_margin(GTK_TEXT_VIEW(text), 6);
1177
1178 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), text, label);
1179
1180 /* Signals. */
1181 g_signal_connect(shell, "destroy",
1182 G_CALLBACK(gtk_widget_destroyed), &races_shell);
1183 g_signal_connect(shell, "response",
1184 G_CALLBACK(races_response), NULL);
1185
1186 g_signal_connect(GTK_COMBO_BOX(races_leader), "changed",
1187 G_CALLBACK(races_leader_callback), NULL);
1188
1189 g_signal_connect(races_sex[0], "toggled",
1190 G_CALLBACK(races_sex_callback), GINT_TO_POINTER(0));
1191 g_signal_connect(races_sex[1], "toggled",
1192 G_CALLBACK(races_sex_callback), GINT_TO_POINTER(1));
1193
1194 /* Finish up. */
1195 gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_CANCEL);
1196
1197 /* You can't assign NO_NATION during a running game. */
1198 if (C_S_RUNNING == client_state()) {
1199 gtk_dialog_set_response_sensitive(GTK_DIALOG(shell), GTK_RESPONSE_NO,
1200 FALSE);
1201 }
1202
1203 gtk_widget_show_all(gtk_dialog_get_content_area(GTK_DIALOG(shell)));
1204
1205 /* Select player's current nation in UI, if any */
1206 if (races_player->nation) {
1211 /* Make sure selected nation is visible
1212 * (last page, "All", will certainly contain it) */
1213 fc_assert(gtk_notebook_get_n_pages(GTK_NOTEBOOK(races_notebook)) > 0);
1214 gtk_notebook_set_current_page(GTK_NOTEBOOK(races_notebook), -1);
1215 } else {
1216 select_nation(-1, NULL, FALSE, 0);
1217 }
1218}
1219
1220/**********************************************************************/
1223void popup_races_dialog(struct player *pplayer)
1224{
1225 if (!pplayer) {
1226 return;
1227 }
1228
1229 if (!races_shell) {
1230 create_races_dialog(pplayer);
1231 gtk_window_present(GTK_WINDOW(races_shell));
1232 }
1233}
1234
1235/**********************************************************************/
1239{
1240 if (races_shell) {
1241 gtk_widget_destroy(races_shell);
1242 }
1243
1244 /* We're probably starting a new game, maybe with a new ruleset.
1245 So we warn the worklist dialog. */
1247}
1248
1249/**********************************************************************/
1254{
1255 int i;
1256
1257 if (!races_shell) {
1258 return;
1259 }
1260
1261 for (i = 0; i <= nation_group_count(); i++) {
1262 if (races_nation_list[i]) {
1263 GtkTreeView *list = GTK_TREE_VIEW(races_nation_list[i]);
1264 GtkTreeModel *model = gtk_tree_view_get_model(list);
1265 GtkTreeSelection* select = gtk_tree_view_get_selection(list);
1266 GtkTreeIter it;
1267 gboolean chosen;
1268
1269 /* Update 'chosen' column in model */
1270 if (gtk_tree_model_get_iter_first(model, &it)) {
1271 do {
1272 int nation_no;
1273 struct nation_type *nation;
1274
1275 gtk_tree_model_get(model, &it, 0, &nation_no, -1);
1276 nation = nation_by_number(nation_no);
1277
1278 chosen = !is_nation_pickable(nation)
1279 || (nation->player && nation->player != races_player);
1280
1281 gtk_list_store_set(GTK_LIST_STORE(model), &it, 1, chosen, -1);
1282
1283 } while (gtk_tree_model_iter_next(model, &it));
1284 }
1285
1286 /* If our selection is now invalid, deselect it */
1287 if (gtk_tree_selection_get_selected(select, &model, &it)) {
1288 gtk_tree_model_get(model, &it, 1, &chosen, -1);
1289
1290 if (chosen) {
1291 gtk_tree_selection_unselect_all(select);
1292 }
1293 }
1294 }
1295 }
1296}
1297
1298/**********************************************************************/
1301static void races_nation_callback(GtkTreeSelection *select, gpointer data)
1302{
1303 GtkTreeModel *model;
1304 GtkTreeIter it;
1305
1306 if (gtk_tree_selection_get_selected(select, &model, &it)) {
1307 gboolean chosen;
1308 int newnation;
1309
1310 gtk_tree_model_get(model, &it, 0, &newnation, 1, &chosen, -1);
1311
1312 /* Only allow nations not chosen by another player */
1313 if (!chosen) {
1314 if (newnation != selected_nation) {
1315 /* Choose a random leader */
1316 select_nation(newnation, NULL, FALSE,
1318 }
1319 return;
1320 }
1321 }
1322
1323 /* Fall-through if no valid nation selected */
1324 select_nation(-1, NULL, FALSE, 0);
1325}
1326
1327/**********************************************************************/
1330static void races_leader_callback(void)
1331{
1332 const struct nation_leader *pleader;
1333 const gchar *name;
1334
1335 name =
1336 gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(races_leader))));
1337
1338 if (selected_nation != -1
1340 name))) {
1342 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(races_sex[selected_sex]),
1343 TRUE);
1344 }
1345}
1346
1347/**********************************************************************/
1350static void races_sex_callback(GtkWidget *w, gpointer data)
1351{
1352 selected_sex = GPOINTER_TO_INT(data);
1353}
1354
1355/**********************************************************************/
1358static gboolean races_selection_func(GtkTreeSelection *select,
1359 GtkTreeModel *model, GtkTreePath *path,
1360 gboolean selected, gpointer data)
1361{
1362 GtkTreeIter it;
1363 gboolean chosen;
1364
1365 gtk_tree_model_get_iter(model, &it, path);
1366 gtk_tree_model_get(model, &it, 1, &chosen, -1);
1367 return (!chosen || selected);
1368}
1369
1370/**********************************************************************/
1373static void races_style_callback(GtkTreeSelection *select, gpointer data)
1374{
1375 GtkTreeModel *model;
1376 GtkTreeIter it;
1377
1378 if (gtk_tree_selection_get_selected(select, &model, &it)) {
1379 gtk_tree_model_get(model, &it, 0, &selected_style, -1);
1380 } else {
1381 selected_style = -1;
1382 }
1383}
1384
1385/**********************************************************************/
1388static void races_response(GtkWidget *w, gint response, gpointer data)
1389{
1390 if (response == GTK_RESPONSE_ACCEPT) {
1391 const char *s;
1392
1393 /* This shouldn't be possible but... */
1394 if (selected_nation == -1) {
1395 return;
1396 }
1397
1398 if (selected_sex == -1) {
1399 output_window_append(ftc_client, _("You must select your sex."));
1400 return;
1401 }
1402
1403 if (selected_style == -1) {
1404 output_window_append(ftc_client, _("You must select your style."));
1405 return;
1406 }
1407
1408 s = gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(races_leader))));
1409
1410 /* Perform a minimum of sanity test on the name. */
1411 /* This could call is_allowed_player_name if it were available. */
1412 if (strlen(s) == 0) {
1413 output_window_append(ftc_client, _("You must type a legal name."));
1414 return;
1415 }
1416
1419 selected_sex, s,
1421 } else if (response == GTK_RESPONSE_NO) {
1424 -1, FALSE, "", 0);
1425 }
1426
1428}
1429
1430
1431/**********************************************************************/
1434gboolean taxrates_callback(GtkWidget *w, GdkEventButton *ev, gpointer data)
1435{
1436 common_taxrates_callback((size_t) data, FALSE);
1437
1438 return TRUE;
1439}
1440
1441/**********************************************************************/
1444void popup_upgrade_dialog(struct unit_list *punits)
1445{
1446 GtkWidget *shell;
1447 char buf[512];
1448
1449 if (!punits || unit_list_size(punits) == 0) {
1450 return;
1451 }
1452
1453 if (!get_units_upgrade_info(buf, sizeof(buf), punits)) {
1454 shell = gtk_message_dialog_new(NULL, 0,
1455 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
1456 "%s", buf);
1457 gtk_window_set_title(GTK_WINDOW(shell), _("Upgrade Unit!"));
1459 g_signal_connect(shell, "response", G_CALLBACK(gtk_widget_destroy),
1460 NULL);
1461 gtk_window_present(GTK_WINDOW(shell));
1462 } else {
1463 shell = gtk_message_dialog_new(NULL, 0,
1464 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1465 "%s", buf);
1466 gtk_window_set_title(GTK_WINDOW(shell), _("Upgrade Obsolete Units"));
1468 gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_YES);
1469
1470 if (gtk_dialog_run(GTK_DIALOG(shell)) == GTK_RESPONSE_YES) {
1471 unit_list_iterate(punits, punit) {
1474 }
1475 gtk_widget_destroy(shell);
1476 }
1477}
1478
1479/**********************************************************************/
1482void popup_disband_dialog(struct unit_list *punits)
1483{
1484 GtkWidget *shell;
1485 char buf[512];
1486
1487 if (!punits || unit_list_size(punits) == 0) {
1488 return;
1489 }
1490
1491 if (!get_units_disband_info(buf, sizeof(buf), punits)) {
1492 shell = gtk_message_dialog_new(NULL, 0,
1493 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
1494 "%s", buf);
1495 gtk_window_set_title(GTK_WINDOW(shell), _("Disband Units"));
1497 g_signal_connect(shell, "response", G_CALLBACK(gtk_widget_destroy),
1498 NULL);
1499 gtk_window_present(GTK_WINDOW(shell));
1500 } else {
1501 shell = gtk_message_dialog_new(NULL, 0,
1502 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1503 "%s", buf);
1504 gtk_window_set_title(GTK_WINDOW(shell), _("Disband Units"));
1506 gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_YES);
1507
1508 if (gtk_dialog_run(GTK_DIALOG(shell)) == GTK_RESPONSE_YES) {
1509 unit_list_iterate(punits, punit) {
1510 if (unit_can_do_action(punit, ACTION_DISBAND_UNIT)) {
1512 }
1514 }
1515 gtk_widget_destroy(shell);
1516 }
1517}
1518
1519/**********************************************************************/
1529
1530/**********************************************************************/
1534{
1535 const struct advance *padvance = valid_advance_by_number(tech);
1536
1537 if (NULL != padvance
1538 && (GUI_GTK_OPTION(popup_tech_help) == GUI_POPUP_TECH_HELP_ENABLED
1539 || (GUI_GTK_OPTION(popup_tech_help) == GUI_POPUP_TECH_HELP_RULESET
1542 }
1543}
1544
1545/**********************************************************************/
1549void show_tileset_error(bool fatal, const char *tset_name, const char *msg)
1550{
1551 if (is_gui_up()) {
1552 GtkWidget *dialog;
1553
1554 if (tset_name != NULL) {
1555 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
1556 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
1557 _("Tileset \"%s\" problem, "
1558 "it's probably incompatible with "
1559 "the ruleset:\n%s"),
1560 tset_name, msg);
1561 } else {
1562 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
1563 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
1564 _("Tileset problem, "
1565 "it's probably incompatible with "
1566 "the ruleset:\n%s"),
1567 msg);
1568 }
1569
1570 setup_dialog(dialog, toplevel);
1571
1572 gtk_dialog_run(GTK_DIALOG(dialog));
1573
1574 gtk_widget_destroy(dialog);
1575 }
1576}
1577
1578/**********************************************************************/
1583{
1584 /* Just tell the client common code to handle this. */
1585 return FALSE;
1586}
1587
1588/**********************************************************************/
1592void popup_combat_info(int attacker_unit_id, int defender_unit_id,
1593 int attacker_hp, int defender_hp,
1594 bool make_att_veteran, bool make_def_veteran)
1595{
1596}
void astr_free(struct astring *astr)
Definition astring.c:153
void astr_set(struct astring *astr, const char *format,...)
Definition astring.c:267
void astr_add(struct astring *astr, const char *format,...)
Definition astring.c:287
static const char * astr_str(const struct astring *astr) fc__attribute((nonnull(1)))
Definition astring.h:93
#define ASTRING_INIT
Definition astring.h:44
#define BV_CLR_ALL(bv)
Definition bitvector.h:95
#define BV_SET(bv, bit)
Definition bitvector.h:81
#define BV_CLR(bv, bit)
Definition bitvector.h:86
void output_window_append(const struct ft_color color, const char *featured_text)
const char * city_style_name_translation(const int style)
Definition city.c:1729
#define city_owner(_pcity_)
Definition city.h:543
void popup_city_dialog(struct city *pcity)
struct civclient client
enum client_states client_state(void)
@ C_S_RUNNING
Definition client_main.h:47
void common_taxrates_callback(int idx, bool reverse)
Definition climisc.c:1187
static struct fc_sockaddr_list * list
Definition clinet.c:102
void request_unit_disband(struct unit *punit)
Definition control.c:2002
void request_new_unit_activity_targeted(struct unit *punit, enum unit_activity act, struct extra_type *tgt)
Definition control.c:1863
void request_unit_upgrade(struct unit *punit)
Definition control.c:2033
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit int const struct action *paction show_tileset_error
Definition dialogs_g.h:84
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit * actor
Definition dialogs_g.h:72
const char * caption
Definition dialogs_g.h:36
const char const char * headline
Definition dialogs_g.h:37
popup_notify_dialog
Definition dialogs_g.h:36
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit int const struct action *paction bool fatal
Definition dialogs_g.h:85
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit * punit
Definition dialogs_g.h:73
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit int const struct action *paction bool const char * tset_name
Definition dialogs_g.h:85
struct extra_type * extra_by_number(int id)
Definition extras.c:175
static struct extra_type extras[MAX_EXTRA_TYPES]
Definition extras.c:31
#define extra_index(_e_)
Definition extras.h:177
int Tech_type_id
Definition fc_types.h:347
int Nation_type_id
Definition fc_types.h:350
#define MAX_NUM_NATION_GROUPS
Definition fc_types.h:58
#define PL_(String1, String2, n)
Definition fcintl.h:71
#define _(String)
Definition fcintl.h:67
const struct ft_color ftc_client
struct civ_game game
Definition game.c:57
struct unit * game_unit_by_number(int id)
Definition game.c:111
static GtkWidget * races_properties
Definition dialogs.c:77
static gboolean races_selection_func(GtkTreeSelection *select, GtkTreeModel *model, GtkTreePath *path, gboolean selected, gpointer data)
Definition dialogs.c:1358
static GtkWidget * races_shell
Definition dialogs.c:71
static void select_nation(int nation, const char *leadername, bool is_male, int style_id)
Definition dialogs.c:519
static void sync_tabs_to_nation(int nation)
Definition dialogs.c:477
static GtkWidget * races_style_list
Definition dialogs.c:80
static void revolution_response(GtkWidget *w, gint response, gpointer data)
Definition dialogs.c:270
static void races_leader_callback(void)
Definition dialogs.c:1330
static int selected_style
Definition dialogs.c:95
static void create_nation_selection_lists(void)
Definition dialogs.c:702
static int is_showing_pillage_dialog
Definition dialogs.c:97
static void create_races_dialog(struct player *pplayer)
Definition dialogs.c:847
static GtkWidget * races_leader
Definition dialogs.c:78
static GtkWidget * races_nation_list[MAX_NUM_NATION_GROUPS+1]
Definition dialogs.c:75
static void populate_leader_list(void)
Definition dialogs.c:493
void unit_select_dialog_popup(struct tile *ptile)
Definition dialogs.c:382
void popup_upgrade_dialog(struct unit_list *punits)
Definition dialogs.c:1444
void races_update_pickable(bool nationset_change)
Definition dialogs.c:737
static void notify_connect_msg_response(GtkWidget *w, gint response)
Definition dialogs.c:184
static void races_sex_callback(GtkWidget *w, gpointer data)
Definition dialogs.c:1350
static void pillage_callback(GtkWidget *dlg, gint arg)
Definition dialogs.c:318
void popup_notify_goto_dialog(const char *headline, const char *lines, const struct text_tag_list *tags, struct tile *ptile)
Definition dialogs.c:194
void show_tech_gained_dialog(Tech_type_id tech)
Definition dialogs.c:1533
static GtkWidget * races_sex[2]
Definition dialogs.c:79
void popup_races_dialog(struct player *pplayer)
Definition dialogs.c:1223
void popup_disband_dialog(struct unit_list *punits)
Definition dialogs.c:1482
static GtkTreePath * path_to_nation_on_list(Nation_type_id nation, GtkTreeView *list)
Definition dialogs.c:404
void popdown_races_dialog(void)
Definition dialogs.c:1238
static int selected_nation
Definition dialogs.c:93
static GtkWidget * races_notebook
Definition dialogs.c:76
void popup_pillage_dialog(struct unit *punit, bv_extras extras)
Definition dialogs.c:343
static void races_response(GtkWidget *w, gint response, gpointer data)
Definition dialogs.c:1388
static void notify_goto_response(GtkWidget *w, gint response)
Definition dialogs.c:157
static void races_nation_callback(GtkTreeSelection *select, gpointer data)
Definition dialogs.c:1301
void popup_connect_msg(const char *headline, const char *message)
Definition dialogs.c:243
bool handmade_scenario_warning(void)
Definition dialogs.c:1582
void unit_select_dialog_update_real(void *unused)
Definition dialogs.c:391
static void nationset_callback(GtkComboBox *b, gpointer data)
Definition dialogs.c:822
void races_toggles_set_sensitive(void)
Definition dialogs.c:1253
static void races_style_callback(GtkTreeSelection *select, gpointer data)
Definition dialogs.c:1373
void popup_combat_info(int attacker_unit_id, int defender_unit_id, int attacker_hp, int defender_hp, bool make_att_veteran, bool make_def_veteran)
Definition dialogs.c:1592
static int selected_sex
Definition dialogs.c:94
struct player * races_player
Definition dialogs.c:73
static GtkWidget * nationsets_chooser
Definition dialogs.c:72
static GtkTextBuffer * races_text
Definition dialogs.c:81
void nationset_sync_to_server(const char *nationset)
Definition dialogs.c:809
gboolean taxrates_callback(GtkWidget *w, GdkEventButton *ev, gpointer data)
Definition dialogs.c:1434
static GtkWidget * create_list_of_nations_in_group(struct nation_group *group, int index)
Definition dialogs.c:615
static void select_nation_on_tab(GtkWidget *tab_list, int nation)
Definition dialogs.c:432
void popdown_all_game_dialogs(void)
Definition dialogs.c:1523
struct property_editor * editprop_get_property_editor(void)
Definition editprop.c:6207
void property_editor_popdown(struct property_editor *pe)
Definition editprop.c:6272
GtkWidget * bottom_notebook
Definition gui_main.c:128
bool is_gui_up(void)
Definition gui_main.c:1864
GtkWidget * toplevel
Definition gui_main.c:124
#define GUI_GTK_OPTION(optname)
Definition gui_main.h:25
void gui_dialog_present(struct gui_dialog *dlg)
Definition gui_stuff.c:834
void gui_dialog_set_default_response(struct gui_dialog *dlg, int response)
Definition gui_stuff.c:733
void gui_dialog_new(struct gui_dialog **pdlg, GtkNotebook *notebook, gpointer user_data, bool check_top)
Definition gui_stuff.c:504
GtkWidget * gui_dialog_add_button(struct gui_dialog *dlg, const char *text, int response)
Definition gui_stuff.c:706
void gui_dialog_show_all(struct gui_dialog *dlg)
Definition gui_stuff.c:794
void gui_dialog_set_title(struct gui_dialog *dlg, const char *title)
Definition gui_stuff.c:932
void gui_dialog_set_default_size(struct gui_dialog *dlg, int width, int height)
Definition gui_stuff.c:916
GtkWidget * gtk_stockbutton_new(const gchar *stock, const gchar *label_text)
Definition gui_stuff.c:74
void gui_dialog_destroy_all(void)
Definition gui_stuff.c:971
void setup_dialog(GtkWidget *shell, GtkWidget *parent)
Definition gui_stuff.c:281
void popup_help_dialog_typed(const char *item, enum help_page_type htype)
Definition helpdlg.c:195
static struct gui_dialog * shell
Definition messagedlg.c:39
GdkPixbuf * get_flag(const struct nation_type *nation)
Definition plrdlg.c:609
const char * title
Definition repodlgs.c:1313
void free_sprite(struct sprite *s)
Definition sprite.c:278
GdkPixbuf * sprite_get_pixbuf(struct sprite *sprite)
Definition sprite.c:402
struct sprite * crop_blankspace(struct sprite *s)
Definition sprite.c:386
void unit_select_dialog_popup_main(struct tile *ptile, bool create)
Definition unitselect.c:193
void unit_select_dialog_popdown(void)
Definition unitselect.c:214
bool select_tgt_extra(struct unit *actor, struct tile *ptile, bv_extras potential_tgt_extras, struct extra_type *suggested_tgt_extra, const gchar *dlg_title, const gchar *actor_label, const gchar *tgt_label, const gchar *do_label, GCallback do_callback)
void blank_max_unit_size(void)
Definition wldlg.c:79
static char * leader_name
Definition dialogs.c:96
void popup_revolution_dialog(void)
Definition dialogs.c:109
void helptext_nation(char *buf, size_t bufsz, struct nation_type *pnation, const char *user_text)
Definition helpdata.c:4871
@ HELP_TECH
Definition helpdlg_g.h:21
const char * name
Definition inputfile.c:127
#define fc_assert(condition)
Definition log.h:176
#define fc_assert_action(condition, action)
Definition log.h:187
void center_tile_mapcanvas(const struct tile *ptile)
#define FC_FREE(ptr)
Definition mem.h:41
#define fc_strdup(str)
Definition mem.h:43
Nation_type_id nation_number(const struct nation_type *pnation)
Definition nation.c:485
struct nation_leader * nation_leader_by_name(const struct nation_type *pnation, const char *name)
Definition nation.c:266
bool nation_leader_is_male(const struct nation_leader *pleader)
Definition nation.c:289
const char * nation_adjective_translation(const struct nation_type *pnation)
Definition nation.c:148
struct nation_type * nation_by_number(const Nation_type_id nation)
Definition nation.c:474
int nation_set_index(const struct nation_set *pset)
Definition nation.c:698
bool is_nation_pickable(const struct nation_type *nation)
Definition nation.c:187
const struct nation_leader_list * nation_leaders(const struct nation_type *pnation)
Definition nation.c:229
const char * nation_set_name_translation(const struct nation_set *pset)
Definition nation.c:817
bool is_nation_playable(const struct nation_type *nation)
Definition nation.c:199
bool nation_is_in_group(const struct nation_type *pnation, const struct nation_group *pgroup)
Definition nation.c:1098
bool nation_is_in_set(const struct nation_type *pnation, const struct nation_set *pset)
Definition nation.c:836
const char * nation_set_description(const struct nation_set *pset)
Definition nation.c:827
const char * nation_group_name_translation(const struct nation_group *pgroup)
Definition nation.c:1089
int nation_set_count(void)
Definition nation.c:690
struct nation_group * nation_group_by_number(int id)
Definition nation.c:1003
struct nation_set * nation_set_by_rule_name(const char *name)
Definition nation.c:778
bool is_nation_group_hidden(struct nation_group *pgroup)
Definition nation.c:1056
struct nation_set * nation_set_by_setting_value(const char *setting)
Definition nation.c:858
const char * nation_leader_name(const struct nation_leader *pleader)
Definition nation.c:280
int nation_group_count(void)
Definition nation.c:934
const char * nation_set_rule_name(const struct nation_set *pset)
Definition nation.c:806
struct nation_style * style_of_nation(const struct nation_type *pnation)
Definition nation.c:671
#define nation_leader_list_iterate(leaderlist, pleader)
Definition nation.h:56
#define nation_sets_iterate_end
Definition nation.h:304
#define nation_sets_iterate(NAME_pset)
Definition nation.h:300
#define nations_iterate_end
Definition nation.h:335
#define nations_iterate(NAME_pnation)
Definition nation.h:332
#define nation_leader_list_iterate_end
Definition nation.h:58
#define nation_groups_iterate(NAME_pgroup)
Definition nation.h:310
#define nation_groups_iterate_end
Definition nation.h:314
const struct option_set * server_optset
Definition options.c:4009
bool option_str_set(struct option *poption, const char *str)
Definition options.c:901
const char * option_str_get(const struct option *poption)
Definition options.c:868
struct client_options gui_options
Definition options.c:71
struct option * optset_option_by_name(const struct option_set *poptset, const char *name)
Definition options.c:406
@ GUI_POPUP_TECH_HELP_RULESET
Definition options.h:76
@ GUI_POPUP_TECH_HELP_ENABLED
Definition options.h:74
int dsend_packet_nation_select_req(struct connection *pc, int player_no, Nation_type_id nation_no, bool is_male, const char *name, int style)
void start_revolution(void)
Definition packhand.c:2517
void set_government_choice(struct government *government)
Definition packhand.c:2504
char * lines
Definition packhand.c:129
int len
Definition packhand.c:125
int player_number(const struct player *pplayer)
Definition player.c:828
const char * player_name(const struct player *pplayer)
Definition player.c:886
#define fc_rand(_size)
Definition rand.h:34
Definition city.h:309
struct packet_ruleset_control control
Definition game.h:83
struct connection conn
Definition client_main.h:96
bool center_when_popup_city
Definition options.h:154
struct player * playing
Definition connection.h:156
GtkWidget * vbox
Definition gui_stuff.h:71
GtkWidget * label
Definition gui_stuff.h:86
Definition mapimg.c:367
struct player * player
Definition nation.h:117
bool is_male
Definition player.h:257
int revolution_finishes
Definition player.h:273
struct nation_type * nation
Definition player.h:260
struct nation_style * style
Definition player.h:279
Definition tile.h:49
char * label
Definition tile.h:64
Definition unit.h:138
int style_number(const struct nation_style *pstyle)
Definition style.c:68
int basic_city_style_for_style(struct nation_style *pstyle)
Definition style.c:210
#define styles_iterate(_p)
Definition style.h:46
#define styles_iterate_end
Definition style.h:52
int fc_break_lines(char *str, size_t desired_len)
Definition support.c:1144
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
const char * advance_name_translation(const struct advance *padvance)
Definition tech.c:290
struct advance * valid_advance_by_number(const Tech_type_id id)
Definition tech.c:176
struct extra_type * get_preferred_pillage(bv_extras extras)
Definition terrain.c:538
bool get_units_upgrade_info(char *buf, size_t bufsz, struct unit_list *punits)
Definition text.c:1290
bool get_units_disband_info(char *buf, size_t bufsz, struct unit_list *punits)
Definition text.c:1356
struct city * tile_city(const struct tile *ptile)
Definition tile.c:83
struct sprite * get_sample_city_sprite(const struct tileset *t, int style_idx)
Definition tilespec.c:6547
bool unit_can_do_action(const struct unit *punit, const action_id act_id)
Definition unit.c:328
#define unit_tile(_pu)
Definition unit.h:395
#define unit_list_iterate(unitlist, punit)
Definition unitlist.h:31
#define unit_list_iterate_end
Definition unitlist.h:33