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(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
2160 if (NULL != client.conn.playing
2161 && city_owner(pdialog->pcity) != client.conn.playing) {
2162 units = pdialog->pcity->client.info_units_supported;
2163 } else {
2164 units = pdialog->pcity->units_supported;
2165 }
2166
2167 nodes = &pdialog->overview.supported_units;
2168
2169 n = unit_list_size(units);
2170 m = unit_node_vector_size(nodes);
2171
2172 if (m > n) {
2173 i = 0;
2174 unit_node_vector_iterate(nodes, elt) {
2175 if (i++ >= n) {
2176 gtk_box_remove(GTK_BOX(pdialog->overview.supported_unit_table),
2177 elt->cmd);
2178 }
2180
2181 unit_node_vector_reserve(nodes, n);
2182 } else {
2183 for (i = m; i < n; i++) {
2184 GtkWidget *cmd, *pix;
2185 struct unit_node node;
2186
2187 cmd = gtk_button_new();
2188 node.cmd = cmd;
2189
2190 gtk_button_set_has_frame(GTK_BUTTON(cmd), FALSE);
2191
2192 pix = gtk_picture_new();
2193 node.pix = pix;
2195
2196 gtk_button_set_child(GTK_BUTTON(cmd), pix);
2197
2198 gtk_box_append(GTK_BOX(pdialog->overview.supported_unit_table),
2199 cmd);
2200
2201 node.left = NULL;
2202 node.middle = NULL;
2203 node.right = NULL;
2204
2205 unit_node_vector_append(nodes, node);
2206 }
2207 }
2208
2209 i = 0;
2210 unit_list_iterate(units, punit) {
2211 struct unit_node *pnode;
2212 int happy_cost = city_unit_unhappiness(punit, &free_unhappy);
2213
2214 pnode = unit_node_vector_get(nodes, i);
2215 if (pnode) {
2216 GtkWidget *cmd, *pix;
2217 GtkGesture *gesture;
2218 GtkEventController *controller;
2219
2220 cmd = pnode->cmd;
2221 pix = pnode->pix;
2222
2223 put_unit_picture_city_overlays(punit, GTK_PICTURE(pix), pnode->height,
2224 punit->upkeep, happy_cost);
2225
2226 if (pnode->left != NULL) {
2227 gtk_widget_remove_controller(cmd, pnode->left);
2228 gtk_widget_remove_controller(cmd, pnode->middle);
2229 gtk_widget_remove_controller(cmd, pnode->right);
2230 }
2231
2232 gtk_widget_set_tooltip_text(cmd, unit_description(punit));
2233
2234 controller = GTK_EVENT_CONTROLLER(gtk_gesture_click_new());
2235 g_signal_connect(controller, "pressed",
2236 G_CALLBACK(supported_unit_callback),
2237 GINT_TO_POINTER(punit->id));
2238 gtk_widget_add_controller(cmd, controller);
2239 pnode->left = controller;
2240 gesture = gtk_gesture_click_new();
2241 gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 2);
2242 controller = GTK_EVENT_CONTROLLER(gesture);
2243 g_signal_connect(controller, "released",
2245 GINT_TO_POINTER(punit->id));
2246 gtk_widget_add_controller(cmd, controller);
2247 pnode->middle = controller;
2248 gesture = gtk_gesture_click_new();
2249 gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 3);
2250 controller = GTK_EVENT_CONTROLLER(gesture);
2251 g_signal_connect(controller, "released",
2252 G_CALLBACK(right_unit_release),
2253 GINT_TO_POINTER(punit->id));
2254 gtk_widget_add_controller(cmd, controller);
2255 pnode->right = controller;
2256
2257 if (city_owner(pdialog->pcity) != client.conn.playing) {
2258 gtk_widget_set_sensitive(cmd, FALSE);
2259 } else {
2260 gtk_widget_set_sensitive(cmd, TRUE);
2261 }
2262
2263 gtk_widget_show(pix);
2264 gtk_widget_show(cmd);
2265 }
2266 i++;
2268
2269 buf = g_strdup_printf(_("Supported units %d"), n);
2270 gtk_frame_set_label(GTK_FRAME(pdialog->overview.supported_units_frame), buf);
2271 g_free(buf);
2272}
2273
2274/***********************************************************************/
2278{
2279 struct unit_list *units;
2280 struct unit_node_vector *nodes;
2281 int n, m, i;
2282 gchar *buf;
2283
2284 if (NULL != client.conn.playing
2285 && city_owner(pdialog->pcity) != client.conn.playing) {
2286 units = pdialog->pcity->client.info_units_present;
2287 } else {
2288 units = pdialog->pcity->tile->units;
2289 }
2290
2291 nodes = &pdialog->overview.present_units;
2292
2293 n = unit_list_size(units);
2294 m = unit_node_vector_size(nodes);
2295
2296 if (m > n) {
2297 i = 0;
2298 unit_node_vector_iterate(nodes, elt) {
2299 if (i++ >= n) {
2300 gtk_box_remove(GTK_BOX(pdialog->overview.present_unit_table),
2301 elt->cmd);
2302 }
2304
2305 unit_node_vector_reserve(nodes, n);
2306 } else {
2307 for (i = m; i < n; i++) {
2308 GtkWidget *cmd, *pix;
2309 struct unit_node node;
2310
2311 cmd = gtk_button_new();
2312 node.cmd = cmd;
2313
2314 gtk_button_set_has_frame(GTK_BUTTON(cmd), FALSE);
2315
2316 pix = gtk_picture_new();
2317 node.pix = pix;
2319
2320 gtk_button_set_child(GTK_BUTTON(cmd), pix);
2321
2322 gtk_box_append(GTK_BOX(pdialog->overview.present_unit_table),
2323 cmd);
2324
2325 node.left = NULL;
2326 node.middle = NULL;
2327 node.right = NULL;
2328
2329 unit_node_vector_append(nodes, node);
2330 }
2331 }
2332
2333 i = 0;
2334 unit_list_iterate(units, punit) {
2335 struct unit_node *pnode;
2336
2337 pnode = unit_node_vector_get(nodes, i);
2338 if (pnode) {
2339 GtkWidget *cmd, *pix;
2340 GtkEventController *controller;
2341 GtkGesture *gesture;
2342
2343 cmd = pnode->cmd;
2344 pix = pnode->pix;
2345
2346 put_unit_picture(punit, GTK_PICTURE(pix), pnode->height);
2347
2348 if (pnode->left != NULL) {
2349 gtk_widget_remove_controller(cmd, pnode->left);
2350 gtk_widget_remove_controller(cmd, pnode->middle);
2351 gtk_widget_remove_controller(cmd, pnode->right);
2352 }
2353
2354 gtk_widget_set_tooltip_text(cmd, unit_description(punit));
2355
2356 controller = GTK_EVENT_CONTROLLER(gtk_gesture_click_new());
2357 g_signal_connect(controller, "pressed",
2358 G_CALLBACK(present_unit_callback),
2359 GINT_TO_POINTER(punit->id));
2360 gtk_widget_add_controller(cmd, controller);
2361 pnode->left = controller;
2362 gesture = gtk_gesture_click_new();
2363 gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 2);
2364 controller = GTK_EVENT_CONTROLLER(gesture);
2365 g_signal_connect(controller, "released",
2366 G_CALLBACK(middle_present_unit_release),
2367 GINT_TO_POINTER(punit->id));
2368 gtk_widget_add_controller(cmd, controller);
2369 pnode->middle = controller;
2370 gesture = gtk_gesture_click_new();
2371 gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 3);
2372 controller = GTK_EVENT_CONTROLLER(gesture);
2373 g_signal_connect(controller, "released",
2374 G_CALLBACK(right_unit_release),
2375 GINT_TO_POINTER(punit->id));
2376 gtk_widget_add_controller(cmd, controller);
2377 pnode->right = controller;
2378
2379 if (city_owner(pdialog->pcity) != client.conn.playing) {
2380 gtk_widget_set_sensitive(cmd, FALSE);
2381 } else {
2382 gtk_widget_set_sensitive(cmd, TRUE);
2383 }
2384
2385 gtk_widget_show(pix);
2386 gtk_widget_show(cmd);
2387 }
2388 i++;
2390
2391 buf = g_strdup_printf(_("Present units %d"), n);
2392 gtk_frame_set_label(GTK_FRAME(pdialog->overview.present_units_frame), buf);
2393 g_free(buf);
2394}
2395
2396/***********************************************************************/
2404{
2405 int count = 0;
2406 int city_number;
2407
2408 if (NULL != client.conn.playing) {
2409 city_number = city_list_size(client.conn.playing->cities);
2410 } else {
2411 city_number = FC_INFINITY; /* ? */
2412 }
2413
2414 /* The first time, we see if all the city dialogs are open */
2416 if (city_owner(pdialog->pcity) == client.conn.playing) {
2417 count++;
2418 }
2420
2421 if (count == city_number) { /* All are open, shouldn't prev/next */
2423 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->prev_command), FALSE);
2424 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->next_command), FALSE);
2426 } else {
2428 if (city_owner(pdialog->pcity) == client.conn.playing) {
2429 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->prev_command), TRUE);
2430 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->next_command), TRUE);
2431 }
2433 }
2434}
2435
2436/***********************************************************************/
2439static void citydlg_response_callback(GtkDialog *dlg, gint response,
2440 void *data)
2441{
2442 switch (response) {
2443 case CDLGR_UNITS:
2444 show_units_response(data);
2445 break;
2446 }
2447}
2448
2449/***********************************************************************/
2452static void show_units_response(void *data)
2453{
2454 struct city_dialog *pdialog = (struct city_dialog *) data;
2455 struct tile *ptile = pdialog->pcity->tile;
2456
2457 if (unit_list_size(ptile->units)) {
2459 }
2460}
2461
2462/***********************************************************************/
2472static bool create_unit_menu(struct city_dialog *pdialog, struct unit *punit,
2473 GtkWidget *wdg, bool supported)
2474{
2475 GMenu *menu;
2476 GActionGroup *group;
2477 GSimpleAction *act;
2478
2479 if (!can_client_issue_orders()) {
2480 return FALSE;
2481 }
2482
2483 if (pdialog->popover != NULL) {
2485 }
2486
2487 group = G_ACTION_GROUP(g_simple_action_group_new());
2488 menu = g_menu_new();
2489
2490 if (supported) {
2491 act = g_simple_action_new("center", NULL);
2492 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2493 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2494 g_signal_connect(act, "activate", G_CALLBACK(unit_center_callback),
2495 GINT_TO_POINTER(punit->id));
2496 menu_item_append_unref(menu, g_menu_item_new(_("Cen_ter"), "win.center"));
2497 }
2498
2499 act = g_simple_action_new("activate", NULL);
2500 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2501 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2502 g_signal_connect(act, "activate", G_CALLBACK(unit_activate_callback),
2503 GINT_TO_POINTER(punit->id));
2504 menu_item_append_unref(menu, g_menu_item_new(_("_Activate unit"),
2505 "win.activate"));
2506
2507 act = g_simple_action_new("activate_close", NULL);
2508 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2509 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2510
2511 if (supported) {
2512 g_signal_connect(act, "activate",
2514 GINT_TO_POINTER(punit->id));
2515 } else {
2516 g_signal_connect(act, "activate",
2518 GINT_TO_POINTER(punit->id));
2519 }
2520
2522 g_menu_item_new(_("Activate unit, _close dialog"),
2523 "win.activate_close"));
2524
2525 if (!supported) {
2526 act = g_simple_action_new("load", NULL);
2527 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2528 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2529 g_signal_connect(act, "activate", G_CALLBACK(unit_load_callback),
2530 GINT_TO_POINTER(punit->id));
2531 g_simple_action_set_enabled(G_SIMPLE_ACTION(act), unit_can_load(punit));
2532 menu_item_append_unref(menu, g_menu_item_new(_("_Load unit"), "win.load"));
2533
2534 act = g_simple_action_new("unload", NULL);
2535 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2536 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2537 g_signal_connect(act, "activate", G_CALLBACK(unit_unload_callback),
2538 GINT_TO_POINTER(punit->id));
2539 g_simple_action_set_enabled(G_SIMPLE_ACTION(act),
2543 unit_tile(punit)));
2544 menu_item_append_unref(menu, g_menu_item_new(_("_Unload unit"),
2545 "win.unload"));
2546
2547 act = g_simple_action_new("sentry", NULL);
2548 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2549 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2550 g_signal_connect(act, "activate", G_CALLBACK(unit_sentry_callback),
2551 GINT_TO_POINTER(punit->id));
2552 g_simple_action_set_enabled(G_SIMPLE_ACTION(act),
2553 punit->activity != ACTIVITY_SENTRY
2555 ACTIVITY_SENTRY));
2556 menu_item_append_unref(menu, g_menu_item_new(_("_Sentry unit"),
2557 "win.sentry"));
2558
2559 act = g_simple_action_new("fortify", NULL);
2560 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2561 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2562 g_signal_connect(act, "activate", G_CALLBACK(unit_fortify_callback),
2563 GINT_TO_POINTER(punit->id));
2564 g_simple_action_set_enabled(G_SIMPLE_ACTION(act),
2565 punit->activity != ACTIVITY_FORTIFYING
2567 ACTIVITY_FORTIFYING));
2568 menu_item_append_unref(menu, g_menu_item_new(_("_Fortify unit"),
2569 "win.fortify"));
2570 }
2571
2572 act = g_simple_action_new("disband", NULL);
2573 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2574 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2575 g_signal_connect(act, "activate", G_CALLBACK(unit_disband_callback),
2576 GINT_TO_POINTER(punit->id));
2577 g_simple_action_set_enabled(G_SIMPLE_ACTION(act),
2578 unit_can_do_action(punit, ACTION_DISBAND_UNIT));
2579 menu_item_append_unref(menu, g_menu_item_new(_("_Disband unit"),
2580 "win.disband"));
2581
2582 if (!supported) {
2583 act = g_simple_action_new("rehome", NULL);
2584 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2585 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2586 g_signal_connect(act, "activate", G_CALLBACK(unit_homecity_callback),
2587 GINT_TO_POINTER(punit->id));
2588 g_simple_action_set_enabled(G_SIMPLE_ACTION(act),
2590 pdialog->pcity));
2592 g_menu_item_new(action_id_name_translation(ACTION_HOME_CITY),
2593 "win.rehome"));
2594
2595 act = g_simple_action_new("upgrade", NULL);
2596 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2597 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2598 g_signal_connect(act, "activate", G_CALLBACK(unit_upgrade_callback),
2599 GINT_TO_POINTER(punit->id));
2600 g_simple_action_set_enabled(G_SIMPLE_ACTION(act),
2601 action_ever_possible(ACTION_UPGRADE_UNIT)
2605 != NULL);
2606 menu_item_append_unref(menu, g_menu_item_new(_("U_pgrade unit"),
2607 "win.upgrade"));
2608 }
2609
2610 pdialog->popover = gtk_popover_menu_new_from_model(G_MENU_MODEL(menu));
2611 g_object_ref(pdialog->popover);
2612 gtk_widget_insert_action_group(pdialog->popover, "win", group);
2613 gtk_widget_set_parent(pdialog->popover, wdg);
2614
2615
2616 gtk_popover_popup(GTK_POPOVER(pdialog->popover));
2617
2618 return TRUE;
2619}
2620
2621/***********************************************************************/
2624static gboolean supported_unit_callback(GtkGestureClick *gesture, int n_press,
2625 double x, double y, gpointer data)
2626{
2627 struct city_dialog *pdialog;
2628 struct city *pcity;
2629 struct unit *punit =
2630 player_unit_by_number(client_player(), (size_t) data);
2631
2632 if (NULL != punit
2633 && NULL != (pcity = game_city_by_number(punit->homecity))
2634 && NULL != (pdialog = get_city_dialog(pcity))) {
2635
2636 return create_unit_menu(pdialog, punit,
2637 gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)),
2638 TRUE);
2639 }
2640
2641 return TRUE;
2642}
2643
2644/***********************************************************************/
2647static gboolean present_unit_callback(GtkGestureClick *gesture, int n_press,
2648 double x, double y, gpointer data)
2649{
2650 struct city_dialog *pdialog;
2651 struct city *pcity;
2652 struct unit *punit =
2653 player_unit_by_number(client_player(), (size_t) data);
2654
2655 if (NULL != punit
2656 && NULL != (pcity = tile_city(unit_tile(punit)))
2657 && NULL != (pdialog = get_city_dialog(pcity))) {
2658
2659 return create_unit_menu(pdialog, punit,
2660 gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)),
2661 FALSE);
2662 }
2663
2664 return TRUE;
2665}
2666
2667/***********************************************************************/
2671static gboolean middle_present_unit_release(GtkGestureClick *gesture,
2672 int n_press, double x, double y,
2673 gpointer data)
2674{
2675 struct city_dialog *pdialog;
2676 struct city *pcity;
2677 struct unit *punit =
2678 player_unit_by_number(client_player(), (size_t) data);
2679
2680 if (NULL != punit
2681 && NULL != (pcity = tile_city(unit_tile(punit)))
2682 && NULL != (pdialog = get_city_dialog(pcity))
2685 close_city_dialog(pdialog);
2686 }
2687
2688 return TRUE;
2689}
2690
2691/***********************************************************************/
2695static gboolean middle_supported_unit_release(GtkGestureClick *gesture, int n_press,
2696 double x, double y, gpointer data)
2697{
2698 struct city_dialog *pdialog;
2699 struct city *pcity;
2700 struct unit *punit =
2701 player_unit_by_number(client_player(), (size_t) data);
2702
2703 if (NULL != punit
2704 && NULL != (pcity = game_city_by_number(punit->homecity))
2705 && NULL != (pdialog = get_city_dialog(pcity))
2708 close_city_dialog(pdialog);
2709 }
2710
2711 return TRUE;
2712}
2713
2714/***********************************************************************/
2717static gboolean right_unit_release(GtkGestureClick *gesture, int n_press,
2718 double x, double y, gpointer data)
2719{
2720 struct unit *punit =
2721 player_unit_by_number(client_player(), (size_t) data);
2722
2723 if (NULL != punit
2726 }
2727
2728 return TRUE;
2729}
2730
2731/***********************************************************************/
2736static void close_citydlg_unit_popover(struct city_dialog *pdialog)
2737{
2738 if (pdialog->popover != NULL) {
2739 gtk_widget_unparent(pdialog->popover);
2740 g_object_unref(pdialog->popover);
2741 pdialog->popover = NULL;
2742 }
2743}
2744
2745/***********************************************************************/
2748static void unit_center_callback(GSimpleAction *action, GVariant *parameter,
2749 gpointer data)
2750{
2751 struct unit *punit =
2752 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2753
2754 if (NULL != punit) {
2756 }
2757
2758 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2759}
2760
2761/***********************************************************************/
2764static void unit_activate_callback(GSimpleAction *action, GVariant *parameter,
2765 gpointer data)
2766{
2767 struct unit *punit =
2768 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2769
2770 if (NULL != punit) {
2772 }
2773
2774 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2775}
2776
2777/***********************************************************************/
2782 GVariant *parameter,
2783 gpointer data)
2784{
2785 struct unit *punit =
2786 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2787
2788 if (NULL != punit) {
2789 struct city *pcity =
2791
2793 if (NULL != pcity) {
2794 struct city_dialog *pdialog = get_city_dialog(pcity);
2795
2796 if (NULL != pdialog) {
2797 close_city_dialog(pdialog);
2798 }
2799 }
2800 }
2801
2802 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2803}
2804
2805/***********************************************************************/
2810 GVariant *parameter,
2811 gpointer data)
2812{
2813 struct unit *punit =
2814 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2815
2816 if (NULL != punit) {
2817 struct city *pcity = tile_city(unit_tile(punit));
2818
2820 if (NULL != pcity) {
2821 struct city_dialog *pdialog = get_city_dialog(pcity);
2822
2823 if (NULL != pdialog) {
2824 close_city_dialog(pdialog);
2825 }
2826 }
2827 }
2828
2829 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2830}
2831
2832/***********************************************************************/
2835static void unit_load_callback(GSimpleAction *action, GVariant *parameter,
2836 gpointer data)
2837{
2838 struct unit *punit =
2839 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2840
2841 if (NULL != punit) {
2843 }
2844
2845 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2846}
2847
2848/***********************************************************************/
2851static void unit_unload_callback(GSimpleAction *action, GVariant *parameter,
2852 gpointer data)
2853{
2854 struct unit *punit =
2855 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2856
2857 if (NULL != punit) {
2859 }
2860
2861 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2862}
2863
2864/***********************************************************************/
2867static void unit_sentry_callback(GSimpleAction *action, GVariant *parameter,
2868 gpointer data)
2869{
2870 struct unit *punit =
2871 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2872
2873 if (NULL != punit) {
2875 }
2876
2877 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2878}
2879
2880/***********************************************************************/
2883static void unit_fortify_callback(GSimpleAction *action, GVariant *parameter,
2884 gpointer data)
2885{
2886 struct unit *punit =
2887 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2888
2889 if (NULL != punit) {
2891 }
2892
2893 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2894}
2895
2896/***********************************************************************/
2899static void unit_disband_callback(GSimpleAction *action, GVariant *parameter,
2900 gpointer data)
2901{
2902 struct unit_list *punits;
2903 struct unit *punit =
2904 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2905
2906 if (NULL == punit) {
2907 return;
2908 }
2909
2910 punits = unit_list_new();
2911 unit_list_append(punits, punit);
2912 popup_disband_dialog(punits);
2913 unit_list_destroy(punits);
2914
2915 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2916}
2917
2918/***********************************************************************/
2922static void unit_homecity_callback(GSimpleAction *action, GVariant *parameter,
2923 gpointer data)
2924{
2925 struct unit *punit =
2926 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2927
2928 if (NULL != punit) {
2930 }
2931
2932 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2933}
2934
2935/***********************************************************************/
2938static void unit_upgrade_callback(GSimpleAction *action, GVariant *parameter,
2939 gpointer data)
2940{
2941 struct unit_list *punits;
2942 struct unit *punit =
2943 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2944
2945 if (NULL == punit) {
2946 return;
2947 }
2948
2949 punits = unit_list_new();
2950 unit_list_append(punits, punit);
2951 popup_upgrade_dialog(punits);
2952 unit_list_destroy(punits);
2953
2954 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2955}
2956
2957/******** Callbacks for citizen bar, map funcs that are not update ********/
2958
2959/***********************************************************************/
2963static gboolean citizens_callback(GtkGestureClick *gesture, int n_press,
2964 double x, double y, gpointer data)
2965{
2966 struct city_dialog *pdialog = data;
2967 struct city *pcity = pdialog->pcity;
2968 int citnum, tlen, len;
2969
2970 if (!can_client_issue_orders()) {
2971 return FALSE;
2972 }
2973
2975 len = (city_size_get(pcity) - 1) * pdialog->cwidth + tlen;
2976
2977 if (x > len) {
2978 /* no citizen that far to the right */
2979 return FALSE;
2980 }
2981 citnum = MIN(city_size_get(pcity) - 1, x / pdialog->cwidth);
2982
2983 city_rotate_specialist(pcity, citnum);
2984
2985 return TRUE;
2986}
2987
2988/***********************************************************************/
2991static void set_city_workertask(GtkWidget *w, gpointer data)
2992{
2993 enum unit_activity act = (enum unit_activity)GPOINTER_TO_INT(data);
2994 struct city *pcity = workertask_req.owner;
2995 struct tile *ptile = workertask_req.loc;
2996 struct packet_worker_task task;
2997
2998 task.city_id32 = pcity->id;
2999 task.city_id16 = task.city_id32;
3000
3001 if (act == ACTIVITY_LAST) {
3002 task.tgt = -1;
3003 task.want = 0;
3004 } else {
3005 enum extra_cause cause = activity_to_extra_cause(act);
3006 enum extra_rmcause rmcause = activity_to_extra_rmcause(act);
3007 struct extra_type *tgt;
3008
3009 if (cause != EC_NONE) {
3010 tgt = next_extra_for_tile(ptile, cause, city_owner(pcity), NULL);
3011 } else if (rmcause != ERM_NONE) {
3012 tgt = prev_extra_in_tile(ptile, rmcause, city_owner(pcity), NULL);
3013 } else {
3014 tgt = NULL;
3015 }
3016
3017 if (tgt == NULL) {
3018 struct terrain *pterr = tile_terrain(ptile);
3019
3020 if ((act != ACTIVITY_TRANSFORM
3021 || pterr->transform_result == NULL || pterr->transform_result == pterr)
3022 && (act != ACTIVITY_CULTIVATE || pterr->cultivate_result == NULL)
3023 && (act != ACTIVITY_PLANT || pterr->plant_result == NULL)) {
3024 /* No extra to order */
3025 output_window_append(ftc_client, _("There's no suitable extra to order."));
3026
3027 return;
3028 }
3029
3030 task.tgt = -1;
3031 } else {
3032 task.tgt = extra_index(tgt);
3033 }
3034
3035 task.want = 100;
3036 }
3037
3038 task.tile_id = ptile->index;
3039 task.activity = act;
3040
3042}
3043
3044/***********************************************************************/
3047static void workertask_dlg_destroy(GtkWidget *w, gpointer data)
3048{
3050}
3051
3052/***********************************************************************/
3055static void popup_workertask_dlg(struct city *pcity, struct tile *ptile)
3056{
3058 GtkWidget *shl;
3059 struct terrain *pterr = tile_terrain(ptile);
3060 struct universal for_terr = { .kind = VUT_TERRAIN,
3061 .value = { .terrain = pterr }};
3062 struct worker_task *ptask;
3063
3065 workertask_req.owner = pcity;
3066 workertask_req.loc = ptile;
3067
3068 shl = choice_dialog_start(GTK_WINDOW(toplevel),
3069 _("What Action to Request"),
3070 _("Select autosettler activity:"));
3071
3072 ptask = worker_task_list_get(pcity->task_reqs, 0);
3073 if (ptask != NULL) {
3074 choice_dialog_add(shl, _("Clear request"),
3075 G_CALLBACK(set_city_workertask),
3076 GINT_TO_POINTER(ACTIVITY_LAST), FALSE, NULL);
3077 }
3078
3079 if (action_id_univs_not_blocking(ACTION_MINE, NULL, &for_terr)) {
3080 choice_dialog_add(shl, Q_("?act:Mine"),
3081 G_CALLBACK(set_city_workertask),
3082 GINT_TO_POINTER(ACTIVITY_MINE), FALSE, NULL);
3083 }
3084 if (pterr->plant_result != NULL
3085 && action_id_univs_not_blocking(ACTION_PLANT,
3086 NULL, &for_terr)) {
3087 choice_dialog_add(shl, _("Plant"),
3088 G_CALLBACK(set_city_workertask),
3089 GINT_TO_POINTER(ACTIVITY_PLANT), FALSE, NULL);
3090 }
3091 if (action_id_univs_not_blocking(ACTION_IRRIGATE, NULL, &for_terr)) {
3092 choice_dialog_add(shl, _("Irrigate"),
3093 G_CALLBACK(set_city_workertask),
3094 GINT_TO_POINTER(ACTIVITY_IRRIGATE), FALSE, NULL);
3095 }
3096 if (pterr->cultivate_result != NULL
3097 && action_id_univs_not_blocking(ACTION_CULTIVATE,
3098 NULL, &for_terr)) {
3099 choice_dialog_add(shl, _("Cultivate"),
3100 G_CALLBACK(set_city_workertask),
3101 GINT_TO_POINTER(ACTIVITY_CULTIVATE), FALSE, NULL);
3102 }
3103 if (next_extra_for_tile(ptile, EC_ROAD, city_owner(pcity), NULL) != NULL) {
3104 choice_dialog_add(shl, _("Road"),
3105 G_CALLBACK(set_city_workertask),
3106 GINT_TO_POINTER(ACTIVITY_GEN_ROAD), FALSE, NULL);
3107 }
3108 if (pterr->transform_result != pterr && pterr->transform_result != NULL
3109 && action_id_univs_not_blocking(ACTION_TRANSFORM_TERRAIN,
3110 NULL, &for_terr)) {
3111 choice_dialog_add(shl, _("Transform"),
3112 G_CALLBACK(set_city_workertask),
3113 GINT_TO_POINTER(ACTIVITY_TRANSFORM), FALSE, NULL);
3114 }
3115 if (prev_extra_in_tile(ptile, ERM_CLEANPOLLUTION,
3116 city_owner(pcity), NULL) != NULL) {
3117 choice_dialog_add(shl, _("Clean Pollution"),
3118 G_CALLBACK(set_city_workertask),
3119 GINT_TO_POINTER(ACTIVITY_POLLUTION), FALSE, NULL);
3120 }
3121 if (prev_extra_in_tile(ptile, ERM_CLEANFALLOUT,
3122 city_owner(pcity), NULL) != NULL) {
3123 choice_dialog_add(shl, _("Clean Fallout"),
3124 G_CALLBACK(set_city_workertask),
3125 GINT_TO_POINTER(ACTIVITY_FALLOUT), FALSE, NULL);
3126 }
3127
3128 choice_dialog_add(shl, _("_Cancel"), 0, 0, FALSE, NULL);
3129 choice_dialog_end(shl);
3130
3131 g_signal_connect(shl, "destroy", G_CALLBACK(workertask_dlg_destroy),
3132 NULL);
3133 }
3134}
3135
3136/***********************************************************************/
3139static gboolean left_button_down_citymap(GtkGestureClick *gesture, int n_press,
3140 double x, double y, gpointer data)
3141{
3142 struct city_dialog *pdialog = data;
3143 int canvas_x, canvas_y, city_x, city_y;
3144
3145 if (!can_client_issue_orders()) {
3146 return FALSE;
3147 }
3148
3149 if (cma_is_city_under_agent(pdialog->pcity, NULL)) {
3150 return FALSE;
3151 }
3152
3153 canvas_x = x * (double)canvas_width / (double)CITYMAP_WIDTH;
3154 canvas_y = y * (double)canvas_height / (double)CITYMAP_HEIGHT;
3155
3156 if (canvas_to_city_pos(&city_x, &city_y,
3157 city_map_radius_sq_get(pdialog->pcity),
3158 canvas_x, canvas_y)) {
3159 city_toggle_worker(pdialog->pcity, city_x, city_y);
3160 }
3161
3162 return TRUE;
3163}
3164
3165/***********************************************************************/
3168static gboolean right_button_down_citymap(GtkGestureClick *gesture, int n_press,
3169 double x, double y, gpointer data)
3170{
3171 struct city_dialog *pdialog = data;
3172 int canvas_x, canvas_y, city_x, city_y;
3173
3174 if (!can_client_issue_orders()) {
3175 return FALSE;
3176 }
3177
3178 canvas_x = x * (double)canvas_width / (double)CITYMAP_WIDTH;
3179 canvas_y = y * (double)canvas_height / (double)CITYMAP_HEIGHT;
3180
3181 if (canvas_to_city_pos(&city_x, &city_y,
3182 city_map_radius_sq_get(pdialog->pcity),
3183 canvas_x, canvas_y)) {
3184 struct city *pcity = pdialog->pcity;
3185
3186 popup_workertask_dlg(pdialog->pcity,
3187 city_map_to_tile(&(wld.map), pcity->tile,
3189 city_x, city_y));
3190 }
3191
3192 return TRUE;
3193}
3194
3195/***********************************************************************/
3198static void draw_map_canvas(struct city_dialog *pdialog)
3199{
3200 gtk_widget_queue_draw(pdialog->overview.map_canvas.darea);
3201 if (pdialog->happiness.map_canvas.darea) { /* in case of spy */
3202 gtk_widget_queue_draw(pdialog->happiness.map_canvas.darea);
3203 }
3204}
3205
3206/************** Callbacks for Buy, Change, Sell, Worklist *****************/
3207
3208/***********************************************************************/
3211static void buy_callback_response(GtkWidget *w, gint response, gpointer data)
3212{
3213 struct city_dialog *pdialog = data;
3214
3215 if (response == GTK_RESPONSE_YES) {
3216 city_buy_production(pdialog->pcity);
3217 }
3218
3219 gtk_window_destroy(GTK_WINDOW(w));
3220}
3221
3222/***********************************************************************/
3225static void buy_callback(GtkWidget *w, gpointer data)
3226{
3227 GtkWidget *shell;
3228 struct city_dialog *pdialog = data;
3229 const char *name = city_production_name_translation(pdialog->pcity);
3230 int value = pdialog->pcity->client.buy_cost;
3231 char buf[1024];
3232
3233 if (!can_client_issue_orders()) {
3234 return;
3235 }
3236
3237 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
3238 "Treasury contains %d gold.",
3239 client_player()->economic.gold),
3240 client_player()->economic.gold);
3241
3242 if (value <= client_player()->economic.gold) {
3243 shell = gtk_message_dialog_new(NULL,
3244 GTK_DIALOG_DESTROY_WITH_PARENT,
3245 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
3246 /* TRANS: Last %s is pre-pluralised "Treasury contains %d gold." */
3247 PL_("Buy %s for %d gold?\n%s",
3248 "Buy %s for %d gold?\n%s", value),
3249 name, value, buf);
3250 setup_dialog(shell, pdialog->shell);
3251 gtk_window_set_title(GTK_WINDOW(shell), _("Buy It!"));
3252 gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_NO);
3253 g_signal_connect(shell, "response", G_CALLBACK(buy_callback_response),
3254 pdialog);
3255 gtk_window_present(GTK_WINDOW(shell));
3256 } else {
3257 shell = gtk_message_dialog_new(NULL,
3258 GTK_DIALOG_DESTROY_WITH_PARENT,
3259 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
3260 /* TRANS: Last %s is pre-pluralised "Treasury contains %d gold." */
3261 PL_("%s costs %d gold.\n%s",
3262 "%s costs %d gold.\n%s", value),
3263 name, value, buf);
3264 setup_dialog(shell, pdialog->shell);
3265 gtk_window_set_title(GTK_WINDOW(shell), _("Buy It!"));
3266 g_signal_connect(shell, "response", G_CALLBACK(gtk_window_destroy),
3267 NULL);
3268 gtk_window_present(GTK_WINDOW(shell));
3269 }
3270}
3271
3272/***********************************************************************/
3275static void change_production_callback(GtkComboBox *combo,
3276 struct city_dialog *pdialog)
3277{
3278 GtkTreeIter iter;
3279
3281 && gtk_combo_box_get_active_iter(combo, &iter)) {
3282 cid id;
3283 struct universal univ;
3284
3285 gtk_tree_model_get(gtk_combo_box_get_model(combo), &iter, 2, &id, -1);
3286 univ = cid_production(id);
3287 city_change_production(pdialog->pcity, &univ);
3288 }
3289}
3290
3291/***********************************************************************/
3294static void sell_callback(struct impr_type *pimprove, gpointer data)
3295{
3296 GtkWidget *shl;
3297 struct city_dialog *pdialog = (struct city_dialog *) data;
3298 pdialog->sell_id = improvement_number(pimprove);
3299 int price;
3300
3301 if (!can_client_issue_orders()) {
3302 return;
3303 }
3304
3306 pimprove) != TR_SUCCESS) {
3307 return;
3308 }
3309
3310 price = impr_sell_gold(pimprove);
3311 shl = gtk_message_dialog_new(NULL,
3312 GTK_DIALOG_DESTROY_WITH_PARENT,
3313 GTK_MESSAGE_QUESTION,
3314 GTK_BUTTONS_YES_NO,
3315 PL_("Sell %s for %d gold?",
3316 "Sell %s for %d gold?", price),
3317 city_improvement_name_translation(pdialog->pcity, pimprove), price);
3318 setup_dialog(shl, pdialog->shell);
3319 pdialog->sell_shell = shl;
3320
3321 gtk_window_set_title(GTK_WINDOW(shl), _("Sell It!"));
3322
3323 g_signal_connect(shl, "response",
3324 G_CALLBACK(sell_callback_response), pdialog);
3325
3326 gtk_window_present(GTK_WINDOW(shl));
3327}
3328
3329/***********************************************************************/
3332static void sell_callback_response(GtkWidget *w, gint response, gpointer data)
3333{
3334 struct city_dialog *pdialog = data;
3335
3336 if (response == GTK_RESPONSE_YES) {
3337 city_sell_improvement(pdialog->pcity, pdialog->sell_id);
3338 }
3339 gtk_window_destroy(GTK_WINDOW(w));
3340
3341 pdialog->sell_shell = NULL;
3342}
3343
3344/***********************************************************************/
3347static void impr_callback(GtkTreeView *view, GtkTreePath *path,
3348 GtkTreeViewColumn *col, gpointer data)
3349{
3350 GtkTreeModel *model;
3351 GtkTreeIter it;
3352 GdkSeat *seat;
3353 GdkModifierType mask;
3354 struct impr_type *pimprove;
3355
3356 model = gtk_tree_view_get_model(view);
3357
3358 if (!gtk_tree_model_get_iter(model, &it, path)) {
3359 return;
3360 }
3361
3362 gtk_tree_model_get(model, &it, 0, &pimprove, -1);
3363
3364 seat = gdk_display_get_default_seat(gtk_widget_get_display(GTK_WIDGET(view)));
3365 mask = gdk_device_get_modifier_state(gdk_seat_get_keyboard(seat));
3366
3367 if (!(mask & GDK_CONTROL_MASK)) {
3368 sell_callback(pimprove, data);
3369 } else {
3370 if (is_great_wonder(pimprove)) {
3372 } else {
3374 }
3375 }
3376}
3377
3378/************ Callbacks for stuff on the Misc. Settings page **************/
3379
3380/***********************************************************************/
3383static void rename_callback(GtkWidget *w, gpointer data)
3384{
3385 struct city_dialog *pdialog;
3386
3387 pdialog = (struct city_dialog *) data;
3388
3389 pdialog->rename_shell = input_dialog_create(GTK_WINDOW(pdialog->shell),
3390 /* "shellrenamecity" */
3391 _("Rename City"),
3392 _("What should we rename the city to?"),
3393 city_name_get(pdialog->pcity),
3394 rename_popup_callback, pdialog);
3395}
3396
3397/***********************************************************************/
3400static void rename_popup_callback(gpointer data, gint response,
3401 const char *input)
3402{
3403 struct city_dialog *pdialog = data;
3404
3405 if (pdialog) {
3406 if (response == GTK_RESPONSE_OK) {
3407 city_rename(pdialog->pcity, input);
3408 } /* else CANCEL or DELETE_EVENT */
3409
3410 pdialog->rename_shell = NULL;
3411 }
3412}
3413
3414/***********************************************************************/
3417static void misc_whichtab_callback(GtkWidget *w, gpointer data)
3418{
3419 new_dialog_def_page = GPOINTER_TO_INT(data);
3420}
3421
3422/***********************************************************************/
3425static void cityopt_callback(GtkWidget *w, gpointer data)
3426{
3427 struct city_dialog *pdialog = (struct city_dialog *) data;
3428
3429 if (!can_client_issue_orders()) {
3430 return;
3431 }
3432
3433 if (!pdialog->misc.block_signal) {
3434 struct city *pcity = pdialog->pcity;
3435 bv_city_options new_options;
3436
3437 fc_assert(CITYO_LAST == 3);
3438
3439 BV_CLR_ALL(new_options);
3440 if (gtk_check_button_get_active(GTK_CHECK_BUTTON(pdialog->misc.disband_on_settler))) {
3441 BV_SET(new_options, CITYO_DISBAND);
3442 }
3443 if (gtk_check_button_get_active(GTK_CHECK_BUTTON(pdialog->misc.new_citizens_radio[1]))) {
3444 BV_SET(new_options, CITYO_SCIENCE_SPECIALISTS);
3445 }
3446 if (gtk_check_button_get_active(GTK_CHECK_BUTTON(pdialog->misc.new_citizens_radio[2]))) {
3447 BV_SET(new_options, CITYO_GOLD_SPECIALISTS);
3448 }
3449
3450 dsend_packet_city_options_req(&client.conn, pcity->id, pcity->id, new_options);
3451 }
3452}
3453
3454/***********************************************************************/
3458static void set_cityopt_values(struct city_dialog *pdialog)
3459{
3460 struct city *pcity = pdialog->pcity;
3461
3462 pdialog->misc.block_signal = 1;
3463
3464 gtk_check_button_set_active(GTK_CHECK_BUTTON(pdialog->misc.disband_on_settler),
3465 is_city_option_set(pcity, CITYO_DISBAND));
3466
3467 if (is_city_option_set(pcity, CITYO_SCIENCE_SPECIALISTS)) {
3468 gtk_check_button_set_active(GTK_CHECK_BUTTON
3469 (pdialog->misc.new_citizens_radio[1]), TRUE);
3470 } else if (is_city_option_set(pcity, CITYO_GOLD_SPECIALISTS)) {
3471 gtk_check_button_set_active(GTK_CHECK_BUTTON
3472 (pdialog->misc.new_citizens_radio[2]), TRUE);
3473 } else {
3474 gtk_check_button_set_active(GTK_CHECK_BUTTON
3475 (pdialog->misc.new_citizens_radio[0]), TRUE);
3476 }
3477 pdialog->misc.block_signal = 0;
3478}
3479
3480/******************** Callbacks for: Close, Prev, Next. *******************/
3481
3482/***********************************************************************/
3485static void close_callback(GtkWidget *w, gpointer data)
3486{
3487 close_city_dialog((struct city_dialog *) data);
3488}
3489
3490/***********************************************************************/
3493static void city_destroy_callback(GtkWidget *w, gpointer data)
3494{
3495 struct city_dialog *pdialog;
3496
3497 pdialog = (struct city_dialog *) data;
3498
3499 gtk_widget_hide(pdialog->shell);
3500
3502 citizens_dialog_close(pdialog->pcity);
3503 }
3504 close_happiness_dialog(pdialog->pcity);
3505 close_cma_dialog(pdialog->pcity);
3506
3507 /* Save size of the city dialog. */
3508 GUI_GTK_OPTION(citydlg_xsize)
3510 gtk_widget_get_allocated_width(pdialog->shell),
3512 GUI_GTK_OPTION(citydlg_ysize)
3514 gtk_widget_get_allocated_height(pdialog->shell),
3516
3517 last_page
3518 = gtk_notebook_get_current_page(GTK_NOTEBOOK(pdialog->notebook));
3519
3521 dialog_list_remove(dialog_list, pdialog);
3522
3523 unit_node_vector_free(&pdialog->overview.supported_units);
3524 unit_node_vector_free(&pdialog->overview.present_units);
3525
3526 if (pdialog->sell_shell) {
3527 gtk_window_destroy(GTK_WINDOW(pdialog->sell_shell));
3528 }
3529 if (pdialog->rename_shell) {
3530 gtk_window_destroy(GTK_WINDOW(pdialog->rename_shell));
3531 }
3532
3533 cairo_surface_destroy(pdialog->map_canvas_store_unscaled);
3534 cairo_surface_destroy(pdialog->citizen_surface);
3535
3536 free(pdialog);
3537
3538 /* Need to do this every time a new dialog is closed. */
3540}
3541
3542/***********************************************************************/
3545static void close_city_dialog(struct city_dialog *pdialog)
3546{
3547 gtk_window_destroy(GTK_WINDOW(pdialog->shell));
3548}
3549
3550/***********************************************************************/
3554static void switch_city_callback(GtkWidget *w, gpointer data)
3555{
3556 struct city_dialog *pdialog = (struct city_dialog *) data;
3557 int i, j, dir, size;
3558 struct city *new_pcity = NULL;
3559
3561 return;
3562 }
3563
3564 size = city_list_size(client.conn.playing->cities);
3565
3567 fc_assert_ret(size >= 1);
3569
3570 if (size == 1) {
3571 return;
3572 }
3573
3574 /* dir = 1 will advance to the city, dir = -1 will get previous */
3575 if (w == GTK_WIDGET(pdialog->next_command)) {
3576 dir = 1;
3577 } else if (w == GTK_WIDGET(pdialog->prev_command)) {
3578 dir = -1;
3579 } else {
3580 /* Always fails. */
3581 fc_assert_ret(w == GTK_WIDGET(pdialog->next_command)
3582 || w == GTK_WIDGET(pdialog->prev_command));
3583 dir = 1;
3584 }
3585
3586 for (i = 0; i < size; i++) {
3587 if (pdialog->pcity == city_list_get(client.conn.playing->cities, i)) {
3588 break;
3589 }
3590 }
3591
3592 fc_assert_ret(i < size);
3593
3594 for (j = 1; j < size; j++) {
3595 struct city *other_pcity = city_list_get(client.conn.playing->cities,
3596 (i + dir * j + size) % size);
3597 struct city_dialog *other_pdialog = get_city_dialog(other_pcity);
3598
3599 fc_assert_ret(other_pdialog != pdialog);
3600 if (!other_pdialog) {
3601 new_pcity = other_pcity;
3602 break;
3603 }
3604 }
3605
3606 if (!new_pcity) {
3607 /* Every other city has an open city dialog. */
3608 return;
3609 }
3610
3611 /* cleanup happiness dialog */
3613 citizens_dialog_close(pdialog->pcity);
3614 }
3615 close_happiness_dialog(pdialog->pcity);
3616
3617 pdialog->pcity = new_pcity;
3618
3619 /* reinitialize happiness, and cma dialogs */
3621 gtk_box_append(GTK_BOX(pdialog->happiness.citizens),
3622 citizens_dialog_display(pdialog->pcity));
3623 }
3624 gtk_box_append(GTK_BOX(pdialog->happiness.widget),
3625 get_top_happiness_display(pdialog->pcity, low_citydlg, pdialog->shell));
3626 if (!client_is_observer()) {
3627 fc_assert(pdialog->cma_editor != NULL);
3628 pdialog->cma_editor->pcity = new_pcity;
3629 }
3630
3631 reset_city_worklist(pdialog->production.worklist, pdialog->pcity);
3632
3633 can_slide = FALSE;
3634 center_tile_mapcanvas(pdialog->pcity->tile);
3635 can_slide = TRUE;
3636 if (!client_is_observer()) {
3637 set_cityopt_values(pdialog); /* Need not be in real_city_dialog_refresh */
3638 }
3639
3641
3642 /* Recenter the city map(s) */
3644 if (pdialog->happiness.map_canvas.sw) {
3646 }
3647}
3648
3649/***********************************************************************/
3653{
3655 refresh_worklist(pdialog->production.worklist);
3657}
const char * action_id_name_translation(action_id act_id)
Definition actions.c:1910
bool action_ever_possible(action_id action)
Definition actions.c:9309
#define action_id_univs_not_blocking(act_id, act_uni, tgt_uni)
Definition actions.h:950
#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:2101
bool can_city_build_now(const struct city *pcity, const struct universal *target)
Definition city.c:989
int city_unit_unhappiness(struct unit *punit, int *free_unhappy)
Definition city.c:2940
int city_build_slots(const struct city *pcity)
Definition city.c:2831
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:1111
int city_improvement_upkeep(const struct city *pcity, const struct impr_type *b)
Definition city.c:1227
bool is_city_option_set(const struct city *pcity, enum city_options option)
Definition city.c:3297
int city_population(const struct city *pcity)
Definition city.c:1165
bool city_unhappy(const struct city *pcity)
Definition city.c:1595
bool city_celebrating(const struct city *pcity)
Definition city.c:1614
int city_illness_calc(const struct city *pcity, int *ill_base, int *ill_size, int *ill_trade, int *ill_pollution)
Definition city.c:2769
bool city_happy(const struct city *pcity)
Definition city.c:1583
int city_map_radius_sq_get(const struct city *pcity)
Definition city.c:132
citizens city_specialists(const struct city *pcity)
Definition city.c:3226
int city_turns_to_grow(const struct city *pcity)
Definition city.c:1965
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:802
void name_and_sort_items(struct universal *targets, int num_targets, struct item *items, bool show_cost, struct city *pcity)
Definition climisc.c:633
cid cid_encode(struct universal target)
Definition climisc.c:475
int collect_already_built_targets(struct universal *targets, struct city *pcity)
Definition climisc.c:895
#define MAX_NUM_PRODUCTION_TARGETS
Definition climisc.h:87
#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:550
void request_unit_fortify(struct unit *punit)
Definition control.c:2213
void unit_focus_set(struct unit *punit)
Definition control.c:502
void request_unit_change_homecity(struct unit *punit)
Definition control.c:1994
void request_unit_unload(struct unit *pcargo)
Definition control.c:2092
void request_unit_sentry(struct unit *punit)
Definition control.c:2202
#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:2756
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:2815
static void popup_workertask_dlg(struct city *pcity, struct tile *ptile)
Definition citydlg.c:2927
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:3346
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:3271
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:2354
static void buy_callback_response(GtkWidget *w, gint response, gpointer data)
Definition citydlg.c:3061
void real_city_dialog_refresh(struct city *pcity)
Definition citydlg.c:481
static void unit_center_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2655
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:2919
static void city_dialog_update_present_units(struct city_dialog *pdialog)
Definition citydlg.c:2211
#define CITYMAP_SCALE
Definition citydlg.c:75
static gboolean citizens_callback(GtkWidget *w, GdkEventButton *ev, gpointer data)
Definition citydlg.c:2836
static void change_production_callback(GtkComboBox *combo, struct city_dialog *pdialog)
Definition citydlg.c:3124
static void unit_load_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2730
static void set_cityopt_values(struct city_dialog *pdialog)
Definition citydlg.c:3312
static void close_city_dialog(struct city_dialog *pdialog)
Definition citydlg.c:3401
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:3074
#define dialog_list_iterate_end
Definition citydlg.c:92
static void impr_callback(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data)
Definition citydlg.c:3197
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:3279
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:3049
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:3143
#define dialog_list_iterate(dialoglist, pdialog)
Definition citydlg.c:90
static void supported_unit_activate_close_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2682
static void city_dialog_update_prev_next(void)
Definition citydlg.c:2318
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:3338
static struct dialog_list * dialog_list
Definition citydlg.c:209
static void sell_callback_response(GtkWidget *w, gint response, gpointer data)
Definition citydlg.c:3182
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:2802
static void unit_fortify_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2769
static gboolean present_unit_callback(GtkWidget *w, GdkEventButton *ev, gpointer data)
Definition citydlg.c:2479
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:2782
#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:3237
static void switch_city_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:3410
#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:2743
static void show_units_response(void *data)
Definition citydlg.c:2367
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:2668
static void present_unit_activate_close_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2707
static void set_city_workertask(GtkWidget *w, gpointer data)
Definition citydlg.c:2863
static void rename_popup_callback(gpointer data, gint response, const char *input)
Definition citydlg.c:3254
@ 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:2415
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:3652
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:3168
static gboolean middle_present_unit_release(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data)
Definition citydlg.c:2671
static bool create_unit_menu(struct city_dialog *pdialog, struct unit *punit, GtkWidget *wdg, bool supported)
Definition citydlg.c:2472
static gboolean right_unit_release(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data)
Definition citydlg.c:2717
static gboolean left_button_down_citymap(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data)
Definition citydlg.c:3139
static void close_citydlg_unit_popover(struct city_dialog *pdialog)
Definition citydlg.c:2736
static gboolean middle_supported_unit_release(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data)
Definition citydlg.c:2695
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:80
struct universal item
Definition climisc.h:81
char descr[MAX_LEN_NAME+40]
Definition climisc.h:82
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:6498
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:6520
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:6441
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 unit *punit, const struct city *pcity)
Definition unit.c:447
struct unit * unit_transport_get(const struct unit *pcargo)
Definition unit.c:2427
bool unit_can_do_action(const struct unit *punit, const action_id act_id)
Definition unit.c:331
bool can_unit_unload(const struct unit *pcargo, const struct unit *ptrans)
Definition unit.c:771
#define unit_tile(_pu)
Definition unit.h:388
#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