Freeciv-3.1
Loading...
Searching...
No Matches
citydlg.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 <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21
22#include <gtk/gtk.h>
23#include <gdk/gdkkeysyms.h>
24
25/* utility */
26#include "bitvector.h"
27#include "fcintl.h"
28#include "log.h"
29#include "mem.h"
30#include "shared.h"
31#include "support.h"
32
33/* common */
34#include "city.h"
35#include "game.h"
36#include "map.h"
37#include "movement.h"
38#include "packets.h"
39#include "player.h"
40#include "unitlist.h"
41
42/* client */
43#include "chatline_common.h"
44#include "client_main.h"
45#include "colors.h"
46#include "control.h"
47#include "climap.h"
48#include "options.h"
49#include "text.h"
50#include "tilespec.h"
51
52/* client/agents */
53#include "cma_fec.h"
54
55/* client/gui-gtk-4.0 */
56#include "choice_dialog.h"
57#include "citizensinfo.h"
58#include "cityrep.h"
59#include "cma_fe.h"
60#include "dialogs.h"
61#include "graphics.h"
62#include "gui_main.h"
63#include "gui_stuff.h"
64#include "happiness.h"
65#include "helpdlg.h"
66#include "inputdlg.h"
67#include "mapview.h"
68#include "repodlgs.h"
69#include "wldlg.h"
70
71#include "citydlg.h"
72
73#define CITYMAP_WIDTH MIN(512, canvas_width)
74#define CITYMAP_HEIGHT (CITYMAP_WIDTH * canvas_height / canvas_width)
75#define CITYMAP_SCALE ((double)CITYMAP_WIDTH / (double)canvas_width)
76
77#define TINYSCREEN_MAX_HEIGHT (500 - 1)
78
79/* Only CDLGR_UNITS button currently uses these, others have
80 * direct callback. */
82
83struct city_dialog;
84
85/* get 'struct dialog_list' and related function */
86#define SPECLIST_TAG dialog
87#define SPECLIST_TYPE struct city_dialog
88#include "speclist.h"
89
90#define dialog_list_iterate(dialoglist, pdialog) \
91 TYPED_LIST_ITERATE(struct city_dialog, dialoglist, pdialog)
92#define dialog_list_iterate_end LIST_ITERATE_END
93
94struct unit_node {
95 GtkWidget *cmd;
96 GtkWidget *pix;
97 int height;
98 GtkEventController *left;
99 GtkEventController *middle;
100 GtkEventController *right;
101};
102
103/* get 'struct unit_node' and related function */
104#define SPECVEC_TAG unit_node
105#define SPECVEC_TYPE struct unit_node
106#include "specvec.h"
107
108#define unit_node_vector_iterate(list, elt) \
109 TYPED_VECTOR_ITERATE(struct unit_node, list, elt)
110#define unit_node_vector_iterate_end VECTOR_ITERATE_END
111
112#define NUM_CITIZENS_SHOWN 30
113
116 NUM_PAGES /* the number of pages in city dialog notebook
117 * must match the entries in misc_whichtab_label[] */
119
120enum {
125 NUM_INFO_FIELDS /* number of fields in city_info panel
126 * must match entries in output_label[] */
128
129/* minimal size for the city map scrolling windows*/
130#define CITY_MAP_MIN_SIZE_X 200
131#define CITY_MAP_MIN_SIZE_Y 150
132
133struct city_map_canvas {
134 GtkWidget *sw;
135 GtkWidget *darea;
136};
137
138struct city_dialog {
139 struct city *pcity;
140
141 GtkWidget *shell;
142 GtkWidget *name_label;
143 cairo_surface_t *map_canvas_store_unscaled;
144 GtkWidget *notebook;
145
146 GtkWidget *popover;
147 GtkWidget *citizen_pics;
148 cairo_surface_t *citizen_surface;
149
150 struct {
152
153 GtkWidget *production_bar;
154 GtkWidget *production_combo;
155 GtkWidget *buy_command;
156 GtkWidget *improvement_list;
157
158 GtkWidget *supported_units_frame;
159 GtkWidget *supported_unit_table;
160
161 GtkWidget *present_units_frame;
162 GtkWidget *present_unit_table;
163
164 struct unit_node_vector supported_units;
165 struct unit_node_vector present_units;
166
167 GtkWidget *info_label[NUM_INFO_FIELDS];
168
169 GtkListStore *change_production_store;
171
172 struct {
173 GtkWidget *production_label;
174 GtkWidget *production_bar;
175 GtkWidget *buy_command;
176 GtkWidget *worklist;
178
179 struct {
181
182 GtkWidget *widget;
183 GtkWidget *info_label[NUM_INFO_FIELDS];
184 GtkWidget *citizens;
186
187 struct cma_dialog *cma_editor;
188
189 struct {
190 GtkWidget *rename_command;
191 GtkWidget *new_citizens_radio[3];
192 GtkWidget *disband_on_settler;
193 GtkWidget *whichtab_radio[NUM_PAGES];
194 short block_signal;
196
197 GtkWidget *sell_shell;
198 GtkTreeSelection *change_selection;
199 GtkWidget *rename_shell;
200
201 GtkWidget *show_units_command;
202 GtkWidget *prev_command;
203 GtkWidget *next_command;
204
206
207 int cwidth;
208};
209
215
217
218static struct
219{
220 struct city *owner;
221 struct tile *loc;
223
224static bool low_citydlg;
225
226/****************************************/
227
228static void initialize_city_dialogs(void);
229static void city_dialog_map_create(struct city_dialog *pdialog,
230 struct city_map_canvas *cmap_canvas);
231static void city_dialog_map_recenter(GtkWidget *map_canvas_sw);
232
233static struct city_dialog *get_city_dialog(struct city *pcity);
234static gboolean citydlg_keyboard_handler(GtkEventControllerKey *controller,
235 guint keyval,
236 guint keycode,
237 GdkModifierType state,
238 gpointer data);
239
240static GtkWidget *create_city_info_table(struct city_dialog *pdialog,
241 GtkWidget **info_label);
242static void create_and_append_overview_page(struct city_dialog *pdialog);
243static void create_and_append_map_page(struct city_dialog *pdialog);
244static void create_and_append_buildings_page(struct city_dialog *pdialog);
245static void create_and_append_worklist_page(struct city_dialog *pdialog);
246static void create_and_append_happiness_page(struct city_dialog *pdialog);
247static void create_and_append_cma_page(struct city_dialog *pdialog);
248static void create_and_append_settings_page(struct city_dialog *pdialog);
249
250static struct city_dialog *create_city_dialog(struct city *pcity);
251
252static void city_dialog_update_title(struct city_dialog *pdialog);
253static void city_dialog_update_citizens(struct city_dialog *pdialog);
254static void city_dialog_update_information(GtkWidget **info_label,
255 struct city_dialog *pdialog);
256static void city_dialog_update_map(struct city_dialog *pdialog);
257static void city_dialog_update_building(struct city_dialog *pdialog);
259 *pdialog);
261 *pdialog);
262static void city_dialog_update_present_units(struct city_dialog *pdialog);
263static void city_dialog_update_prev_next(void);
264
265static void show_units_response(void *data);
266
267static gboolean supported_unit_callback(GtkGestureClick *gesture, int n_press,
268 double x, double y, gpointer data);
269static gboolean present_unit_callback(GtkGestureClick *gesture, int n_press,
270 double x, double y, gpointer data);
271static gboolean middle_supported_unit_release(GtkGestureClick *gesture, int n_press,
272 double x, double y, gpointer data);
273static gboolean middle_present_unit_release(GtkGestureClick *gesture, int n_press,
274 double x, double y, gpointer data);
275static gboolean right_unit_release(GtkGestureClick *gesture, int n_press,
276 double x, double y, gpointer data);
277
278static void close_citydlg_unit_popover(struct city_dialog *pdialog);
279
280static void unit_center_callback(GSimpleAction *action, GVariant *parameter,
281 gpointer data);
282static void unit_activate_callback(GSimpleAction *action, GVariant *parameter,
283 gpointer data);
284static void supported_unit_activate_close_callback(GSimpleAction *action,
285 GVariant *parameter,
286 gpointer data);
287static void present_unit_activate_close_callback(GSimpleAction *action,
288 GVariant *parameter,
289 gpointer data);
290static void unit_load_callback(GSimpleAction *action, GVariant *parameter,
291 gpointer data);
292static void unit_unload_callback(GSimpleAction *action, GVariant *parameter,
293 gpointer data);
294static void unit_sentry_callback(GSimpleAction *action, GVariant *parameter,
295 gpointer data);
296static void unit_fortify_callback(GSimpleAction *action, GVariant *parameter,
297 gpointer data);
298static void unit_disband_callback(GSimpleAction *action, GVariant *parameter,
299 gpointer data);
300static void unit_homecity_callback(GSimpleAction *action, GVariant *parameter,
301 gpointer data);
302static void unit_upgrade_callback(GSimpleAction *action, GVariant *parameter,
303 gpointer data);
304static gboolean citizens_callback(GtkGestureClick *gesture, int n_press,
305 double x, double y, gpointer data);
306static gboolean left_button_down_citymap(GtkGestureClick *gesture, int n_press,
307 double x, double y, gpointer data);
308static gboolean right_button_down_citymap(GtkGestureClick *gesture, int n_press,
309 double x, double y, gpointer data);
310static void draw_map_canvas(struct city_dialog *pdialog);
311
312static void buy_callback(GtkWidget * w, gpointer data);
313static void change_production_callback(GtkComboBox *combo,
314 struct city_dialog *pdialog);
315
316static void sell_callback(struct impr_type *pimprove, gpointer data);
317static void sell_callback_response(GtkWidget *w, gint response, gpointer data);
318
319static void impr_callback(GtkTreeView *view, GtkTreePath *path,
320 GtkTreeViewColumn *col, gpointer data);
321
322static void rename_callback(GtkWidget * w, gpointer data);
323static void rename_popup_callback(gpointer data, gint response,
324 const char *input);
325static void set_cityopt_values(struct city_dialog *pdialog);
326static void cityopt_callback(GtkWidget * w, gpointer data);
327static void misc_whichtab_callback(GtkWidget * w, gpointer data);
328
329static void city_destroy_callback(GtkWidget *w, gpointer data);
330static void close_city_dialog(struct city_dialog *pdialog);
331static void citydlg_response_callback(GtkDialog *dlg, gint response,
332 void *data);
333static void close_callback(GtkWidget *w, gpointer data);
334static void switch_city_callback(GtkWidget *w, gpointer data);
335
336/***********************************************************************/
345
346/***********************************************************************/
349static void initialize_city_dialogs(void)
350{
351 int height;
352
354
355 dialog_list = dialog_list_new();
358
359 /* Use default layout when height cannot be determined
360 * (when height == 0) */
361 if (height > 0 && height <= TINYSCREEN_MAX_HEIGHT) {
363 } else {
365 }
366
368}
369
370/***********************************************************************/
374{
376 return;
377 }
378
380
382 /* There's no reasonable way to resize a GtkImage, so we don't try.
383 Instead we just redraw the overview within the existing area. The
384 player has to close and reopen the dialog to fix this. */
385 city_dialog_update_map(pdialog);
387
389}
390
391/***********************************************************************/
395static struct city_dialog *get_city_dialog(struct city *pcity)
396{
399 }
400
402 if (pdialog->pcity == pcity) {
403 return pdialog;
404 }
406
407 return NULL;
408}
409
410/***********************************************************************/
413static void canvas_draw_cb(GtkDrawingArea *w, cairo_t *cr,
414 int width, int height, gpointer data)
415{
416 struct city_dialog *pdialog = data;
417
418 cairo_scale(cr, CITYMAP_SCALE, CITYMAP_SCALE);
419 cairo_set_source_surface(cr, pdialog->map_canvas_store_unscaled, 0, 0);
420 if (cma_is_city_under_agent(pdialog->pcity, NULL)) {
421 cairo_paint_with_alpha(cr, 0.5);
422 } else {
423 cairo_paint(cr);
424 }
425}
426
427/***********************************************************************/
430static void city_dialog_map_create(struct city_dialog *pdialog,
431 struct city_map_canvas *cmap_canvas)
432{
433 GtkWidget *sw, *darea;
434 GtkGesture *gesture;
435 GtkEventController *controller;
436
437 sw = gtk_scrolled_window_new();
438 gtk_scrolled_window_set_min_content_width(GTK_SCROLLED_WINDOW(sw),
440 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(sw),
442 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
443 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
444 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), FALSE);
445
446 darea = gtk_drawing_area_new();
447 gtk_widget_set_size_request(darea, CITYMAP_WIDTH, CITYMAP_HEIGHT);
448 gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(darea),
449 canvas_draw_cb, pdialog, NULL);
450
451 controller = GTK_EVENT_CONTROLLER(gtk_gesture_click_new());
452 g_signal_connect(controller, "pressed",
453 G_CALLBACK(left_button_down_citymap), pdialog);
454 gtk_widget_add_controller(darea, controller);
455 gesture = gtk_gesture_click_new();
456 gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 3);
457 controller = GTK_EVENT_CONTROLLER(gesture);
458 g_signal_connect(controller, "pressed",
459 G_CALLBACK(right_button_down_citymap), pdialog);
460 gtk_widget_add_controller(darea, controller);
461 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), darea);
462
463 /* save all widgets for the city map */
464 cmap_canvas->sw = sw;
465 cmap_canvas->darea = darea;
466}
467
468/***********************************************************************/
471static void city_dialog_map_recenter(GtkWidget *map_canvas_sw)
472{
473 GtkAdjustment *adjust = NULL;
474 gdouble value;
475
476 fc_assert_ret(map_canvas_sw != NULL);
477
478 adjust = gtk_scrolled_window_get_hadjustment(
479 GTK_SCROLLED_WINDOW(map_canvas_sw));
480 value = (gtk_adjustment_get_lower(adjust)
481 + gtk_adjustment_get_upper(adjust)
482 - gtk_adjustment_get_page_size(adjust)) / 2;
483 gtk_adjustment_set_value(adjust, value);
484
485 adjust = gtk_scrolled_window_get_vadjustment(
486 GTK_SCROLLED_WINDOW(map_canvas_sw));
487 value = (gtk_adjustment_get_lower(adjust)
488 + gtk_adjustment_get_upper(adjust)
489 - gtk_adjustment_get_page_size(adjust)) / 2;
490 gtk_adjustment_set_value(adjust, value);
491}
492
493/***********************************************************************/
497{
498 struct city_dialog *pdialog = get_city_dialog(pcity);
499
500 log_debug("CITYMAP_WIDTH: %d", CITYMAP_WIDTH);
501 log_debug("CITYMAP_HEIGHT: %d", CITYMAP_HEIGHT);
502 log_debug("CITYMAP_SCALE: %.3f", CITYMAP_SCALE);
503
507 }
508
509 if (!pdialog) {
510 return;
511 }
512
516 city_dialog_update_map(pdialog);
521
523 bool have_present_units = (unit_list_size(pcity->tile->units) > 0);
524
526
527 if (!low_citydlg) {
529 }
533 }
534
535 if (!client_is_observer()) {
537 }
538
539 gtk_widget_set_sensitive(pdialog->show_units_command,
541 && have_present_units);
542 } else {
543 /* Set the buttons we do not want live while a Diplomat investigates */
544 gtk_widget_set_sensitive(pdialog->show_units_command, FALSE);
545 }
546}
547
548/***********************************************************************/
553{
554 struct city *pcity_sup, *pcity_pre;
555 struct city_dialog *pdialog;
556
557 pcity_sup = game_city_by_number(punit->homecity);
558 pcity_pre = tile_city(unit_tile(punit));
559
560 if (pcity_sup && (pdialog = get_city_dialog(pcity_sup))) {
562 }
563
564 if (pcity_pre && (pdialog = get_city_dialog(pcity_pre))) {
566 }
567}
568
569/***********************************************************************/
573{
574 struct city_dialog *pdialog;
575
576 if (!(pdialog = get_city_dialog(pcity))) {
577 pdialog = create_city_dialog(pcity);
578 }
579
580 gtk_window_present(GTK_WINDOW(pdialog->shell));
581
582 /* center the city map(s); this must be *after* the city dialog was drawn
583 * else the size information is missing! */
585 if (pdialog->happiness.map_canvas.sw) {
587 }
588}
589
590/***********************************************************************/
594{
595 return get_city_dialog(pcity) != NULL;
596}
597
598/***********************************************************************/
602{
603 struct city_dialog *pdialog = get_city_dialog(pcity);
604
605 if (pdialog) {
606 close_city_dialog(pdialog);
607 }
608}
609
610/***********************************************************************/
614{
616 return;
617 }
618
619 while (dialog_list_size(dialog_list)) {
620 close_city_dialog(dialog_list_get(dialog_list, 0));
621 }
622 dialog_list_destroy(dialog_list);
623
625}
626
627/***********************************************************************/
630static gboolean citydlg_keyboard_handler(GtkEventControllerKey *controller,
631 guint keyval,
632 guint keycode,
633 GdkModifierType state,
634 gpointer data)
635{
636 struct city_dialog *pdialog = (struct city_dialog *)data;
637
638 if (state & GDK_CONTROL_MASK) {
639 switch (keyval) {
640 case GDK_KEY_Left:
641 gtk_notebook_prev_page(GTK_NOTEBOOK(pdialog->notebook));
642 return TRUE;
643
644 case GDK_KEY_Right:
645 gtk_notebook_next_page(GTK_NOTEBOOK(pdialog->notebook));
646 return TRUE;
647
648 default:
649 break;
650 }
651 }
652
653 return FALSE;
654}
655
656/***********************************************************************/
659static gboolean show_info_popup(GtkGestureClick *gesture, int n_press,
660 double x, double y, gpointer data)
661{
662 GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture));
663 struct city_dialog *pdialog = g_object_get_data(G_OBJECT(w), "pdialog");
664 GtkWidget *p, *label;
665 char buf[1024];
666
667 switch (GPOINTER_TO_UINT(data)) {
668 case INFO_SIZE:
669 fc_snprintf(buf, sizeof(buf), _("Population: %d, Specialists: %d"),
670 pdialog->pcity->size, city_specialists(pdialog->pcity));
671 break;
672 case INFO_FOOD:
673 get_city_dialog_output_text(pdialog->pcity, O_FOOD, buf, sizeof(buf));
674 break;
675 case INFO_SHIELD:
677 buf, sizeof(buf));
678 break;
679 case INFO_TRADE:
680 get_city_dialog_output_text(pdialog->pcity, O_TRADE, buf, sizeof(buf));
681 break;
682 case INFO_GOLD:
683 get_city_dialog_output_text(pdialog->pcity, O_GOLD, buf, sizeof(buf));
684 break;
685 case INFO_SCIENCE:
687 buf, sizeof(buf));
688 break;
689 case INFO_LUXURY:
691 buf, sizeof(buf));
692 break;
693 case INFO_CULTURE:
694 get_city_dialog_culture_text(pdialog->pcity, buf, sizeof(buf));
695 break;
696 case INFO_POLLUTION:
697 get_city_dialog_pollution_text(pdialog->pcity, buf, sizeof(buf));
698 break;
699 case INFO_ILLNESS:
700 get_city_dialog_illness_text(pdialog->pcity, buf, sizeof(buf));
701 break;
702 case INFO_AIRLIFT:
703 get_city_dialog_airlift_text(pdialog->pcity, buf, sizeof(buf));
704 break;
705 default:
706 return TRUE;
707 }
708
709 p = gtk_popover_new();
710
711 gtk_widget_set_parent(p, w);
712
713 label = gtk_label_new(buf);
714 gtk_widget_set_name(label, "city_label");
715 gtk_widget_set_margin_start(label, 4);
716 gtk_widget_set_margin_end(label, 4);
717 gtk_widget_set_margin_top(label, 4);
718 gtk_widget_set_margin_bottom(label, 4);
719
720 gtk_popover_set_child(GTK_POPOVER(p), label);
721
722 gtk_popover_popup(GTK_POPOVER(p));
723
724 return TRUE;
725}
726
727/***********************************************************************/
731static GtkWidget *create_city_info_table(struct city_dialog *pdialog,
732 GtkWidget **info_label)
733{
734 int i;
735 GtkWidget *table, *label;
736
737 static const char *output_label[NUM_INFO_FIELDS] = {
738 N_("Size:"),
739 N_("Food:"),
740 N_("Prod:"),
741 N_("Trade:"),
742 N_("Gold:"),
743 N_("Luxury:"),
744 N_("Science:"),
745 N_("Granary:"),
746 N_("Change in:"),
747 N_("Corruption:"),
748 N_("Waste:"),
749 N_("Culture:"),
750 N_("Pollution:"),
751 N_("Plague risk:"),
752 N_("Tech Stolen:"),
753 N_("Airlift:"),
754 };
755 static bool output_label_done;
756 GtkEventController *controller;
757
758 table = gtk_grid_new();
759 gtk_widget_set_margin_bottom(table, 4);
760 gtk_widget_set_margin_end(table, 4);
761 gtk_widget_set_margin_start(table, 4);
762 gtk_widget_set_margin_top(table, 4);
763
764 intl_slist(ARRAY_SIZE(output_label), output_label, &output_label_done);
765
766 for (i = 0; i < NUM_INFO_FIELDS; i++) {
767 label = gtk_label_new(output_label[i]);
768 switch (i) {
769 case INFO_SIZE:
770 case INFO_TRADE:
771 case INFO_SCIENCE:
772 case INFO_GROWTH:
773 gtk_widget_set_margin_bottom(label, 5);
774 break;
775
776 case INFO_FOOD:
777 case INFO_GOLD:
778 case INFO_GRANARY:
779 case INFO_CORRUPTION:
780 gtk_widget_set_margin_top(label, 5);
781 break;
782 default:
783 break;
784 }
785 gtk_widget_set_margin_end(label, 5);
786 gtk_widget_set_name(label, "city_label"); /* for font style? */
787 gtk_widget_set_halign(label, GTK_ALIGN_START);
788 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
789 gtk_grid_attach(GTK_GRID(table), label, 0, i, 1, 1);
790
791 label = gtk_label_new("");
792 switch (i) {
793 case INFO_TRADE:
794 case INFO_SCIENCE:
795 case INFO_GROWTH:
796 gtk_widget_set_margin_bottom(label, 5);
797 break;
798
799 case INFO_GOLD:
800 case INFO_GRANARY:
801 case INFO_CORRUPTION:
802 gtk_widget_set_margin_top(label, 5);
803 break;
804 default:
805 break;
806 }
807
808 g_object_set_data(G_OBJECT(label), "pdialog", pdialog);
809
810 controller = GTK_EVENT_CONTROLLER(gtk_gesture_click_new());
811 g_signal_connect(controller, "pressed",
812 G_CALLBACK(show_info_popup), GUINT_TO_POINTER(i));
813 gtk_widget_add_controller(label, controller);
814
815 info_label[i] = label;
816 gtk_widget_set_name(label, "city_label"); /* ditto */
817 gtk_widget_set_halign(label, GTK_ALIGN_START);
818 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
819
820 gtk_grid_attach(GTK_GRID(table), label, 1, i, 1, 1);
821 }
822
823 /*
824 * Allow special highlighting of emergencies for granary etc by
825 * city_dialog_update_information().
826 */
827 {
828 /* This will persist, and can be shared between overview and happiness
829 * pages. */
830 static GtkCssProvider *emergency_provider = NULL;
831
832 if (emergency_provider == NULL) {
833 emergency_provider = gtk_css_provider_new();
834
835 gtk_css_provider_load_from_data(emergency_provider,
836 ".emergency {\n"
837 " color: rgba(255, 0.0, 0.0, 255);\n"
838 "}",
839 -1);
840
841 gtk_style_context_add_provider_for_display(
842 gtk_widget_get_display(toplevel),
843 GTK_STYLE_PROVIDER(emergency_provider),
844 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
845 }
846 }
847
848 gtk_widget_show(table);
849
850 return table;
851}
852
853/***********************************************************************/
858static void create_citydlg_main_map(struct city_dialog *pdialog,
859 GtkWidget *grid, int col, int row)
860{
861 GtkWidget *frame;
862
863 frame = gtk_frame_new(_("City map"));
864 gtk_widget_set_size_request(frame, CITY_MAP_MIN_SIZE_X,
866 gtk_grid_attach(GTK_GRID(grid), frame, col, row, 1, 1);
867
868 city_dialog_map_create(pdialog, &pdialog->overview.map_canvas);
869 gtk_frame_set_child(GTK_FRAME(frame), pdialog->overview.map_canvas.sw);
870}
871
872/***********************************************************************/
875static GtkWidget *create_citydlg_improvement_list(struct city_dialog *pdialog)
876{
877 GtkWidget *view;
878 GtkListStore *store;
879 GtkCellRenderer *rend;
880
881 /* improvements */
882 /* gtk list store columns: 0 - sell value, 1 - sprite,
883 2 - description, 3 - upkeep, 4 - is redundant, 5 - tooltip */
884 store = gtk_list_store_new(6, G_TYPE_POINTER, GDK_TYPE_PIXBUF,
885 G_TYPE_STRING, G_TYPE_INT, G_TYPE_BOOLEAN,
886 G_TYPE_STRING);
887
888 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
889 gtk_widget_set_hexpand(view, TRUE);
890 gtk_widget_set_vexpand(view, TRUE);
891 g_object_unref(store);
892 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
893 gtk_widget_set_name(view, "small_font");
894 pdialog->overview.improvement_list = view;
895
896 rend = gtk_cell_renderer_pixbuf_new();
897 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, NULL,
898 rend, "pixbuf", 1, NULL);
899 rend = gtk_cell_renderer_text_new();
900 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, NULL,
901 rend, "text", 2,
902 "strikethrough", 4, NULL);
903 rend = gtk_cell_renderer_text_new();
904 g_object_set(rend, "xalign", 1.0, NULL);
905 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, NULL,
906 rend, "text", 3,
907 "strikethrough", 4, NULL);
908
909 gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(view), 5);
910
911 g_signal_connect(view, "row_activated", G_CALLBACK(impr_callback),
912 pdialog);
913
914 return view;
915}
916
917/***********************************************************************/
934{
935 GtkWidget *page, *bottom;
936 GtkWidget *right, *frame, *table;
937 GtkWidget *label, *sw, *view, *bar, *production_combo;
938 GtkCellRenderer *rend;
939 GtkListStore *production_store;
940 /* TRANS: Overview tab in city dialog */
941 const char *tab_title = _("_Overview");
942 int unit_height = tileset_unit_with_upkeep_height(tileset);
943 int page_row = 0;
944 int bottom_col = 0;
945 int right_row = 0;
946
947 /* main page */
948 page = gtk_grid_new();
949 gtk_orientable_set_orientation(GTK_ORIENTABLE(page),
950 GTK_ORIENTATION_VERTICAL);
951 gtk_widget_set_margin_start(page, 8);
952 gtk_widget_set_margin_end(page, 8);
953 gtk_widget_set_margin_top(page, 8);
954 gtk_widget_set_margin_bottom(page, 8);
955 label = gtk_label_new_with_mnemonic(tab_title);
956 gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), page, label);
957
958 if (!low_citydlg) {
959 GtkWidget *middle;
960 GtkWidget *vgrid;
961 GtkWidget *hgrid;
962 int middle_col = 0;
963 int grid_row = 0;
964 int grid_col = 0;
965
966 /* middle: city map, improvements */
967 middle = gtk_grid_new();
968 gtk_grid_set_column_spacing(GTK_GRID(middle), 6);
969 gtk_grid_attach(GTK_GRID(page), middle, 0, page_row++, 1, 1);
970
971 /* city map */
972 create_citydlg_main_map(pdialog, middle, middle_col++, 0);
973
974 /* improvements */
975 vgrid = gtk_grid_new();
976 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
977 GTK_ORIENTATION_VERTICAL);
978 gtk_grid_attach(GTK_GRID(middle), vgrid, middle_col++, 0, 1, 1);
979
981
982 label = g_object_new(GTK_TYPE_LABEL, "label", _("Production:"),
983 "xalign", 0.0, "yalign", 0.5, NULL);
984 gtk_grid_attach(GTK_GRID(vgrid), label, 0, grid_row++, 1, 1);
985
986 hgrid = gtk_grid_new();
987 gtk_grid_set_column_spacing(GTK_GRID(hgrid), 10);
988 gtk_grid_attach(GTK_GRID(vgrid), hgrid, 0, grid_row++, 1, 1);
989
990 production_store = gtk_list_store_new(4, GDK_TYPE_PIXBUF, G_TYPE_STRING,
991 G_TYPE_INT, G_TYPE_BOOLEAN);
992 pdialog->overview.change_production_store = production_store;
993
994 bar = gtk_progress_bar_new();
995 gtk_progress_bar_set_show_text(GTK_PROGRESS_BAR(bar), TRUE);
996 pdialog->overview.production_bar = bar;
997 gtk_grid_attach(GTK_GRID(hgrid), bar, grid_col++, 0, 1, 1);
998
999 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(bar), _("%d/%d %d turns"));
1000
1002 = gtk_combo_box_new_with_model(GTK_TREE_MODEL(production_store));
1003 gtk_widget_set_hexpand(production_combo, TRUE);
1005 gtk_grid_attach(GTK_GRID(hgrid), production_combo, grid_col++, 0, 1, 1);
1006 g_object_unref(production_store);
1007 g_signal_connect(production_combo, "changed",
1008 G_CALLBACK(change_production_callback), pdialog);
1009
1010 gtk_cell_layout_clear(GTK_CELL_LAYOUT(production_combo));
1011 rend = gtk_cell_renderer_pixbuf_new();
1012 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(production_combo), rend, TRUE);
1013 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(production_combo),
1014 rend, "pixbuf", 0, NULL);
1015 g_object_set(rend, "xalign", 0.0, NULL);
1016
1017 rend = gtk_cell_renderer_text_new();
1018 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(production_combo), rend, TRUE);
1019 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(production_combo),
1020 rend, "text", 1, "strikethrough", 3, NULL);
1021
1022 pdialog->overview.buy_command
1023 = icon_label_button_new("system-run", _("_Buy"));
1024 gtk_grid_attach(GTK_GRID(hgrid), GTK_WIDGET(pdialog->overview.buy_command),
1025 grid_col++, 0, 1, 1);
1026 g_signal_connect(pdialog->overview.buy_command, "clicked",
1027 G_CALLBACK(buy_callback), pdialog);
1028
1029 label = g_object_new(GTK_TYPE_LABEL, "use-underline", TRUE,
1030 "mnemonic-widget", view,
1031 "label", _("I_mprovements:"),
1032 "xalign", 0.0, "yalign", 0.5, NULL);
1033 gtk_grid_attach(GTK_GRID(vgrid), label, 0, grid_row++, 1, 1);
1034
1035 sw = gtk_scrolled_window_new();
1036 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), TRUE);
1037 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1038 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1039 gtk_grid_attach(GTK_GRID(vgrid), sw, 0, grid_row++, 1, 1);
1040
1041 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), view);
1042 } else {
1043 pdialog->overview.buy_command = NULL;
1044 pdialog->overview.production_bar = NULL;
1045 pdialog->overview.production_combo = NULL;
1046 pdialog->overview.change_production_store = NULL;
1047 }
1048
1049 /* bottom: info, units */
1050 bottom = gtk_grid_new();
1051 gtk_grid_set_column_spacing(GTK_GRID(bottom), 6);
1052 gtk_grid_attach(GTK_GRID(page), bottom, 0, page_row++, 1, 1);
1053
1054 /* info */
1055 frame = gtk_frame_new(_("Info"));
1056 gtk_grid_attach(GTK_GRID(bottom), frame, bottom_col++, 0, 1, 1);
1057
1058 table = create_city_info_table(pdialog,
1059 pdialog->overview.info_label);
1060 gtk_widget_set_halign(table, GTK_ALIGN_CENTER);
1061 gtk_widget_set_valign(table, GTK_ALIGN_CENTER);
1062 gtk_frame_set_child(GTK_FRAME(frame), table);
1063
1064 /* right: present and supported units (overview page) */
1065 right = gtk_grid_new();
1066 gtk_orientable_set_orientation(GTK_ORIENTABLE(right),
1067 GTK_ORIENTATION_VERTICAL);
1068 gtk_grid_attach(GTK_GRID(bottom), right, bottom_col++, 0, 1, 1);
1069
1070 pdialog->overview.supported_units_frame = gtk_frame_new("");
1071 gtk_grid_attach(GTK_GRID(right), pdialog->overview.supported_units_frame,
1072 0, right_row++, 1, 1);
1073 pdialog->overview.present_units_frame = gtk_frame_new("");
1074 gtk_grid_attach(GTK_GRID(right), pdialog->overview.present_units_frame,
1075 0, right_row++, 1, 1);
1076
1077 /* supported units */
1078 sw = gtk_scrolled_window_new();
1079 gtk_widget_set_hexpand(sw, TRUE);
1080 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1081 GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
1082 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), FALSE);
1083 gtk_frame_set_child(GTK_FRAME(pdialog->overview.supported_units_frame),
1084 sw);
1085
1086
1087 table = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
1088 gtk_widget_set_size_request(table, -1, unit_height);
1089 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), table);
1090
1091 pdialog->overview.supported_unit_table = table;
1092 unit_node_vector_init(&pdialog->overview.supported_units);
1093
1094 /* present units */
1095 sw = gtk_scrolled_window_new();
1096 gtk_widget_set_hexpand(sw, TRUE);
1097 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1098 GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
1099 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), FALSE);
1100 gtk_frame_set_child(GTK_FRAME(pdialog->overview.present_units_frame), sw);
1101
1102 table = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
1103 gtk_widget_set_size_request(table, -1, unit_height);
1104 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), table);
1105
1106 pdialog->overview.present_unit_table = table;
1107 unit_node_vector_init(&pdialog->overview.present_units);
1108
1109 /* show page */
1110 gtk_widget_show(page);
1111}
1112
1113/***********************************************************************/
1116static void create_and_append_map_page(struct city_dialog *pdialog)
1117{
1118 if (low_citydlg) {
1119 GtkWidget *page;
1120 GtkWidget *label;
1121 const char *tab_title = _("Citymap");
1122 int page_row = 0;
1123
1124 page = gtk_grid_new();
1125 gtk_orientable_set_orientation(GTK_ORIENTABLE(page),
1126 GTK_ORIENTATION_VERTICAL);
1127 gtk_widget_set_margin_start(page, 8);
1128 gtk_widget_set_margin_end(page, 8);
1129 gtk_widget_set_margin_top(page, 8);
1130 gtk_widget_set_margin_bottom(page, 8);
1131 label = gtk_label_new_with_mnemonic(tab_title);
1132 gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), page, label);
1133
1134 create_citydlg_main_map(pdialog, page, 0, page_row++);
1135
1136 gtk_widget_show(page);
1137 }
1138}
1139
1140/***********************************************************************/
1143static gboolean target_drag_data_received(GtkDropTarget *target,
1144 const GValue *value,
1145 double x, double y, gpointer data)
1146{
1147 struct city_dialog *pdialog = (struct city_dialog *) data;
1148 cid id;
1149 struct universal univ;
1150
1151 if (NULL != client.conn.playing
1152 && city_owner(pdialog->pcity) != client.conn.playing) {
1153 return FALSE;
1154 }
1155
1156 id = g_value_get_int(value);
1157 univ = cid_production(id);
1158
1159 city_change_production(pdialog->pcity, &univ);
1160
1161 return TRUE;
1162}
1163
1164/***********************************************************************/
1168static int create_production_header(struct city_dialog *pdialog,
1169 GtkWidget *grid, int row)
1170{
1171 GtkWidget *hgrid, *bar;
1172 int grid_col = 0;
1173
1174 hgrid = gtk_grid_new();
1175 gtk_widget_set_margin_bottom(hgrid, 2);
1176 gtk_widget_set_margin_end(hgrid, 2);
1177 gtk_widget_set_margin_start(hgrid, 2);
1178 gtk_widget_set_margin_top(hgrid, 2);
1179 gtk_grid_set_column_spacing(GTK_GRID(hgrid), 10);
1180 gtk_grid_attach(GTK_GRID(grid), hgrid, 0, row++, 1, 1);
1181
1182 /* The label is set in city_dialog_update_building() */
1183 bar = gtk_progress_bar_new();
1184 gtk_widget_set_hexpand(bar, TRUE);
1185 gtk_progress_bar_set_show_text(GTK_PROGRESS_BAR(bar), TRUE);
1186 pdialog->production.production_bar = bar;
1187 gtk_grid_attach(GTK_GRID(hgrid), bar, grid_col++, 0, 1, 1);
1188 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(bar), _("%d/%d %d turns"));
1189
1191
1192 pdialog->production.buy_command
1193 = icon_label_button_new("system-run", _("_Buy"));
1194 gtk_grid_attach(GTK_GRID(hgrid), GTK_WIDGET(pdialog->production.buy_command),
1195 grid_col++, 0, 1, 1);
1196
1197 g_signal_connect(pdialog->production.buy_command, "clicked",
1198 G_CALLBACK(buy_callback), pdialog);
1199
1200 return row;
1201}
1202
1203/***********************************************************************/
1207{
1208 if (low_citydlg) {
1209 GtkWidget *page;
1210 GtkWidget *label;
1211 GtkWidget *vgrid;
1212 GtkWidget *view;
1213 const char *tab_title = _("Buildings");
1214 int page_row = 0;
1215 int grid_row = 0;
1216
1217 page = gtk_grid_new();
1218 gtk_orientable_set_orientation(GTK_ORIENTABLE(page),
1219 GTK_ORIENTATION_VERTICAL);
1220 gtk_widget_set_margin_start(page, 8);
1221 gtk_widget_set_margin_end(page, 8);
1222 gtk_widget_set_margin_top(page, 8);
1223 gtk_widget_set_margin_bottom(page, 8);
1224 label = gtk_label_new_with_mnemonic(tab_title);
1225
1226 page_row = create_production_header(pdialog, page, page_row);
1227 gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), page, label);
1228
1229 vgrid = gtk_grid_new();
1230 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
1231 GTK_ORIENTATION_VERTICAL);
1232 gtk_grid_attach(GTK_GRID(page), vgrid, 0, page_row++, 1, 1);
1233
1235
1236 gtk_grid_attach(GTK_GRID(vgrid), view, 0, grid_row++, 1, 1);
1237
1238 gtk_widget_show(page);
1239 }
1240}
1241
1242/***********************************************************************/
1246{
1247 const char *tab_title = _("P_roduction");
1248 GtkWidget *label = gtk_label_new_with_mnemonic(tab_title);
1249 GtkWidget *page, *editor;
1250 int page_row = 0;
1251
1252 page = gtk_grid_new();
1253 gtk_orientable_set_orientation(GTK_ORIENTABLE(page),
1254 GTK_ORIENTATION_VERTICAL);
1255 gtk_widget_set_margin_start(page, 8);
1256 gtk_widget_set_margin_end(page, 8);
1257 gtk_widget_set_margin_top(page, 8);
1258 gtk_widget_set_margin_bottom(page, 8);
1259 gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), page, label);
1260
1261 /* stuff that's being currently built */
1262 if (!low_citydlg) {
1263 label = g_object_new(GTK_TYPE_LABEL,
1264 "label", _("Production:"),
1265 "xalign", 0.0, "yalign", 0.5, NULL);
1266 pdialog->production.production_label = label;
1267 gtk_grid_attach(GTK_GRID(page), label, 0, page_row++, 1, 1);
1268
1269 page_row = create_production_header(pdialog, page, page_row);
1270 } else {
1271 pdialog->production.production_label = NULL;
1272 }
1273
1275 gtk_widget_set_margin_bottom(editor, 6);
1276 gtk_widget_set_margin_end(editor, 6);
1277 gtk_widget_set_margin_start(editor, 6);
1278 gtk_widget_set_margin_top(editor, 6);
1279 reset_city_worklist(editor, pdialog->pcity);
1280 gtk_grid_attach(GTK_GRID(page), editor, 0, page_row++, 1, 1);
1281 pdialog->production.worklist = editor;
1282
1283 gtk_widget_show(page);
1284}
1285
1286/***********************************************************************/
1297{
1298 GtkWidget *page, *label, *table, *right, *left, *frame;
1299 const char *tab_title = _("Happ_iness");
1300 int page_col = 0;
1301 int left_row = 0;
1302 int right_row = 0;
1303
1304 /* main page */
1305 page = gtk_grid_new();
1306 gtk_grid_set_column_spacing(GTK_GRID(page), 6);
1307 gtk_widget_set_margin_start(page, 8);
1308 gtk_widget_set_margin_end(page, 8);
1309 gtk_widget_set_margin_top(page, 8);
1310 gtk_widget_set_margin_bottom(page, 8);
1311 label = gtk_label_new_with_mnemonic(tab_title);
1312 gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), page, label);
1313
1314 /* left: info, citizens */
1315 left = gtk_grid_new();
1316 gtk_orientable_set_orientation(GTK_ORIENTABLE(left),
1317 GTK_ORIENTATION_VERTICAL);
1318 gtk_grid_attach(GTK_GRID(page), left, page_col++, 0, 1, 1);
1319
1320 if (!low_citydlg) {
1321 /* upper left: info */
1322 frame = gtk_frame_new(_("Info"));
1323 gtk_grid_attach(GTK_GRID(left), frame, 0, left_row++, 1, 1);
1324
1325 table = create_city_info_table(pdialog,
1326 pdialog->happiness.info_label);
1327 gtk_widget_set_halign(table, GTK_ALIGN_CENTER);
1328 gtk_frame_set_child(GTK_FRAME(frame), table);
1329 }
1330
1331 /* lower left: citizens */
1333 pdialog->happiness.citizens = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
1334 gtk_grid_attach(GTK_GRID(left), pdialog->happiness.citizens,
1335 0, left_row++, 1, 1);
1336 gtk_box_append(GTK_BOX(pdialog->happiness.citizens),
1337 citizens_dialog_display(pdialog->pcity));
1338 }
1339
1340 /* right: city map, happiness */
1341 right = gtk_grid_new();
1342 gtk_orientable_set_orientation(GTK_ORIENTABLE(right),
1343 GTK_ORIENTATION_VERTICAL);
1344 gtk_grid_attach(GTK_GRID(page), right, page_col++, 0, 1, 1);
1345
1346 if (!low_citydlg) {
1347 /* upper right: city map */
1348 frame = gtk_frame_new(_("City map"));
1349 gtk_widget_set_size_request(frame, CITY_MAP_MIN_SIZE_X,
1351 gtk_grid_attach(GTK_GRID(right), frame, 0, right_row++, 1, 1);
1352
1353 city_dialog_map_create(pdialog, &pdialog->happiness.map_canvas);
1354 gtk_frame_set_child(GTK_FRAME(frame), pdialog->happiness.map_canvas.sw);
1355 }
1356
1357 /* lower right: happiness */
1358 pdialog->happiness.widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
1359 gtk_grid_attach(GTK_GRID(right), pdialog->happiness.widget, 0, right_row++, 1, 1);
1360 gtk_box_append(GTK_BOX(pdialog->happiness.widget),
1361 get_top_happiness_display(pdialog->pcity, low_citydlg, pdialog->shell));
1362
1363 /* show page */
1364 gtk_widget_show(page);
1365}
1366
1367/***********************************************************************/
1370static void create_and_append_cma_page(struct city_dialog *pdialog)
1371{
1372 GtkWidget *page, *label;
1373 const char *tab_title = _("_Governor");
1374
1375 page = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1376
1377 label = gtk_label_new_with_mnemonic(tab_title);
1378
1379 gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), page, label);
1380
1381 pdialog->cma_editor = create_cma_dialog(pdialog->pcity, low_citydlg);
1382 gtk_box_append(GTK_BOX(page), pdialog->cma_editor->shell);
1383
1384 gtk_widget_show(page);
1385}
1386
1387/***********************************************************************/
1391{
1392 int i;
1393 GtkWidget *vgrid, *page, *frame, *label, *button;
1394 GtkSizeGroup *size;
1395 GtkWidget *group;
1396 const char *tab_title = _("_Settings");
1397 int grid_row = 0;
1398
1399 static const char *new_citizens_output_label[] = {
1400 N_("Luxury"),
1401 N_("Science"),
1402 N_("Gold")
1403 };
1404
1405 static const char *disband_label
1406 = N_("Allow unit production to disband city");
1407
1408 static const char *misc_whichtab_label[NUM_PAGES] = {
1409 N_("Overview page"),
1410 N_("Production page"),
1411 N_("Happiness page"),
1412 N_("Governor page"),
1413 N_("This Settings page"),
1414 N_("Last active page")
1415 };
1416
1417 static bool new_citizens_label_done;
1418 static bool misc_whichtab_label_done;
1419
1420 /* initialize signal_blocker */
1421 pdialog->misc.block_signal = 0;
1422
1423
1424 page = gtk_grid_new();
1425 gtk_grid_set_column_spacing(GTK_GRID(page), 18);
1426 gtk_widget_set_margin_start(page, 8);
1427 gtk_widget_set_margin_end(page, 8);
1428 gtk_widget_set_margin_top(page, 8);
1429 gtk_widget_set_margin_bottom(page, 8);
1430
1431 size = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
1432
1433 label = gtk_label_new_with_mnemonic(tab_title);
1434
1435 gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), page, label);
1436
1437 /* new_citizens radio */
1438 frame = gtk_frame_new(_("New citizens produce"));
1439 gtk_grid_attach(GTK_GRID(page), frame, 0, 0, 1, 1);
1440 gtk_size_group_add_widget(size, frame);
1441
1442 vgrid = gtk_grid_new();
1443 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
1444 GTK_ORIENTATION_VERTICAL);
1445 gtk_frame_set_child(GTK_FRAME(frame), vgrid);
1446
1447 intl_slist(ARRAY_SIZE(new_citizens_output_label), new_citizens_output_label,
1448 &new_citizens_label_done);
1449
1450 group = NULL;
1451 for (i = 0; i < ARRAY_SIZE(new_citizens_output_label); i++) {
1452 button = gtk_check_button_new_with_mnemonic(new_citizens_output_label[i]);
1453 gtk_check_button_set_group(GTK_CHECK_BUTTON(button),
1454 GTK_CHECK_BUTTON(group));
1455 pdialog->misc.new_citizens_radio[i] = button;
1456 gtk_grid_attach(GTK_GRID(vgrid), button, 0, grid_row++, 1, 1);
1457 g_signal_connect(button, "toggled",
1458 G_CALLBACK(cityopt_callback), pdialog);
1459 group = button;
1460 }
1461
1462 /* next is the next-time-open radio group in the right column */
1463 frame = gtk_frame_new(_("Next time open"));
1464 gtk_grid_attach(GTK_GRID(page), frame, 1, 0, 1, 1);
1465 gtk_size_group_add_widget(size, frame);
1466
1467 vgrid = gtk_grid_new();
1468 grid_row = 0;
1469 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
1470 GTK_ORIENTATION_VERTICAL);
1471 gtk_frame_set_child(GTK_FRAME(frame), vgrid);
1472
1473 intl_slist(ARRAY_SIZE(misc_whichtab_label), misc_whichtab_label,
1474 &misc_whichtab_label_done);
1475
1476 group = NULL;
1477 for (i = 0; i < ARRAY_SIZE(misc_whichtab_label); i++) {
1478 button = gtk_check_button_new_with_mnemonic(misc_whichtab_label[i]);
1479 gtk_check_button_set_group(GTK_CHECK_BUTTON(button),
1480 GTK_CHECK_BUTTON(group));
1481 pdialog->misc.whichtab_radio[i] = button;
1482 gtk_grid_attach(GTK_GRID(vgrid), button, 0, grid_row++, 1, 1);
1483 g_signal_connect(button, "toggled",
1484 G_CALLBACK(misc_whichtab_callback), GINT_TO_POINTER(i));
1485 group = button;
1486 }
1487
1488 /* now we go back and fill the hbox rename */
1489 frame = gtk_frame_new(_("City"));
1490 gtk_widget_set_margin_top(frame, 12);
1491 gtk_widget_set_margin_bottom(frame, 12);
1492 gtk_grid_attach(GTK_GRID(page), frame, 0, 1, 1, 1);
1493
1494 vgrid = gtk_grid_new();
1495 grid_row = 0;
1496 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
1497 GTK_ORIENTATION_VERTICAL);
1498 gtk_frame_set_child(GTK_FRAME(frame), vgrid);
1499
1500 button = gtk_button_new_with_mnemonic(_("R_ename..."));
1501 pdialog->misc.rename_command = button;
1502 gtk_grid_attach(GTK_GRID(vgrid), button, 0, grid_row++, 1, 1);
1503 g_signal_connect(button, "clicked",
1504 G_CALLBACK(rename_callback), pdialog);
1505
1506 gtk_widget_set_sensitive(button, can_client_issue_orders());
1507
1508 /* the disband-city-on-unit-production button */
1509 button = gtk_check_button_new_with_mnemonic(_(disband_label));
1510 pdialog->misc.disband_on_settler = button;
1511 gtk_grid_attach(GTK_GRID(vgrid), button, 0, grid_row++, 1, 1);
1512 g_signal_connect(button, "toggled",
1513 G_CALLBACK(cityopt_callback), pdialog);
1514
1515 /* We choose which page to popup by default */
1516 gtk_check_button_set_active(GTK_CHECK_BUTTON
1517 (pdialog->
1519 TRUE);
1520
1521 set_cityopt_values(pdialog);
1522
1523 gtk_widget_show(page);
1524
1525 if (new_dialog_def_page == (NUM_PAGES - 1)) {
1526 gtk_notebook_set_current_page(GTK_NOTEBOOK(pdialog->notebook),
1527 last_page);
1528 } else {
1529 gtk_notebook_set_current_page(GTK_NOTEBOOK(pdialog->notebook),
1531 }
1532}
1533
1534/***********************************************************************/
1543{
1544 struct city_dialog *pdialog;
1545 GtkWidget *close_command;
1546 GtkWidget *vbox, *hbox, *cbox;
1547 int citizen_bar_width;
1548 int citizen_bar_height;
1549 int ccol = 0;
1550 GtkEventController *controller;
1551 struct player *owner;
1552
1555 }
1556
1557 pdialog = fc_malloc(sizeof(struct city_dialog));
1558 pdialog->pcity = pcity;
1559 pdialog->sell_shell = NULL;
1560 pdialog->rename_shell = NULL;
1561 pdialog->happiness.map_canvas.sw = NULL; /* Make sure NULL if spy */
1562 pdialog->happiness.map_canvas.darea = NULL; /* Ditto */
1563 pdialog->happiness.citizens = NULL; /* Ditto */
1564 pdialog->production.buy_command = NULL;
1565 pdialog->production.production_label = NULL;
1566 pdialog->production.production_bar = NULL;
1567 pdialog->cma_editor = NULL;
1569 = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
1571
1572 pdialog->shell = gtk_dialog_new();
1573 gtk_window_set_title(GTK_WINDOW(pdialog->shell), city_name_get(pcity));
1574 setup_dialog(pdialog->shell, toplevel);
1575
1576 g_signal_connect(pdialog->shell, "destroy",
1577 G_CALLBACK(city_destroy_callback), pdialog);
1578 gtk_widget_set_name(pdialog->shell, "Freeciv");
1579
1580 gtk_widget_realize(pdialog->shell);
1581
1582 /* Keep the icon of the executable on Windows (see PR#36491) */
1583#ifndef FREECIV_MSWINDOWS
1584 {
1585 gtk_window_set_icon_name(GTK_WINDOW(pdialog->shell), "citydlg");
1586 }
1587#endif /* FREECIV_MSWINDOWS */
1588
1589 /* Restore size of the city dialog. */
1590 gtk_window_set_default_size(GTK_WINDOW(pdialog->shell),
1591 GUI_GTK_OPTION(citydlg_xsize),
1592 GUI_GTK_OPTION(citydlg_ysize));
1593
1594 pdialog->popover = NULL;
1595
1596 vbox = gtk_dialog_get_content_area(GTK_DIALOG(pdialog->shell));
1597 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
1598 gtk_box_set_homogeneous(GTK_BOX(hbox), TRUE);
1599 gtk_box_append(GTK_BOX(vbox), hbox);
1600
1601 /**** Citizens bar here ****/
1602 cbox = gtk_grid_new();
1603 gtk_box_append(GTK_BOX(hbox), cbox);
1604
1606 citizen_bar_height = tileset_small_sprite_height(tileset);
1607
1608 pdialog->citizen_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
1609 citizen_bar_width,
1610 citizen_bar_height);
1611 pdialog->citizen_pics = gtk_picture_new();
1612
1613 gtk_widget_set_margin_start(pdialog->citizen_pics, 2);
1614 gtk_widget_set_margin_end(pdialog->citizen_pics, 2);
1615 gtk_widget_set_margin_top(pdialog->citizen_pics, 2);
1616 gtk_widget_set_margin_bottom(pdialog->citizen_pics, 2);
1617 gtk_widget_set_size_request(pdialog->citizen_pics,
1618 citizen_bar_width, citizen_bar_height);
1619 gtk_widget_set_halign(pdialog->citizen_pics, GTK_ALIGN_START);
1620 gtk_widget_set_valign(pdialog->citizen_pics, GTK_ALIGN_CENTER);
1621 gtk_grid_attach(GTK_GRID(cbox), pdialog->citizen_pics, ccol++, 0, 1, 1);
1622
1623 controller = GTK_EVENT_CONTROLLER(gtk_gesture_click_new());
1624 g_signal_connect(controller, "pressed",
1625 G_CALLBACK(citizens_callback), pdialog);
1626 gtk_widget_add_controller(pdialog->citizen_pics, controller);
1627
1628 /**** City name label here ****/
1629 pdialog->name_label = gtk_label_new(NULL);
1630 gtk_widget_set_hexpand(pdialog->name_label, TRUE);
1631 gtk_widget_set_halign(pdialog->name_label, GTK_ALIGN_START);
1632 gtk_widget_set_valign(pdialog->name_label, GTK_ALIGN_CENTER);
1633 gtk_box_append(GTK_BOX(hbox), pdialog->name_label);
1634
1635 /**** -Start of Notebook- ****/
1636
1637 pdialog->notebook = gtk_notebook_new();
1638 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(pdialog->notebook),
1639 GTK_POS_BOTTOM);
1640 gtk_box_append(GTK_BOX(vbox), pdialog->notebook);
1641
1645
1646 owner = city_owner(pcity);
1647
1648 /* Only create these tabs if not a spy */
1652 }
1653
1654 if (owner == client_player()
1655 && !client_is_observer()) {
1658 } else {
1659 gtk_notebook_set_current_page(GTK_NOTEBOOK(pdialog->notebook),
1661 }
1662
1663 /**** End of Notebook ****/
1664
1665 /* Bottom buttons */
1666
1667 pdialog->show_units_command =
1668 gtk_dialog_add_button(GTK_DIALOG(pdialog->shell), _("_List present units..."), CDLGR_UNITS);
1669
1670 g_signal_connect(GTK_DIALOG(pdialog->shell), "response",
1671 G_CALLBACK(citydlg_response_callback), pdialog);
1672
1673 pdialog->prev_command = gtk_button_new_from_icon_name("go-previous");
1674 gtk_dialog_add_action_widget(GTK_DIALOG(pdialog->shell),
1675 GTK_WIDGET(pdialog->prev_command), 1);
1676
1677 pdialog->next_command = gtk_button_new_from_icon_name("go-next");
1678 gtk_dialog_add_action_widget(GTK_DIALOG(pdialog->shell),
1679 GTK_WIDGET(pdialog->next_command), 2);
1680
1681 if (owner != client_player()) {
1682 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->prev_command), FALSE);
1683 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->next_command), FALSE);
1684 }
1685
1686 close_command = gtk_dialog_add_button(GTK_DIALOG(pdialog->shell),
1687 _("_Close"), GTK_RESPONSE_CLOSE);
1688
1689 gtk_dialog_set_default_response(GTK_DIALOG(pdialog->shell),
1690 GTK_RESPONSE_CLOSE);
1691
1692 g_signal_connect(close_command, "clicked",
1693 G_CALLBACK(close_callback), pdialog);
1694
1695 g_signal_connect(pdialog->prev_command, "clicked",
1696 G_CALLBACK(switch_city_callback), pdialog);
1697
1698 g_signal_connect(pdialog->next_command, "clicked",
1699 G_CALLBACK(switch_city_callback), pdialog);
1700
1701 /* Some other things we gotta do */
1702
1703 controller = gtk_event_controller_key_new();
1704 g_signal_connect(controller, "key-pressed",
1705 G_CALLBACK(citydlg_keyboard_handler), pdialog);
1706 gtk_widget_add_controller(pdialog->shell, controller);
1707
1708 dialog_list_prepend(dialog_list, pdialog);
1709
1711
1712 /* Need to do this every time a new dialog is opened. */
1714
1715 gtk_widget_show(pdialog->shell);
1716
1717 gtk_window_set_focus(GTK_WINDOW(pdialog->shell), close_command);
1718
1719 return pdialog;
1720}
1721
1722/**************** Functions to update parts of the dialog *****************/
1723
1724/***********************************************************************/
1727static void city_dialog_update_title(struct city_dialog *pdialog)
1728{
1729 gchar *buf;
1730 const gchar *now;
1731
1732 if (city_unhappy(pdialog->pcity)) {
1733 /* TRANS: city dialog title */
1734 buf = g_strdup_printf(_("<b>%s</b> - %s citizens - DISORDER"),
1735 city_name_get(pdialog->pcity),
1737 } else if (city_celebrating(pdialog->pcity)) {
1738 /* TRANS: city dialog title */
1739 buf = g_strdup_printf(_("<b>%s</b> - %s citizens - celebrating"),
1740 city_name_get(pdialog->pcity),
1742 } else if (city_happy(pdialog->pcity)) {
1743 /* TRANS: city dialog title */
1744 buf = g_strdup_printf(_("<b>%s</b> - %s citizens - happy"),
1745 city_name_get(pdialog->pcity),
1747 } else {
1748 /* TRANS: city dialog title */
1749 buf = g_strdup_printf(_("<b>%s</b> - %s citizens"),
1750 city_name_get(pdialog->pcity),
1752 }
1753
1754 now = gtk_label_get_text(GTK_LABEL(pdialog->name_label));
1755 if (strcmp(now, buf) != 0) {
1756 gtk_window_set_title(GTK_WINDOW(pdialog->shell), city_name_get(pdialog->pcity));
1757 gtk_label_set_markup(GTK_LABEL(pdialog->name_label), buf);
1758 }
1759
1760 g_free(buf);
1761}
1762
1763/***********************************************************************/
1766static void city_dialog_update_citizens(struct city_dialog *pdialog)
1767{
1768 enum citizen_category categories[MAX_CITY_SIZE];
1769 int i, width, full_width, total_used_width;
1770 int citizen_bar_width, citizen_bar_height;
1771 struct city *pcity = pdialog->pcity;
1772 int num_citizens = get_city_citizen_types(pcity, FEELING_FINAL, categories);
1773 cairo_t *cr;
1774
1775 /* If there is not enough space we stack the icons. We draw from left to */
1776 /* right. width is how far we go to the right for each drawn pixmap. The */
1777 /* last icon is always drawn in full, and so has reserved */
1778 /* tileset_small_sprite_width(tileset) pixels. */
1779
1780 full_width = tileset_small_sprite_width(tileset);
1781 if (num_citizens > 1) {
1782 width = MIN(full_width, ((NUM_CITIZENS_SHOWN - 1) * full_width)
1783 / (num_citizens - 1));
1784 } else {
1785 width = full_width;
1786 }
1787 pdialog->cwidth = width;
1788
1789 /* overview page */
1790 /* keep these values in sync with create_city_dialog */
1791 citizen_bar_width = full_width * NUM_CITIZENS_SHOWN;
1792 citizen_bar_height = tileset_small_sprite_height(tileset);
1793
1794 cr = cairo_create(pdialog->citizen_surface);
1795
1796 for (i = 0; i < num_citizens; i++) {
1797 cairo_set_source_surface(cr,
1798 get_citizen_sprite(tileset, categories[i], i, pcity)->surface,
1799 i * width, 0);
1800 cairo_rectangle(cr, i * width, 0,
1801 /* Always draw last citizen in full */
1802 i + 1 < num_citizens ? width : full_width,
1803 citizen_bar_height);
1804 cairo_fill(cr);
1805 }
1806
1807 total_used_width = (i - 1) * width + full_width;
1808
1809 if (total_used_width < citizen_bar_width) {
1810 /* Clear the rest of the area.
1811 * Note that this might still be necessary even in cases where
1812 * num_citizens > NUM_CITIZENS_SHOWN, if the available width cannot be
1813 * divided perfectly. */
1814 cairo_rectangle(cr, total_used_width, 0,
1815 citizen_bar_width - total_used_width,
1816 citizen_bar_height);
1817 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
1818 cairo_fill(cr);
1819 }
1820
1821 cairo_destroy(cr);
1822
1823 picture_set_from_surface(GTK_PICTURE(pdialog->citizen_pics),
1824 pdialog->citizen_surface);
1825
1826 gtk_widget_queue_draw(pdialog->citizen_pics);
1827}
1828
1829/***********************************************************************/
1833 struct city_dialog *pdialog)
1834{
1835 int i, illness = 0;
1836 char buf[NUM_INFO_FIELDS][512];
1837 struct city *pcity = pdialog->pcity;
1838 int granaryturns;
1839 int non_workers = city_specialists(pcity);
1840
1841 /* fill the buffers with the necessary info */
1842 if (non_workers) {
1843 fc_snprintf(buf[INFO_SIZE], sizeof(buf[INFO_SIZE]), "%3d (%3d)",
1844 pcity->size, non_workers);
1845 } else {
1846 fc_snprintf(buf[INFO_SIZE], sizeof(buf[INFO_SIZE]), "%3d", pcity->size);
1847 }
1848 fc_snprintf(buf[INFO_FOOD], sizeof(buf[INFO_FOOD]), "%3d (%+4d)",
1849 pcity->prod[O_FOOD], pcity->surplus[O_FOOD]);
1850 fc_snprintf(buf[INFO_SHIELD], sizeof(buf[INFO_SHIELD]), "%3d (%+4d)",
1851 pcity->prod[O_SHIELD] + pcity->waste[O_SHIELD],
1852 pcity->surplus[O_SHIELD]);
1853 fc_snprintf(buf[INFO_TRADE], sizeof(buf[INFO_TRADE]), "%3d (%+4d)",
1854 pcity->surplus[O_TRADE] + pcity->waste[O_TRADE],
1855 pcity->surplus[O_TRADE]);
1856 fc_snprintf(buf[INFO_GOLD], sizeof(buf[INFO_GOLD]), "%3d (%+4d)",
1857 pcity->prod[O_GOLD], pcity->surplus[O_GOLD]);
1858 fc_snprintf(buf[INFO_LUXURY], sizeof(buf[INFO_LUXURY]), "%3d",
1859 pcity->prod[O_LUXURY]);
1860 fc_snprintf(buf[INFO_SCIENCE], sizeof(buf[INFO_SCIENCE]), "%3d",
1861 pcity->prod[O_SCIENCE]);
1862 fc_snprintf(buf[INFO_GRANARY], sizeof(buf[INFO_GRANARY]), "%4d/%-4d",
1864
1865 granaryturns = city_turns_to_grow(pcity);
1866 if (granaryturns == 0) {
1867 /* TRANS: city growth is blocked. Keep short. */
1868 fc_snprintf(buf[INFO_GROWTH], sizeof(buf[INFO_GROWTH]), _("blocked"));
1869 } else if (granaryturns == FC_INFINITY) {
1870 /* TRANS: city is not growing. Keep short. */
1871 fc_snprintf(buf[INFO_GROWTH], sizeof(buf[INFO_GROWTH]), _("never"));
1872 } else {
1873 /* A negative value means we'll have famine in that many turns.
1874 But that's handled down below. */
1875 /* TRANS: city growth turns. Keep short. */
1876 fc_snprintf(buf[INFO_GROWTH], sizeof(buf[INFO_GROWTH]),
1877 PL_("%d turn", "%d turns", abs(granaryturns)),
1878 abs(granaryturns));
1879 }
1880 fc_snprintf(buf[INFO_CORRUPTION], sizeof(buf[INFO_CORRUPTION]), "%4d",
1881 pcity->waste[O_TRADE]);
1882 fc_snprintf(buf[INFO_WASTE], sizeof(buf[INFO_WASTE]), "%4d",
1883 pcity->waste[O_SHIELD]);
1884 fc_snprintf(buf[INFO_CULTURE], sizeof(buf[INFO_CULTURE]), "%4d",
1885 pcity->client.culture);
1886 fc_snprintf(buf[INFO_POLLUTION], sizeof(buf[INFO_POLLUTION]), "%4d",
1887 pcity->pollution);
1888 if (!game.info.illness_on) {
1889 fc_snprintf(buf[INFO_ILLNESS], sizeof(buf[INFO_ILLNESS]), " -.-");
1890 } else {
1891 illness = city_illness_calc(pcity, NULL, NULL, NULL, NULL);
1892 /* illness is in tenth of percent */
1893 fc_snprintf(buf[INFO_ILLNESS], sizeof(buf[INFO_ILLNESS]), "%5.1f%%",
1894 (float)illness / 10.0);
1895 }
1896 if (pcity->steal) {
1897 fc_snprintf(buf[INFO_STEAL], sizeof(buf[INFO_STEAL]), PL_("%d time", "%d times", pcity->steal),
1898 pcity->steal);
1899 } else {
1900 fc_snprintf(buf[INFO_STEAL], sizeof(buf[INFO_STEAL]), _("Not stolen"));
1901 }
1902
1903 get_city_dialog_airlift_value(pcity, buf[INFO_AIRLIFT], sizeof(buf[INFO_AIRLIFT]));
1904
1905 /* stick 'em in the labels */
1906 for (i = 0; i < NUM_INFO_FIELDS; i++) {
1907 gtk_label_set_text(GTK_LABEL(info_label[i]), buf[i]);
1908 }
1909
1910 /*
1911 * Make use of the emergency-indicating styles set up for certain labels
1912 * in create_city_info_table().
1913 */
1914 /* For starvation, the "4" below is arbitrary. 3 turns should be enough
1915 * of a warning. */
1916 if (granaryturns > -4 && granaryturns < 0) {
1917 gtk_widget_add_css_class(info_label[INFO_GRANARY], "emergency");
1918 } else {
1919 gtk_widget_remove_css_class(info_label[INFO_GRANARY], "emergency");
1920 }
1921
1922 if (granaryturns == 0 || pcity->surplus[O_FOOD] < 0) {
1923 gtk_widget_add_css_class(info_label[INFO_GROWTH], "emergency");
1924 } else {
1925 gtk_widget_remove_css_class(info_label[INFO_GROWTH], "emergency");
1926 }
1927
1928 /* Someone could add the color &orange for better granularity here */
1929 if (pcity->pollution >= 10) {
1930 gtk_widget_add_css_class(info_label[INFO_POLLUTION], "emergency");
1931 } else {
1932 gtk_widget_remove_css_class(info_label[INFO_POLLUTION], "emergency");
1933 }
1934
1935 /* Illness is in tenth of percent, i.e 100 == 10.0% */
1936 if (illness >= 100) {
1937 gtk_widget_add_css_class(info_label[INFO_ILLNESS], "emergency");
1938 } else {
1939 gtk_widget_remove_css_class(info_label[INFO_ILLNESS], "emergency");
1940 }
1941}
1942
1943/***********************************************************************/
1946static void city_dialog_update_map(struct city_dialog *pdialog)
1947{
1948 struct canvas store = FC_STATIC_CANVAS_INIT;
1949
1950 store.surface = pdialog->map_canvas_store_unscaled;
1951
1952 /* The drawing is done in three steps.
1953 * 1. First we render to a pixmap with the appropriate canvas size.
1954 * 2. Then the pixmap is rendered into a pixbuf of equal size.
1955 * 3. Finally this pixbuf is composited and scaled onto the GtkImage's
1956 * target pixbuf.
1957 */
1958
1959 city_dialog_redraw_map(pdialog->pcity, &store);
1960
1961 /* draw to real window */
1962 draw_map_canvas(pdialog);
1963}
1964
1965/***********************************************************************/
1968static void city_dialog_update_building(struct city_dialog *pdialog)
1969{
1970 char buf[32], buf2[200];
1971 gdouble pct;
1972 GtkListStore *store;
1973 GtkTreeIter iter;
1974 struct universal targets[MAX_NUM_PRODUCTION_TARGETS];
1975 struct item items[MAX_NUM_PRODUCTION_TARGETS];
1976 int targets_used, item;
1977 struct city *pcity = pdialog->pcity;
1978 gboolean sensitive = city_can_buy(pcity);
1979 const char *descr = city_production_name_translation(pcity);
1981
1982 if (pdialog->overview.buy_command != NULL) {
1983 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->overview.buy_command), sensitive);
1984 }
1985 if (pdialog->production.buy_command != NULL) {
1986 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->production.buy_command), sensitive);
1987 }
1988
1989 /* Make sure build slots info is up to date */
1990 if (pdialog->production.production_label != NULL) {
1991 int build_slots = city_build_slots(pcity);
1992
1993 /* Only display extra info if more than one slot is available */
1994 if (build_slots > 1) {
1995 fc_snprintf(buf2, sizeof(buf2),
1996 /* TRANS: never actually used with built_slots <= 1 */
1997 PL_("Production (up to %d unit per turn):",
1998 "Production (up to %d units per turn):", build_slots),
1999 build_slots);
2000 gtk_label_set_text(
2001 GTK_LABEL(pdialog->production.production_label), buf2);
2002 } else {
2003 gtk_label_set_text(
2004 GTK_LABEL(pdialog->production.production_label), _("Production:"));
2005 }
2006 }
2007
2008 /* Update what the city is working on */
2009 get_city_dialog_production(pcity, buf, sizeof(buf));
2010
2011 if (cost > 0) {
2012 pct = (gdouble) pcity->shield_stock / (gdouble) cost;
2013 pct = CLAMP(pct, 0.0, 1.0);
2014 } else {
2015 pct = 1.0;
2016 }
2017
2018 if (pdialog->overview.production_bar != NULL) {
2019 fc_snprintf(buf2, sizeof(buf2), "%s%s\n%s", descr,
2020 worklist_is_empty(&pcity->worklist) ? "" : " (+)", buf);
2021 gtk_progress_bar_set_text(
2022 GTK_PROGRESS_BAR(pdialog->overview.production_bar), buf2);
2023 gtk_progress_bar_set_fraction(
2024 GTK_PROGRESS_BAR(pdialog->overview.production_bar), pct);
2025 }
2026
2027 if (pdialog->production.production_bar != NULL) {
2028 fc_snprintf(buf2, sizeof(buf2), "%s%s: %s", descr,
2029 worklist_is_empty(&pcity->worklist) ? "" : " (+)", buf);
2030 gtk_progress_bar_set_text(
2031 GTK_PROGRESS_BAR(pdialog->production.production_bar), buf2);
2032 gtk_progress_bar_set_fraction(
2033 GTK_PROGRESS_BAR(pdialog->production.production_bar), pct);
2034 }
2035
2036 store = pdialog->overview.change_production_store;
2037 if (store != NULL) {
2038 int cur = -1;
2039 int actcount = 0;
2040
2041 if (pdialog->overview.production_combo != NULL) {
2042 gtk_combo_box_set_active(GTK_COMBO_BOX(pdialog->overview.production_combo),
2043 -1);
2044 }
2045
2046 gtk_list_store_clear(store);
2047
2048 targets_used
2049 = collect_eventually_buildable_targets(targets, pdialog->pcity, FALSE);
2050 name_and_sort_items(targets, targets_used, items, FALSE, pcity);
2051
2052 for (item = 0; item < targets_used; item++) {
2053 if (can_city_build_now(&(wld.map), pcity, &items[item].item)) {
2054 const char *name;
2055 struct sprite *sprite;
2056 GdkPixbuf *pix;
2057 struct universal *target = &items[item].item;
2058 bool useless;
2059
2060 if (VUT_UTYPE == target->kind) {
2063 direction8_invalid());
2064 useless = FALSE;
2065 } else {
2068 useless = is_improvement_redundant(pcity, target->value.building);
2069 }
2071 gtk_list_store_append(store, &iter);
2072 gtk_list_store_set(store, &iter, 0, pix,
2073 1, name, 3, useless,
2074 2, (gint)cid_encode(items[item].item), -1);
2075 g_object_unref(G_OBJECT(pix));
2076
2077 if (are_universals_equal(target, &pcity->production)) {
2078 cur = actcount;
2079 }
2080
2081 actcount++;
2082 }
2083 }
2084
2085 if (pdialog->overview.production_combo != NULL) {
2086 gtk_combo_box_set_active(GTK_COMBO_BOX(pdialog->overview.production_combo),
2087 cur);
2088 }
2089 }
2090}
2091
2092/***********************************************************************/
2096{
2097 int item, targets_used;
2098 struct universal targets[MAX_NUM_PRODUCTION_TARGETS];
2099 struct item items[MAX_NUM_PRODUCTION_TARGETS];
2100 GtkTreeModel *model;
2101 GtkListStore *store;
2102
2103 const char *tooltip_sellable = _("Press <b>ENTER</b> or double-click to "
2104 "sell an improvement.");
2105 const char *tooltip_great_wonder = _("Great Wonder - cannot be sold.");
2106 const char *tooltip_small_wonder = _("Small Wonder - cannot be sold.");
2107
2108 model =
2109 gtk_tree_view_get_model(GTK_TREE_VIEW(pdialog->overview.improvement_list));
2110 store = GTK_LIST_STORE(model);
2111
2112 targets_used = collect_already_built_targets(targets, pdialog->pcity);
2113 name_and_sort_items(targets, targets_used, items, FALSE, pdialog->pcity);
2114
2115 gtk_list_store_clear(store);
2116
2117 for (item = 0; item < targets_used; item++) {
2118 GdkPixbuf *pix;
2119 GtkTreeIter it;
2120 int upkeep;
2121 struct sprite *sprite;
2122 struct universal target = items[item].item;
2123
2124 fc_assert_action(VUT_IMPROVEMENT == target.kind, continue);
2125 /* This takes effects (like Adam Smith's) into account. */
2126 upkeep = city_improvement_upkeep(pdialog->pcity, target.value.building);
2128
2130 gtk_list_store_append(store, &it);
2131 gtk_list_store_set(store, &it,
2132 0, target.value.building,
2133 1, pix,
2134 2, items[item].descr,
2135 3, upkeep,
2136 4,
2138 target.value.building),
2139 5,
2141 tooltip_great_wonder :
2142 (is_small_wonder(target.value.building) ?
2143 tooltip_small_wonder : tooltip_sellable),
2144 -1);
2145 g_object_unref(G_OBJECT(pix));
2146 }
2147}
2148
2149/***********************************************************************/
2153{
2154 struct unit_list *units;
2155 struct unit_node_vector *nodes;
2156 int n, m, i;
2157 gchar *buf;
2158 int free_unhappy = get_city_bonus(pdialog->pcity, EFT_MAKE_CONTENT_MIL);
2159 const struct civ_map *nmap = &(wld.map);
2160
2161 if (NULL != client.conn.playing
2162 && city_owner(pdialog->pcity) != client.conn.playing) {
2163 units = pdialog->pcity->client.info_units_supported;
2164 } else {
2165 units = pdialog->pcity->units_supported;
2166 }
2167
2168 nodes = &pdialog->overview.supported_units;
2169
2170 n = unit_list_size(units);
2171 m = unit_node_vector_size(nodes);
2172
2173 if (m > n) {
2174 i = 0;
2175 unit_node_vector_iterate(nodes, elt) {
2176 if (i++ >= n) {
2177 gtk_box_remove(GTK_BOX(pdialog->overview.supported_unit_table),
2178 elt->cmd);
2179 }
2181
2182 unit_node_vector_reserve(nodes, n);
2183 } else {
2184 for (i = m; i < n; i++) {
2185 GtkWidget *cmd, *pix;
2186 struct unit_node node;
2187
2188 cmd = gtk_button_new();
2189 node.cmd = cmd;
2190
2191 gtk_button_set_has_frame(GTK_BUTTON(cmd), FALSE);
2192
2193 pix = gtk_picture_new();
2194 node.pix = pix;
2196
2197 gtk_button_set_child(GTK_BUTTON(cmd), pix);
2198
2199 gtk_box_append(GTK_BOX(pdialog->overview.supported_unit_table),
2200 cmd);
2201
2202 node.left = NULL;
2203 node.middle = NULL;
2204 node.right = NULL;
2205
2206 unit_node_vector_append(nodes, node);
2207 }
2208 }
2209
2210 i = 0;
2211 unit_list_iterate(units, punit) {
2212 struct unit_node *pnode;
2213 int happy_cost = city_unit_unhappiness(nmap, punit, &free_unhappy);
2214
2215 pnode = unit_node_vector_get(nodes, i);
2216 if (pnode) {
2217 GtkWidget *cmd, *pix;
2218 GtkGesture *gesture;
2219 GtkEventController *controller;
2220
2221 cmd = pnode->cmd;
2222 pix = pnode->pix;
2223
2224 put_unit_picture_city_overlays(punit, GTK_PICTURE(pix), pnode->height,
2225 punit->upkeep, happy_cost);
2226
2227 if (pnode->left != NULL) {
2228 gtk_widget_remove_controller(cmd, pnode->left);
2229 gtk_widget_remove_controller(cmd, pnode->middle);
2230 gtk_widget_remove_controller(cmd, pnode->right);
2231 }
2232
2233 gtk_widget_set_tooltip_text(cmd, unit_description(punit));
2234
2235 controller = GTK_EVENT_CONTROLLER(gtk_gesture_click_new());
2236 g_signal_connect(controller, "pressed",
2237 G_CALLBACK(supported_unit_callback),
2238 GINT_TO_POINTER(punit->id));
2239 gtk_widget_add_controller(cmd, controller);
2240 pnode->left = controller;
2241 gesture = gtk_gesture_click_new();
2242 gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 2);
2243 controller = GTK_EVENT_CONTROLLER(gesture);
2244 g_signal_connect(controller, "released",
2246 GINT_TO_POINTER(punit->id));
2247 gtk_widget_add_controller(cmd, controller);
2248 pnode->middle = controller;
2249 gesture = gtk_gesture_click_new();
2250 gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 3);
2251 controller = GTK_EVENT_CONTROLLER(gesture);
2252 g_signal_connect(controller, "released",
2253 G_CALLBACK(right_unit_release),
2254 GINT_TO_POINTER(punit->id));
2255 gtk_widget_add_controller(cmd, controller);
2256 pnode->right = controller;
2257
2258 if (city_owner(pdialog->pcity) != client.conn.playing) {
2259 gtk_widget_set_sensitive(cmd, FALSE);
2260 } else {
2261 gtk_widget_set_sensitive(cmd, TRUE);
2262 }
2263
2264 gtk_widget_show(pix);
2265 gtk_widget_show(cmd);
2266 }
2267 i++;
2269
2270 buf = g_strdup_printf(_("Supported units %d"), n);
2271 gtk_frame_set_label(GTK_FRAME(pdialog->overview.supported_units_frame), buf);
2272 g_free(buf);
2273}
2274
2275/***********************************************************************/
2279{
2280 struct unit_list *units;
2281 struct unit_node_vector *nodes;
2282 int n, m, i;
2283 gchar *buf;
2284
2285 if (NULL != client.conn.playing
2286 && city_owner(pdialog->pcity) != client.conn.playing) {
2287 units = pdialog->pcity->client.info_units_present;
2288 } else {
2289 units = pdialog->pcity->tile->units;
2290 }
2291
2292 nodes = &pdialog->overview.present_units;
2293
2294 n = unit_list_size(units);
2295 m = unit_node_vector_size(nodes);
2296
2297 if (m > n) {
2298 i = 0;
2299 unit_node_vector_iterate(nodes, elt) {
2300 if (i++ >= n) {
2301 gtk_box_remove(GTK_BOX(pdialog->overview.present_unit_table),
2302 elt->cmd);
2303 }
2305
2306 unit_node_vector_reserve(nodes, n);
2307 } else {
2308 for (i = m; i < n; i++) {
2309 GtkWidget *cmd, *pix;
2310 struct unit_node node;
2311
2312 cmd = gtk_button_new();
2313 node.cmd = cmd;
2314
2315 gtk_button_set_has_frame(GTK_BUTTON(cmd), FALSE);
2316
2317 pix = gtk_picture_new();
2318 node.pix = pix;
2320
2321 gtk_button_set_child(GTK_BUTTON(cmd), pix);
2322
2323 gtk_box_append(GTK_BOX(pdialog->overview.present_unit_table),
2324 cmd);
2325
2326 node.left = NULL;
2327 node.middle = NULL;
2328 node.right = NULL;
2329
2330 unit_node_vector_append(nodes, node);
2331 }
2332 }
2333
2334 i = 0;
2335 unit_list_iterate(units, punit) {
2336 struct unit_node *pnode;
2337
2338 pnode = unit_node_vector_get(nodes, i);
2339 if (pnode) {
2340 GtkWidget *cmd, *pix;
2341 GtkEventController *controller;
2342 GtkGesture *gesture;
2343
2344 cmd = pnode->cmd;
2345 pix = pnode->pix;
2346
2347 put_unit_picture(punit, GTK_PICTURE(pix), pnode->height);
2348
2349 if (pnode->left != NULL) {
2350 gtk_widget_remove_controller(cmd, pnode->left);
2351 gtk_widget_remove_controller(cmd, pnode->middle);
2352 gtk_widget_remove_controller(cmd, pnode->right);
2353 }
2354
2355 gtk_widget_set_tooltip_text(cmd, unit_description(punit));
2356
2357 controller = GTK_EVENT_CONTROLLER(gtk_gesture_click_new());
2358 g_signal_connect(controller, "pressed",
2359 G_CALLBACK(present_unit_callback),
2360 GINT_TO_POINTER(punit->id));
2361 gtk_widget_add_controller(cmd, controller);
2362 pnode->left = controller;
2363 gesture = gtk_gesture_click_new();
2364 gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 2);
2365 controller = GTK_EVENT_CONTROLLER(gesture);
2366 g_signal_connect(controller, "released",
2367 G_CALLBACK(middle_present_unit_release),
2368 GINT_TO_POINTER(punit->id));
2369 gtk_widget_add_controller(cmd, controller);
2370 pnode->middle = controller;
2371 gesture = gtk_gesture_click_new();
2372 gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 3);
2373 controller = GTK_EVENT_CONTROLLER(gesture);
2374 g_signal_connect(controller, "released",
2375 G_CALLBACK(right_unit_release),
2376 GINT_TO_POINTER(punit->id));
2377 gtk_widget_add_controller(cmd, controller);
2378 pnode->right = controller;
2379
2380 if (city_owner(pdialog->pcity) != client.conn.playing) {
2381 gtk_widget_set_sensitive(cmd, FALSE);
2382 } else {
2383 gtk_widget_set_sensitive(cmd, TRUE);
2384 }
2385
2386 gtk_widget_show(pix);
2387 gtk_widget_show(cmd);
2388 }
2389 i++;
2391
2392 buf = g_strdup_printf(_("Present units %d"), n);
2393 gtk_frame_set_label(GTK_FRAME(pdialog->overview.present_units_frame), buf);
2394 g_free(buf);
2395}
2396
2397/***********************************************************************/
2405{
2406 int count = 0;
2407 int city_number;
2408
2409 if (NULL != client.conn.playing) {
2410 city_number = city_list_size(client.conn.playing->cities);
2411 } else {
2412 city_number = FC_INFINITY; /* ? */
2413 }
2414
2415 /* The first time, we see if all the city dialogs are open */
2417 if (city_owner(pdialog->pcity) == client.conn.playing) {
2418 count++;
2419 }
2421
2422 if (count == city_number) { /* All are open, shouldn't prev/next */
2424 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->prev_command), FALSE);
2425 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->next_command), FALSE);
2427 } else {
2429 if (city_owner(pdialog->pcity) == client.conn.playing) {
2430 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->prev_command), TRUE);
2431 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->next_command), TRUE);
2432 }
2434 }
2435}
2436
2437/***********************************************************************/
2440static void citydlg_response_callback(GtkDialog *dlg, gint response,
2441 void *data)
2442{
2443 switch (response) {
2444 case CDLGR_UNITS:
2445 show_units_response(data);
2446 break;
2447 }
2448}
2449
2450/***********************************************************************/
2453static void show_units_response(void *data)
2454{
2455 struct city_dialog *pdialog = (struct city_dialog *) data;
2456 struct tile *ptile = pdialog->pcity->tile;
2457
2458 if (unit_list_size(ptile->units)) {
2460 }
2461}
2462
2463/***********************************************************************/
2473static bool create_unit_menu(struct city_dialog *pdialog, struct unit *punit,
2474 GtkWidget *wdg, bool supported)
2475{
2476 GMenu *menu;
2477 GActionGroup *group;
2478 GSimpleAction *act;
2479
2480 if (!can_client_issue_orders()) {
2481 return FALSE;
2482 }
2483
2484 if (pdialog->popover != NULL) {
2486 }
2487
2488 group = G_ACTION_GROUP(g_simple_action_group_new());
2489 menu = g_menu_new();
2490
2491 if (supported) {
2492 act = g_simple_action_new("center", NULL);
2493 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2494 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2495 g_signal_connect(act, "activate", G_CALLBACK(unit_center_callback),
2496 GINT_TO_POINTER(punit->id));
2497 menu_item_append_unref(menu, g_menu_item_new(_("Cen_ter"), "win.center"));
2498 }
2499
2500 act = g_simple_action_new("activate", NULL);
2501 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2502 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2503 g_signal_connect(act, "activate", G_CALLBACK(unit_activate_callback),
2504 GINT_TO_POINTER(punit->id));
2505 menu_item_append_unref(menu, g_menu_item_new(_("_Activate unit"),
2506 "win.activate"));
2507
2508 act = g_simple_action_new("activate_close", NULL);
2509 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2510 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2511
2512 if (supported) {
2513 g_signal_connect(act, "activate",
2515 GINT_TO_POINTER(punit->id));
2516 } else {
2517 g_signal_connect(act, "activate",
2519 GINT_TO_POINTER(punit->id));
2520 }
2521
2523 g_menu_item_new(_("Activate unit, _close dialog"),
2524 "win.activate_close"));
2525
2526 if (!supported) {
2527 act = g_simple_action_new("load", NULL);
2528 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2529 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2530 g_signal_connect(act, "activate", G_CALLBACK(unit_load_callback),
2531 GINT_TO_POINTER(punit->id));
2532 g_simple_action_set_enabled(G_SIMPLE_ACTION(act), unit_can_load(punit));
2533 menu_item_append_unref(menu, g_menu_item_new(_("_Load unit"), "win.load"));
2534
2535 act = g_simple_action_new("unload", NULL);
2536 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2537 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2538 g_signal_connect(act, "activate", G_CALLBACK(unit_unload_callback),
2539 GINT_TO_POINTER(punit->id));
2540 g_simple_action_set_enabled(G_SIMPLE_ACTION(act),
2544 unit_tile(punit)));
2545 menu_item_append_unref(menu, g_menu_item_new(_("_Unload unit"),
2546 "win.unload"));
2547
2548 act = g_simple_action_new("sentry", NULL);
2549 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2550 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2551 g_signal_connect(act, "activate", G_CALLBACK(unit_sentry_callback),
2552 GINT_TO_POINTER(punit->id));
2553 g_simple_action_set_enabled(G_SIMPLE_ACTION(act),
2554 punit->activity != ACTIVITY_SENTRY
2556 ACTIVITY_SENTRY));
2557 menu_item_append_unref(menu, g_menu_item_new(_("_Sentry unit"),
2558 "win.sentry"));
2559
2560 act = g_simple_action_new("fortify", NULL);
2561 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2562 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2563 g_signal_connect(act, "activate", G_CALLBACK(unit_fortify_callback),
2564 GINT_TO_POINTER(punit->id));
2565 g_simple_action_set_enabled(G_SIMPLE_ACTION(act),
2566 punit->activity != ACTIVITY_FORTIFYING
2568 ACTIVITY_FORTIFYING));
2569 menu_item_append_unref(menu, g_menu_item_new(_("_Fortify unit"),
2570 "win.fortify"));
2571 }
2572
2573 act = g_simple_action_new("disband", NULL);
2574 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2575 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2576 g_signal_connect(act, "activate", G_CALLBACK(unit_disband_callback),
2577 GINT_TO_POINTER(punit->id));
2578 g_simple_action_set_enabled(G_SIMPLE_ACTION(act),
2579 unit_can_do_action(punit, ACTION_DISBAND_UNIT));
2580 menu_item_append_unref(menu, g_menu_item_new(_("_Disband unit"),
2581 "win.disband"));
2582
2583 if (!supported) {
2584 act = g_simple_action_new("rehome", NULL);
2585 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2586 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2587 g_signal_connect(act, "activate", G_CALLBACK(unit_homecity_callback),
2588 GINT_TO_POINTER(punit->id));
2589 g_simple_action_set_enabled(G_SIMPLE_ACTION(act),
2591 pdialog->pcity));
2593 g_menu_item_new(action_id_name_translation(ACTION_HOME_CITY),
2594 "win.rehome"));
2595
2596 act = g_simple_action_new("upgrade", NULL);
2597 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2598 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2599 g_signal_connect(act, "activate", G_CALLBACK(unit_upgrade_callback),
2600 GINT_TO_POINTER(punit->id));
2601 g_simple_action_set_enabled(G_SIMPLE_ACTION(act),
2602 action_ever_possible(ACTION_UPGRADE_UNIT)
2606 != NULL);
2607 menu_item_append_unref(menu, g_menu_item_new(_("U_pgrade unit"),
2608 "win.upgrade"));
2609 }
2610
2611 pdialog->popover = gtk_popover_menu_new_from_model(G_MENU_MODEL(menu));
2612 g_object_ref(pdialog->popover);
2613 gtk_widget_insert_action_group(pdialog->popover, "win", group);
2614 gtk_widget_set_parent(pdialog->popover, wdg);
2615
2616
2617 gtk_popover_popup(GTK_POPOVER(pdialog->popover));
2618
2619 return TRUE;
2620}
2621
2622/***********************************************************************/
2625static gboolean supported_unit_callback(GtkGestureClick *gesture, int n_press,
2626 double x, double y, gpointer data)
2627{
2628 struct city_dialog *pdialog;
2629 struct city *pcity;
2630 struct unit *punit =
2631 player_unit_by_number(client_player(), (size_t) data);
2632
2633 if (NULL != punit
2634 && NULL != (pcity = game_city_by_number(punit->homecity))
2635 && NULL != (pdialog = get_city_dialog(pcity))) {
2636
2637 return create_unit_menu(pdialog, punit,
2638 gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)),
2639 TRUE);
2640 }
2641
2642 return TRUE;
2643}
2644
2645/***********************************************************************/
2648static gboolean present_unit_callback(GtkGestureClick *gesture, int n_press,
2649 double x, double y, gpointer data)
2650{
2651 struct city_dialog *pdialog;
2652 struct city *pcity;
2653 struct unit *punit =
2654 player_unit_by_number(client_player(), (size_t) data);
2655
2656 if (NULL != punit
2657 && NULL != (pcity = tile_city(unit_tile(punit)))
2658 && NULL != (pdialog = get_city_dialog(pcity))) {
2659
2660 return create_unit_menu(pdialog, punit,
2661 gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)),
2662 FALSE);
2663 }
2664
2665 return TRUE;
2666}
2667
2668/***********************************************************************/
2672static gboolean middle_present_unit_release(GtkGestureClick *gesture,
2673 int n_press, double x, double y,
2674 gpointer data)
2675{
2676 struct city_dialog *pdialog;
2677 struct city *pcity;
2678 struct unit *punit =
2679 player_unit_by_number(client_player(), (size_t) data);
2680
2681 if (NULL != punit
2682 && NULL != (pcity = tile_city(unit_tile(punit)))
2683 && NULL != (pdialog = get_city_dialog(pcity))
2686 close_city_dialog(pdialog);
2687 }
2688
2689 return TRUE;
2690}
2691
2692/***********************************************************************/
2696static gboolean middle_supported_unit_release(GtkGestureClick *gesture, int n_press,
2697 double x, double y, gpointer data)
2698{
2699 struct city_dialog *pdialog;
2700 struct city *pcity;
2701 struct unit *punit =
2702 player_unit_by_number(client_player(), (size_t) data);
2703
2704 if (NULL != punit
2705 && NULL != (pcity = game_city_by_number(punit->homecity))
2706 && NULL != (pdialog = get_city_dialog(pcity))
2709 close_city_dialog(pdialog);
2710 }
2711
2712 return TRUE;
2713}
2714
2715/***********************************************************************/
2718static gboolean right_unit_release(GtkGestureClick *gesture, int n_press,
2719 double x, double y, gpointer data)
2720{
2721 struct unit *punit =
2722 player_unit_by_number(client_player(), (size_t) data);
2723
2724 if (NULL != punit
2727 }
2728
2729 return TRUE;
2730}
2731
2732/***********************************************************************/
2737static void close_citydlg_unit_popover(struct city_dialog *pdialog)
2738{
2739 if (pdialog->popover != NULL) {
2740 gtk_widget_unparent(pdialog->popover);
2741 g_object_unref(pdialog->popover);
2742 pdialog->popover = NULL;
2743 }
2744}
2745
2746/***********************************************************************/
2749static void unit_center_callback(GSimpleAction *action, GVariant *parameter,
2750 gpointer data)
2751{
2752 struct unit *punit =
2753 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2754
2755 if (NULL != punit) {
2757 }
2758
2759 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2760}
2761
2762/***********************************************************************/
2765static void unit_activate_callback(GSimpleAction *action, GVariant *parameter,
2766 gpointer data)
2767{
2768 struct unit *punit =
2769 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2770
2771 if (NULL != punit) {
2773 }
2774
2775 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2776}
2777
2778/***********************************************************************/
2783 GVariant *parameter,
2784 gpointer data)
2785{
2786 struct unit *punit =
2787 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2788
2789 if (NULL != punit) {
2790 struct city *pcity =
2792
2794 if (NULL != pcity) {
2795 struct city_dialog *pdialog = get_city_dialog(pcity);
2796
2797 if (NULL != pdialog) {
2798 close_city_dialog(pdialog);
2799 }
2800 }
2801 }
2802
2803 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2804}
2805
2806/***********************************************************************/
2811 GVariant *parameter,
2812 gpointer data)
2813{
2814 struct unit *punit =
2815 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2816
2817 if (NULL != punit) {
2818 struct city *pcity = tile_city(unit_tile(punit));
2819
2821 if (NULL != pcity) {
2822 struct city_dialog *pdialog = get_city_dialog(pcity);
2823
2824 if (NULL != pdialog) {
2825 close_city_dialog(pdialog);
2826 }
2827 }
2828 }
2829
2830 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2831}
2832
2833/***********************************************************************/
2836static void unit_load_callback(GSimpleAction *action, GVariant *parameter,
2837 gpointer data)
2838{
2839 struct unit *punit =
2840 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2841
2842 if (NULL != punit) {
2844 }
2845
2846 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2847}
2848
2849/***********************************************************************/
2852static void unit_unload_callback(GSimpleAction *action, GVariant *parameter,
2853 gpointer data)
2854{
2855 struct unit *punit =
2856 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2857
2858 if (NULL != punit) {
2860 }
2861
2862 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2863}
2864
2865/***********************************************************************/
2868static void unit_sentry_callback(GSimpleAction *action, GVariant *parameter,
2869 gpointer data)
2870{
2871 struct unit *punit =
2872 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2873
2874 if (NULL != punit) {
2876 }
2877
2878 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2879}
2880
2881/***********************************************************************/
2884static void unit_fortify_callback(GSimpleAction *action, GVariant *parameter,
2885 gpointer data)
2886{
2887 struct unit *punit =
2888 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2889
2890 if (NULL != punit) {
2892 }
2893
2894 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2895}
2896
2897/***********************************************************************/
2900static void unit_disband_callback(GSimpleAction *action, GVariant *parameter,
2901 gpointer data)
2902{
2903 struct unit_list *punits;
2904 struct unit *punit =
2905 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2906
2907 if (NULL == punit) {
2908 return;
2909 }
2910
2911 punits = unit_list_new();
2912 unit_list_append(punits, punit);
2913 popup_disband_dialog(punits);
2914 unit_list_destroy(punits);
2915
2916 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2917}
2918
2919/***********************************************************************/
2923static void unit_homecity_callback(GSimpleAction *action, GVariant *parameter,
2924 gpointer data)
2925{
2926 struct unit *punit =
2927 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2928
2929 if (NULL != punit) {
2931 }
2932
2933 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2934}
2935
2936/***********************************************************************/
2939static void unit_upgrade_callback(GSimpleAction *action, GVariant *parameter,
2940 gpointer data)
2941{
2942 struct unit_list *punits;
2943 struct unit *punit =
2944 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2945
2946 if (NULL == punit) {
2947 return;
2948 }
2949
2950 punits = unit_list_new();
2951 unit_list_append(punits, punit);
2952 popup_upgrade_dialog(punits);
2953 unit_list_destroy(punits);
2954
2955 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2956}
2957
2958/******** Callbacks for citizen bar, map funcs that are not update ********/
2959
2960/***********************************************************************/
2964static gboolean citizens_callback(GtkGestureClick *gesture, int n_press,
2965 double x, double y, gpointer data)
2966{
2967 struct city_dialog *pdialog = data;
2968 struct city *pcity = pdialog->pcity;
2969 int citnum, tlen, len;
2970
2971 if (!can_client_issue_orders()) {
2972 return FALSE;
2973 }
2974
2976 len = (city_size_get(pcity) - 1) * pdialog->cwidth + tlen;
2977
2978 if (x > len) {
2979 /* no citizen that far to the right */
2980 return FALSE;
2981 }
2982 citnum = MIN(city_size_get(pcity) - 1, x / pdialog->cwidth);
2983
2984 city_rotate_specialist(pcity, citnum);
2985
2986 return TRUE;
2987}
2988
2989/***********************************************************************/
2992static void set_city_workertask(GtkWidget *w, gpointer data)
2993{
2994 enum unit_activity act = (enum unit_activity)GPOINTER_TO_INT(data);
2995 struct city *pcity = workertask_req.owner;
2996 struct tile *ptile = workertask_req.loc;
2997 struct packet_worker_task task;
2998
2999 task.city_id32 = pcity->id;
3000 task.city_id16 = task.city_id32;
3001
3002 if (act == ACTIVITY_LAST) {
3003 task.tgt = -1;
3004 task.want = 0;
3005 } else {
3006 enum extra_cause cause = activity_to_extra_cause(act);
3007 enum extra_rmcause rmcause = activity_to_extra_rmcause(act);
3008 struct extra_type *tgt;
3009
3010 if (cause != EC_NONE) {
3011 tgt = next_extra_for_tile(ptile, cause, city_owner(pcity), NULL);
3012 } else if (rmcause != ERM_NONE) {
3013 tgt = prev_extra_in_tile(ptile, rmcause, city_owner(pcity), NULL);
3014 } else {
3015 tgt = NULL;
3016 }
3017
3018 if (tgt == NULL) {
3019 struct terrain *pterr = tile_terrain(ptile);
3020
3021 if ((act != ACTIVITY_TRANSFORM
3022 || pterr->transform_result == NULL || pterr->transform_result == pterr)
3023 && (act != ACTIVITY_CULTIVATE || pterr->cultivate_result == NULL)
3024 && (act != ACTIVITY_PLANT || pterr->plant_result == NULL)) {
3025 /* No extra to order */
3026 output_window_append(ftc_client, _("There's no suitable extra to order."));
3027
3028 return;
3029 }
3030
3031 task.tgt = -1;
3032 } else {
3033 task.tgt = extra_index(tgt);
3034 }
3035
3036 task.want = 100;
3037 }
3038
3039 task.tile_id = ptile->index;
3040 task.activity = act;
3041
3043}
3044
3045/***********************************************************************/
3048static void workertask_dlg_destroy(GtkWidget *w, gpointer data)
3049{
3051}
3052
3053/***********************************************************************/
3056static void popup_workertask_dlg(struct city *pcity, struct tile *ptile)
3057{
3059 GtkWidget *shl;
3060 struct terrain *pterr = tile_terrain(ptile);
3061 struct universal for_terr = { .kind = VUT_TERRAIN,
3062 .value = { .terrain = pterr }};
3063 struct worker_task *ptask;
3064
3066 workertask_req.owner = pcity;
3067 workertask_req.loc = ptile;
3068
3069 shl = choice_dialog_start(GTK_WINDOW(toplevel),
3070 _("What Action to Request"),
3071 _("Select autosettler activity:"));
3072
3073 ptask = worker_task_list_get(pcity->task_reqs, 0);
3074 if (ptask != NULL) {
3075 choice_dialog_add(shl, _("Clear request"),
3076 G_CALLBACK(set_city_workertask),
3077 GINT_TO_POINTER(ACTIVITY_LAST), FALSE, NULL);
3078 }
3079
3080 if (action_id_univs_not_blocking(ACTION_MINE, NULL, &for_terr)) {
3081 choice_dialog_add(shl, Q_("?act:Mine"),
3082 G_CALLBACK(set_city_workertask),
3083 GINT_TO_POINTER(ACTIVITY_MINE), FALSE, NULL);
3084 }
3085 if (pterr->plant_result != NULL
3086 && action_id_univs_not_blocking(ACTION_PLANT,
3087 NULL, &for_terr)) {
3088 choice_dialog_add(shl, _("Plant"),
3089 G_CALLBACK(set_city_workertask),
3090 GINT_TO_POINTER(ACTIVITY_PLANT), FALSE, NULL);
3091 }
3092 if (action_id_univs_not_blocking(ACTION_IRRIGATE, NULL, &for_terr)) {
3093 choice_dialog_add(shl, _("Irrigate"),
3094 G_CALLBACK(set_city_workertask),
3095 GINT_TO_POINTER(ACTIVITY_IRRIGATE), FALSE, NULL);
3096 }
3097 if (pterr->cultivate_result != NULL
3098 && action_id_univs_not_blocking(ACTION_CULTIVATE,
3099 NULL, &for_terr)) {
3100 choice_dialog_add(shl, _("Cultivate"),
3101 G_CALLBACK(set_city_workertask),
3102 GINT_TO_POINTER(ACTIVITY_CULTIVATE), FALSE, NULL);
3103 }
3104 if (next_extra_for_tile(ptile, EC_ROAD, city_owner(pcity), NULL) != NULL) {
3105 choice_dialog_add(shl, _("Road"),
3106 G_CALLBACK(set_city_workertask),
3107 GINT_TO_POINTER(ACTIVITY_GEN_ROAD), FALSE, NULL);
3108 }
3109 if (pterr->transform_result != pterr && pterr->transform_result != NULL
3110 && action_id_univs_not_blocking(ACTION_TRANSFORM_TERRAIN,
3111 NULL, &for_terr)) {
3112 choice_dialog_add(shl, _("Transform"),
3113 G_CALLBACK(set_city_workertask),
3114 GINT_TO_POINTER(ACTIVITY_TRANSFORM), FALSE, NULL);
3115 }
3116 if (prev_extra_in_tile(ptile, ERM_CLEANPOLLUTION,
3117 city_owner(pcity), NULL) != NULL) {
3118 choice_dialog_add(shl, _("Clean Pollution"),
3119 G_CALLBACK(set_city_workertask),
3120 GINT_TO_POINTER(ACTIVITY_POLLUTION), FALSE, NULL);
3121 }
3122 if (prev_extra_in_tile(ptile, ERM_CLEANFALLOUT,
3123 city_owner(pcity), NULL) != NULL) {
3124 choice_dialog_add(shl, _("Clean Fallout"),
3125 G_CALLBACK(set_city_workertask),
3126 GINT_TO_POINTER(ACTIVITY_FALLOUT), FALSE, NULL);
3127 }
3128
3129 choice_dialog_add(shl, _("_Cancel"), 0, 0, FALSE, NULL);
3130 choice_dialog_end(shl);
3131
3132 g_signal_connect(shl, "destroy", G_CALLBACK(workertask_dlg_destroy),
3133 NULL);
3134 }
3135}
3136
3137/***********************************************************************/
3140static gboolean left_button_down_citymap(GtkGestureClick *gesture, int n_press,
3141 double x, double y, gpointer data)
3142{
3143 struct city_dialog *pdialog = data;
3144 int canvas_x, canvas_y, city_x, city_y;
3145
3146 if (!can_client_issue_orders()) {
3147 return FALSE;
3148 }
3149
3150 if (cma_is_city_under_agent(pdialog->pcity, NULL)) {
3151 return FALSE;
3152 }
3153
3154 canvas_x = x * (double)canvas_width / (double)CITYMAP_WIDTH;
3155 canvas_y = y * (double)canvas_height / (double)CITYMAP_HEIGHT;
3156
3157 if (canvas_to_city_pos(&city_x, &city_y,
3158 city_map_radius_sq_get(pdialog->pcity),
3159 canvas_x, canvas_y)) {
3160 city_toggle_worker(pdialog->pcity, city_x, city_y);
3161 }
3162
3163 return TRUE;
3164}
3165
3166/***********************************************************************/
3169static gboolean right_button_down_citymap(GtkGestureClick *gesture, int n_press,
3170 double x, double y, gpointer data)
3171{
3172 struct city_dialog *pdialog = data;
3173 int canvas_x, canvas_y, city_x, city_y;
3174
3175 if (!can_client_issue_orders()) {
3176 return FALSE;
3177 }
3178
3179 canvas_x = x * (double)canvas_width / (double)CITYMAP_WIDTH;
3180 canvas_y = y * (double)canvas_height / (double)CITYMAP_HEIGHT;
3181
3182 if (canvas_to_city_pos(&city_x, &city_y,
3183 city_map_radius_sq_get(pdialog->pcity),
3184 canvas_x, canvas_y)) {
3185 struct city *pcity = pdialog->pcity;
3186
3187 popup_workertask_dlg(pdialog->pcity,
3188 city_map_to_tile(&(wld.map), pcity->tile,
3190 city_x, city_y));
3191 }
3192
3193 return TRUE;
3194}
3195
3196/***********************************************************************/
3199static void draw_map_canvas(struct city_dialog *pdialog)
3200{
3201 gtk_widget_queue_draw(pdialog->overview.map_canvas.darea);
3202 if (pdialog->happiness.map_canvas.darea) { /* in case of spy */
3203 gtk_widget_queue_draw(pdialog->happiness.map_canvas.darea);
3204 }
3205}
3206
3207/************** Callbacks for Buy, Change, Sell, Worklist *****************/
3208
3209/***********************************************************************/
3212static void buy_callback_response(GtkWidget *w, gint response, gpointer data)
3213{
3214 struct city_dialog *pdialog = data;
3215
3216 if (response == GTK_RESPONSE_YES) {
3217 city_buy_production(pdialog->pcity);
3218 }
3219
3220 gtk_window_destroy(GTK_WINDOW(w));
3221}
3222
3223/***********************************************************************/
3226static void buy_callback(GtkWidget *w, gpointer data)
3227{
3228 GtkWidget *shell;
3229 struct city_dialog *pdialog = data;
3230 const char *name = city_production_name_translation(pdialog->pcity);
3231 int value = pdialog->pcity->client.buy_cost;
3232 char buf[1024];
3233
3234 if (!can_client_issue_orders()) {
3235 return;
3236 }
3237
3238 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
3239 "Treasury contains %d gold.",
3240 client_player()->economic.gold),
3241 client_player()->economic.gold);
3242
3243 if (value <= client_player()->economic.gold) {
3244 shell = gtk_message_dialog_new(NULL,
3245 GTK_DIALOG_DESTROY_WITH_PARENT,
3246 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
3247 /* TRANS: Last %s is pre-pluralised "Treasury contains %d gold." */
3248 PL_("Buy %s for %d gold?\n%s",
3249 "Buy %s for %d gold?\n%s", value),
3250 name, value, buf);
3251 setup_dialog(shell, pdialog->shell);
3252 gtk_window_set_title(GTK_WINDOW(shell), _("Buy It!"));
3253 gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_NO);
3254 g_signal_connect(shell, "response", G_CALLBACK(buy_callback_response),
3255 pdialog);
3256 gtk_window_present(GTK_WINDOW(shell));
3257 } else {
3258 shell = gtk_message_dialog_new(NULL,
3259 GTK_DIALOG_DESTROY_WITH_PARENT,
3260 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
3261 /* TRANS: Last %s is pre-pluralised "Treasury contains %d gold." */
3262 PL_("%s costs %d gold.\n%s",
3263 "%s costs %d gold.\n%s", value),
3264 name, value, buf);
3265 setup_dialog(shell, pdialog->shell);
3266 gtk_window_set_title(GTK_WINDOW(shell), _("Buy It!"));
3267 g_signal_connect(shell, "response", G_CALLBACK(gtk_window_destroy),
3268 NULL);
3269 gtk_window_present(GTK_WINDOW(shell));
3270 }
3271}
3272
3273/***********************************************************************/
3276static void change_production_callback(GtkComboBox *combo,
3277 struct city_dialog *pdialog)
3278{
3279 GtkTreeIter iter;
3280
3282 && gtk_combo_box_get_active_iter(combo, &iter)) {
3283 cid id;
3284 struct universal univ;
3285
3286 gtk_tree_model_get(gtk_combo_box_get_model(combo), &iter, 2, &id, -1);
3287 univ = cid_production(id);
3288 city_change_production(pdialog->pcity, &univ);
3289 }
3290}
3291
3292/***********************************************************************/
3295static void sell_callback(struct impr_type *pimprove, gpointer data)
3296{
3297 GtkWidget *shl;
3298 struct city_dialog *pdialog = (struct city_dialog *) data;
3299 pdialog->sell_id = improvement_number(pimprove);
3300 int price;
3301
3302 if (!can_client_issue_orders()) {
3303 return;
3304 }
3305
3307 pimprove) != TR_SUCCESS) {
3308 return;
3309 }
3310
3311 price = impr_sell_gold(pimprove);
3312 shl = gtk_message_dialog_new(NULL,
3313 GTK_DIALOG_DESTROY_WITH_PARENT,
3314 GTK_MESSAGE_QUESTION,
3315 GTK_BUTTONS_YES_NO,
3316 PL_("Sell %s for %d gold?",
3317 "Sell %s for %d gold?", price),
3318 city_improvement_name_translation(pdialog->pcity, pimprove), price);
3319 setup_dialog(shl, pdialog->shell);
3320 pdialog->sell_shell = shl;
3321
3322 gtk_window_set_title(GTK_WINDOW(shl), _("Sell It!"));
3323
3324 g_signal_connect(shl, "response",
3325 G_CALLBACK(sell_callback_response), pdialog);
3326
3327 gtk_window_present(GTK_WINDOW(shl));
3328}
3329
3330/***********************************************************************/
3333static void sell_callback_response(GtkWidget *w, gint response, gpointer data)
3334{
3335 struct city_dialog *pdialog = data;
3336
3337 if (response == GTK_RESPONSE_YES) {
3338 city_sell_improvement(pdialog->pcity, pdialog->sell_id);
3339 }
3340 gtk_window_destroy(GTK_WINDOW(w));
3341
3342 pdialog->sell_shell = NULL;
3343}
3344
3345/***********************************************************************/
3348static void impr_callback(GtkTreeView *view, GtkTreePath *path,
3349 GtkTreeViewColumn *col, gpointer data)
3350{
3351 GtkTreeModel *model;
3352 GtkTreeIter it;
3353 GdkSeat *seat;
3354 GdkModifierType mask;
3355 struct impr_type *pimprove;
3356
3357 model = gtk_tree_view_get_model(view);
3358
3359 if (!gtk_tree_model_get_iter(model, &it, path)) {
3360 return;
3361 }
3362
3363 gtk_tree_model_get(model, &it, 0, &pimprove, -1);
3364
3365 seat = gdk_display_get_default_seat(gtk_widget_get_display(GTK_WIDGET(view)));
3366 mask = gdk_device_get_modifier_state(gdk_seat_get_keyboard(seat));
3367
3368 if (!(mask & GDK_CONTROL_MASK)) {
3369 sell_callback(pimprove, data);
3370 } else {
3371 if (is_great_wonder(pimprove)) {
3373 } else {
3375 }
3376 }
3377}
3378
3379/************ Callbacks for stuff on the Misc. Settings page **************/
3380
3381/***********************************************************************/
3384static void rename_callback(GtkWidget *w, gpointer data)
3385{
3386 struct city_dialog *pdialog;
3387
3388 pdialog = (struct city_dialog *) data;
3389
3390 pdialog->rename_shell = input_dialog_create(GTK_WINDOW(pdialog->shell),
3391 /* "shellrenamecity" */
3392 _("Rename City"),
3393 _("What should we rename the city to?"),
3394 city_name_get(pdialog->pcity),
3395 rename_popup_callback, pdialog);
3396}
3397
3398/***********************************************************************/
3401static void rename_popup_callback(gpointer data, gint response,
3402 const char *input)
3403{
3404 struct city_dialog *pdialog = data;
3405
3406 if (pdialog) {
3407 if (response == GTK_RESPONSE_OK) {
3408 city_rename(pdialog->pcity, input);
3409 } /* else CANCEL or DELETE_EVENT */
3410
3411 pdialog->rename_shell = NULL;
3412 }
3413}
3414
3415/***********************************************************************/
3418static void misc_whichtab_callback(GtkWidget *w, gpointer data)
3419{
3420 new_dialog_def_page = GPOINTER_TO_INT(data);
3421}
3422
3423/***********************************************************************/
3426static void cityopt_callback(GtkWidget *w, gpointer data)
3427{
3428 struct city_dialog *pdialog = (struct city_dialog *) data;
3429
3430 if (!can_client_issue_orders()) {
3431 return;
3432 }
3433
3434 if (!pdialog->misc.block_signal) {
3435 struct city *pcity = pdialog->pcity;
3436 bv_city_options new_options;
3437
3438 fc_assert(CITYO_LAST == 3);
3439
3440 BV_CLR_ALL(new_options);
3441 if (gtk_check_button_get_active(GTK_CHECK_BUTTON(pdialog->misc.disband_on_settler))) {
3442 BV_SET(new_options, CITYO_DISBAND);
3443 }
3444 if (gtk_check_button_get_active(GTK_CHECK_BUTTON(pdialog->misc.new_citizens_radio[1]))) {
3445 BV_SET(new_options, CITYO_SCIENCE_SPECIALISTS);
3446 }
3447 if (gtk_check_button_get_active(GTK_CHECK_BUTTON(pdialog->misc.new_citizens_radio[2]))) {
3448 BV_SET(new_options, CITYO_GOLD_SPECIALISTS);
3449 }
3450
3451 dsend_packet_city_options_req(&client.conn, pcity->id, pcity->id, new_options);
3452 }
3453}
3454
3455/***********************************************************************/
3459static void set_cityopt_values(struct city_dialog *pdialog)
3460{
3461 struct city *pcity = pdialog->pcity;
3462
3463 pdialog->misc.block_signal = 1;
3464
3465 gtk_check_button_set_active(GTK_CHECK_BUTTON(pdialog->misc.disband_on_settler),
3466 is_city_option_set(pcity, CITYO_DISBAND));
3467
3468 if (is_city_option_set(pcity, CITYO_SCIENCE_SPECIALISTS)) {
3469 gtk_check_button_set_active(GTK_CHECK_BUTTON
3470 (pdialog->misc.new_citizens_radio[1]), TRUE);
3471 } else if (is_city_option_set(pcity, CITYO_GOLD_SPECIALISTS)) {
3472 gtk_check_button_set_active(GTK_CHECK_BUTTON
3473 (pdialog->misc.new_citizens_radio[2]), TRUE);
3474 } else {
3475 gtk_check_button_set_active(GTK_CHECK_BUTTON
3476 (pdialog->misc.new_citizens_radio[0]), TRUE);
3477 }
3478 pdialog->misc.block_signal = 0;
3479}
3480
3481/******************** Callbacks for: Close, Prev, Next. *******************/
3482
3483/***********************************************************************/
3486static void close_callback(GtkWidget *w, gpointer data)
3487{
3488 close_city_dialog((struct city_dialog *) data);
3489}
3490
3491/***********************************************************************/
3494static void city_destroy_callback(GtkWidget *w, gpointer data)
3495{
3496 struct city_dialog *pdialog;
3497
3498 pdialog = (struct city_dialog *) data;
3499
3500 gtk_widget_hide(pdialog->shell);
3501
3503 citizens_dialog_close(pdialog->pcity);
3504 }
3505 close_happiness_dialog(pdialog->pcity);
3506 close_cma_dialog(pdialog->pcity);
3507
3508 /* Save size of the city dialog. */
3509 GUI_GTK_OPTION(citydlg_xsize)
3511 gtk_widget_get_allocated_width(pdialog->shell),
3513 GUI_GTK_OPTION(citydlg_ysize)
3515 gtk_widget_get_allocated_height(pdialog->shell),
3517
3518 last_page
3519 = gtk_notebook_get_current_page(GTK_NOTEBOOK(pdialog->notebook));
3520
3522 dialog_list_remove(dialog_list, pdialog);
3523
3524 unit_node_vector_free(&pdialog->overview.supported_units);
3525 unit_node_vector_free(&pdialog->overview.present_units);
3526
3527 if (pdialog->sell_shell) {
3528 gtk_window_destroy(GTK_WINDOW(pdialog->sell_shell));
3529 }
3530 if (pdialog->rename_shell) {
3531 gtk_window_destroy(GTK_WINDOW(pdialog->rename_shell));
3532 }
3533
3534 cairo_surface_destroy(pdialog->map_canvas_store_unscaled);
3535 cairo_surface_destroy(pdialog->citizen_surface);
3536
3537 free(pdialog);
3538
3539 /* Need to do this every time a new dialog is closed. */
3541}
3542
3543/***********************************************************************/
3546static void close_city_dialog(struct city_dialog *pdialog)
3547{
3548 gtk_window_destroy(GTK_WINDOW(pdialog->shell));
3549}
3550
3551/***********************************************************************/
3555static void switch_city_callback(GtkWidget *w, gpointer data)
3556{
3557 struct city_dialog *pdialog = (struct city_dialog *) data;
3558 int i, j, dir, size;
3559 struct city *new_pcity = NULL;
3560
3562 return;
3563 }
3564
3565 size = city_list_size(client.conn.playing->cities);
3566
3568 fc_assert_ret(size >= 1);
3570
3571 if (size == 1) {
3572 return;
3573 }
3574
3575 /* dir = 1 will advance to the city, dir = -1 will get previous */
3576 if (w == GTK_WIDGET(pdialog->next_command)) {
3577 dir = 1;
3578 } else if (w == GTK_WIDGET(pdialog->prev_command)) {
3579 dir = -1;
3580 } else {
3581 /* Always fails. */
3582 fc_assert_ret(w == GTK_WIDGET(pdialog->next_command)
3583 || w == GTK_WIDGET(pdialog->prev_command));
3584 dir = 1;
3585 }
3586
3587 for (i = 0; i < size; i++) {
3588 if (pdialog->pcity == city_list_get(client.conn.playing->cities, i)) {
3589 break;
3590 }
3591 }
3592
3593 fc_assert_ret(i < size);
3594
3595 for (j = 1; j < size; j++) {
3596 struct city *other_pcity = city_list_get(client.conn.playing->cities,
3597 (i + dir * j + size) % size);
3598 struct city_dialog *other_pdialog = get_city_dialog(other_pcity);
3599
3600 fc_assert_ret(other_pdialog != pdialog);
3601 if (!other_pdialog) {
3602 new_pcity = other_pcity;
3603 break;
3604 }
3605 }
3606
3607 if (!new_pcity) {
3608 /* Every other city has an open city dialog. */
3609 return;
3610 }
3611
3612 /* cleanup happiness dialog */
3614 citizens_dialog_close(pdialog->pcity);
3615 }
3616 close_happiness_dialog(pdialog->pcity);
3617
3618 pdialog->pcity = new_pcity;
3619
3620 /* reinitialize happiness, and cma dialogs */
3622 gtk_box_append(GTK_BOX(pdialog->happiness.citizens),
3623 citizens_dialog_display(pdialog->pcity));
3624 }
3625 gtk_box_append(GTK_BOX(pdialog->happiness.widget),
3626 get_top_happiness_display(pdialog->pcity, low_citydlg, pdialog->shell));
3627 if (!client_is_observer()) {
3628 fc_assert(pdialog->cma_editor != NULL);
3629 pdialog->cma_editor->pcity = new_pcity;
3630 }
3631
3632 reset_city_worklist(pdialog->production.worklist, pdialog->pcity);
3633
3634 can_slide = FALSE;
3635 center_tile_mapcanvas(pdialog->pcity->tile);
3636 can_slide = TRUE;
3637 if (!client_is_observer()) {
3638 set_cityopt_values(pdialog); /* Need not be in real_city_dialog_refresh */
3639 }
3640
3642
3643 /* Recenter the city map(s) */
3645 if (pdialog->happiness.map_canvas.sw) {
3647 }
3648}
3649
3650/***********************************************************************/
3654{
3656 refresh_worklist(pdialog->production.worklist);
3658}
const char * action_id_name_translation(action_id act_id)
Definition actions.c:1910
bool action_ever_possible(action_id action)
Definition actions.c:9305
#define action_id_univs_not_blocking(act_id, act_uni, tgt_uni)
Definition actions.h:962
#define n
Definition astring.c:77
#define BV_CLR_ALL(bv)
Definition bitvector.h:95
#define BV_SET(bv, bit)
Definition bitvector.h:81
struct canvas int int struct sprite int int int int height
Definition canvas_g.h:44
struct canvas int int canvas_y
Definition canvas_g.h:43
struct canvas int canvas_x
Definition canvas_g.h:43
struct canvas int int struct sprite int int int width
Definition canvas_g.h:44
void output_window_append(const struct ft_color color, const char *featured_text)
const char * city_improvement_name_translation(const struct city *pcity, const struct impr_type *pimprove)
Definition city.c:658
int city_production_build_shield_cost(const struct city *pcity)
Definition city.c:722
int city_granary_size(int city_size)
Definition city.c:2104
int city_build_slots(const struct city *pcity)
Definition city.c:2834
struct tile * city_map_to_tile(const struct civ_map *nmap, const struct tile *city_center, int city_radius_sq, int city_map_x, int city_map_y)
Definition city.c:300
const char * city_name_get(const struct city *pcity)
Definition city.c:1115
int city_improvement_upkeep(const struct city *pcity, const struct impr_type *b)
Definition city.c:1231
bool is_city_option_set(const struct city *pcity, enum city_options option)
Definition city.c:3301
int city_population(const struct city *pcity)
Definition city.c:1169
int city_unit_unhappiness(const struct civ_map *nmap, struct unit *punit, int *free_unhappy)
Definition city.c:2943
bool city_unhappy(const struct city *pcity)
Definition city.c:1599
bool city_celebrating(const struct city *pcity)
Definition city.c:1618
int city_illness_calc(const struct city *pcity, int *ill_base, int *ill_size, int *ill_trade, int *ill_pollution)
Definition city.c:2772
bool city_happy(const struct city *pcity)
Definition city.c:1587
int city_map_radius_sq_get(const struct city *pcity)
Definition city.c:132
citizens city_specialists(const struct city *pcity)
Definition city.c:3230
bool can_city_build_now(const struct civ_map *nmap, const struct city *pcity, const struct universal *target)
Definition city.c:991
int city_turns_to_grow(const struct city *pcity)
Definition city.c:1969
const char * city_production_name_translation(const struct city *pcity)
Definition city.c:695
static citizens city_size_get(const struct city *pcity)
Definition city.h:549
citizen_category
Definition city.h:259
#define city_owner(_pcity_)
Definition city.h:543
#define MAX_CITY_SIZE
Definition city.h:98
@ FEELING_FINAL
Definition city.h:276
void get_city_dialog_output_text(const struct city *pcity, Output_type_id otype, char *buf, size_t bufsz)
void get_city_dialog_production(struct city *pcity, char *buffer, size_t buffer_len)
int city_rename(struct city *pcity, const char *name)
int get_city_citizen_types(struct city *pcity, enum citizen_feeling idx, enum citizen_category *categories)
int city_buy_production(struct city *pcity)
int city_toggle_worker(struct city *pcity, int city_x, int city_y)
void get_city_dialog_airlift_text(const struct city *pcity, char *buf, size_t bufsz)
int city_change_production(struct city *pcity, struct universal *target)
void city_rotate_specialist(struct city *pcity, int citizen_index)
int get_citydlg_canvas_width(void)
bool canvas_to_city_pos(int *city_x, int *city_y, int city_radius_sq, int canvas_x, int canvas_y)
void get_city_dialog_airlift_value(const struct city *pcity, char *buf, size_t bufsz)
void city_dialog_redraw_map(struct city *pcity, struct canvas *pcanvas)
int city_sell_improvement(struct city *pcity, Impr_type_id sell_id)
void get_city_dialog_pollution_text(const struct city *pcity, char *buf, size_t bufsz)
void get_city_dialog_culture_text(const struct city *pcity, char *buf, size_t bufsz)
bool city_can_buy(const struct city *pcity)
int get_citydlg_canvas_height(void)
void get_city_dialog_illness_text(const struct city *pcity, char *buf, size_t bufsz)
void city_report_dialog_update_city(struct city *pcity)
bool client_is_global_observer(void)
bool client_is_observer(void)
struct civclient client
bool can_client_issue_orders(void)
bool client_has_player(void)
#define client_player()
int collect_eventually_buildable_targets(struct universal *targets, struct city *pcity, bool advanced_tech)
Definition climisc.c:812
void name_and_sort_items(struct universal *targets, int num_targets, struct item *items, bool show_cost, struct city *pcity)
Definition climisc.c:643
cid cid_encode(struct universal target)
Definition climisc.c:476
int collect_already_built_targets(struct universal *targets, struct city *pcity)
Definition climisc.c:906
#define MAX_NUM_PRODUCTION_TARGETS
Definition climisc.h:89
#define cid_production
Definition climisc.h:71
int cid
Definition climisc.h:31
bool cma_is_city_under_agent(const struct city *pcity, struct cm_parameter *parameter)
Definition cma_core.c:551
void request_unit_fortify(struct unit *punit)
Definition control.c:2240
void unit_focus_set(struct unit *punit)
Definition control.c:507
void request_unit_change_homecity(struct unit *punit)
Definition control.c:2021
void request_unit_unload(struct unit *pcargo)
Definition control.c:2119
void request_unit_sentry(struct unit *punit)
Definition control.c:2229
#define can_unit_do_activity_client(_punit_, _act_)
Definition control.h:40
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 cost
Definition dialogs_g.h:73
int int id
Definition editgui_g.h:28
static struct editor_state * editor
Definition editor.c:100
int get_city_bonus(const struct city *pcity, enum effect_type effect_type)
Definition effects.c:789
struct extra_type * next_extra_for_tile(const struct tile *ptile, enum extra_cause cause, const struct player *pplayer, const struct unit *punit)
Definition extras.c:740
struct extra_type * prev_extra_in_tile(const struct tile *ptile, enum extra_rmcause rmcause, const struct player *pplayer, const struct unit *punit)
Definition extras.c:765
enum extra_cause activity_to_extra_cause(enum unit_activity act)
Definition extras.c:1028
enum extra_rmcause activity_to_extra_rmcause(enum unit_activity act)
Definition extras.c:1049
#define extra_index(_e_)
Definition extras.h:177
int Impr_type_id
Definition fc_types.h:346
#define EC_NONE
Definition fc_types.h:967
@ TR_SUCCESS
Definition fc_types.h:1098
#define ERM_NONE
Definition fc_types.h:992
@ O_SHIELD
Definition fc_types.h:91
@ O_FOOD
Definition fc_types.h:91
@ O_TRADE
Definition fc_types.h:91
@ O_SCIENCE
Definition fc_types.h:91
@ O_LUXURY
Definition fc_types.h:91
@ O_GOLD
Definition fc_types.h:91
#define Q_(String)
Definition fcintl.h:70
#define PL_(String1, String2, n)
Definition fcintl.h:71
#define _(String)
Definition fcintl.h:67
#define N_(String)
Definition fcintl.h:69
const struct ft_color ftc_client
const char * population_to_text(int thousand_citizen)
Definition game.c:714
struct civ_game game
Definition game.c:57
struct world wld
Definition game.c:58
struct city * game_city_by_number(int id)
Definition game.c:102
#define FC_STATIC_CANVAS_INIT
Definition canvas.h:27
GtkWidget * choice_dialog_start(GtkWindow *parent, const gchar *name, const gchar *text)
void choice_dialog_end(GtkWidget *dshell)
void choice_dialog_add(GtkWidget *dshell, const gchar *label, GCallback handler, gpointer data, bool meta, const gchar *tool_tip)
GtkWidget * citizens_dialog_display(const struct city *pcity)
void citizens_dialog_refresh(const struct city *pcity)
void citizens_dialog_close(const struct city *pcity)
static void unit_sentry_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2758
citydlg_response
Definition citydlg.c:81
@ CDLGR_UNITS
Definition citydlg.c:81
@ CDLGR_PREV
Definition citydlg.c:81
@ CDLGR_NEXT
Definition citydlg.c:81
static int new_dialog_def_page
Definition citydlg.c:212
static void create_and_append_buildings_page(struct city_dialog *pdialog)
Definition citydlg.c:1193
static void unit_upgrade_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2817
static void popup_workertask_dlg(struct city *pcity, struct tile *ptile)
Definition citydlg.c:2929
static void city_dialog_update_citizens(struct city_dialog *pdialog)
Definition citydlg.c:1735
static void city_destroy_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:3348
static void city_dialog_update_title(struct city_dialog *pdialog)
Definition citydlg.c:1696
static int last_page
Definition citydlg.c:213
static void init_citydlg_dimensions(void)
Definition citydlg.c:324
static void create_and_append_worklist_page(struct city_dialog *pdialog)
Definition citydlg.c:1227
struct tile * loc
Definition citydlg.c:220
#define CITY_MAP_MIN_SIZE_X
Definition citydlg.c:127
void real_city_dialog_popup(struct city *pcity)
Definition citydlg.c:558
static void misc_whichtab_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:3273
static bool low_citydlg
Definition citydlg.c:223
bool city_dialog_is_open(struct city *pcity)
Definition citydlg.c:579
static void city_dialog_update_building(struct city_dialog *pdialog)
Definition citydlg.c:1926
static void citydlg_response_callback(GtkDialog *dlg, gint response, void *data)
Definition citydlg.c:2355
static void buy_callback_response(GtkWidget *w, gint response, gpointer data)
Definition citydlg.c:3063
void real_city_dialog_refresh(struct city *pcity)
Definition citydlg.c:481
static void unit_center_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2657
static struct city_dialog * get_city_dialog(struct city *pcity)
Definition citydlg.c:379
#define CITY_MAP_MIN_SIZE_Y
Definition citydlg.c:128
static void city_dialog_update_information(GtkWidget **info_ebox, GtkWidget **info_label, struct city_dialog *pdialog)
Definition citydlg.c:1798
static GtkWidget * create_citydlg_improvement_list(struct city_dialog *pdialog, GtkWidget *vbox)
Definition citydlg.c:852
static void create_production_header(struct city_dialog *pdialog, GtkContainer *contain)
Definition citydlg.c:1160
static void workertask_dlg_destroy(GtkWidget *w, gpointer data)
Definition citydlg.c:2921
static void city_dialog_update_present_units(struct city_dialog *pdialog)
Definition citydlg.c:2212
#define CITYMAP_SCALE
Definition citydlg.c:75
static gboolean citizens_callback(GtkWidget *w, GdkEventButton *ev, gpointer data)
Definition citydlg.c:2838
static void change_production_callback(GtkComboBox *combo, struct city_dialog *pdialog)
Definition citydlg.c:3126
static void unit_load_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2732
static void set_cityopt_values(struct city_dialog *pdialog)
Definition citydlg.c:3314
static void close_city_dialog(struct city_dialog *pdialog)
Definition citydlg.c:3403
static gboolean show_info_popup(GtkWidget *w, GdkEventButton *ev, gpointer data)
Definition citydlg.c:653
static void create_and_append_overview_page(struct city_dialog *pdialog)
Definition citydlg.c:911
static void create_and_append_happiness_page(struct city_dialog *pdialog)
Definition citydlg.c:1271
void popdown_all_city_dialogs(void)
Definition citydlg.c:599
static void buy_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:3076
#define dialog_list_iterate_end
Definition citydlg.c:92
static void impr_callback(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data)
Definition citydlg.c:3199
static void create_and_append_map_page(struct city_dialog *pdialog)
Definition citydlg.c:1099
static void city_dialog_map_create(struct city_dialog *pdialog, struct city_map_canvas *cmap_canvas)
Definition citydlg.c:415
void refresh_unit_city_dialogs(struct unit *punit)
Definition citydlg.c:538
void reset_city_dialogs(void)
Definition citydlg.c:357
static void cityopt_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:3281
static void city_dialog_map_recenter(GtkWidget *map_canvas_sw)
Definition citydlg.c:454
static void draw_map_canvas(struct city_dialog *pdialog)
Definition citydlg.c:3051
static bool is_showing_workertask_dialog
Definition citydlg.c:215
#define unit_node_vector_iterate_end
Definition citydlg.c:107
static void sell_callback(struct impr_type *pimprove, gpointer data)
Definition citydlg.c:3145
#define dialog_list_iterate(dialoglist, pdialog)
Definition citydlg.c:90
static void supported_unit_activate_close_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2684
static void city_dialog_update_prev_next(void)
Definition citydlg.c:2319
static void create_and_append_settings_page(struct city_dialog *pdialog)
Definition citydlg.c:1364
static bool city_dialogs_have_been_initialised
Definition citydlg.c:210
static void close_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:3340
static struct dialog_list * dialog_list
Definition citydlg.c:209
static void sell_callback_response(GtkWidget *w, gint response, gpointer data)
Definition citydlg.c:3184
static void create_citydlg_main_map(struct city_dialog *pdialog, GtkWidget *container)
Definition citydlg.c:835
#define NUM_CITIZENS_SHOWN
Definition citydlg.c:109
#define CITYMAP_HEIGHT
Definition citydlg.c:74
static void unit_homecity_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2804
static void unit_fortify_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2771
static gboolean present_unit_callback(GtkWidget *w, GdkEventButton *ev, gpointer data)
Definition citydlg.c:2480
struct city * owner
Definition citydlg.c:219
static GtkWidget * create_city_info_table(struct city_dialog *pdialog, GtkWidget **info_ebox, GtkWidget **info_label)
Definition citydlg.c:737
static struct city_dialog * create_city_dialog(struct city *pcity)
Definition citydlg.c:1508
static void target_drag_data_received(GtkWidget *w, GdkDragContext *context, gint x, gint y, GtkSelectionData *data, guint info, guint time, gpointer user_data)
Definition citydlg.c:1122
static void unit_disband_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2784
#define unit_node_vector_iterate(list, elt)
Definition citydlg.c:105
@ INFO_LUXURY
Definition citydlg.c:119
@ INFO_STEAL
Definition citydlg.c:121
@ INFO_CORRUPTION
Definition citydlg.c:120
@ NUM_INFO_FIELDS
Definition citydlg.c:122
@ INFO_ILLNESS
Definition citydlg.c:121
@ INFO_WASTE
Definition citydlg.c:120
@ INFO_SIZE
Definition citydlg.c:118
@ INFO_GROWTH
Definition citydlg.c:119
@ INFO_SHIELD
Definition citydlg.c:118
@ INFO_CULTURE
Definition citydlg.c:120
@ INFO_GOLD
Definition citydlg.c:118
@ INFO_SCIENCE
Definition citydlg.c:119
@ INFO_POLLUTION
Definition citydlg.c:120
@ INFO_TRADE
Definition citydlg.c:118
@ INFO_AIRLIFT
Definition citydlg.c:121
@ INFO_GRANARY
Definition citydlg.c:119
@ INFO_FOOD
Definition citydlg.c:118
static void rename_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:3239
static void switch_city_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:3412
#define CITYMAP_WIDTH
Definition citydlg.c:73
static void city_dialog_update_map(struct city_dialog *pdialog)
Definition citydlg.c:1904
static void unit_unload_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2745
static void show_units_response(void *data)
Definition citydlg.c:2368
static void initialize_city_dialogs(void)
Definition citydlg.c:333
static int canvas_height
Definition citydlg.c:211
static int canvas_width
Definition citydlg.c:211
#define TINYSCREEN_MAX_HEIGHT
Definition citydlg.c:77
static void city_dialog_update_supported_units(struct city_dialog *pdialog)
Definition citydlg.c:2105
static void unit_activate_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2670
static void present_unit_activate_close_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2709
static void set_city_workertask(GtkWidget *w, gpointer data)
Definition citydlg.c:2865
static void rename_popup_callback(gpointer data, gint response, const char *input)
Definition citydlg.c:3256
@ WORKLIST_PAGE
Definition citydlg.c:111
@ CMA_PAGE
Definition citydlg.c:111
@ HAPPINESS_PAGE
Definition citydlg.c:111
@ SETTINGS_PAGE
Definition citydlg.c:112
@ STICKY_PAGE
Definition citydlg.c:112
@ NUM_PAGES
Definition citydlg.c:113
@ OVERVIEW_PAGE
Definition citydlg.c:111
static void city_dialog_update_improvement_list(struct city_dialog *pdialog)
Definition citydlg.c:2048
static void create_and_append_cma_page(struct city_dialog *pdialog)
Definition citydlg.c:1344
void popdown_city_dialog(struct city *pcity)
Definition citydlg.c:587
static struct @139 workertask_req
static gboolean supported_unit_callback(GtkWidget *w, GdkEventButton *ev, gpointer data)
Definition citydlg.c:2416
void close_cma_dialog(struct city *pcity)
Definition cma_fe.c:104
struct cma_dialog * create_cma_dialog(struct city *pcity, bool tiny)
Definition cma_fe.c:214
void refresh_cma_dialog(struct city *pcity, enum cma_refresh refresh)
Definition cma_fe.c:472
@ REFRESH_ALL
Definition cma_fe.h:26
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 popup_disband_dialog(struct unit_list *punits)
Definition dialogs.c:1482
GtkWidget * toplevel
Definition gui_main.c:124
GtkWidget * map_canvas
Definition gui_main.c:106
int screen_height(void)
Definition gui_main.c:2376
#define GUI_GTK_OPTION(optname)
Definition gui_main.h:25
void setup_dialog(GtkWidget *shell, GtkWidget *parent)
Definition gui_stuff.c:281
void intl_slist(int n, const char **s, bool *done)
Definition gui_stuff.c:105
void close_happiness_dialog(struct city *pcity)
Definition happiness.c:330
void refresh_happiness_dialog(struct city *pcity)
Definition happiness.c:317
GtkWidget * get_top_happiness_display(struct city *pcity, bool low_dlg, GtkWidget *win)
Definition happiness.c:356
void popup_help_dialog_typed(const char *item, enum help_page_type htype)
Definition helpdlg.c:195
GtkWidget * input_dialog_create(GtkWindow *parent, const char *dialogname, const char *text, const char *postinputtest, input_dialog_callback_t response_callback, gpointer response_cli_data)
Definition inputdlg.c:66
static struct gui_dialog * shell
Definition messagedlg.c:39
GdkPixbuf * sprite_get_pixbuf(struct sprite *sprite)
Definition sprite.c:402
bool request_transport(struct unit *cargo, struct tile *ptile)
void refresh_worklist(GtkWidget *editor)
Definition wldlg.c:1329
void add_worklist_dnd_target(GtkWidget *w)
Definition wldlg.c:337
void reset_city_worklist(GtkWidget *editor, struct city *pcity)
Definition wldlg.c:1281
GtkWidget * create_worklist(void)
Definition wldlg.c:1054
GtkWidget * icon_label_button_new(const gchar *icon_name, const gchar *label_text)
Definition gui_stuff.c:76
void refresh_all_city_worklists(void)
Definition citydlg.c:3653
static void canvas_draw_cb(GtkDrawingArea *w, cairo_t *cr, int width, int height, gpointer data)
Definition citydlg.c:413
static gboolean right_button_down_citymap(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data)
Definition citydlg.c:3169
static gboolean middle_present_unit_release(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data)
Definition citydlg.c:2672
static bool create_unit_menu(struct city_dialog *pdialog, struct unit *punit, GtkWidget *wdg, bool supported)
Definition citydlg.c:2473
static gboolean right_unit_release(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data)
Definition citydlg.c:2718
static gboolean left_button_down_citymap(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data)
Definition citydlg.c:3140
static void close_citydlg_unit_popover(struct city_dialog *pdialog)
Definition citydlg.c:2737
static gboolean middle_supported_unit_release(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data)
Definition citydlg.c:2696
static gboolean citydlg_keyboard_handler(GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, gpointer data)
Definition citydlg.c:630
#define menu_item_append_unref(menu, item)
Definition gui_stuff.h:149
void put_unit_picture_city_overlays(struct unit *punit, GtkPicture *p, int height, int *upkeep_cost, int happy_cost)
Definition mapview.c:517
void put_unit_picture(struct unit *punit, GtkPicture *p, int height)
Definition mapview.c:492
void picture_set_from_surface(GtkPicture *pic, cairo_surface_t *surf)
Definition sprite.c:544
@ HELP_IMPROVEMENT
Definition helpdlg_g.h:20
@ HELP_WONDER
Definition helpdlg_g.h:21
int impr_sell_gold(const struct impr_type *pimprove)
enum test_result test_player_sell_building_now(struct player *pplayer, struct city *pcity, const struct impr_type *pimprove)
bool is_improvement_redundant(const struct city *pcity, const struct impr_type *pimprove)
Impr_type_id improvement_number(const struct impr_type *pimprove)
bool is_great_wonder(const struct impr_type *pimprove)
const char * improvement_name_translation(const struct impr_type *pimprove)
bool is_small_wonder(const struct impr_type *pimprove)
const char * name
Definition inputfile.c:127
#define fc_assert_ret(condition)
Definition log.h:191
#define fc_assert(condition)
Definition log.h:176
#define fc_assert_action(condition, action)
Definition log.h:187
#define log_debug(message,...)
Definition log.h:115
void center_tile_mapcanvas(const struct tile *ptile)
bool can_slide
#define fc_malloc(sz)
Definition mem.h:34
bool can_unit_exist_at_tile(const struct civ_map *nmap, const struct unit *punit, const struct tile *ptile)
Definition movement.c:304
bool unit_can_load(const struct unit *punit)
Definition movement.c:841
#define GUI_GTK4_CITYDLG_MAX_XSIZE
Definition options.h:614
#define GUI_GTK4_CITYDLG_MIN_XSIZE
Definition options.h:613
int send_packet_worker_task(struct connection *pc, const struct packet_worker_task *packet)
int dsend_packet_city_options_req(struct connection *pc, int city_id16, int city_id32, bv_city_options options)
int len
Definition packhand.c:125
struct unit * player_unit_by_number(const struct player *pplayer, int unit_id)
Definition player.c:1205
struct city * player_city_by_number(const struct player *pplayer, int city_id)
Definition player.c:1179
void economy_report_dialog_update(void)
bool are_universals_equal(const struct universal *psource1, const struct universal *psource2)
#define CLIP(lower, current, upper)
Definition shared.h:57
#define ARRAY_SIZE(x)
Definition shared.h:85
#define MIN(x, y)
Definition shared.h:55
#define FC_INFINITY
Definition shared.h:36
size_t size
Definition specvec.h:72
cairo_surface_t * surface
Definition canvas.h:22
GtkWidget * prev_command
Definition citydlg.c:202
GtkWidget * name_label
Definition citydlg.c:140
GtkWidget * rename_shell
Definition citydlg.c:199
GtkWidget * rename_command
Definition citydlg.c:190
GtkWidget * production_bar
Definition citydlg.c:151
GtkWidget * supported_units_frame
Definition citydlg.c:156
GtkWidget * citizen_pics
Definition citydlg.c:147
GtkWidget * sell_shell
Definition citydlg.c:197
GtkWidget * production_label
Definition citydlg.c:172
struct city_dialog::@143 misc
GtkWidget * widget
Definition citydlg.c:181
GtkWidget * supported_unit_table
Definition citydlg.c:157
GtkWidget * popover
Definition citydlg.c:146
GtkWidget * disband_on_settler
Definition citydlg.c:192
enum city_dialog::@211 page
struct city_map_canvas map_canvas
Definition citydlg.c:149
GtkWidget * improvement_list
Definition citydlg.c:154
GtkWidget * buy_command
Definition citydlg.c:153
short block_signal
Definition citydlg.c:194
GtkWidget * whichtab_radio[NUM_PAGES]
Definition citydlg.c:193
struct unit_node_vector supported_units
Definition citydlg.c:162
cairo_surface_t * map_canvas_store_unscaled
Definition citydlg.c:141
struct city * pcity
Definition citydlg.c:137
struct unit_node_vector present_units
Definition citydlg.c:163
struct city_dialog::@142 happiness
city_map * view
Definition citydlg.h:450
struct city_dialog::@141 production
GtkWidget * citizens
Definition citydlg.c:184
GtkWidget * show_units_command
Definition citydlg.c:201
Impr_type_id sell_id
Definition citydlg.c:204
GtkWidget * production_combo
Definition citydlg.c:152
struct city_dialog::@140 overview
struct cma_dialog * cma_editor
Definition citydlg.c:187
cairo_surface_t * citizen_surface
Definition citydlg.c:146
GtkWidget * shell
Definition citydlg.c:139
GtkWidget * worklist
Definition citydlg.c:175
GtkWidget * present_units_frame
Definition citydlg.c:159
GtkWidget * info_label[NUM_INFO_FIELDS]
Definition citydlg.c:166
GtkWidget * new_citizens_radio[3]
Definition citydlg.c:191
GtkListStore * change_production_store
Definition citydlg.c:168
GtkWidget * present_unit_table
Definition citydlg.c:160
GtkWidget * notebook
Definition citydlg.c:142
GtkWidget * next_command
Definition citydlg.c:202
GtkTreeSelection * change_selection
Definition citydlg.c:198
GtkWidget * darea
Definition citydlg.c:133
GtkWidget * sw
Definition citydlg.c:131
Definition city.h:309
struct worker_task_list * task_reqs
Definition city.h:395
int surplus[O_LAST]
Definition city.h:343
int food_stock
Definition city.h:354
int pollution
Definition city.h:356
int id
Definition city.h:315
int waste[O_LAST]
Definition city.h:344
struct unit_list * info_units_present
Definition city.h:457
struct player * owner
Definition city.h:312
struct unit_list * info_units_supported
Definition city.h:456
struct worklist worklist
Definition city.h:387
struct universal production
Definition city.h:382
int steal
Definition city.h:397
citizens size
Definition city.h:320
int illness
Definition city.h:417
int culture
Definition city.h:448
int buy_cost
Definition city.h:449
struct tile * tile
Definition city.h:311
int shield_stock
Definition city.h:355
int prod[O_LAST]
Definition city.h:346
struct unit_list * units_supported
Definition city.h:391
struct city::@17::@20 client
struct packet_game_info info
Definition game.h:89
struct connection conn
Definition client_main.h:96
GtkWidget * shell
Definition cma_fe.h:33
struct city * pcity
Definition cma_fe.h:32
struct player * playing
Definition connection.h:156
Definition climisc.h:82
struct universal item
Definition climisc.h:83
char descr[MAX_LEN_NAME+40]
Definition climisc.h:84
enum unit_activity activity
struct city_list * cities
Definition player.h:281
struct terrain * cultivate_result
Definition terrain.h:203
struct terrain * plant_result
Definition terrain.h:206
struct terrain * transform_result
Definition terrain.h:217
Definition tile.h:49
int index
Definition tile.h:50
struct unit_list * units
Definition tile.h:57
int height
Definition citydlg.c:97
GtkWidget * cmd
Definition citydlg.c:95
GtkWidget * pix
Definition citydlg.c:96
GtkEventController * middle
Definition citydlg.c:99
GtkEventController * left
Definition citydlg.c:98
GtkEventController * right
Definition citydlg.c:100
Definition unit.h:138
int upkeep[O_LAST]
Definition unit.h:148
enum unit_activity activity
Definition unit.h:157
int id
Definition unit.h:145
int homecity
Definition unit.h:146
enum universals_n kind
Definition fc_types.h:758
universals_u value
Definition fc_types.h:757
struct tile * ptile
Definition workertask.h:22
struct civ_map map
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:969
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
const char * unit_description(struct unit *punit)
Definition text.c:508
struct city * tile_city(const struct tile *ptile)
Definition tile.c:83
#define tile_terrain(_tile)
Definition tile.h:109
struct sprite * get_building_sprite(const struct tileset *t, const struct impr_type *pimprove)
Definition tilespec.c:6494
int tileset_small_sprite_width(const struct tileset *t)
Definition tilespec.c:864
struct sprite * get_unittype_sprite(const struct tileset *t, const struct unit_type *punittype, enum direction8 facing)
Definition tilespec.c:6516
int tileset_full_tile_height(const struct tileset *t)
Definition tilespec.c:752
int tileset_small_sprite_height(const struct tileset *t)
Definition tilespec.c:900
int tileset_unit_with_upkeep_height(const struct tileset *t)
Definition tilespec.c:822
struct sprite * get_citizen_sprite(const struct tileset *t, enum citizen_category type, int citizen_index, const struct city *pcity)
Definition tilespec.c:6437
const struct unit_type * utype
Definition fc_types.h:604
const struct impr_type * building
Definition fc_types.h:598
bool can_unit_change_homecity_to(const struct civ_map *nmap, const struct unit *punit, const struct city *pcity)
Definition unit.c:444
struct unit * unit_transport_get(const struct unit *pcargo)
Definition unit.c:2425
bool unit_can_do_action(const struct unit *punit, const action_id act_id)
Definition unit.c:328
bool can_unit_unload(const struct unit *pcargo, const struct unit *ptrans)
Definition unit.c:771
#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
const struct unit_type * unit_type_get(const struct unit *punit)
Definition unittype.c:123
const struct unit_type * can_upgrade_unittype(const struct player *pplayer, const struct unit_type *punittype)
Definition unittype.c:1755
const char * utype_name_translation(const struct unit_type *punittype)
Definition unittype.c:1612
static SDL_Surface * info_label
Definition widget.c:57
bool worklist_is_empty(const struct worklist *pwl)
Definition worklist.c:66