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.22 */
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, "window-close", _("_Close"),
112 GTK_RESPONSE_CLOSE);
113 gui_dialog_set_default_response(shell, GTK_RESPONSE_CLOSE);
114
115 vbox = gtk_grid_new();
116 gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox),
117 GTK_ORIENTATION_VERTICAL);
118 gtk_grid_set_row_spacing(GTK_GRID(vbox), 2);
119 gtk_container_add(GTK_CONTAINER(shell->vbox), vbox);
120
121 headline_label = gtk_label_new(headline);
122 gtk_container_add(GTK_CONTAINER(vbox), headline_label);
123 gtk_widget_set_name(headline_label, "notify_label");
124
125 gtk_label_set_justify(GTK_LABEL(headline_label), GTK_JUSTIFY_LEFT);
126 gtk_widget_set_halign(headline_label, GTK_ALIGN_START);
127 gtk_widget_set_valign(headline_label, GTK_ALIGN_START);
128
129 sw = gtk_scrolled_window_new(NULL, NULL);
130 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
131 GTK_SHADOW_ETCHED_IN);
132 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
133 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
134 label = gtk_label_new(lines);
135 gtk_widget_set_hexpand(label, TRUE);
136 gtk_widget_set_vexpand(label, TRUE);
137 gtk_container_add(GTK_CONTAINER(sw), label);
138
139 gtk_widget_set_name(label, "notify_label");
140 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
141 gtk_widget_set_halign(label, GTK_ALIGN_START);
142 gtk_widget_set_valign(label, GTK_ALIGN_START);
143
144 gtk_container_add(GTK_CONTAINER(vbox), sw);
145
147
150
151 shell = NULL;
152}
153
154/**********************************************************************/
158static void notify_goto_response(GtkWidget *w, gint response)
159{
160 struct city *pcity = NULL;
161 struct tile *ptile = g_object_get_data(G_OBJECT(w), "tile");
162
163 switch (response) {
164 case 1:
166 break;
167 case 2:
168 pcity = tile_city(ptile);
169
172 }
173
174 if (pcity) {
175 popup_city_dialog(pcity);
176 }
177 break;
178 }
179 gtk_widget_destroy(w);
180}
181
182/**********************************************************************/
185static void notify_connect_msg_response(GtkWidget *w, gint response)
186{
187 gtk_widget_destroy(w);
188}
189
190/**********************************************************************/
195void popup_notify_goto_dialog(const char *headline, const char *lines,
196 const struct text_tag_list *tags,
197 struct tile *ptile)
198{
199 GtkWidget *shell, *label;
200
201 if (ptile == NULL) {
202 shell = gtk_dialog_new_with_buttons(headline, NULL, 0,
203 _("_Close"), GTK_RESPONSE_CLOSE,
204 NULL);
205 } else {
206 struct city *pcity = tile_city(ptile);
207
208 if (pcity != NULL && city_owner(pcity) == client.conn.playing) {
209 shell = gtk_dialog_new_with_buttons(headline, NULL, 0,
210 _("Goto _Location"), 1,
211 _("I_nspect City"), 2,
212 _("_Close"), GTK_RESPONSE_CLOSE,
213 NULL);
214 } else {
215 shell = gtk_dialog_new_with_buttons(headline, NULL, 0,
216 _("Goto _Location"), 1,
217 _("_Close"), GTK_RESPONSE_CLOSE,
218 NULL);
219 }
220 }
222 gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_CLOSE);
223 gtk_window_set_position(GTK_WINDOW(shell), GTK_WIN_POS_CENTER_ON_PARENT);
224
225 label = gtk_label_new(lines);
226 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(shell))), label);
227 gtk_widget_show(label);
228
229 g_object_set_data(G_OBJECT(shell), "tile", ptile);
230
231 g_signal_connect(shell, "response", G_CALLBACK(notify_goto_response), NULL);
232 gtk_widget_show(shell);
233}
234
235/**********************************************************************/
238void popup_connect_msg(const char *headline, const char *message)
239{
240 GtkWidget *shell, *label;
241
242 shell = gtk_dialog_new();
243 gtk_window_set_title(GTK_WINDOW(shell), headline);
245 gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_CLOSE);
246 gtk_window_set_position(GTK_WINDOW(shell), GTK_WIN_POS_CENTER_ON_PARENT);
247
248 label = gtk_label_new(message);
249 gtk_label_set_selectable(GTK_LABEL(label), 1);
250
251 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(shell))), label);
252 gtk_widget_show(label);
253
254 gtk_dialog_add_button(GTK_DIALOG(shell), _("_Close"),GTK_RESPONSE_CLOSE);
255
256 g_signal_connect(shell, "response", G_CALLBACK(notify_connect_msg_response),
257 NULL);
258 gtk_widget_show(shell);
259}
260
261/**********************************************************************/
264static void revolution_response(GtkWidget *w, gint response, gpointer data)
265{
266 struct government *government = data;
267
268 if (response == GTK_RESPONSE_YES) {
269 if (!government) {
271 } else {
273 }
274 }
275 if (w) {
276 gtk_widget_destroy(w);
277 }
278}
279
280/**********************************************************************/
284{
285 static GtkWidget *shell = NULL;
286
288 if (!shell) {
289 shell = gtk_message_dialog_new(NULL,
290 0,
291 GTK_MESSAGE_WARNING,
292 GTK_BUTTONS_YES_NO,
293 _("You say you wanna revolution?"));
294 gtk_window_set_title(GTK_WINDOW(shell), _("Revolution!"));
296
297 g_signal_connect(shell, "destroy",
298 G_CALLBACK(gtk_widget_destroyed), &shell);
299 }
300 g_signal_connect(shell, "response",
301 G_CALLBACK(revolution_response), government);
302
303 gtk_window_present(GTK_WINDOW(shell));
304 } else {
305 revolution_response(shell, GTK_RESPONSE_YES, government);
306 }
307}
308
309/**********************************************************************/
312static void pillage_callback(GtkWidget *dlg, gint arg)
313{
315
316 if (arg == GTK_RESPONSE_YES) {
317 int au_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dlg),
318 "actor"));
319 struct unit *actor = game_unit_by_number(au_id);
320
321 int tgt_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dlg),
322 "target"));
323 struct extra_type *tgt_extra = extra_by_number(tgt_id);
324
325 if (actor && tgt_extra) {
327 tgt_extra);
328 }
329 }
330
331 gtk_widget_destroy(dlg);
332}
333
334/**********************************************************************/
337void popup_pillage_dialog(struct unit *punit, bv_extras extras)
338{
340 /* Possibly legal target extras. */
341 bv_extras alternative;
342 /* Selected by default. */
343 struct extra_type *preferred_tgt;
344 /* Current target to check. */
345 struct extra_type *tgt;
346
348
349 BV_CLR_ALL(alternative);
350 preferred_tgt = get_preferred_pillage(extras);
351
352 while ((tgt = get_preferred_pillage(extras))) {
353 int what;
354
355 what = extra_index(tgt);
356 BV_CLR(extras, what);
357 BV_SET(alternative, what);
358 }
359
360 select_tgt_extra(punit, unit_tile(punit), alternative, preferred_tgt,
361 /* TRANS: Pillage dialog title. */
362 _("What To Pillage"),
363 /* TRANS: Pillage dialog actor text. */
364 _("Looking for target extra:"),
365 /* TRANS: Pillage dialog target text. */
366 _("Select what to pillage:"),
367 /* TRANS: Pillage dialog do button text. */
368 _("Pillage"), G_CALLBACK(pillage_callback));
369 }
370}
371
372/**********************************************************************/
377{
379}
380
381/**********************************************************************/
389
390/**************************************************************************
391 NATION SELECTION DIALOG
392**************************************************************************/
393/**********************************************************************/
398static GtkTreePath *path_to_nation_on_list(Nation_type_id nation,
399 GtkTreeView *list)
400{
401 if (nation == -1 || list == NULL) {
402 return NULL;
403 } else {
404 GtkTreeModel *model = gtk_tree_view_get_model(list);
405 GtkTreeIter iter;
406 GtkTreePath *path = NULL;
407 gtk_tree_model_get_iter_first(model, &iter);
408 do {
409 int nation_of_row;
410 gtk_tree_model_get(model, &iter, 0, &nation_of_row, -1);
411 if (nation == nation_of_row) {
412 path = gtk_tree_model_get_path(model, &iter);
413 break;
414 }
415 } while (gtk_tree_model_iter_next(model, &iter));
416 return path;
417 }
418}
419
420/**********************************************************************/
426static void select_nation_on_tab(GtkWidget *tab_list, int nation)
427{
428 /* tab_list is a GtkTreeView (not its enclosing GtkScrolledWindow). */
429 GtkTreeView *list = GTK_TREE_VIEW(tab_list);
430 GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
431 GtkTreePath *path = path_to_nation_on_list(nation, list);
432
433 /* Suppress normal effects of selection change to avoid loops. */
434 g_signal_handlers_block_by_func(select, races_nation_callback, NULL);
435 if (path) {
436 /* Found nation on this list. */
437 /* Avoid disturbing tabs that already have the correct selection. */
438 if (!gtk_tree_selection_path_is_selected(select, path)) {
439 /* Set cursor -- this will cause the nation to be selected */
440 gtk_tree_view_set_cursor(list, path, NULL, FALSE);
441 /* Make sure selected nation is visible in list */
442 gtk_tree_view_scroll_to_cell(list, path, NULL, FALSE, 0, 0);
443 }
444 } else {
445 /* Either no nation was selected, or the nation is not mentioned in
446 * this tab. Either way we want to end up with no selection. */
447 GtkTreePath *cursorpath;
448 /* If there is no cursor, Gtk tends to focus and select the first row
449 * at the first opportunity, disturbing any existing state. We want to
450 * allow the no-rows-selected state, so detect this case and defuse
451 * it by setting a cursor. */
452 gtk_tree_view_get_cursor(list, &cursorpath, NULL);
453 /* Set the cursor in the case above, or if there was a previous
454 * selection */
455 if (!cursorpath || gtk_tree_selection_get_selected(select, NULL, NULL)) {
456 cursorpath = gtk_tree_path_new_first();
457 gtk_tree_view_set_cursor(list, cursorpath, NULL, FALSE);
458 }
459 gtk_tree_selection_unselect_all(select);
460 gtk_tree_path_free(cursorpath);
461 }
462 gtk_tree_path_free(path);
463 /* Re-enable selection change side-effects */
464 g_signal_handlers_unblock_by_func(select, races_nation_callback, NULL);
465}
466
467/**********************************************************************/
470static void sync_tabs_to_nation(int nation)
471{
472 /* Ensure that all tabs are in sync with the new selection */
473 int i;
474
475 for (i = 0; i <= nation_group_count(); i++) {
476 if (races_nation_list[i]) {
478 }
479 }
480}
481
482/**********************************************************************/
486static void populate_leader_list(void)
487{
488 int i;
489 GtkListStore *model =
490 GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(races_leader)));
491
492 i = 0;
493 gtk_list_store_clear(model);
494 if (selected_nation >= 0) {
496 (selected_nation)), pleader) {
497 const char *leader_name = nation_leader_name(pleader);
498 GtkTreeIter iter; /* unused */
499
500 gtk_list_store_insert_with_values(model, &iter, i, 0, leader_name, -1);
501 i++;
503 }
504}
505
506/**********************************************************************/
512static void select_nation(int nation,
513 const char *leadername, bool is_male,
514 int style_id)
515{
516 selected_nation = nation;
517
518 /* Refresh the available leaders. */
520
521 if (selected_nation != -1) {
522
523 /* Select leader name and sex. */
524 if (leadername) {
525 gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(races_leader))),
526 leadername);
527 /* Assume is_male is valid too. */
528 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(races_sex[is_male]),
529 TRUE);
530 } else {
531 int idx = fc_rand(nation_leader_list_size(
533
534 gtk_combo_box_set_active(GTK_COMBO_BOX(races_leader), idx);
535 /* This also updates the leader sex, eventually. */
536 }
537
538 /* Select the appropriate city style entry. */
539 {
540 int i;
541 int j = 0;
542 GtkTreePath *path;
543
544 styles_iterate(pstyle) {
545 i = basic_city_style_for_style(pstyle);
546
547 if (i >= 0 && i < style_id) {
548 j++;
549 } else {
550 break;
551 }
553
554 path = gtk_tree_path_new();
555 gtk_tree_path_append_index(path, j);
556 gtk_tree_view_set_cursor(GTK_TREE_VIEW(races_style_list), path,
557 NULL, FALSE);
558 gtk_tree_path_free(path);
559 }
560
561 /* Update nation description. */
562 {
563 char buf[4096];
564
565 helptext_nation(buf, sizeof(buf),
567 gtk_text_buffer_set_text(races_text, buf, -1);
568 }
569
570 gtk_widget_set_sensitive(races_properties, TRUE);
571 /* Once we've made a nation selection, allow user to ok */
572 gtk_dialog_set_response_sensitive(GTK_DIALOG(races_shell),
573 GTK_RESPONSE_ACCEPT, TRUE);
574 } else {
575 /* No nation selected. Blank properties and make controls insensitive. */
576 /* Leader name */
577 gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(races_leader))),
578 "");
579 /* Leader sex (*shrug*) */
580 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(races_sex[0]), TRUE);
581 /* City style */
582 {
583 GtkTreeSelection* select
584 = gtk_tree_view_get_selection(GTK_TREE_VIEW(races_style_list));
585
586 gtk_tree_selection_unselect_all(select);
587 }
588 /* Nation description */
589 gtk_text_buffer_set_text(races_text, "", 0);
590
591 gtk_widget_set_sensitive(races_properties, FALSE);
592 /* Don't allow OK without a selection
593 * (user can still do "Random Nation") */
594 gtk_dialog_set_response_sensitive(GTK_DIALOG(races_shell),
595 GTK_RESPONSE_ACCEPT, FALSE);
596 }
597
598 /* Update notebook to reflect the current selection */
600}
601
602/**********************************************************************/
608static GtkWidget* create_list_of_nations_in_group(struct nation_group* group,
609 int index)
610{
611 GtkWidget *sw = NULL;
612 GtkListStore *store = NULL;
613 GtkWidget *list = NULL;
614
615 /* Populate nation list store. */
616 nations_iterate(pnation) {
617 bool used;
618 GdkPixbuf *img;
619 GtkTreeIter it;
620 GValue value = { 0, };
621
622 if (!is_nation_playable(pnation) || !is_nation_pickable(pnation)) {
623 continue;
624 }
625
626 if (NULL != group && !nation_is_in_group(pnation, group)) {
627 continue;
628 }
629
630 /* Only create tab on demand -- we don't want it if there aren't any
631 * currently pickable nations in this group. */
632 if (sw == NULL) {
633 GtkTreeSelection *select;
634 GtkCellRenderer *render;
635 GtkTreeViewColumn *column;
636
637 store = gtk_list_store_new(4, G_TYPE_INT, G_TYPE_BOOLEAN,
638 GDK_TYPE_PIXBUF, G_TYPE_STRING);
639 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store),
640 3, GTK_SORT_ASCENDING);
641
642 list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
643 gtk_widget_set_hexpand(list, TRUE);
644 gtk_widget_set_vexpand(list, TRUE);
645 gtk_tree_view_set_search_column(GTK_TREE_VIEW(list), 3);
646 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), FALSE);
647 g_object_unref(store);
648
649 select = gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
650 g_signal_connect(select, "changed", G_CALLBACK(races_nation_callback),
651 NULL);
652 gtk_tree_selection_set_select_function(select, races_selection_func,
653 NULL, NULL);
654
655 sw = gtk_scrolled_window_new(NULL, NULL);
656 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
657 GTK_SHADOW_ETCHED_IN);
658 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
659 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
660 gtk_container_add(GTK_CONTAINER(sw), list);
661
662 render = gtk_cell_renderer_pixbuf_new();
663 column = gtk_tree_view_column_new_with_attributes("Flag", render,
664 "pixbuf", 2, NULL);
665 gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
666 render = gtk_cell_renderer_text_new();
667 column = gtk_tree_view_column_new_with_attributes("Nation", render,
668 "text", 3, "strikethrough", 1, NULL);
669 gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
670 }
671
672 gtk_list_store_append(store, &it);
673
674 used = (pnation->player != NULL && pnation->player != races_player);
675 gtk_list_store_set(store, &it, 0, nation_number(pnation), 1, used, -1);
676 img = get_flag(pnation);
677 if (img != NULL) {
678 gtk_list_store_set(store, &it, 2, img, -1);
679 g_object_unref(img);
680 }
681
682 g_value_init(&value, G_TYPE_STRING);
683 g_value_set_static_string(&value, nation_adjective_translation(pnation));
684 gtk_list_store_set_value(store, &it, 3, &value);
685 g_value_unset(&value);
687
688 races_nation_list[index] = list;
689 return sw;
690}
691
692/**********************************************************************/
696{
697 GtkWidget *nation_list;
698 GtkWidget *group_name_label;
699
700 int i;
701
702 for (i = 0; i < nation_group_count(); i++) {
703 struct nation_group* group = (nation_group_by_number(i));
704 if (is_nation_group_hidden(group)) {
705 races_nation_list[i] = NULL;
706 continue;
707 }
708 nation_list = create_list_of_nations_in_group(group, i);
709 if (nation_list) {
710 group_name_label = gtk_label_new(nation_group_name_translation(group));
711 gtk_notebook_append_page(GTK_NOTEBOOK(races_notebook), nation_list,
712 group_name_label);
713 }
714 }
715
717 /* Even this list can be empty if there are no pickable nations (due to
718 * a combination of start position and nationset restrictions). */
719 if (nation_list) {
720 group_name_label = gtk_label_new(_("All"));
721 gtk_notebook_append_page(GTK_NOTEBOOK(races_notebook), nation_list,
722 group_name_label);
723 }
724}
725
726/**********************************************************************/
730void races_update_pickable(bool nationset_change)
731{
732 int tab, groupidx;
733
734 if (!races_shell) {
735 return;
736 }
737
738 /* Save selected tab */
739 tab = gtk_notebook_get_current_page(GTK_NOTEBOOK(races_notebook));
740 if (tab != -1) {
741 int i = 0;
742 groupidx = 0;
743 /* Turn tab index into a nation group index (they're not always equal,
744 * as some groups may not currently have tabs). */
745 do {
746 while (groupidx <= nation_group_count()
747 && races_nation_list[groupidx] == NULL) {
748 groupidx++;
749 }
750 fc_assert_action(groupidx <= nation_group_count(), break);
751 /* Nation group 'groupidx' is what's displayed on the i'th tab */
752 if (i == tab) {
753 break;
754 }
755 i++;
756 groupidx++;
757 } while (TRUE);
758 } else {
759 /* No tabs currently */
760 groupidx = -1;
761 }
762
763 /* selected_nation already contains currently selected nation; however,
764 * it may no longer be a valid choice */
765 if (selected_nation != -1
767 select_nation(-1, NULL, FALSE, 0);
768 }
769
770 /* Delete all list stores, treeviews, tabs */
771 while (gtk_notebook_get_n_pages(GTK_NOTEBOOK(races_notebook)) > 0) {
772 gtk_notebook_remove_page(GTK_NOTEBOOK(races_notebook), -1);
773 }
774
775 /* (Re)create all of them */
777
778 /* Can't set current tab before child widget is visible */
779 gtk_widget_show_all(GTK_WIDGET(races_notebook));
780
781 /* Restore selected tab */
782 if (groupidx != -1 && races_nation_list[groupidx] != NULL) {
783 int i;
784 tab = 0;
785 for (i = 0; i < groupidx; i++) {
786 if (races_nation_list[i] != NULL) {
787 tab++;
788 }
789 }
790 gtk_notebook_set_current_page(GTK_NOTEBOOK(races_notebook), tab);
791 }
792
793 /* Restore selected nation */
795}
796
797/**********************************************************************/
800void nationset_sync_to_server(const char *nationset)
801{
802 if (nationsets_chooser) {
803 struct nation_set *set = nation_set_by_setting_value(nationset);
804
805 gtk_combo_box_set_active(GTK_COMBO_BOX(nationsets_chooser),
806 nation_set_index(set));
807 }
808}
809
810/**********************************************************************/
813static void nationset_callback(GtkComboBox *b, gpointer data)
814{
815 GtkTreeIter iter;
816 if (gtk_combo_box_get_active_iter(b, &iter)) {
817 struct option *poption = optset_option_by_name(server_optset, "nationset");
818 gchar *rule_name;
819
820 gtk_tree_model_get(gtk_combo_box_get_model(b), &iter,
821 0, &rule_name, -1);
822 /* Suppress propagation of an option value equivalent to the current
823 * server state, after canonicalisation, to avoid loops from
824 * nationset_sync_to_server().
825 * (HACK: relies on local Gtk "changed" signal getting here before
826 * server response.) */
828 != nation_set_by_rule_name(rule_name)) {
829 option_str_set(poption, rule_name);
830 }
831 FC_FREE(rule_name);
832 }
833}
834
835/**********************************************************************/
838static void create_races_dialog(struct player *pplayer)
839{
840 GtkWidget *shell;
841 GtkWidget *cmd;
842 GtkWidget *hbox, *table;
843 GtkWidget *frame, *label, *combo;
844 GtkWidget *text;
845 GtkWidget *notebook;
846 GtkWidget *sw;
847 GtkWidget *list;
848 GtkListStore *store;
849 GtkCellRenderer *render;
850 GtkTreeViewColumn *column;
851 int i;
852 char *title;
853
854 /* Init. */
855 selected_nation = -1;
856
857 if (C_S_RUNNING == client_state()) {
858 title = _("Edit Nation");
859 } else if (NULL != pplayer && pplayer == client.conn.playing) {
860 title = _("What Nation Will You Be?");
861 } else {
862 title = _("Pick Nation");
863 }
864
865 shell = gtk_dialog_new_with_buttons(title,
866 NULL,
867 0,
868 _("_Cancel"),
869 GTK_RESPONSE_CANCEL,
870 _("_Random Nation"),
871 GTK_RESPONSE_NO, /* arbitrary */
872 _("_OK"),
873 GTK_RESPONSE_ACCEPT,
874 NULL);
876 races_player = pplayer;
878
879 gtk_window_set_position(GTK_WINDOW(shell), GTK_WIN_POS_CENTER_ON_PARENT);
880 gtk_window_set_default_size(GTK_WINDOW(shell), -1, 590);
881
882 frame = gtk_frame_new(_("Select a nation"));
883 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(shell))), frame);
884
885 hbox = gtk_grid_new();
886 gtk_grid_set_column_spacing(GTK_GRID(hbox), 18);
887 gtk_container_set_border_width(GTK_CONTAINER(hbox), 3);
888 gtk_container_add(GTK_CONTAINER(frame), hbox);
889
890 /* Left side: nation list */
891 {
892 GtkWidget* nation_selection_list = gtk_grid_new();
893 nationsets_chooser = NULL;
894
895 gtk_grid_set_row_spacing(GTK_GRID(nation_selection_list), 2);
896
897 /* Nationset selector dropdown */
898 /* Only present this if there is more than one choice.
899 * (If ruleset is changed, possibly changing the number of available sets
900 * and invalidating this decision, then dialog will be popped down.) */
901 if (nation_set_count() > 1) {
902 GtkListStore *sets_model = gtk_list_store_new(4, G_TYPE_STRING,
903 G_TYPE_STRING,
904 G_TYPE_STRING,
905 G_TYPE_STRING);
906 GtkCellRenderer *renderer;
907 nation_sets_iterate(pset) {
908 /* Index in list store must match nation_set_index(). */
909 gchar *escaped;
910 struct astring s = ASTRING_INIT;
911 int num_nations = 0;
912
913 nations_iterate(pnation) {
914 if (is_nation_playable(pnation) && nation_is_in_set(pnation, pset)) {
915 num_nations++;
916 }
918 escaped = g_markup_escape_text(nation_set_name_translation(pset), -1);
919 /* TRANS: nation set name followed by number of playable nations;
920 * <b> and </b> are Pango markup and should be left alone */
921 astr_set(&s, PL_("<b>%s</b> (%d nation)",
922 "<b>%s</b> (%d nations)", num_nations),
923 escaped, num_nations);
924 g_free(escaped);
925 if (strlen(nation_set_description(pset)) > 0) {
926 /* While in principle it would be better to get Gtk to wrap the
927 * drop-down (e.g. via "wrap-width" property), there's no way
928 * to specify the indentation we want. So we do it ourselves. */
929 char *desc = fc_strdup(_(nation_set_description(pset)));
930 char *p = desc;
931
932 fc_break_lines(desc, 70);
933 astr_add(&s, "\n");
934 while (*p) {
935 int len = strcspn(p, "\n");
936
937 if (p[len] == '\n') {
938 len++;
939 }
940 escaped = g_markup_escape_text(p, len);
941 astr_add(&s, "\t%s", escaped);
942 g_free(escaped);
943 p += len;
944 }
945 FC_FREE(desc);
946 }
947 gtk_list_store_insert_with_values(sets_model, NULL, -1,
948 0, nation_set_rule_name(pset),
949 1, astr_str(&s),
951 -1);
952 astr_free(&s);
954
955 /* We want a combo box where the button displays just the set name,
956 * but the dropdown displays the expanded description. */
958 = gtk_combo_box_new_with_model_and_entry(GTK_TREE_MODEL(sets_model));
959 g_object_unref(G_OBJECT(sets_model));
960 {
961 /* Do our best to turn the text-entry widget into something more
962 * like a cell-view: disable editing, and focusing (which removes
963 * the caret). */
964 GtkWidget *entry = gtk_bin_get_child(GTK_BIN(nationsets_chooser));
965
966 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
967 gtk_widget_set_can_focus(entry, FALSE);
968 }
969 /* The entry displays the set name. */
970 gtk_combo_box_set_entry_text_column(GTK_COMBO_BOX(nationsets_chooser),
971 2);
972 /* The dropdown displays the marked-up description. */
973 renderer = gtk_cell_renderer_text_new();
974 gtk_cell_layout_clear(GTK_CELL_LAYOUT(nationsets_chooser));
975 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(nationsets_chooser),
976 renderer, TRUE);
977 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(nationsets_chooser),
978 renderer, "markup", 1, NULL);
979 g_signal_connect(nationsets_chooser, "destroy",
980 G_CALLBACK(gtk_widget_destroyed), &nationsets_chooser);
981 g_signal_connect(nationsets_chooser, "changed",
982 G_CALLBACK(nationset_callback), NULL);
983 {
984 /* Populate initially from client's view of server setting */
986 "nationset");
987 if (poption) {
989 }
990 }
991
992 label = g_object_new(GTK_TYPE_LABEL,
993 "use-underline", TRUE,
994 "label", _("_Nation Set:"),
995 "xalign", 0.0,
996 "yalign", 0.5,
997 NULL);
998 gtk_label_set_mnemonic_widget(GTK_LABEL(label), nationsets_chooser);
999
1000 gtk_widget_set_hexpand(nationsets_chooser, TRUE);
1001 gtk_grid_attach(GTK_GRID(nation_selection_list), label,
1002 0, 0, 1, 1);
1003 gtk_grid_attach(GTK_GRID(nation_selection_list), nationsets_chooser,
1004 1, 0, 1, 1);
1005 }
1006
1007 races_notebook = gtk_notebook_new();
1008 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(races_notebook), GTK_POS_LEFT);
1009 gtk_grid_attach(GTK_GRID(nation_selection_list), races_notebook,
1010 0, 2, 2, 1);
1011
1012 /* Suppress notebook tabs if there will be only one ("All") */
1013 {
1014 bool show_groups = FALSE;
1015
1016 nation_groups_iterate(pgroup) {
1017 if (!is_nation_group_hidden(pgroup)) {
1018 show_groups = TRUE;
1019 break;
1020 }
1022 if (!show_groups) {
1023 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(races_notebook), FALSE);
1024 } else {
1025 label = g_object_new(GTK_TYPE_LABEL,
1026 "use-underline", TRUE,
1027 "label", _("Nation _Groups:"),
1028 "xalign", 0.0,
1029 "yalign", 0.5,
1030 NULL);
1031 gtk_label_set_mnemonic_widget(GTK_LABEL(label), races_notebook);
1032 gtk_grid_attach(GTK_GRID(nation_selection_list), label,
1033 0, 1, 2, 1);
1034 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(races_notebook), TRUE);
1035 }
1036 }
1037
1038 /* Populate treeview */
1040
1041 gtk_container_add(GTK_CONTAINER(hbox), nation_selection_list);
1042 }
1043
1044 /* Right side. */
1045 notebook = gtk_notebook_new();
1046 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_BOTTOM);
1047 gtk_container_add(GTK_CONTAINER(hbox), notebook);
1048
1049 /* Properties pane. */
1050 label = gtk_label_new_with_mnemonic(_("_Properties"));
1051
1052 races_properties = table = gtk_grid_new();
1053 g_signal_connect(table, "destroy",
1054 G_CALLBACK(gtk_widget_destroyed), &races_properties);
1055 g_object_set(table, "margin", 6, NULL);
1056 gtk_grid_set_row_spacing(GTK_GRID(table), 2);
1057 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), table, label);
1058
1059 /* Leader. */
1060 {
1061 GtkListStore *model = gtk_list_store_new(1, G_TYPE_STRING);
1062
1063 combo = gtk_combo_box_new_with_model_and_entry(GTK_TREE_MODEL(model));
1064 gtk_combo_box_set_entry_text_column(GTK_COMBO_BOX(combo), 0);
1065 g_object_unref(G_OBJECT(model));
1066 }
1067 races_leader = combo;
1068 label = g_object_new(GTK_TYPE_LABEL,
1069 "use-underline", TRUE,
1070 "mnemonic-widget", GTK_COMBO_BOX(combo),
1071 "label", _("_Leader:"),
1072 "xalign", 0.0,
1073 "yalign", 0.5,
1074 NULL);
1075 gtk_widget_set_margin_bottom(label, 6);
1076 gtk_widget_set_margin_end(label, 12);
1077 gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 2);
1078 gtk_grid_attach(GTK_GRID(table), combo, 1, 0, 2, 1);
1079
1080 cmd = gtk_radio_button_new_with_mnemonic(NULL, _("_Female"));
1081 gtk_widget_set_margin_bottom(cmd, 6);
1082 races_sex[0] = cmd;
1083 gtk_grid_attach(GTK_GRID(table), cmd, 1, 1, 1, 1);
1084
1085 cmd = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(cmd),
1086 _("_Male"));
1087 gtk_widget_set_margin_bottom(cmd, 6);
1088 races_sex[1] = cmd;
1089 gtk_grid_attach(GTK_GRID(table), cmd, 2, 1, 1, 1);
1090
1091 /* City style. */
1092 store = gtk_list_store_new(3, G_TYPE_INT,
1093 GDK_TYPE_PIXBUF, G_TYPE_STRING);
1094
1095 list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1096 gtk_widget_set_hexpand(list, TRUE);
1097 gtk_widget_set_vexpand(list, TRUE);
1099 g_object_unref(store);
1100 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), FALSE);
1101 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(list)), "changed",
1102 G_CALLBACK(races_style_callback), NULL);
1103
1104 sw = gtk_scrolled_window_new(NULL, NULL);
1105 gtk_widget_set_margin_top(sw, 6);
1106 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
1107 GTK_SHADOW_ETCHED_IN);
1108 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1109 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1110 gtk_container_add(GTK_CONTAINER(sw), list);
1111 gtk_grid_attach(GTK_GRID(table), sw, 1, 2, 2, 2);
1112
1113 label = g_object_new(GTK_TYPE_LABEL,
1114 "use-underline", TRUE,
1115 "mnemonic-widget", list,
1116 "label", _("City _Styles:"),
1117 "xalign", 0.0,
1118 "yalign", 0.5,
1119 NULL);
1120 gtk_widget_set_margin_top(label, 6);
1121 gtk_widget_set_margin_end(label, 12);
1122 gtk_grid_attach(GTK_GRID(table), label, 0, 2, 1, 1);
1123
1124 render = gtk_cell_renderer_pixbuf_new();
1125 column = gtk_tree_view_column_new_with_attributes(NULL, render,
1126 "pixbuf", 1, NULL);
1127 gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
1128 render = gtk_cell_renderer_text_new();
1129 column = gtk_tree_view_column_new_with_attributes(NULL, render,
1130 "text", 2, NULL);
1131 gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
1132
1133 /* Populate style store. */
1134 styles_iterate(pstyle) {
1135 GdkPixbuf *img;
1136 struct sprite *s;
1137 GtkTreeIter it;
1138
1139 i = basic_city_style_for_style(pstyle);
1140
1141 if (i >= 0) {
1142 gtk_list_store_append(store, &it);
1143
1146 free_sprite(s);
1147 gtk_list_store_set(store, &it, 0, i, 1, img, 2,
1149 g_object_unref(img);
1150 }
1152
1153 /* Legend pane. */
1154 label = gtk_label_new_with_mnemonic(_("_Description"));
1155
1156 text = gtk_text_view_new();
1157 g_object_set(text, "margin", 6, NULL);
1158 gtk_widget_set_hexpand(text, TRUE);
1159 gtk_widget_set_vexpand(text, TRUE);
1160 races_text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text));
1161 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD);
1162 gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);
1163 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(text), FALSE);
1164 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text), 6);
1165 gtk_text_view_set_right_margin(GTK_TEXT_VIEW(text), 6);
1166
1167 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), text, label);
1168
1169 /* Signals. */
1170 g_signal_connect(shell, "destroy",
1171 G_CALLBACK(gtk_widget_destroyed), &races_shell);
1172 g_signal_connect(shell, "response",
1173 G_CALLBACK(races_response), NULL);
1174
1175 g_signal_connect(GTK_COMBO_BOX(races_leader), "changed",
1176 G_CALLBACK(races_leader_callback), NULL);
1177
1178 g_signal_connect(races_sex[0], "toggled",
1179 G_CALLBACK(races_sex_callback), GINT_TO_POINTER(0));
1180 g_signal_connect(races_sex[1], "toggled",
1181 G_CALLBACK(races_sex_callback), GINT_TO_POINTER(1));
1182
1183 /* Finish up. */
1184 gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_CANCEL);
1185
1186 /* You can't assign NO_NATION during a running game. */
1187 if (C_S_RUNNING == client_state()) {
1188 gtk_dialog_set_response_sensitive(GTK_DIALOG(shell), GTK_RESPONSE_NO,
1189 FALSE);
1190 }
1191
1192 gtk_widget_show_all(gtk_dialog_get_content_area(GTK_DIALOG(shell)));
1193
1194 /* Select player's current nation in UI, if any */
1195 if (races_player->nation) {
1200 /* Make sure selected nation is visible
1201 * (last page, "All", will certainly contain it) */
1202 fc_assert(gtk_notebook_get_n_pages(GTK_NOTEBOOK(races_notebook)) > 0);
1203 gtk_notebook_set_current_page(GTK_NOTEBOOK(races_notebook), -1);
1204 } else {
1205 select_nation(-1, NULL, FALSE, 0);
1206 }
1207}
1208
1209/**********************************************************************/
1212void popup_races_dialog(struct player *pplayer)
1213{
1214 if (!pplayer) {
1215 return;
1216 }
1217
1218 if (!races_shell) {
1219 create_races_dialog(pplayer);
1220 gtk_window_present(GTK_WINDOW(races_shell));
1221 }
1222}
1223
1224/**********************************************************************/
1228{
1229 if (races_shell) {
1230 gtk_widget_destroy(races_shell);
1231 }
1232
1233 /* We're probably starting a new game, maybe with a new ruleset.
1234 So we warn the worklist dialog. */
1236}
1237
1238/**********************************************************************/
1243{
1244 int i;
1245
1246 if (!races_shell) {
1247 return;
1248 }
1249
1250 for (i = 0; i <= nation_group_count(); i++) {
1251 if (races_nation_list[i]) {
1252 GtkTreeView *list = GTK_TREE_VIEW(races_nation_list[i]);
1253 GtkTreeModel *model = gtk_tree_view_get_model(list);
1254 GtkTreeSelection* select = gtk_tree_view_get_selection(list);
1255 GtkTreeIter it;
1256 gboolean chosen;
1257
1258 /* Update 'chosen' column in model */
1259 if (gtk_tree_model_get_iter_first(model, &it)) {
1260 do {
1261 int nation_no;
1262 struct nation_type *nation;
1263
1264 gtk_tree_model_get(model, &it, 0, &nation_no, -1);
1265 nation = nation_by_number(nation_no);
1266
1267 chosen = !is_nation_pickable(nation)
1268 || (nation->player && nation->player != races_player);
1269
1270 gtk_list_store_set(GTK_LIST_STORE(model), &it, 1, chosen, -1);
1271
1272 } while (gtk_tree_model_iter_next(model, &it));
1273 }
1274
1275 /* If our selection is now invalid, deselect it */
1276 if (gtk_tree_selection_get_selected(select, &model, &it)) {
1277 gtk_tree_model_get(model, &it, 1, &chosen, -1);
1278
1279 if (chosen) {
1280 gtk_tree_selection_unselect_all(select);
1281 }
1282 }
1283 }
1284 }
1285}
1286
1287/**********************************************************************/
1290static void races_nation_callback(GtkTreeSelection *select, gpointer data)
1291{
1292 GtkTreeModel *model;
1293 GtkTreeIter it;
1294
1295 if (gtk_tree_selection_get_selected(select, &model, &it)) {
1296 gboolean chosen;
1297 int newnation;
1298
1299 gtk_tree_model_get(model, &it, 0, &newnation, 1, &chosen, -1);
1300
1301 /* Only allow nations not chosen by another player */
1302 if (!chosen) {
1303 if (newnation != selected_nation) {
1304 /* Choose a random leader */
1305 select_nation(newnation, NULL, FALSE,
1307 }
1308 return;
1309 }
1310 }
1311
1312 /* Fall-through if no valid nation selected */
1313 select_nation(-1, NULL, FALSE, 0);
1314}
1315
1316/**********************************************************************/
1319static void races_leader_callback(void)
1320{
1321 const struct nation_leader *pleader;
1322 const gchar *name;
1323
1324 name =
1325 gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(races_leader))));
1326
1327 if (selected_nation != -1
1329 name))) {
1331 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(races_sex[selected_sex]),
1332 TRUE);
1333 }
1334}
1335
1336/**********************************************************************/
1339static void races_sex_callback(GtkWidget *w, gpointer data)
1340{
1341 selected_sex = GPOINTER_TO_INT(data);
1342}
1343
1344/**********************************************************************/
1347static gboolean races_selection_func(GtkTreeSelection *select,
1348 GtkTreeModel *model, GtkTreePath *path,
1349 gboolean selected, gpointer data)
1350{
1351 GtkTreeIter it;
1352 gboolean chosen;
1353
1354 gtk_tree_model_get_iter(model, &it, path);
1355 gtk_tree_model_get(model, &it, 1, &chosen, -1);
1356 return (!chosen || selected);
1357}
1358
1359/**********************************************************************/
1362static void races_style_callback(GtkTreeSelection *select, gpointer data)
1363{
1364 GtkTreeModel *model;
1365 GtkTreeIter it;
1366
1367 if (gtk_tree_selection_get_selected(select, &model, &it)) {
1368 gtk_tree_model_get(model, &it, 0, &selected_style, -1);
1369 } else {
1370 selected_style = -1;
1371 }
1372}
1373
1374/**********************************************************************/
1377static void races_response(GtkWidget *w, gint response, gpointer data)
1378{
1379 if (response == GTK_RESPONSE_ACCEPT) {
1380 const char *s;
1381
1382 /* This shouldn't be possible but... */
1383 if (selected_nation == -1) {
1384 return;
1385 }
1386
1387 if (selected_sex == -1) {
1388 output_window_append(ftc_client, _("You must select your sex."));
1389 return;
1390 }
1391
1392 if (selected_style == -1) {
1393 output_window_append(ftc_client, _("You must select your style."));
1394 return;
1395 }
1396
1397 s = gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(races_leader))));
1398
1399 /* Perform a minimum of sanity test on the name. */
1400 /* This could call is_allowed_player_name if it were available. */
1401 if (strlen(s) == 0) {
1402 output_window_append(ftc_client, _("You must type a legal name."));
1403 return;
1404 }
1405
1408 selected_sex, s,
1410 } else if (response == GTK_RESPONSE_NO) {
1413 -1, FALSE, "", 0);
1414 }
1415
1417}
1418
1419/**********************************************************************/
1422gboolean taxrates_callback(GtkWidget *w, GdkEventButton *ev, gpointer data)
1423{
1424 common_taxrates_callback((size_t) data, FALSE);
1425
1426 return TRUE;
1427}
1428
1429/**********************************************************************/
1432void popup_upgrade_dialog(struct unit_list *punits)
1433{
1434 GtkWidget *shell;
1435 char buf[512];
1436
1437 if (!punits || unit_list_size(punits) == 0) {
1438 return;
1439 }
1440
1441 if (!get_units_upgrade_info(buf, sizeof(buf), punits)) {
1442 shell = gtk_message_dialog_new(NULL, 0,
1443 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
1444 "%s", buf);
1445 gtk_window_set_title(GTK_WINDOW(shell), _("Upgrade Unit!"));
1447 g_signal_connect(shell, "response", G_CALLBACK(gtk_widget_destroy),
1448 NULL);
1449 gtk_window_present(GTK_WINDOW(shell));
1450 } else {
1451 shell = gtk_message_dialog_new(NULL, 0,
1452 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1453 "%s", buf);
1454 gtk_window_set_title(GTK_WINDOW(shell), _("Upgrade Obsolete Units"));
1456 gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_YES);
1457
1458 if (gtk_dialog_run(GTK_DIALOG(shell)) == GTK_RESPONSE_YES) {
1459 unit_list_iterate(punits, punit) {
1462 }
1463 gtk_widget_destroy(shell);
1464 }
1465}
1466
1467/**********************************************************************/
1470void popup_disband_dialog(struct unit_list *punits)
1471{
1472 GtkWidget *shell;
1473 char buf[512];
1474
1475 if (!punits || unit_list_size(punits) == 0) {
1476 return;
1477 }
1478
1479 if (!get_units_disband_info(buf, sizeof(buf), punits)) {
1480 shell = gtk_message_dialog_new(NULL, 0,
1481 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
1482 "%s", buf);
1483 gtk_window_set_title(GTK_WINDOW(shell), _("Disband Units"));
1485 g_signal_connect(shell, "response", G_CALLBACK(gtk_widget_destroy),
1486 NULL);
1487 gtk_window_present(GTK_WINDOW(shell));
1488 } else {
1489 shell = gtk_message_dialog_new(NULL, 0,
1490 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1491 "%s", buf);
1492 gtk_window_set_title(GTK_WINDOW(shell), _("Disband Units"));
1494 gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_YES);
1495
1496 if (gtk_dialog_run(GTK_DIALOG(shell)) == GTK_RESPONSE_YES) {
1497 unit_list_iterate(punits, punit) {
1498 if (unit_can_do_action(punit, ACTION_DISBAND_UNIT)) {
1500 }
1502 }
1503 gtk_widget_destroy(shell);
1504 }
1505}
1506
1507/**********************************************************************/
1517
1518/**********************************************************************/
1522{
1523 const struct advance *padvance = valid_advance_by_number(tech);
1524
1525 if (NULL != padvance
1526 && (GUI_GTK_OPTION(popup_tech_help) == GUI_POPUP_TECH_HELP_ENABLED
1527 || (GUI_GTK_OPTION(popup_tech_help) == GUI_POPUP_TECH_HELP_RULESET
1530 }
1531}
1532
1533/**********************************************************************/
1537void show_tileset_error(bool fatal, const char *tset_name, const char *msg)
1538{
1539 if (is_gui_up()) {
1540 GtkWidget *dialog;
1541
1542 if (tset_name != NULL) {
1543 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
1544 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
1545 _("Tileset \"%s\" problem, "
1546 "it's probably incompatible with "
1547 "the ruleset:\n%s"),
1548 tset_name, msg);
1549 } else {
1550 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
1551 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
1552 _("Tileset problem, "
1553 "it's probably incompatible with "
1554 "the ruleset:\n%s"),
1555 msg);
1556 }
1557
1558 setup_dialog(dialog, toplevel);
1559
1560 gtk_dialog_run(GTK_DIALOG(dialog));
1561
1562 gtk_widget_destroy(dialog);
1563 }
1564}
1565
1566/**********************************************************************/
1571{
1572 /* Just tell the client common code to handle this. */
1573 return FALSE;
1574}
1575
1576/**********************************************************************/
1580void popup_combat_info(int attacker_unit_id, int defender_unit_id,
1581 int attacker_hp, int defender_hp,
1582 bool make_att_veteran, bool make_def_veteran)
1583{
1584}
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
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