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-4.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 *vgrid, *label, *headline_label, *sw;
107 int grid_row = 0;
108
109 gui_dialog_new(&shell, GTK_NOTEBOOK(bottom_notebook), NULL, TRUE);
111
112 gui_dialog_add_button(shell, "window-close", _("_Close"),
113 GTK_RESPONSE_CLOSE);
114
115 vgrid = gtk_grid_new();
116 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
117 GTK_ORIENTATION_VERTICAL);
118 gtk_grid_set_row_spacing(GTK_GRID(vgrid), 2);
120
121 headline_label = gtk_label_new(headline);
122 gtk_grid_attach(GTK_GRID(vgrid), headline_label, 0, grid_row++, 1, 1);
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();
130 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), TRUE);
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_scrolled_window_set_child(GTK_SCROLLED_WINDOW(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_grid_attach(GTK_GRID(vgrid), sw, 0, grid_row++, 1, 1);
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
179 gtk_window_destroy(GTK_WINDOW(w));
180}
181
182/**********************************************************************/
185static void notify_connect_msg_response(GtkWidget *w, gint response)
186{
187 gtk_window_destroy(GTK_WINDOW(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
224 label = gtk_label_new(lines);
225 gtk_box_append(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(shell))), label);
226 gtk_widget_show(label);
227
228 g_object_set_data(G_OBJECT(shell), "tile", ptile);
229
230 g_signal_connect(shell, "response", G_CALLBACK(notify_goto_response), NULL);
231 gtk_widget_show(shell);
232}
233
234/**********************************************************************/
237void popup_connect_msg(const char *headline, const char *message)
238{
239 GtkWidget *shell, *label;
240
241 shell = gtk_dialog_new();
242 gtk_window_set_title(GTK_WINDOW(shell), headline);
244 gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_CLOSE);
245
246 label = gtk_label_new(message);
247 gtk_label_set_selectable(GTK_LABEL(label), 1);
248
249 gtk_box_append(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(shell))), label);
250 gtk_widget_show(label);
251
252 gtk_dialog_add_button(GTK_DIALOG(shell), _("_Close"),GTK_RESPONSE_CLOSE);
253
254 g_signal_connect(shell, "response", G_CALLBACK(notify_connect_msg_response),
255 NULL);
256 gtk_widget_show(shell);
257}
258
259/**********************************************************************/
262static void revolution_response(GtkWidget *w, gint response, gpointer data)
263{
264 struct government *government = data;
265
266 if (response == GTK_RESPONSE_YES) {
267 if (!government) {
269 } else {
271 }
272 }
273 if (w) {
274 gtk_window_destroy(GTK_WINDOW(w));
275 }
276}
277
278/**********************************************************************/
282{
283 static GtkWidget *shell = NULL;
284
286 if (!shell) {
287 shell = gtk_message_dialog_new(NULL,
288 0,
289 GTK_MESSAGE_WARNING,
290 GTK_BUTTONS_YES_NO,
291 _("You say you wanna revolution?"));
292 gtk_window_set_title(GTK_WINDOW(shell), _("Revolution!"));
294
295 g_signal_connect(shell, "destroy",
296 G_CALLBACK(widget_destroyed), &shell);
297 }
298 g_signal_connect(shell, "response",
299 G_CALLBACK(revolution_response), government);
300
301 gtk_window_present(GTK_WINDOW(shell));
302 } else {
303 revolution_response(shell, GTK_RESPONSE_YES, government);
304 }
305}
306
307/**********************************************************************/
310static void pillage_callback(GtkWidget *dlg, gint arg)
311{
313
314 if (arg == GTK_RESPONSE_YES) {
315 int au_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dlg),
316 "actor"));
317 struct unit *actor = game_unit_by_number(au_id);
318
319 int tgt_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dlg),
320 "target"));
321 struct extra_type *tgt_extra = extra_by_number(tgt_id);
322
323 if (actor && tgt_extra) {
325 tgt_extra);
326 }
327 }
328
329 gtk_window_destroy(GTK_WINDOW(dlg));
330}
331
332/**********************************************************************/
335void popup_pillage_dialog(struct unit *punit, bv_extras extras)
336{
338 /* Possibly legal target extras. */
339 bv_extras alternative;
340 /* Selected by default. */
341 struct extra_type *preferred_tgt;
342 /* Current target to check. */
343 struct extra_type *tgt;
344
346
347 BV_CLR_ALL(alternative);
348 preferred_tgt = get_preferred_pillage(extras);
349
350 while ((tgt = get_preferred_pillage(extras))) {
351 int what;
352
353 what = extra_index(tgt);
354 BV_CLR(extras, what);
355 BV_SET(alternative, what);
356 }
357
358 select_tgt_extra(punit, unit_tile(punit), alternative, preferred_tgt,
359 /* TRANS: Pillage dialog title. */
360 _("What To Pillage"),
361 /* TRANS: Pillage dialog actor text. */
362 _("Looking for target extra:"),
363 /* TRANS: Pillage dialog target text. */
364 _("Select what to pillage:"),
365 /* TRANS: Pillage dialog do button text. */
366 _("Pillage"), G_CALLBACK(pillage_callback));
367 }
368}
369
370/**********************************************************************/
375{
377}
378
379/**********************************************************************/
387
388/**************************************************************************
389 NATION SELECTION DIALOG
390**************************************************************************/
391/**********************************************************************/
396static GtkTreePath *path_to_nation_on_list(Nation_type_id nation,
397 GtkTreeView *list)
398{
399 if (nation == -1 || list == NULL) {
400 return NULL;
401 } else {
402 GtkTreeModel *model = gtk_tree_view_get_model(list);
403 GtkTreeIter iter;
404 GtkTreePath *path = NULL;
405
406 gtk_tree_model_get_iter_first(model, &iter);
407 do {
408 int nation_of_row;
409
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
449 /* If there is no cursor, Gtk tends to focus and select the first row
450 * at the first opportunity, disturbing any existing state. We want to
451 * allow the no-rows-selected state, so detect this case and defuse
452 * it by setting a cursor. */
453 gtk_tree_view_get_cursor(list, &cursorpath, NULL);
454 /* Set the cursor in the case above, or if there was a previous
455 * selection */
456 if (!cursorpath || gtk_tree_selection_get_selected(select, NULL, NULL)) {
457 cursorpath = gtk_tree_path_new_first();
458 gtk_tree_view_set_cursor(list, cursorpath, NULL, FALSE);
459 }
460 gtk_tree_selection_unselect_all(select);
461 gtk_tree_path_free(cursorpath);
462 }
463 gtk_tree_path_free(path);
464 /* Re-enable selection change side-effects */
465 g_signal_handlers_unblock_by_func(select, races_nation_callback, NULL);
466}
467
468/**********************************************************************/
471static void sync_tabs_to_nation(int nation)
472{
473 /* Ensure that all tabs are in sync with the new selection */
474 int i;
475
476 for (i = 0; i <= nation_group_count(); i++) {
477 if (races_nation_list[i]) {
479 }
480 }
481}
482
483/**********************************************************************/
487static void populate_leader_list(void)
488{
489 int i;
490 GtkListStore *model =
491 GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(races_leader)));
492
493 i = 0;
494 gtk_list_store_clear(model);
495 if (selected_nation >= 0) {
497 (selected_nation)), pleader) {
498 const char *leader_name = nation_leader_name(pleader);
499 GtkTreeIter iter; /* unused */
500
501 gtk_list_store_insert_with_values(model, &iter, i, 0, leader_name, -1);
502 i++;
504 }
505}
506
507/**********************************************************************/
513static void select_nation(int nation,
514 const char *leadername, bool is_male,
515 int style_id)
516{
517 GtkEntryBuffer *buffer = gtk_entry_get_buffer(GTK_ENTRY(gtk_combo_box_get_child(GTK_COMBO_BOX(races_leader))));
518
519 selected_nation = nation;
520
521 /* Refresh the available leaders. */
523
524 if (selected_nation != -1) {
525
526 /* Select leader name and sex. */
527 if (leadername) {
528 gtk_entry_buffer_set_text(buffer, leadername, -1);
529 /* Assume is_male is valid too. */
530 gtk_check_button_set_active(GTK_CHECK_BUTTON(races_sex[is_male]),
531 TRUE);
532 } else {
533 int idx = fc_rand(nation_leader_list_size(
535
536 gtk_combo_box_set_active(GTK_COMBO_BOX(races_leader), idx);
537 /* This also updates the leader sex, eventually. */
538 }
539
540 /* Select the appropriate city style entry. */
541 {
542 int i;
543 int j = 0;
544 GtkTreePath *path;
545
546 styles_iterate(pstyle) {
547 i = basic_city_style_for_style(pstyle);
548
549 if (i >= 0 && i < style_id) {
550 j++;
551 } else {
552 break;
553 }
555
556 path = gtk_tree_path_new();
557 gtk_tree_path_append_index(path, j);
558 gtk_tree_view_set_cursor(GTK_TREE_VIEW(races_style_list), path,
559 NULL, FALSE);
560 gtk_tree_path_free(path);
561 }
562
563 /* Update nation description. */
564 {
565 char buf[4096];
566
567 helptext_nation(buf, sizeof(buf),
569 gtk_text_buffer_set_text(races_text, buf, -1);
570 }
571
572 gtk_widget_set_sensitive(races_properties, TRUE);
573 /* Once we've made a nation selection, allow user to ok */
574 gtk_dialog_set_response_sensitive(GTK_DIALOG(races_shell),
575 GTK_RESPONSE_ACCEPT, TRUE);
576 } else {
577 /* No nation selected. Blank properties and make controls insensitive. */
578 /* Leader name */
579 gtk_entry_buffer_set_text(buffer, "", -1);
580 /* Leader sex (*shrug*) */
581 gtk_check_button_set_active(GTK_CHECK_BUTTON(races_sex[0]), TRUE);
582 /* City style */
583 {
584 GtkTreeSelection* select
585 = gtk_tree_view_get_selection(GTK_TREE_VIEW(races_style_list));
586
587 gtk_tree_selection_unselect_all(select);
588 }
589 /* Nation description */
590 gtk_text_buffer_set_text(races_text, "", 0);
591
592 gtk_widget_set_sensitive(races_properties, FALSE);
593 /* Don't allow OK without a selection
594 * (user can still do "Random Nation") */
595 gtk_dialog_set_response_sensitive(GTK_DIALOG(races_shell),
596 GTK_RESPONSE_ACCEPT, FALSE);
597 }
598
599 /* Update notebook to reflect the current selection */
601}
602
603/**********************************************************************/
609static GtkWidget* create_list_of_nations_in_group(struct nation_group* group,
610 int index)
611{
612 GtkWidget *sw = NULL;
613 GtkListStore *store = NULL;
614 GtkWidget *list = NULL;
615
616 /* Populate nation list store. */
617 nations_iterate(pnation) {
618 bool used;
619 GdkPixbuf *img;
620 GtkTreeIter it;
621 GValue value = { 0, };
622
623 if (!is_nation_playable(pnation) || !is_nation_pickable(pnation)) {
624 continue;
625 }
626
627 if (NULL != group && !nation_is_in_group(pnation, group)) {
628 continue;
629 }
630
631 /* Only create tab on demand -- we don't want it if there aren't any
632 * currently pickable nations in this group. */
633 if (sw == NULL) {
634 GtkTreeSelection *select;
635 GtkCellRenderer *render;
636 GtkTreeViewColumn *column;
637
638 store = gtk_list_store_new(4, G_TYPE_INT, G_TYPE_BOOLEAN,
639 GDK_TYPE_PIXBUF, G_TYPE_STRING);
640 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store),
641 3, GTK_SORT_ASCENDING);
642
643 list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
644 gtk_widget_set_hexpand(list, TRUE);
645 gtk_widget_set_vexpand(list, TRUE);
646 gtk_tree_view_set_search_column(GTK_TREE_VIEW(list), 3);
647 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), FALSE);
648 g_object_unref(store);
649
650 select = gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
651 g_signal_connect(select, "changed", G_CALLBACK(races_nation_callback),
652 NULL);
653 gtk_tree_selection_set_select_function(select, races_selection_func,
654 NULL, NULL);
655
656 sw = gtk_scrolled_window_new();
657 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), TRUE);
658 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
659 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
660 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(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 int i;
700
701 for (i = 0; i < nation_group_count(); i++) {
702 struct nation_group* group = (nation_group_by_number(i));
703
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
743 groupidx = 0;
744 /* Turn tab index into a nation group index (they're not always equal,
745 * as some groups may not currently have tabs). */
746 do {
747 while (groupidx <= nation_group_count()
748 && races_nation_list[groupidx] == NULL) {
749 groupidx++;
750 }
751 fc_assert_action(groupidx <= nation_group_count(), break);
752 /* Nation group 'groupidx' is what's displayed on the i'th tab */
753 if (i == tab) {
754 break;
755 }
756 i++;
757 groupidx++;
758 } while (TRUE);
759 } else {
760 /* No tabs currently */
761 groupidx = -1;
762 }
763
764 /* selected_nation already contains currently selected nation; however,
765 * it may no longer be a valid choice */
766 if (selected_nation != -1
768 select_nation(-1, NULL, FALSE, 0);
769 }
770
771 /* Delete all list stores, treeviews, tabs */
772 while (gtk_notebook_get_n_pages(GTK_NOTEBOOK(races_notebook)) > 0) {
773 gtk_notebook_remove_page(GTK_NOTEBOOK(races_notebook), -1);
774 }
775
776 /* (Re)create all of them */
778
779 /* Can't set current tab before child widget is visible */
780 gtk_widget_show(GTK_WIDGET(races_notebook));
781
782 /* Restore selected tab */
783 if (groupidx != -1 && races_nation_list[groupidx] != NULL) {
784 int i;
785
786 tab = 0;
787 for (i = 0; i < groupidx; i++) {
788 if (races_nation_list[i] != NULL) {
789 tab++;
790 }
791 }
792 gtk_notebook_set_current_page(GTK_NOTEBOOK(races_notebook), tab);
793 }
794
795 /* Restore selected nation */
797}
798
799/**********************************************************************/
802void nationset_sync_to_server(const char *nationset)
803{
804 if (nationsets_chooser) {
805 struct nation_set *set = nation_set_by_setting_value(nationset);
806
807 gtk_combo_box_set_active(GTK_COMBO_BOX(nationsets_chooser),
808 nation_set_index(set));
809 }
810}
811
812/**********************************************************************/
815static void nationset_callback(GtkComboBox *b, gpointer data)
816{
817 GtkTreeIter iter;
818
819 if (gtk_combo_box_get_active_iter(b, &iter)) {
820 struct option *poption = optset_option_by_name(server_optset, "nationset");
821 gchar *rule_name;
822
823 gtk_tree_model_get(gtk_combo_box_get_model(b), &iter,
824 0, &rule_name, -1);
825 /* Suppress propagation of an option value equivalent to the current
826 * server state, after canonicalisation, to avoid loops from
827 * nationset_sync_to_server().
828 * (HACK: relies on local Gtk "changed" signal getting here before
829 * server response.) */
831 != nation_set_by_rule_name(rule_name)) {
832 option_str_set(poption, rule_name);
833 }
834 FC_FREE(rule_name);
835 }
836}
837
838/**********************************************************************/
841static void create_races_dialog(struct player *pplayer)
842{
843 GtkWidget *shell;
844 GtkWidget *cmd;
845 GtkWidget *group;
846 GtkWidget *hgrid, *table;
847 GtkWidget *frame, *label, *combo;
848 GtkWidget *text;
849 GtkWidget *notebook;
850 GtkWidget *sw;
851 GtkWidget *list;
852 GtkListStore *store;
853 GtkCellRenderer *render;
854 GtkTreeViewColumn *column;
855 int i;
856 char *title;
857 int grid_col = 0;
858
859 /* Init. */
860 selected_nation = -1;
861
862 if (C_S_RUNNING == client_state()) {
863 title = _("Edit Nation");
864 } else if (NULL != pplayer && pplayer == client.conn.playing) {
865 title = _("What Nation Will You Be?");
866 } else {
867 title = _("Pick Nation");
868 }
869
870 shell = gtk_dialog_new_with_buttons(title,
871 NULL,
872 0,
873 _("_Cancel"),
874 GTK_RESPONSE_CANCEL,
875 _("_Random Nation"),
876 GTK_RESPONSE_NO, /* arbitrary */
877 _("_OK"),
878 GTK_RESPONSE_ACCEPT,
879 NULL);
881 races_player = pplayer;
883
884 gtk_window_set_default_size(GTK_WINDOW(shell), -1, 590);
885
886 frame = gtk_frame_new(_("Select a nation"));
887 gtk_box_append(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(shell))), frame);
888
889 hgrid = gtk_grid_new();
890 gtk_grid_set_column_spacing(GTK_GRID(hgrid), 18);
891 gtk_widget_set_margin_start(hgrid, 3);
892 gtk_widget_set_margin_end(hgrid, 3);
893 gtk_widget_set_margin_top(hgrid, 3);
894 gtk_widget_set_margin_bottom(hgrid, 3);
895
896 gtk_frame_set_child(GTK_FRAME(frame), hgrid);
897
898 /* Left side: nation list */
899 {
900 GtkWidget* nation_selection_list = gtk_grid_new();
901
902 nationsets_chooser = NULL;
903
904 gtk_grid_set_row_spacing(GTK_GRID(nation_selection_list), 2);
905
906 /* Nationset selector dropdown */
907 /* Only present this if there is more than one choice.
908 * (If ruleset is changed, possibly changing the number of available sets
909 * and invalidating this decision, then dialog will be popped down.) */
910 if (nation_set_count() > 1) {
911 GtkListStore *sets_model = gtk_list_store_new(4, G_TYPE_STRING,
912 G_TYPE_STRING,
913 G_TYPE_STRING,
914 G_TYPE_STRING);
915 GtkCellRenderer *renderer;
916
917 nation_sets_iterate(pset) {
918 /* Index in list store must match nation_set_index(). */
919 gchar *escaped;
920 struct astring s = ASTRING_INIT;
921 int num_nations = 0;
922
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_combo_box_get_child(GTK_COMBO_BOX(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",
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 if (poption) {
999 }
1000 }
1001
1002 label = g_object_new(GTK_TYPE_LABEL,
1003 "use-underline", TRUE,
1004 "label", _("_Nation Set:"),
1005 "xalign", 0.0,
1006 "yalign", 0.5,
1007 NULL);
1008 gtk_label_set_mnemonic_widget(GTK_LABEL(label), nationsets_chooser);
1009
1010 gtk_widget_set_hexpand(nationsets_chooser, TRUE);
1011 gtk_grid_attach(GTK_GRID(nation_selection_list), label,
1012 0, 0, 1, 1);
1013 gtk_grid_attach(GTK_GRID(nation_selection_list), nationsets_chooser,
1014 1, 0, 1, 1);
1015 }
1016
1017 races_notebook = gtk_notebook_new();
1018 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(races_notebook), GTK_POS_LEFT);
1019 gtk_grid_attach(GTK_GRID(nation_selection_list), races_notebook,
1020 0, 2, 2, 1);
1021
1022 /* Suppress notebook tabs if there will be only one ("All") */
1023 {
1024 bool show_groups = FALSE;
1025
1026 nation_groups_iterate(pgroup) {
1027 if (!is_nation_group_hidden(pgroup)) {
1028 show_groups = TRUE;
1029 break;
1030 }
1032 if (!show_groups) {
1033 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(races_notebook), FALSE);
1034 } else {
1035 label = g_object_new(GTK_TYPE_LABEL,
1036 "use-underline", TRUE,
1037 "label", _("Nation _Groups:"),
1038 "xalign", 0.0,
1039 "yalign", 0.5,
1040 NULL);
1041 gtk_label_set_mnemonic_widget(GTK_LABEL(label), races_notebook);
1042 gtk_grid_attach(GTK_GRID(nation_selection_list), label,
1043 0, 1, 2, 1);
1044 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(races_notebook), TRUE);
1045 }
1046 }
1047
1048 /* Populate treeview */
1050
1051 gtk_grid_attach(GTK_GRID(hgrid), nation_selection_list, grid_col++, 0, 1, 1);
1052 }
1053
1054 /* Right side. */
1055 notebook = gtk_notebook_new();
1056 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_BOTTOM);
1057 gtk_grid_attach(GTK_GRID(hgrid), notebook, grid_col++, 0, 1, 1);
1058
1059 /* Properties pane. */
1060 label = gtk_label_new_with_mnemonic(_("_Properties"));
1061
1062 races_properties = table = gtk_grid_new();
1063 g_signal_connect(table, "destroy",
1064 G_CALLBACK(widget_destroyed), &races_properties);
1065 gtk_widget_set_margin_bottom(table, 6);
1066 gtk_widget_set_margin_end(table, 6);
1067 gtk_widget_set_margin_start(table, 6);
1068 gtk_widget_set_margin_top(table, 6);
1069 gtk_grid_set_row_spacing(GTK_GRID(table), 2);
1070 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), table, label);
1071
1072 /* Leader. */
1073 {
1074 GtkListStore *model = gtk_list_store_new(1, G_TYPE_STRING);
1075
1076 combo = gtk_combo_box_new_with_model_and_entry(GTK_TREE_MODEL(model));
1077 gtk_combo_box_set_entry_text_column(GTK_COMBO_BOX(combo), 0);
1078 g_object_unref(G_OBJECT(model));
1079 }
1080 races_leader = combo;
1081 label = g_object_new(GTK_TYPE_LABEL,
1082 "use-underline", TRUE,
1083 "mnemonic-widget", GTK_COMBO_BOX(combo),
1084 "label", _("_Leader:"),
1085 "xalign", 0.0,
1086 "yalign", 0.5,
1087 NULL);
1088 gtk_widget_set_margin_bottom(label, 6);
1089 gtk_widget_set_margin_end(label, 12);
1090 gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 2);
1091 gtk_grid_attach(GTK_GRID(table), combo, 1, 0, 2, 1);
1092
1093 cmd = gtk_check_button_new_with_mnemonic(_("_Female"));
1094 gtk_widget_set_margin_bottom(cmd, 6);
1095 races_sex[0] = cmd;
1096 gtk_grid_attach(GTK_GRID(table), cmd, 1, 1, 1, 1);
1097 group = cmd;
1098
1099 cmd = gtk_check_button_new_with_mnemonic(_("_Male"));
1100 gtk_check_button_set_group(GTK_CHECK_BUTTON(cmd),
1101 GTK_CHECK_BUTTON(group));
1102 gtk_widget_set_margin_bottom(cmd, 6);
1103 races_sex[1] = cmd;
1104 gtk_grid_attach(GTK_GRID(table), cmd, 2, 1, 1, 1);
1105
1106 /* City style. */
1107 store = gtk_list_store_new(3, G_TYPE_INT,
1108 GDK_TYPE_PIXBUF, G_TYPE_STRING);
1109
1110 list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1111 gtk_widget_set_hexpand(list, TRUE);
1112 gtk_widget_set_vexpand(list, TRUE);
1114 g_object_unref(store);
1115 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), FALSE);
1116 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(list)), "changed",
1117 G_CALLBACK(races_style_callback), NULL);
1118
1119 sw = gtk_scrolled_window_new();
1120 gtk_widget_set_margin_top(sw, 6);
1121 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), TRUE);
1122 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1123 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1124 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), list);
1125 gtk_grid_attach(GTK_GRID(table), sw, 1, 2, 2, 2);
1126
1127 label = g_object_new(GTK_TYPE_LABEL,
1128 "use-underline", TRUE,
1129 "mnemonic-widget", list,
1130 "label", _("City _Styles:"),
1131 "xalign", 0.0,
1132 "yalign", 0.5,
1133 NULL);
1134 gtk_widget_set_margin_top(label, 6);
1135 gtk_widget_set_margin_end(label, 12);
1136 gtk_grid_attach(GTK_GRID(table), label, 0, 2, 1, 1);
1137
1138 render = gtk_cell_renderer_pixbuf_new();
1139 column = gtk_tree_view_column_new_with_attributes(NULL, render,
1140 "pixbuf", 1, NULL);
1141 gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
1142 render = gtk_cell_renderer_text_new();
1143 column = gtk_tree_view_column_new_with_attributes(NULL, render,
1144 "text", 2, NULL);
1145 gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
1146
1147 /* Populate style store. */
1148 styles_iterate(pstyle) {
1149 GdkPixbuf *img;
1150 struct sprite *s;
1151 GtkTreeIter it;
1152
1153 i = basic_city_style_for_style(pstyle);
1154
1155 if (i >= 0) {
1156 gtk_list_store_append(store, &it);
1157
1160 free_sprite(s);
1161 gtk_list_store_set(store, &it, 0, i, 1, img, 2,
1163 g_object_unref(img);
1164 }
1166
1167 /* Legend pane. */
1168 label = gtk_label_new_with_mnemonic(_("_Description"));
1169
1170 text = gtk_text_view_new();
1171 gtk_widget_set_margin_bottom(text, 6);
1172 gtk_widget_set_margin_end(text, 6);
1173 gtk_widget_set_margin_start(text, 6);
1174 gtk_widget_set_margin_top(text, 6);
1175 gtk_widget_set_hexpand(text, TRUE);
1176 gtk_widget_set_vexpand(text, TRUE);
1177 races_text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text));
1178 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD);
1179 gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);
1180 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(text), FALSE);
1181 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text), 6);
1182 gtk_text_view_set_right_margin(GTK_TEXT_VIEW(text), 6);
1183
1184 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), text, label);
1185
1186 /* Signals. */
1187 g_signal_connect(shell, "destroy",
1188 G_CALLBACK(widget_destroyed), &races_shell);
1189 g_signal_connect(shell, "response",
1190 G_CALLBACK(races_response), NULL);
1191
1192 g_signal_connect(GTK_COMBO_BOX(races_leader), "changed",
1193 G_CALLBACK(races_leader_callback), NULL);
1194
1195 g_signal_connect(races_sex[0], "toggled",
1196 G_CALLBACK(races_sex_callback), GINT_TO_POINTER(0));
1197 g_signal_connect(races_sex[1], "toggled",
1198 G_CALLBACK(races_sex_callback), GINT_TO_POINTER(1));
1199
1200 /* Finish up. */
1201 gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_CANCEL);
1202
1203 /* You can't assign NO_NATION during a running game. */
1204 if (C_S_RUNNING == client_state()) {
1205 gtk_dialog_set_response_sensitive(GTK_DIALOG(shell), GTK_RESPONSE_NO,
1206 FALSE);
1207 }
1208
1209 gtk_widget_show(gtk_dialog_get_content_area(GTK_DIALOG(shell)));
1210
1211 /* Select player's current nation in UI, if any */
1212 if (races_player->nation) {
1217 /* Make sure selected nation is visible
1218 * (last page, "All", will certainly contain it) */
1219 fc_assert(gtk_notebook_get_n_pages(GTK_NOTEBOOK(races_notebook)) > 0);
1220 gtk_notebook_set_current_page(GTK_NOTEBOOK(races_notebook), -1);
1221 } else {
1222 select_nation(-1, NULL, FALSE, 0);
1223 }
1224}
1225
1226/**********************************************************************/
1229void popup_races_dialog(struct player *pplayer)
1230{
1231 if (!pplayer) {
1232 return;
1233 }
1234
1235 if (!races_shell) {
1236 create_races_dialog(pplayer);
1237 gtk_window_present(GTK_WINDOW(races_shell));
1238 }
1239}
1240
1241/**********************************************************************/
1245{
1246 if (races_shell) {
1247 gtk_window_destroy(GTK_WINDOW(races_shell));
1248 }
1249
1250 /* We're probably starting a new game, maybe with a new ruleset.
1251 So we warn the worklist dialog. */
1253}
1254
1255/**********************************************************************/
1260{
1261 int i;
1262
1263 if (!races_shell) {
1264 return;
1265 }
1266
1267 for (i = 0; i <= nation_group_count(); i++) {
1268 if (races_nation_list[i]) {
1269 GtkTreeView *list = GTK_TREE_VIEW(races_nation_list[i]);
1270 GtkTreeModel *model = gtk_tree_view_get_model(list);
1271 GtkTreeSelection* select = gtk_tree_view_get_selection(list);
1272 GtkTreeIter it;
1273 gboolean chosen;
1274
1275 /* Update 'chosen' column in model */
1276 if (gtk_tree_model_get_iter_first(model, &it)) {
1277 do {
1278 int nation_no;
1279 struct nation_type *nation;
1280
1281 gtk_tree_model_get(model, &it, 0, &nation_no, -1);
1282 nation = nation_by_number(nation_no);
1283
1284 chosen = !is_nation_pickable(nation)
1285 || (nation->player && nation->player != races_player);
1286
1287 gtk_list_store_set(GTK_LIST_STORE(model), &it, 1, chosen, -1);
1288
1289 } while (gtk_tree_model_iter_next(model, &it));
1290 }
1291
1292 /* If our selection is now invalid, deselect it */
1293 if (gtk_tree_selection_get_selected(select, &model, &it)) {
1294 gtk_tree_model_get(model, &it, 1, &chosen, -1);
1295
1296 if (chosen) {
1297 gtk_tree_selection_unselect_all(select);
1298 }
1299 }
1300 }
1301 }
1302}
1303
1304/**********************************************************************/
1307static void races_nation_callback(GtkTreeSelection *select, gpointer data)
1308{
1309 GtkTreeModel *model;
1310 GtkTreeIter it;
1311
1312 if (gtk_tree_selection_get_selected(select, &model, &it)) {
1313 gboolean chosen;
1314 int newnation;
1315
1316 gtk_tree_model_get(model, &it, 0, &newnation, 1, &chosen, -1);
1317
1318 /* Only allow nations not chosen by another player */
1319 if (!chosen) {
1320 if (newnation != selected_nation) {
1321 /* Choose a random leader */
1322 select_nation(newnation, NULL, FALSE,
1324 }
1325 return;
1326 }
1327 }
1328
1329 /* Fall-through if no valid nation selected */
1330 select_nation(-1, NULL, FALSE, 0);
1331}
1332
1333/**********************************************************************/
1336static void races_leader_callback(void)
1337{
1338 const struct nation_leader *pleader;
1339 const gchar *name;
1340
1341 name =
1342 gtk_entry_buffer_get_text(gtk_entry_get_buffer(GTK_ENTRY(gtk_combo_box_get_child(GTK_COMBO_BOX(races_leader)))));
1343
1344 if (selected_nation != -1
1346 name))) {
1348 gtk_check_button_set_active(GTK_CHECK_BUTTON(races_sex[selected_sex]),
1349 TRUE);
1350 }
1351}
1352
1353/**********************************************************************/
1356static void races_sex_callback(GtkWidget *w, gpointer data)
1357{
1358 selected_sex = GPOINTER_TO_INT(data);
1359}
1360
1361/**********************************************************************/
1364static gboolean races_selection_func(GtkTreeSelection *select,
1365 GtkTreeModel *model, GtkTreePath *path,
1366 gboolean selected, gpointer data)
1367{
1368 GtkTreeIter it;
1369 gboolean chosen;
1370
1371 gtk_tree_model_get_iter(model, &it, path);
1372 gtk_tree_model_get(model, &it, 1, &chosen, -1);
1373 return (!chosen || selected);
1374}
1375
1376/**********************************************************************/
1379static void races_style_callback(GtkTreeSelection *select, gpointer data)
1380{
1381 GtkTreeModel *model;
1382 GtkTreeIter it;
1383
1384 if (gtk_tree_selection_get_selected(select, &model, &it)) {
1385 gtk_tree_model_get(model, &it, 0, &selected_style, -1);
1386 } else {
1387 selected_style = -1;
1388 }
1389}
1390
1391/**********************************************************************/
1394static void races_response(GtkWidget *w, gint response, gpointer data)
1395{
1396 if (response == GTK_RESPONSE_ACCEPT) {
1397 const char *s;
1398
1399 /* This shouldn't be possible but... */
1400 if (selected_nation == -1) {
1401 return;
1402 }
1403
1404 if (selected_sex == -1) {
1405 output_window_append(ftc_client, _("You must select your sex."));
1406 return;
1407 }
1408
1409 if (selected_style == -1) {
1410 output_window_append(ftc_client, _("You must select your style."));
1411 return;
1412 }
1413
1414 s = gtk_entry_buffer_get_text(gtk_entry_get_buffer(
1415 GTK_ENTRY(gtk_combo_box_get_child(GTK_COMBO_BOX(races_leader)))));
1416
1417 /* Perform a minimum of sanity test on the name. */
1418 /* This could call is_allowed_player_name if it were available. */
1419 if (strlen(s) == 0) {
1420 output_window_append(ftc_client, _("You must type a legal name."));
1421 return;
1422 }
1423
1426 selected_sex, s,
1428 } else if (response == GTK_RESPONSE_NO) {
1431 -1, FALSE, "", 0);
1432 }
1433
1435}
1436
1437/**********************************************************************/
1440gboolean taxrates_callback(GtkGestureClick *gesture, int n_press,
1441 double x, double y)
1442{
1443 GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture));
1444
1445 common_taxrates_callback(GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(widget),
1446 "rate_button")), FALSE);
1447
1448 return TRUE;
1449}
1450
1451/**********************************************************************/
1454gboolean reverse_taxrates_callback(GtkGestureClick *gesture, int n_press,
1455 double x, double y)
1456{
1457 GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture));
1458
1459 common_taxrates_callback(GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(widget),
1460 "rate_button")), TRUE);
1461
1462 return TRUE;
1463}
1464
1465/**********************************************************************/
1468void popup_upgrade_dialog(struct unit_list *punits)
1469{
1470 GtkWidget *shell;
1471 char buf[512];
1472
1473 if (!punits || unit_list_size(punits) == 0) {
1474 return;
1475 }
1476
1477 if (!get_units_upgrade_info(buf, sizeof(buf), punits)) {
1478 shell = gtk_message_dialog_new(NULL, 0,
1479 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
1480 "%s", buf);
1481 gtk_window_set_title(GTK_WINDOW(shell), _("Upgrade Unit!"));
1483 g_signal_connect(shell, "response", G_CALLBACK(gtk_window_destroy),
1484 NULL);
1485 gtk_window_present(GTK_WINDOW(shell));
1486 } else {
1487 shell = gtk_message_dialog_new(NULL, 0,
1488 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1489 "%s", buf);
1490 gtk_window_set_title(GTK_WINDOW(shell), _("Upgrade Obsolete Units"));
1492 gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_YES);
1493
1494 /* FIXME: Should not block */
1495 if (blocking_dialog(shell) == GTK_RESPONSE_YES) {
1496 unit_list_iterate(punits, punit) {
1499 }
1500 gtk_window_destroy(GTK_WINDOW(shell));
1501 }
1502}
1503
1504/**********************************************************************/
1507void popup_disband_dialog(struct unit_list *punits)
1508{
1509 GtkWidget *shell;
1510 char buf[512];
1511
1512 if (!punits || unit_list_size(punits) == 0) {
1513 return;
1514 }
1515
1516 if (!get_units_disband_info(buf, sizeof(buf), punits)) {
1517 shell = gtk_message_dialog_new(NULL, 0,
1518 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
1519 "%s", buf);
1520 gtk_window_set_title(GTK_WINDOW(shell), _("Disband Units"));
1522 g_signal_connect(shell, "response", G_CALLBACK(gtk_window_destroy),
1523 NULL);
1524 gtk_window_present(GTK_WINDOW(shell));
1525 } else {
1526 shell = gtk_message_dialog_new(NULL, 0,
1527 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1528 "%s", buf);
1529 gtk_window_set_title(GTK_WINDOW(shell), _("Disband Units"));
1531 gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_YES);
1532
1533 /* FIXME: Should not block */
1534 if (blocking_dialog(shell) == GTK_RESPONSE_YES) {
1535 unit_list_iterate(punits, punit) {
1536 if (unit_can_do_action(punit, ACTION_DISBAND_UNIT)) {
1538 }
1540 }
1541 gtk_window_destroy(GTK_WINDOW(shell));
1542 }
1543}
1544
1545/**********************************************************************/
1555
1556/**********************************************************************/
1560{
1561 const struct advance *padvance = valid_advance_by_number(tech);
1562
1563 if (NULL != padvance
1564 && (GUI_GTK_OPTION(popup_tech_help) == GUI_POPUP_TECH_HELP_ENABLED
1565 || (GUI_GTK_OPTION(popup_tech_help) == GUI_POPUP_TECH_HELP_RULESET
1568 }
1569}
1570
1571/**********************************************************************/
1575void show_tileset_error(bool fatal, const char *tset_name, const char *msg)
1576{
1577 if (is_gui_up()) {
1578 GtkWidget *dialog;
1579
1580 if (tset_name != NULL) {
1581 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
1582 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
1583 _("Tileset \"%s\" problem, "
1584 "it's probably incompatible with "
1585 "the ruleset:\n%s"),
1586 tset_name, msg);
1587 } else {
1588 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
1589 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
1590 _("Tileset problem, "
1591 "it's probably incompatible with "
1592 "the ruleset:\n%s"),
1593 msg);
1594 }
1595
1596 setup_dialog(dialog, toplevel);
1597
1598 blocking_dialog(dialog);
1599
1600 gtk_window_destroy(GTK_WINDOW(dialog));
1601 }
1602}
1603
1604/**********************************************************************/
1609{
1610 /* Just tell the client common code to handle this. */
1611 return FALSE;
1612}
1613
1614/**********************************************************************/
1618void popup_combat_info(int attacker_unit_id, int defender_unit_id,
1619 int attacker_hp, int defender_hp,
1620 bool make_att_veteran, bool make_def_veteran)
1621{
1622}
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_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
gboolean reverse_taxrates_callback(GtkGestureClick *gesture, int n_press, double x, double y)
Definition dialogs.c:1454
gint blocking_dialog(GtkWidget *dlg)
Definition gui_stuff.c:1126
void gui_dialog_add_content_widget(struct gui_dialog *dlg, GtkWidget *wdg)
Definition gui_stuff.c:1095
void widget_destroyed(GtkWidget *wdg, void *data)
Definition gui_stuff.c:1145
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 * 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