Freeciv-3.3: /fast/freeciv/nightly/main/client/gui-gtk-4.0/citydlg.c Source File

Freeciv-3.3

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 "update_queue.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. */
81 enum citydlg_response { CDLGR_UNITS, CDLGR_PREV, CDLGR_NEXT };
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
114 enum { OVERVIEW_PAGE, WORKLIST_PAGE, HAPPINESS_PAGE, CMA_PAGE,
115 SETTINGS_PAGE, STICKY_PAGE,
116 NUM_PAGES /* The number of pages in city dialog notebook
117 * must match the entries in misc_whichtab_label[] */
118};
119
120enum {
121 INFO_SIZE, INFO_FOOD, INFO_SHIELD, INFO_TRADE, INFO_GOLD,
122 INFO_LUXURY, INFO_SCIENCE, INFO_GRANARY, INFO_GROWTH,
123 INFO_CORRUPTION, INFO_WASTE, INFO_CULTURE, INFO_POLLUTION,
124 INFO_ILLNESS, INFO_STEAL, INFO_AIRLIFT,
125 NUM_INFO_FIELDS /* Number of fields in city_info panel
126 * must match entries in output_label[] */
127};
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 {
151 struct city_map_canvas map_canvas;
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;
170 } overview;
171
172 struct {
173 GtkWidget *production_label;
174 GtkWidget *production_bar;
175 GtkWidget *buy_command;
176 GtkWidget *worklist;
177 } production;
178
179 struct {
180 struct city_map_canvas map_canvas;
181
182 GtkWidget *widget;
183 GtkWidget *info_label[NUM_INFO_FIELDS];
184 GtkWidget *citizens;
185 } happiness;
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;
195 } misc;
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
205 Impr_type_id sell_id;
206
207 int cwidth;
208};
209
210 static struct dialog_list *dialog_list;
211 static bool city_dialogs_have_been_initialised = FALSE;
212 static int canvas_width, canvas_height;
213 static int new_dialog_def_page = OVERVIEW_PAGE;
214 static int last_page = OVERVIEW_PAGE;
215
216 static bool is_showing_workertask_dialog = FALSE;
217
218static struct
219{
220 struct city *owner;
221 struct tile *loc;
222} workertask_req;
223
224 static 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);
258static void city_dialog_update_improvement_list(struct city_dialog
259 *pdialog);
260static void city_dialog_update_supported_units(struct city_dialog
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/***********************************************************************/
340 static void init_citydlg_dimensions(void)
341{
342 canvas_width = get_citydlg_canvas_width();
343 canvas_height = get_citydlg_canvas_height();
344}
345
346/***********************************************************************/
349 static void initialize_city_dialogs(void)
350{
351 int height;
352
353 fc_assert_ret(!city_dialogs_have_been_initialised);
354
355 dialog_list = dialog_list_new();
356 init_citydlg_dimensions();
357 height = screen_height();
358
359 /* Use default layout when height cannot be determined
360 * (when height == 0) */
361 if (height > 0 && height <= TINYSCREEN_MAX_HEIGHT) {
362 low_citydlg = TRUE;
363 } else {
364 low_citydlg = FALSE;
365 }
366
367 city_dialogs_have_been_initialised = TRUE;
368}
369
370/***********************************************************************/
373 void reset_city_dialogs(void)
374{
375 if (!city_dialogs_have_been_initialised) {
376 return;
377 }
378
379 init_citydlg_dimensions();
380
381 dialog_list_iterate(dialog_list, pdialog) {
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.
384 The player has to close and reopen the dialog to fix this. */
385 city_dialog_update_map(pdialog);
386 } dialog_list_iterate_end;
387
388 popdown_all_city_dialogs();
389}
390
391/***********************************************************************/
395 static struct city_dialog *get_city_dialog(struct city *pcity)
396{
397 if (!city_dialogs_have_been_initialised) {
398 initialize_city_dialogs();
399 }
400
401 dialog_list_iterate(dialog_list, pdialog) {
402 if (pdialog->pcity == pcity) {
403 return pdialog;
404 }
405 } dialog_list_iterate_end;
406
407 return NULL;
408}
409
410/***********************************************************************/
413 static 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/***********************************************************************/
430 static 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),
439 CITYMAP_WIDTH);
440 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(sw),
441 CITYMAP_HEIGHT);
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/***********************************************************************/
471 static 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/***********************************************************************/
496 void real_city_dialog_refresh(struct city *pcity)
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
504 if (city_owner(pcity) == client.conn.playing) {
505 city_report_dialog_update_city(pcity);
506 economy_report_dialog_update();
507 }
508
509 if (!pdialog) {
510 return;
511 }
512
513 city_dialog_update_title(pdialog);
514 city_dialog_update_citizens(pdialog);
515 city_dialog_update_information(pdialog->overview.info_label, pdialog);
516 city_dialog_update_map(pdialog);
517 city_dialog_update_building(pdialog);
518 city_dialog_update_improvement_list(pdialog);
519 city_dialog_update_supported_units(pdialog);
520 city_dialog_update_present_units(pdialog);
521
522 if (!client_has_player() || city_owner(pcity) == client_player()) {
523 bool have_present_units = (unit_list_size(pcity->tile->units) > 0);
524
525 refresh_worklist(pdialog->production.worklist);
526
527 if (!low_citydlg) {
528 city_dialog_update_information(pdialog->happiness.info_label, pdialog);
529 }
530 refresh_happiness_dialog(pdialog->pcity);
531 if (game.info.citizen_nationality) {
532 citizens_dialog_refresh(pdialog->pcity);
533 }
534
535 if (!client_is_observer()) {
536 refresh_cma_dialog(pdialog->pcity, REFRESH_ALL);
537 }
538
539 gtk_widget_set_sensitive(pdialog->show_units_command,
540 can_client_issue_orders()
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/***********************************************************************/
552 void refresh_unit_city_dialogs(struct unit *punit)
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))) {
561 city_dialog_update_supported_units(pdialog);
562 }
563
564 if (pcity_pre && (pdialog = get_city_dialog(pcity_pre))) {
565 city_dialog_update_present_units(pdialog);
566 }
567}
568
569/***********************************************************************/
572 void real_city_dialog_popup(struct city *pcity)
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! */
584 city_dialog_map_recenter(pdialog->overview.map_canvas.sw);
585 if (pdialog->happiness.map_canvas.sw) {
586 city_dialog_map_recenter(pdialog->happiness.map_canvas.sw);
587 }
588}
589
590/***********************************************************************/
593 bool city_dialog_is_open(struct city *pcity)
594{
595 return get_city_dialog(pcity) != NULL;
596}
597
598/***********************************************************************/
601 void popdown_city_dialog(struct city *pcity)
602{
603 struct city_dialog *pdialog = get_city_dialog(pcity);
604
605 if (pdialog) {
606 close_city_dialog(pdialog);
607 }
608}
609
610/***********************************************************************/
613 void popdown_all_city_dialogs(void)
614{
615 if (!city_dialogs_have_been_initialised) {
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
624 city_dialogs_have_been_initialised = FALSE;
625}
626
627/***********************************************************************/
630 static 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/***********************************************************************/
659 static 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:
676 get_city_dialog_output_text(pdialog->pcity, O_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:
686 get_city_dialog_output_text(pdialog->pcity, O_SCIENCE,
687 buf, sizeof(buf));
688 break;
689 case INFO_LUXURY:
690 get_city_dialog_output_text(pdialog->pcity, O_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/***********************************************************************/
731 static 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_set_visible(table, TRUE);
849
850 return table;
851}
852
853/***********************************************************************/
858 static 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,
865 CITY_MAP_MIN_SIZE_Y);
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/***********************************************************************/
875 static 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/***********************************************************************/
933 static void create_and_append_overview_page(struct city_dialog *pdialog)
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
945 /* Main page */
946 page = gtk_grid_new();
947 gtk_orientable_set_orientation(GTK_ORIENTABLE(page),
948 GTK_ORIENTATION_VERTICAL);
949 gtk_widget_set_margin_start(page, 8);
950 gtk_widget_set_margin_end(page, 8);
951 gtk_widget_set_margin_top(page, 8);
952 gtk_widget_set_margin_bottom(page, 8);
953 label = gtk_label_new_with_mnemonic(tab_title);
954 gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), page, label);
955
956 if (!low_citydlg) {
957 GtkWidget *middle;
958 GtkWidget *vbox;
959 GtkWidget *hbox;
960 int middle_col = 0;
961
962 /* Middle: city map, improvements */
963 middle = gtk_grid_new();
964 gtk_grid_set_column_spacing(GTK_GRID(middle), 6);
965 gtk_grid_attach(GTK_GRID(page), middle, 0, page_row++, 1, 1);
966
967 /* City map */
968 create_citydlg_main_map(pdialog, middle, middle_col++, 0);
969
970 /* Improvements */
971 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
972 gtk_grid_attach(GTK_GRID(middle), vbox, middle_col++, 0, 1, 1);
973
974 view = create_citydlg_improvement_list(pdialog);
975
976 label = g_object_new(GTK_TYPE_LABEL, "label", _("Production:"),
977 "xalign", 0.0, "yalign", 0.5, NULL);
978 gtk_box_append(GTK_BOX(vbox), label);
979
980 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10);
981 gtk_box_append(GTK_BOX(vbox), hbox);
982
983 production_store = gtk_list_store_new(4, GDK_TYPE_PIXBUF, G_TYPE_STRING,
984 G_TYPE_INT, G_TYPE_BOOLEAN);
985 pdialog->overview.change_production_store = production_store;
986
987 bar = gtk_progress_bar_new();
988 gtk_progress_bar_set_show_text(GTK_PROGRESS_BAR(bar), TRUE);
989 pdialog->overview.production_bar = bar;
990 gtk_box_append(GTK_BOX(hbox), bar);
991
992 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(bar), _("%d/%d %d turns"));
993
994 production_combo
995 = gtk_combo_box_new_with_model(GTK_TREE_MODEL(production_store));
996 gtk_widget_set_hexpand(production_combo, TRUE);
997 pdialog->overview.production_combo = production_combo;
998 gtk_box_append(GTK_BOX(hbox), production_combo);
999 g_object_unref(production_store);
1000 g_signal_connect(production_combo, "changed",
1001 G_CALLBACK(change_production_callback), pdialog);
1002
1003 gtk_cell_layout_clear(GTK_CELL_LAYOUT(production_combo));
1004 rend = gtk_cell_renderer_pixbuf_new();
1005 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(production_combo), rend, TRUE);
1006 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(production_combo),
1007 rend, "pixbuf", 0, NULL);
1008 g_object_set(rend, "xalign", 0.0, NULL);
1009
1010 rend = gtk_cell_renderer_text_new();
1011 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(production_combo), rend, TRUE);
1012 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(production_combo),
1013 rend, "text", 1, "strikethrough", 3, NULL);
1014
1015 pdialog->overview.buy_command
1016 = icon_label_button_new("system-run", _("_Buy"));
1017 gtk_box_append(GTK_BOX(hbox), GTK_WIDGET(pdialog->overview.buy_command));
1018 g_signal_connect(pdialog->overview.buy_command, "clicked",
1019 G_CALLBACK(buy_callback), pdialog);
1020
1021 label = g_object_new(GTK_TYPE_LABEL, "use-underline", TRUE,
1022 "mnemonic-widget", view,
1023 "label", _("I_mprovements:"),
1024 "xalign", 0.0, "yalign", 0.5, NULL);
1025 gtk_box_append(GTK_BOX(vbox), label);
1026
1027 sw = gtk_scrolled_window_new();
1028 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), TRUE);
1029 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1030 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1031 gtk_box_append(GTK_BOX(vbox), sw);
1032
1033 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), view);
1034 } else {
1035 pdialog->overview.buy_command = NULL;
1036 pdialog->overview.production_bar = NULL;
1037 pdialog->overview.production_combo = NULL;
1038 pdialog->overview.change_production_store = NULL;
1039 }
1040
1041 /* Bottom: info, units */
1042 bottom = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
1043 gtk_grid_attach(GTK_GRID(page), bottom, 0, page_row++, 1, 1);
1044
1045 /* Info */
1046 frame = gtk_frame_new(_("Info"));
1047 gtk_box_append(GTK_BOX(bottom), frame);
1048
1049 table = create_city_info_table(pdialog,
1050 pdialog->overview.info_label);
1051 gtk_widget_set_halign(table, GTK_ALIGN_CENTER);
1052 gtk_widget_set_valign(table, GTK_ALIGN_CENTER);
1053 gtk_frame_set_child(GTK_FRAME(frame), table);
1054
1055 /* Right: present and supported units (overview page) */
1056 right = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
1057 gtk_box_append(GTK_BOX(bottom), right);
1058
1059 pdialog->overview.supported_units_frame = gtk_frame_new("");
1060 gtk_box_append(GTK_BOX(right), pdialog->overview.supported_units_frame);
1061 pdialog->overview.present_units_frame = gtk_frame_new("");
1062 gtk_box_append(GTK_BOX(right), pdialog->overview.present_units_frame);
1063
1064 /* Supported units */
1065 sw = gtk_scrolled_window_new();
1066 gtk_widget_set_hexpand(sw, TRUE);
1067 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1068 GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
1069 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), FALSE);
1070 gtk_frame_set_child(GTK_FRAME(pdialog->overview.supported_units_frame),
1071 sw);
1072
1073
1074 table = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
1075 gtk_widget_set_size_request(table, -1, unit_height);
1076 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), table);
1077
1078 pdialog->overview.supported_unit_table = table;
1079 unit_node_vector_init(&pdialog->overview.supported_units);
1080
1081 /* Present units */
1082 sw = gtk_scrolled_window_new();
1083 gtk_widget_set_hexpand(sw, TRUE);
1084 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1085 GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
1086 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), FALSE);
1087 gtk_frame_set_child(GTK_FRAME(pdialog->overview.present_units_frame), sw);
1088
1089 table = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
1090 gtk_widget_set_size_request(table, -1, unit_height);
1091 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), table);
1092
1093 pdialog->overview.present_unit_table = table;
1094 unit_node_vector_init(&pdialog->overview.present_units);
1095
1096 /* Show page */
1097 gtk_widget_set_visible(page, TRUE);
1098}
1099
1100/***********************************************************************/
1103 static void create_and_append_map_page(struct city_dialog *pdialog)
1104{
1105 if (low_citydlg) {
1106 GtkWidget *page;
1107 GtkWidget *label;
1108 const char *tab_title = _("Citymap");
1109 int page_row = 0;
1110
1111 page = gtk_grid_new();
1112 gtk_orientable_set_orientation(GTK_ORIENTABLE(page),
1113 GTK_ORIENTATION_VERTICAL);
1114 gtk_widget_set_margin_start(page, 8);
1115 gtk_widget_set_margin_end(page, 8);
1116 gtk_widget_set_margin_top(page, 8);
1117 gtk_widget_set_margin_bottom(page, 8);
1118 label = gtk_label_new_with_mnemonic(tab_title);
1119 gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), page, label);
1120
1121 create_citydlg_main_map(pdialog, page, 0, page_row++);
1122
1123 gtk_widget_set_visible(page, TRUE);
1124 }
1125}
1126
1127/***********************************************************************/
1130 static gboolean target_drag_data_received(GtkDropTarget *target,
1131 const GValue *value,
1132 double x, double y, gpointer data)
1133{
1134 struct city_dialog *pdialog = (struct city_dialog *) data;
1135 cid id;
1136 struct universal univ;
1137
1138 if (NULL != client.conn.playing
1139 && city_owner(pdialog->pcity) != client.conn.playing) {
1140 return FALSE;
1141 }
1142
1143 id = g_value_get_int(value);
1144 univ = cid_production(id);
1145
1146 city_change_production(pdialog->pcity, &univ);
1147
1148 return TRUE;
1149}
1150
1151/***********************************************************************/
1155 static int create_production_header(struct city_dialog *pdialog,
1156 GtkWidget *grid, int row)
1157{
1158 GtkWidget *hgrid, *bar;
1159 int grid_col = 0;
1160
1161 hgrid = gtk_grid_new();
1162 gtk_widget_set_margin_bottom(hgrid, 2);
1163 gtk_widget_set_margin_end(hgrid, 2);
1164 gtk_widget_set_margin_start(hgrid, 2);
1165 gtk_widget_set_margin_top(hgrid, 2);
1166 gtk_grid_set_column_spacing(GTK_GRID(hgrid), 10);
1167 gtk_grid_attach(GTK_GRID(grid), hgrid, 0, row++, 1, 1);
1168
1169 /* The label is set in city_dialog_update_building() */
1170 bar = gtk_progress_bar_new();
1171 gtk_widget_set_hexpand(bar, TRUE);
1172 gtk_progress_bar_set_show_text(GTK_PROGRESS_BAR(bar), TRUE);
1173 pdialog->production.production_bar = bar;
1174 gtk_grid_attach(GTK_GRID(hgrid), bar, grid_col++, 0, 1, 1);
1175 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(bar), _("%d/%d %d turns"));
1176
1177 add_worklist_dnd_target(bar, target_drag_data_received, pdialog);
1178
1179 pdialog->production.buy_command
1180 = icon_label_button_new("system-run", _("_Buy"));
1181 gtk_grid_attach(GTK_GRID(hgrid), GTK_WIDGET(pdialog->production.buy_command),
1182 grid_col++, 0, 1, 1);
1183
1184 g_signal_connect(pdialog->production.buy_command, "clicked",
1185 G_CALLBACK(buy_callback), pdialog);
1186
1187 return row;
1188}
1189
1190/***********************************************************************/
1193 static void create_and_append_buildings_page(struct city_dialog *pdialog)
1194{
1195 if (low_citydlg) {
1196 GtkWidget *page;
1197 GtkWidget *label;
1198 GtkWidget *vbox;
1199 GtkWidget *view;
1200 const char *tab_title = _("Buildings");
1201 int page_row = 0;
1202
1203 page = gtk_grid_new();
1204 gtk_orientable_set_orientation(GTK_ORIENTABLE(page),
1205 GTK_ORIENTATION_VERTICAL);
1206 gtk_widget_set_margin_start(page, 8);
1207 gtk_widget_set_margin_end(page, 8);
1208 gtk_widget_set_margin_top(page, 8);
1209 gtk_widget_set_margin_bottom(page, 8);
1210 label = gtk_label_new_with_mnemonic(tab_title);
1211
1212 page_row = create_production_header(pdialog, page, page_row);
1213 gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), page, label);
1214
1215 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
1216 gtk_grid_attach(GTK_GRID(page), vbox, 0, page_row++, 1, 1);
1217
1218 view = create_citydlg_improvement_list(pdialog);
1219
1220 gtk_box_append(GTK_BOX(vbox), view);
1221
1222 gtk_widget_set_visible(page, TRUE);
1223 }
1224}
1225
1226/***********************************************************************/
1229 static void create_and_append_worklist_page(struct city_dialog *pdialog)
1230{
1231 const char *tab_title = _("P_roduction");
1232 GtkWidget *label = gtk_label_new_with_mnemonic(tab_title);
1233 GtkWidget *page, *editor;
1234 int page_row = 0;
1235
1236 page = gtk_grid_new();
1237 gtk_orientable_set_orientation(GTK_ORIENTABLE(page),
1238 GTK_ORIENTATION_VERTICAL);
1239 gtk_widget_set_margin_start(page, 8);
1240 gtk_widget_set_margin_end(page, 8);
1241 gtk_widget_set_margin_top(page, 8);
1242 gtk_widget_set_margin_bottom(page, 8);
1243 gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), page, label);
1244
1245 /* Stuff that's being currently built */
1246 if (!low_citydlg) {
1247 label = g_object_new(GTK_TYPE_LABEL,
1248 "label", _("Production:"),
1249 "xalign", 0.0, "yalign", 0.5, NULL);
1250 pdialog->production.production_label = label;
1251 gtk_grid_attach(GTK_GRID(page), label, 0, page_row++, 1, 1);
1252
1253 page_row = create_production_header(pdialog, page, page_row);
1254 } else {
1255 pdialog->production.production_label = NULL;
1256 }
1257
1258 editor = create_worklist();
1259 gtk_widget_set_margin_bottom(editor, 6);
1260 gtk_widget_set_margin_end(editor, 6);
1261 gtk_widget_set_margin_start(editor, 6);
1262 gtk_widget_set_margin_top(editor, 6);
1263 reset_city_worklist(editor, pdialog->pcity);
1264 gtk_grid_attach(GTK_GRID(page), editor, 0, page_row++, 1, 1);
1265 pdialog->production.worklist = editor;
1266
1267 gtk_widget_set_visible(page, TRUE);
1268}
1269
1270/***********************************************************************/
1280 static void create_and_append_happiness_page(struct city_dialog *pdialog)
1281{
1282 GtkWidget *page, *label, *table, *right, *left, *frame;
1283 const char *tab_title = _("Happ_iness");
1284 int page_col = 0;
1285 int left_row = 0;
1286
1287 /* Main page */
1288 page = gtk_grid_new();
1289 gtk_grid_set_column_spacing(GTK_GRID(page), 6);
1290 gtk_widget_set_margin_start(page, 8);
1291 gtk_widget_set_margin_end(page, 8);
1292 gtk_widget_set_margin_top(page, 8);
1293 gtk_widget_set_margin_bottom(page, 8);
1294 label = gtk_label_new_with_mnemonic(tab_title);
1295 gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), page, label);
1296
1297 /* Left: info, citizens */
1298 left = gtk_grid_new();
1299 gtk_orientable_set_orientation(GTK_ORIENTABLE(left),
1300 GTK_ORIENTATION_VERTICAL);
1301 gtk_grid_attach(GTK_GRID(page), left, page_col++, 0, 1, 1);
1302
1303 if (!low_citydlg) {
1304 /* Upper left: info */
1305 frame = gtk_frame_new(_("Info"));
1306 gtk_grid_attach(GTK_GRID(left), frame, 0, left_row++, 1, 1);
1307
1308 table = create_city_info_table(pdialog,
1309 pdialog->happiness.info_label);
1310 gtk_widget_set_halign(table, GTK_ALIGN_CENTER);
1311 gtk_frame_set_child(GTK_FRAME(frame), table);
1312 }
1313
1314 /* Lower left: citizens */
1315 if (game.info.citizen_nationality) {
1316 pdialog->happiness.citizens = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
1317 gtk_grid_attach(GTK_GRID(left), pdialog->happiness.citizens,
1318 0, left_row++, 1, 1);
1319 gtk_box_append(GTK_BOX(pdialog->happiness.citizens),
1320 citizens_dialog_display(pdialog->pcity));
1321 }
1322
1323 /* Right: city map, happiness */
1324 right = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
1325 gtk_grid_attach(GTK_GRID(page), right, page_col++, 0, 1, 1);
1326
1327 if (!low_citydlg) {
1328 /* Upper right: city map */
1329 frame = gtk_frame_new(_("City map"));
1330 gtk_widget_set_size_request(frame, CITY_MAP_MIN_SIZE_X,
1331 CITY_MAP_MIN_SIZE_Y);
1332 gtk_box_append(GTK_BOX(right), frame);
1333
1334 city_dialog_map_create(pdialog, &pdialog->happiness.map_canvas);
1335 gtk_frame_set_child(GTK_FRAME(frame), pdialog->happiness.map_canvas.sw);
1336 }
1337
1338 /* Lower right: happiness */
1339 pdialog->happiness.widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
1340 gtk_box_append(GTK_BOX(right), pdialog->happiness.widget);
1341 gtk_box_append(GTK_BOX(pdialog->happiness.widget),
1342 get_top_happiness_display(pdialog->pcity, low_citydlg,
1343 pdialog->shell));
1344
1345 /* Show page */
1346 gtk_widget_set_visible(page, TRUE);
1347}
1348
1349/***********************************************************************/
1352 static void create_and_append_cma_page(struct city_dialog *pdialog)
1353{
1354 GtkWidget *page, *label;
1355 const char *tab_title = _("_Governor");
1356
1357 page = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1358
1359 label = gtk_label_new_with_mnemonic(tab_title);
1360
1361 gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), page, label);
1362
1363 pdialog->cma_editor = create_cma_dialog(pdialog->pcity, low_citydlg);
1364 gtk_box_append(GTK_BOX(page), pdialog->cma_editor->shell);
1365
1366 gtk_widget_set_visible(page, TRUE);
1367}
1368
1369/***********************************************************************/
1372 static void create_and_append_settings_page(struct city_dialog *pdialog)
1373{
1374 int i;
1375 GtkWidget *vgrid, *page, *frame, *label, *button;
1376 GtkSizeGroup *size;
1377 GtkWidget *group;
1378 const char *tab_title = _("_Settings");
1379 int grid_row = 0;
1380
1381 static const char *new_citizens_output_label[] = {
1382 N_("Luxury"),
1383 N_("Science"),
1384 N_("Gold")
1385 };
1386
1387 static const char *disband_label
1388 = N_("Allow unit production to disband city");
1389
1390 static const char *misc_whichtab_label[NUM_PAGES] = {
1391 N_("Overview page"),
1392 N_("Production page"),
1393 N_("Happiness page"),
1394 N_("Governor page"),
1395 N_("This Settings page"),
1396 N_("Last active page")
1397 };
1398
1399 static bool new_citizens_label_done;
1400 static bool misc_whichtab_label_done;
1401
1402 /* Initialize signal_blocker */
1403 pdialog->misc.block_signal = 0;
1404
1405
1406 page = gtk_grid_new();
1407 gtk_grid_set_column_spacing(GTK_GRID(page), 18);
1408 gtk_widget_set_margin_start(page, 8);
1409 gtk_widget_set_margin_end(page, 8);
1410 gtk_widget_set_margin_top(page, 8);
1411 gtk_widget_set_margin_bottom(page, 8);
1412
1413 size = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
1414
1415 label = gtk_label_new_with_mnemonic(tab_title);
1416
1417 gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), page, label);
1418
1419 /* new_citizens radio */
1420 frame = gtk_frame_new(_("New citizens produce"));
1421 gtk_grid_attach(GTK_GRID(page), frame, 0, 0, 1, 1);
1422 gtk_size_group_add_widget(size, frame);
1423
1424 vgrid = gtk_grid_new();
1425 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
1426 GTK_ORIENTATION_VERTICAL);
1427 gtk_frame_set_child(GTK_FRAME(frame), vgrid);
1428
1429 intl_slist(ARRAY_SIZE(new_citizens_output_label), new_citizens_output_label,
1430 &new_citizens_label_done);
1431
1432 group = NULL;
1433 for (i = 0; i < ARRAY_SIZE(new_citizens_output_label); i++) {
1434 button = gtk_check_button_new_with_mnemonic(new_citizens_output_label[i]);
1435 gtk_check_button_set_group(GTK_CHECK_BUTTON(button),
1436 GTK_CHECK_BUTTON(group));
1437 pdialog->misc.new_citizens_radio[i] = button;
1438 gtk_grid_attach(GTK_GRID(vgrid), button, 0, grid_row++, 1, 1);
1439 g_signal_connect(button, "toggled",
1440 G_CALLBACK(cityopt_callback), pdialog);
1441 group = button;
1442 }
1443
1444 /* Next is the next-time-open radio group in the right column */
1445 frame = gtk_frame_new(_("Next time open"));
1446 gtk_grid_attach(GTK_GRID(page), frame, 1, 0, 1, 1);
1447 gtk_size_group_add_widget(size, frame);
1448
1449 vgrid = gtk_grid_new();
1450 grid_row = 0;
1451 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
1452 GTK_ORIENTATION_VERTICAL);
1453 gtk_frame_set_child(GTK_FRAME(frame), vgrid);
1454
1455 intl_slist(ARRAY_SIZE(misc_whichtab_label), misc_whichtab_label,
1456 &misc_whichtab_label_done);
1457
1458 group = NULL;
1459 for (i = 0; i < ARRAY_SIZE(misc_whichtab_label); i++) {
1460 button = gtk_check_button_new_with_mnemonic(misc_whichtab_label[i]);
1461 gtk_check_button_set_group(GTK_CHECK_BUTTON(button),
1462 GTK_CHECK_BUTTON(group));
1463 pdialog->misc.whichtab_radio[i] = button;
1464 gtk_grid_attach(GTK_GRID(vgrid), button, 0, grid_row++, 1, 1);
1465 g_signal_connect(button, "toggled",
1466 G_CALLBACK(misc_whichtab_callback), GINT_TO_POINTER(i));
1467 group = button;
1468 }
1469
1470 /* Now we go back and fill the hbox rename */
1471 frame = gtk_frame_new(_("City"));
1472 gtk_widget_set_margin_top(frame, 12);
1473 gtk_widget_set_margin_bottom(frame, 12);
1474 gtk_grid_attach(GTK_GRID(page), frame, 0, 1, 1, 1);
1475
1476 vgrid = gtk_grid_new();
1477 grid_row = 0;
1478 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
1479 GTK_ORIENTATION_VERTICAL);
1480 gtk_frame_set_child(GTK_FRAME(frame), vgrid);
1481
1482 button = gtk_button_new_with_mnemonic(_("R_ename..."));
1483 pdialog->misc.rename_command = button;
1484 gtk_grid_attach(GTK_GRID(vgrid), button, 0, grid_row++, 1, 1);
1485 g_signal_connect(button, "clicked",
1486 G_CALLBACK(rename_callback), pdialog);
1487
1488 gtk_widget_set_sensitive(button, can_client_issue_orders());
1489
1490 /* The disband-city-on-unit-production button */
1491 button = gtk_check_button_new_with_mnemonic(_(disband_label));
1492 pdialog->misc.disband_on_settler = button;
1493 gtk_grid_attach(GTK_GRID(vgrid), button, 0, grid_row++, 1, 1);
1494 g_signal_connect(button, "toggled",
1495 G_CALLBACK(cityopt_callback), pdialog);
1496
1497 /* We choose which page to popup by default */
1498 gtk_check_button_set_active(GTK_CHECK_BUTTON
1499 (pdialog->
1500 misc.whichtab_radio[new_dialog_def_page]),
1501 TRUE);
1502
1503 set_cityopt_values(pdialog);
1504
1505 gtk_widget_set_visible(page, TRUE);
1506
1507 if (new_dialog_def_page == (NUM_PAGES - 1)) {
1508 gtk_notebook_set_current_page(GTK_NOTEBOOK(pdialog->notebook),
1509 last_page);
1510 } else {
1511 gtk_notebook_set_current_page(GTK_NOTEBOOK(pdialog->notebook),
1512 new_dialog_def_page);
1513 }
1514}
1515
1516/***********************************************************************/
1524 static struct city_dialog *create_city_dialog(struct city *pcity)
1525{
1526 struct city_dialog *pdialog;
1527 GtkWidget *close_command;
1528 GtkWidget *vbox, *hbox, *cbox;
1529 int citizen_bar_width;
1530 int citizen_bar_height;
1531 int ccol = 0;
1532 GtkEventController *controller;
1533 struct player *owner;
1534
1535 if (!city_dialogs_have_been_initialised) {
1536 initialize_city_dialogs();
1537 }
1538
1539 pdialog = fc_malloc(sizeof(struct city_dialog));
1540 pdialog->pcity = pcity;
1541 pdialog->sell_shell = NULL;
1542 pdialog->rename_shell = NULL;
1543 pdialog->happiness.map_canvas.sw = NULL; /* Make sure NULL if spy */
1544 pdialog->happiness.map_canvas.darea = NULL; /* Ditto */
1545 pdialog->happiness.citizens = NULL; /* Ditto */
1546 pdialog->production.buy_command = NULL;
1547 pdialog->production.production_label = NULL;
1548 pdialog->production.production_bar = NULL;
1549 pdialog->cma_editor = NULL;
1550 pdialog->map_canvas_store_unscaled
1551 = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
1552 canvas_width, canvas_height);
1553
1554 pdialog->shell = gtk_dialog_new();
1555 gtk_window_set_title(GTK_WINDOW(pdialog->shell), city_name_get(pcity));
1556 setup_dialog(pdialog->shell, toplevel);
1557
1558 g_signal_connect(pdialog->shell, "destroy",
1559 G_CALLBACK(city_destroy_callback), pdialog);
1560 gtk_widget_set_name(pdialog->shell, "Freeciv");
1561
1562 gtk_widget_realize(pdialog->shell);
1563
1564 /* Keep the icon of the executable on Windows (see PR#36491) */
1565#ifndef FREECIV_MSWINDOWS
1566 {
1567 gtk_window_set_icon_name(GTK_WINDOW(pdialog->shell), "citydlg");
1568 }
1569#endif /* FREECIV_MSWINDOWS */
1570
1571 /* Restore size of the city dialog. */
1572 gtk_window_set_default_size(GTK_WINDOW(pdialog->shell),
1573 GUI_GTK_OPTION(citydlg_xsize),
1574 GUI_GTK_OPTION(citydlg_ysize));
1575
1576 pdialog->popover = NULL;
1577
1578 vbox = gtk_dialog_get_content_area(GTK_DIALOG(pdialog->shell));
1579 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
1580 gtk_box_set_homogeneous(GTK_BOX(hbox), TRUE);
1581 gtk_box_append(GTK_BOX(vbox), hbox);
1582
1583 /**** Citizens bar here ****/
1584 cbox = gtk_grid_new();
1585 gtk_box_append(GTK_BOX(hbox), cbox);
1586
1587 citizen_bar_width = tileset_small_sprite_width(tileset) * NUM_CITIZENS_SHOWN;
1588 citizen_bar_height = tileset_small_sprite_height(tileset);
1589
1590 pdialog->citizen_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
1591 citizen_bar_width,
1592 citizen_bar_height);
1593 pdialog->citizen_pics = gtk_picture_new();
1594
1595 gtk_widget_set_margin_start(pdialog->citizen_pics, 2);
1596 gtk_widget_set_margin_end(pdialog->citizen_pics, 2);
1597 gtk_widget_set_margin_top(pdialog->citizen_pics, 2);
1598 gtk_widget_set_margin_bottom(pdialog->citizen_pics, 2);
1599 gtk_widget_set_size_request(pdialog->citizen_pics,
1600 citizen_bar_width, citizen_bar_height);
1601 gtk_widget_set_halign(pdialog->citizen_pics, GTK_ALIGN_START);
1602 gtk_widget_set_valign(pdialog->citizen_pics, GTK_ALIGN_CENTER);
1603 gtk_grid_attach(GTK_GRID(cbox), pdialog->citizen_pics, ccol++, 0, 1, 1);
1604
1605 controller = GTK_EVENT_CONTROLLER(gtk_gesture_click_new());
1606 g_signal_connect(controller, "pressed",
1607 G_CALLBACK(citizens_callback), pdialog);
1608 gtk_widget_add_controller(pdialog->citizen_pics, controller);
1609
1610 /**** City name label here ****/
1611 pdialog->name_label = gtk_label_new(NULL);
1612 gtk_widget_set_hexpand(pdialog->name_label, TRUE);
1613 gtk_widget_set_halign(pdialog->name_label, GTK_ALIGN_START);
1614 gtk_widget_set_valign(pdialog->name_label, GTK_ALIGN_CENTER);
1615 gtk_box_append(GTK_BOX(hbox), pdialog->name_label);
1616
1617 /**** -Start of Notebook- ****/
1618
1619 pdialog->notebook = gtk_notebook_new();
1620 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(pdialog->notebook),
1621 GTK_POS_BOTTOM);
1622 gtk_box_append(GTK_BOX(vbox), pdialog->notebook);
1623
1624 create_and_append_overview_page(pdialog);
1625 create_and_append_map_page(pdialog);
1626 create_and_append_buildings_page(pdialog);
1627
1628 owner = city_owner(pcity);
1629
1630 /* Only create these tabs if not a spy */
1631 if (owner == client_player() || client_is_global_observer()) {
1632 create_and_append_worklist_page(pdialog);
1633 create_and_append_happiness_page(pdialog);
1634 }
1635
1636 if (owner == client_player()
1637 && !client_is_observer()) {
1638 create_and_append_cma_page(pdialog);
1639 create_and_append_settings_page(pdialog);
1640 } else {
1641 gtk_notebook_set_current_page(GTK_NOTEBOOK(pdialog->notebook),
1642 OVERVIEW_PAGE);
1643 }
1644
1645 /**** End of Notebook ****/
1646
1647 /* Bottom buttons */
1648
1649 pdialog->show_units_command =
1650 gtk_dialog_add_button(GTK_DIALOG(pdialog->shell), _("_List present units..."), CDLGR_UNITS);
1651
1652 g_signal_connect(GTK_DIALOG(pdialog->shell), "response",
1653 G_CALLBACK(citydlg_response_callback), pdialog);
1654
1655 pdialog->prev_command = gtk_button_new_from_icon_name("go-previous");
1656 gtk_dialog_add_action_widget(GTK_DIALOG(pdialog->shell),
1657 GTK_WIDGET(pdialog->prev_command), 1);
1658
1659 pdialog->next_command = gtk_button_new_from_icon_name("go-next");
1660 gtk_dialog_add_action_widget(GTK_DIALOG(pdialog->shell),
1661 GTK_WIDGET(pdialog->next_command), 2);
1662
1663 if (owner != client_player()) {
1664 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->prev_command), FALSE);
1665 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->next_command), FALSE);
1666 }
1667
1668 close_command = gtk_dialog_add_button(GTK_DIALOG(pdialog->shell),
1669 _("_Close"), GTK_RESPONSE_CLOSE);
1670
1671 gtk_dialog_set_default_response(GTK_DIALOG(pdialog->shell),
1672 GTK_RESPONSE_CLOSE);
1673
1674 g_signal_connect(close_command, "clicked",
1675 G_CALLBACK(close_callback), pdialog);
1676
1677 g_signal_connect(pdialog->prev_command, "clicked",
1678 G_CALLBACK(switch_city_callback), pdialog);
1679
1680 g_signal_connect(pdialog->next_command, "clicked",
1681 G_CALLBACK(switch_city_callback), pdialog);
1682
1683 /* Some other things we gotta do */
1684
1685 controller = gtk_event_controller_key_new();
1686 g_signal_connect(controller, "key-pressed",
1687 G_CALLBACK(citydlg_keyboard_handler), pdialog);
1688 gtk_widget_add_controller(pdialog->shell, controller);
1689
1690 dialog_list_prepend(dialog_list, pdialog);
1691
1692 real_city_dialog_refresh(pdialog->pcity);
1693
1694 /* Need to do this every time a new dialog is opened. */
1695 city_dialog_update_prev_next();
1696
1697 gtk_widget_set_visible(pdialog->shell, TRUE);
1698
1699 gtk_window_set_focus(GTK_WINDOW(pdialog->shell), close_command);
1700
1701 return pdialog;
1702}
1703
1704/**************** Functions to update parts of the dialog *****************/
1705
1706/***********************************************************************/
1709 static void city_dialog_update_title(struct city_dialog *pdialog)
1710{
1711 gchar *buf;
1712 const gchar *now;
1713
1714 if (city_unhappy(pdialog->pcity)) {
1715 /* TRANS: city dialog title */
1716 buf = g_strdup_printf(_("<b>%s</b> - %s citizens - DISORDER"),
1717 city_name_get(pdialog->pcity),
1718 population_to_text(city_population(pdialog->pcity)));
1719 } else if (city_celebrating(pdialog->pcity)) {
1720 /* TRANS: city dialog title */
1721 buf = g_strdup_printf(_("<b>%s</b> - %s citizens - celebrating"),
1722 city_name_get(pdialog->pcity),
1723 population_to_text(city_population(pdialog->pcity)));
1724 } else if (city_happy(pdialog->pcity)) {
1725 /* TRANS: city dialog title */
1726 buf = g_strdup_printf(_("<b>%s</b> - %s citizens - happy"),
1727 city_name_get(pdialog->pcity),
1728 population_to_text(city_population(pdialog->pcity)));
1729 } else {
1730 /* TRANS: city dialog title */
1731 buf = g_strdup_printf(_("<b>%s</b> - %s citizens"),
1732 city_name_get(pdialog->pcity),
1733 population_to_text(city_population(pdialog->pcity)));
1734 }
1735
1736 now = gtk_label_get_text(GTK_LABEL(pdialog->name_label));
1737 if (strcmp(now, buf) != 0) {
1738 gtk_window_set_title(GTK_WINDOW(pdialog->shell), city_name_get(pdialog->pcity));
1739 gtk_label_set_markup(GTK_LABEL(pdialog->name_label), buf);
1740 }
1741
1742 g_free(buf);
1743}
1744
1745/***********************************************************************/
1748 static void city_dialog_update_citizens(struct city_dialog *pdialog)
1749{
1750 enum citizen_category categories[MAX_CITY_SIZE];
1751 int i, width, full_width, total_used_width;
1752 int citizen_bar_width, citizen_bar_height;
1753 struct city *pcity = pdialog->pcity;
1754 int num_citizens = get_city_citizen_types(pcity, FEELING_FINAL, categories);
1755 cairo_t *cr;
1756
1757 /* If there is not enough space we stack the icons. We draw from left to */
1758 /* right. width is how far we go to the right for each drawn pixmap. The */
1759 /* last icon is always drawn in full, and so has reserved */
1760 /* tileset_small_sprite_width(tileset) pixels. */
1761
1762 full_width = tileset_small_sprite_width(tileset);
1763 if (num_citizens > 1) {
1764 width = MIN(full_width, ((NUM_CITIZENS_SHOWN - 1) * full_width)
1765 / (num_citizens - 1));
1766 } else {
1767 width = full_width;
1768 }
1769 pdialog->cwidth = width;
1770
1771 /* overview page */
1772 /* keep these values in sync with create_city_dialog */
1773 citizen_bar_width = full_width * NUM_CITIZENS_SHOWN;
1774 citizen_bar_height = tileset_small_sprite_height(tileset);
1775
1776 cr = cairo_create(pdialog->citizen_surface);
1777
1778 for (i = 0; i < num_citizens; i++) {
1779 cairo_set_source_surface(cr,
1780 get_citizen_sprite(tileset, categories[i], i, pcity)->surface,
1781 i * width, 0);
1782 cairo_rectangle(cr, i * width, 0,
1783 /* Always draw last citizen in full */
1784 i + 1 < num_citizens ? width : full_width,
1785 citizen_bar_height);
1786 cairo_fill(cr);
1787 }
1788
1789 total_used_width = (i - 1) * width + full_width;
1790
1791 if (total_used_width < citizen_bar_width) {
1792 /* Clear the rest of the area.
1793 * Note that this might still be necessary even in cases where
1794 * num_citizens > NUM_CITIZENS_SHOWN, if the available width cannot be
1795 * divided perfectly. */
1796 cairo_rectangle(cr, total_used_width, 0,
1797 citizen_bar_width - total_used_width,
1798 citizen_bar_height);
1799 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
1800 cairo_fill(cr);
1801 }
1802
1803 cairo_destroy(cr);
1804
1805 picture_set_from_surface(GTK_PICTURE(pdialog->citizen_pics),
1806 pdialog->citizen_surface);
1807
1808 gtk_widget_queue_draw(pdialog->citizen_pics);
1809}
1810
1811/***********************************************************************/
1814 static void city_dialog_update_information(GtkWidget **info_label,
1815 struct city_dialog *pdialog)
1816{
1817 int i, illness = 0;
1818 char buf[NUM_INFO_FIELDS][512];
1819 struct city *pcity = pdialog->pcity;
1820 int granaryturns;
1821 int non_workers = city_specialists(pcity);
1822
1823 /* fill the buffers with the necessary info */
1824 if (non_workers) {
1825 fc_snprintf(buf[INFO_SIZE], sizeof(buf[INFO_SIZE]), "%3d (%3d)",
1826 pcity->size, non_workers);
1827 } else {
1828 fc_snprintf(buf[INFO_SIZE], sizeof(buf[INFO_SIZE]), "%3d", pcity->size);
1829 }
1830 fc_snprintf(buf[INFO_FOOD], sizeof(buf[INFO_FOOD]), "%3d (%+4d)",
1831 pcity->prod[O_FOOD], pcity->surplus[O_FOOD]);
1832 fc_snprintf(buf[INFO_SHIELD], sizeof(buf[INFO_SHIELD]), "%3d (%+4d)",
1833 pcity->prod[O_SHIELD] + pcity->waste[O_SHIELD],
1834 pcity->surplus[O_SHIELD]);
1835 fc_snprintf(buf[INFO_TRADE], sizeof(buf[INFO_TRADE]), "%3d (%+4d)",
1836 pcity->surplus[O_TRADE] + pcity->waste[O_TRADE],
1837 pcity->surplus[O_TRADE]);
1838 fc_snprintf(buf[INFO_GOLD], sizeof(buf[INFO_GOLD]), "%3d (%+4d)",
1839 pcity->prod[O_GOLD], pcity->surplus[O_GOLD]);
1840 fc_snprintf(buf[INFO_LUXURY], sizeof(buf[INFO_LUXURY]), "%3d",
1841 pcity->prod[O_LUXURY]);
1842 fc_snprintf(buf[INFO_SCIENCE], sizeof(buf[INFO_SCIENCE]), "%3d",
1843 pcity->prod[O_SCIENCE]);
1844 fc_snprintf(buf[INFO_GRANARY], sizeof(buf[INFO_GRANARY]), "%4d/%-4d",
1845 pcity->food_stock, city_granary_size(city_size_get(pcity)));
1846
1847 granaryturns = city_turns_to_grow(pcity);
1848 if (granaryturns == 0) {
1849 /* TRANS: city growth is blocked. Keep short. */
1850 fc_snprintf(buf[INFO_GROWTH], sizeof(buf[INFO_GROWTH]), _("blocked"));
1851 } else if (granaryturns == FC_INFINITY) {
1852 /* TRANS: city is not growing. Keep short. */
1853 fc_snprintf(buf[INFO_GROWTH], sizeof(buf[INFO_GROWTH]), _("never"));
1854 } else {
1855 /* A negative value means we'll have famine in that many turns.
1856 But that's handled down below. */
1857 /* TRANS: city growth turns. Keep short. */
1858 fc_snprintf(buf[INFO_GROWTH], sizeof(buf[INFO_GROWTH]),
1859 PL_("%d turn", "%d turns", abs(granaryturns)),
1860 abs(granaryturns));
1861 }
1862 fc_snprintf(buf[INFO_CORRUPTION], sizeof(buf[INFO_CORRUPTION]), "%4d",
1863 pcity->waste[O_TRADE]);
1864 fc_snprintf(buf[INFO_WASTE], sizeof(buf[INFO_WASTE]), "%4d",
1865 pcity->waste[O_SHIELD]);
1866 fc_snprintf(buf[INFO_CULTURE], sizeof(buf[INFO_CULTURE]), "%4d",
1867 pcity->client.culture);
1868 fc_snprintf(buf[INFO_POLLUTION], sizeof(buf[INFO_POLLUTION]), "%4d",
1869 pcity->pollution);
1870 if (!game.info.illness_on) {
1871 fc_snprintf(buf[INFO_ILLNESS], sizeof(buf[INFO_ILLNESS]), " -.-");
1872 } else {
1873 illness = city_illness_calc(pcity, NULL, NULL, NULL, NULL);
1874 /* illness is in tenth of percent */
1875 fc_snprintf(buf[INFO_ILLNESS], sizeof(buf[INFO_ILLNESS]), "%5.1f%%",
1876 (float)illness / 10.0);
1877 }
1878 if (pcity->steal) {
1879 fc_snprintf(buf[INFO_STEAL], sizeof(buf[INFO_STEAL]), PL_("%d time", "%d times", pcity->steal),
1880 pcity->steal);
1881 } else {
1882 fc_snprintf(buf[INFO_STEAL], sizeof(buf[INFO_STEAL]), _("Not stolen"));
1883 }
1884
1885 get_city_dialog_airlift_value(pcity, buf[INFO_AIRLIFT], sizeof(buf[INFO_AIRLIFT]));
1886
1887 /* stick 'em in the labels */
1888 for (i = 0; i < NUM_INFO_FIELDS; i++) {
1889 gtk_label_set_text(GTK_LABEL(info_label[i]), buf[i]);
1890 }
1891
1892 /*
1893 * Make use of the emergency-indicating styles set up for certain labels
1894 * in create_city_info_table().
1895 */
1896 /* For starvation, the "4" below is arbitrary. 3 turns should be enough
1897 * of a warning. */
1898 if (granaryturns > -4 && granaryturns < 0) {
1899 gtk_widget_add_css_class(info_label[INFO_GRANARY], "emergency");
1900 } else {
1901 gtk_widget_remove_css_class(info_label[INFO_GRANARY], "emergency");
1902 }
1903
1904 if (granaryturns == 0 || pcity->surplus[O_FOOD] < 0) {
1905 gtk_widget_add_css_class(info_label[INFO_GROWTH], "emergency");
1906 } else {
1907 gtk_widget_remove_css_class(info_label[INFO_GROWTH], "emergency");
1908 }
1909
1910 /* Someone could add the color &orange for better granularity here */
1911 if (pcity->pollution >= 10) {
1912 gtk_widget_add_css_class(info_label[INFO_POLLUTION], "emergency");
1913 } else {
1914 gtk_widget_remove_css_class(info_label[INFO_POLLUTION], "emergency");
1915 }
1916
1917 /* Illness is in tenth of percent, i.e 100 == 10.0% */
1918 if (illness >= 100) {
1919 gtk_widget_add_css_class(info_label[INFO_ILLNESS], "emergency");
1920 } else {
1921 gtk_widget_remove_css_class(info_label[INFO_ILLNESS], "emergency");
1922 }
1923}
1924
1925/***********************************************************************/
1928 static void city_dialog_update_map(struct city_dialog *pdialog)
1929{
1930 struct canvas store = FC_STATIC_CANVAS_INIT;
1931
1932 store.surface = pdialog->map_canvas_store_unscaled;
1933
1934 /* The drawing is done in three steps.
1935 * 1. First we render to a pixmap with the appropriate canvas size.
1936 * 2. Then the pixmap is rendered into a pixbuf of equal size.
1937 * 3. Finally this pixbuf is composited and scaled onto the GtkImage's
1938 * target pixbuf.
1939 */
1940
1941 city_dialog_redraw_map(pdialog->pcity, &store);
1942
1943 /* draw to real window */
1944 draw_map_canvas(pdialog);
1945}
1946
1947/***********************************************************************/
1950 static void city_dialog_update_building(struct city_dialog *pdialog)
1951{
1952 char buf[32], buf2[200];
1953 gdouble pct;
1954 GtkListStore *store;
1955 GtkTreeIter iter;
1956 struct universal targets[MAX_NUM_PRODUCTION_TARGETS];
1957 struct item items[MAX_NUM_PRODUCTION_TARGETS];
1958 int targets_used, item;
1959 struct city *pcity = pdialog->pcity;
1960 gboolean sensitive = city_can_buy(pcity);
1961 const char *descr = city_production_name_translation(pcity);
1962 int cost = city_production_build_shield_cost(pcity);
1963
1964 if (pdialog->overview.buy_command != NULL) {
1965 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->overview.buy_command), sensitive);
1966 }
1967 if (pdialog->production.buy_command != NULL) {
1968 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->production.buy_command), sensitive);
1969 }
1970
1971 /* Make sure build slots info is up to date */
1972 if (pdialog->production.production_label != NULL) {
1973 int build_slots = city_build_slots(pcity);
1974
1975 /* Only display extra info if more than one slot is available */
1976 if (build_slots > 1) {
1977 fc_snprintf(buf2, sizeof(buf2),
1978 /* TRANS: never actually used with built_slots <= 1 */
1979 PL_("Production (up to %d unit per turn):",
1980 "Production (up to %d units per turn):", build_slots),
1981 build_slots);
1982 gtk_label_set_text(
1983 GTK_LABEL(pdialog->production.production_label), buf2);
1984 } else {
1985 gtk_label_set_text(
1986 GTK_LABEL(pdialog->production.production_label), _("Production:"));
1987 }
1988 }
1989
1990 /* Update what the city is working on */
1991 get_city_dialog_production(pcity, buf, sizeof(buf));
1992
1993 if (cost > 0) {
1994 pct = (gdouble) pcity->shield_stock / (gdouble) cost;
1995 pct = CLAMP(pct, 0.0, 1.0);
1996 } else {
1997 pct = 1.0;
1998 }
1999
2000 if (pdialog->overview.production_bar != NULL) {
2001 fc_snprintf(buf2, sizeof(buf2), "%s%s\n%s", descr,
2002 worklist_is_empty(&pcity->worklist) ? "" : " (+)", buf);
2003 gtk_progress_bar_set_text(
2004 GTK_PROGRESS_BAR(pdialog->overview.production_bar), buf2);
2005 gtk_progress_bar_set_fraction(
2006 GTK_PROGRESS_BAR(pdialog->overview.production_bar), pct);
2007 }
2008
2009 if (pdialog->production.production_bar != NULL) {
2010 fc_snprintf(buf2, sizeof(buf2), "%s%s: %s", descr,
2011 worklist_is_empty(&pcity->worklist) ? "" : " (+)", buf);
2012 gtk_progress_bar_set_text(
2013 GTK_PROGRESS_BAR(pdialog->production.production_bar), buf2);
2014 gtk_progress_bar_set_fraction(
2015 GTK_PROGRESS_BAR(pdialog->production.production_bar), pct);
2016 }
2017
2018 store = pdialog->overview.change_production_store;
2019 if (store != NULL) {
2020 int cur = -1;
2021 int actcount = 0;
2022
2023 if (pdialog->overview.production_combo != NULL) {
2024 gtk_combo_box_set_active(GTK_COMBO_BOX(pdialog->overview.production_combo),
2025 -1);
2026 }
2027
2028 gtk_list_store_clear(store);
2029
2030 targets_used
2031 = collect_eventually_buildable_targets(targets, pdialog->pcity, FALSE);
2032 name_and_sort_items(targets, targets_used, items, FALSE, pcity);
2033
2034 for (item = 0; item < targets_used; item++) {
2035 if (can_city_build_now(pcity, &items[item].item)) {
2036 const char *name;
2037 struct sprite *sprite;
2038 GdkPixbuf *pix;
2039 struct universal *target = &items[item].item;
2040 bool useless;
2041
2042 if (VUT_UTYPE == target->kind) {
2043 name = utype_name_translation(target->value.utype);
2044 sprite = get_unittype_sprite(tileset, target->value.utype,
2045 ACTIVITY_LAST, direction8_invalid());
2046 useless = FALSE;
2047 } else {
2048 name = improvement_name_translation(target->value.building);
2049 sprite = get_building_sprite(tileset, target->value.building);
2050 useless = is_improvement_redundant(pcity, target->value.building);
2051 }
2052 pix = sprite_get_pixbuf(sprite);
2053 gtk_list_store_append(store, &iter);
2054 gtk_list_store_set(store, &iter, 0, pix,
2055 1, name, 3, useless,
2056 2, (gint)cid_encode(items[item].item), -1);
2057 g_object_unref(G_OBJECT(pix));
2058
2059 if (are_universals_equal(target, &pcity->production)) {
2060 cur = actcount;
2061 }
2062
2063 actcount++;
2064 }
2065 }
2066
2067 if (pdialog->overview.production_combo != NULL) {
2068 gtk_combo_box_set_active(GTK_COMBO_BOX(pdialog->overview.production_combo),
2069 cur);
2070 }
2071 }
2072}
2073
2074/***********************************************************************/
2077 static void city_dialog_update_improvement_list(struct city_dialog *pdialog)
2078{
2079 int item, targets_used;
2080 struct universal targets[MAX_NUM_PRODUCTION_TARGETS];
2081 struct item items[MAX_NUM_PRODUCTION_TARGETS];
2082 GtkTreeModel *model;
2083 GtkListStore *store;
2084
2085 const char *tooltip_sellable = _("Press <b>ENTER</b> or double-click to "
2086 "sell an improvement.");
2087 const char *tooltip_great_wonder = _("Great Wonder - cannot be sold.");
2088 const char *tooltip_small_wonder = _("Small Wonder - cannot be sold.");
2089
2090 model =
2091 gtk_tree_view_get_model(GTK_TREE_VIEW(pdialog->overview.improvement_list));
2092 store = GTK_LIST_STORE(model);
2093
2094 targets_used = collect_already_built_targets(targets, pdialog->pcity);
2095 name_and_sort_items(targets, targets_used, items, FALSE, pdialog->pcity);
2096
2097 gtk_list_store_clear(store);
2098
2099 for (item = 0; item < targets_used; item++) {
2100 GdkPixbuf *pix;
2101 GtkTreeIter it;
2102 int upkeep;
2103 struct sprite *sprite;
2104 struct universal target = items[item].item;
2105
2106 fc_assert_action(VUT_IMPROVEMENT == target.kind, continue);
2107 /* This takes effects (like Adam Smith's) into account. */
2108 upkeep = city_improvement_upkeep(pdialog->pcity, target.value.building);
2109 sprite = get_building_sprite(tileset, target.value.building);
2110
2111 pix = sprite_get_pixbuf(sprite);
2112 gtk_list_store_append(store, &it);
2113 gtk_list_store_set(store, &it,
2114 0, target.value.building,
2115 1, pix,
2116 2, items[item].descr,
2117 3, upkeep,
2118 4,
2119 is_improvement_redundant(pdialog->pcity,
2120 target.value.building),
2121 5,
2122 is_great_wonder(target.value.building) ?
2123 tooltip_great_wonder :
2124 (is_small_wonder(target.value.building) ?
2125 tooltip_small_wonder : tooltip_sellable),
2126 -1);
2127 g_object_unref(G_OBJECT(pix));
2128 }
2129}
2130
2131/***********************************************************************/
2134 static void city_dialog_update_supported_units(struct city_dialog *pdialog)
2135{
2136 struct unit_list *units;
2137 struct unit_node_vector *nodes;
2138 int n, m, i;
2139 gchar *buf;
2140 int free_unhappy = get_city_bonus(pdialog->pcity, EFT_MAKE_CONTENT_MIL);
2141
2142 if (NULL != client.conn.playing
2143 && city_owner(pdialog->pcity) != client.conn.playing) {
2144 units = pdialog->pcity->client.info_units_supported;
2145 } else {
2146 units = pdialog->pcity->units_supported;
2147 }
2148
2149 nodes = &pdialog->overview.supported_units;
2150
2151 n = unit_list_size(units);
2152 m = unit_node_vector_size(nodes);
2153
2154 if (m > n) {
2155 i = 0;
2156 unit_node_vector_iterate(nodes, elt) {
2157 if (i++ >= n) {
2158 gtk_box_remove(GTK_BOX(pdialog->overview.supported_unit_table),
2159 elt->cmd);
2160 }
2161 } unit_node_vector_iterate_end;
2162
2163 unit_node_vector_reserve(nodes, n);
2164 } else {
2165 for (i = m; i < n; i++) {
2166 GtkWidget *cmd, *pix;
2167 struct unit_node node;
2168
2169 cmd = gtk_button_new();
2170 node.cmd = cmd;
2171
2172 gtk_button_set_has_frame(GTK_BUTTON(cmd), FALSE);
2173
2174 pix = gtk_picture_new();
2175 node.pix = pix;
2176 node.height = tileset_unit_with_upkeep_height(tileset);
2177
2178 gtk_button_set_child(GTK_BUTTON(cmd), pix);
2179
2180 gtk_box_append(GTK_BOX(pdialog->overview.supported_unit_table),
2181 cmd);
2182
2183 node.left = NULL;
2184 node.middle = NULL;
2185 node.right = NULL;
2186
2187 unit_node_vector_append(nodes, node);
2188 }
2189 }
2190
2191 i = 0;
2192 unit_list_iterate(units, punit) {
2193 struct unit_node *pnode;
2194 int happy_cost = city_unit_unhappiness(punit, &free_unhappy);
2195
2196 pnode = unit_node_vector_get(nodes, i);
2197 if (pnode) {
2198 GtkWidget *cmd, *pix;
2199 GtkGesture *gesture;
2200 GtkEventController *controller;
2201
2202 cmd = pnode->cmd;
2203 pix = pnode->pix;
2204
2205 put_unit_picture_city_overlays(punit, GTK_PICTURE(pix), pnode->height,
2206 punit->upkeep, happy_cost);
2207
2208 if (pnode->left != NULL) {
2209 gtk_widget_remove_controller(cmd, pnode->left);
2210 gtk_widget_remove_controller(cmd, pnode->middle);
2211 gtk_widget_remove_controller(cmd, pnode->right);
2212 }
2213
2214 gtk_widget_set_tooltip_text(cmd, unit_description(punit));
2215
2216 controller = GTK_EVENT_CONTROLLER(gtk_gesture_click_new());
2217 g_signal_connect(controller, "pressed",
2218 G_CALLBACK(supported_unit_callback),
2219 GINT_TO_POINTER(punit->id));
2220 gtk_widget_add_controller(cmd, controller);
2221 pnode->left = controller;
2222 gesture = gtk_gesture_click_new();
2223 gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 2);
2224 controller = GTK_EVENT_CONTROLLER(gesture);
2225 g_signal_connect(controller, "released",
2226 G_CALLBACK(middle_supported_unit_release),
2227 GINT_TO_POINTER(punit->id));
2228 gtk_widget_add_controller(cmd, controller);
2229 pnode->middle = controller;
2230 gesture = gtk_gesture_click_new();
2231 gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 3);
2232 controller = GTK_EVENT_CONTROLLER(gesture);
2233 g_signal_connect(controller, "released",
2234 G_CALLBACK(right_unit_release),
2235 GINT_TO_POINTER(punit->id));
2236 gtk_widget_add_controller(cmd, controller);
2237 pnode->right = controller;
2238
2239 if (city_owner(pdialog->pcity) != client.conn.playing) {
2240 gtk_widget_set_sensitive(cmd, FALSE);
2241 } else {
2242 gtk_widget_set_sensitive(cmd, TRUE);
2243 }
2244
2245 gtk_widget_set_visible(pix, TRUE);
2246 gtk_widget_set_visible(cmd, TRUE);
2247 }
2248 i++;
2249 } unit_list_iterate_end;
2250
2251 buf = g_strdup_printf(_("Supported units %d"), n);
2252 gtk_frame_set_label(GTK_FRAME(pdialog->overview.supported_units_frame), buf);
2253 g_free(buf);
2254}
2255
2256/***********************************************************************/
2259 static void city_dialog_update_present_units(struct city_dialog *pdialog)
2260{
2261 struct unit_list *units;
2262 struct unit_node_vector *nodes;
2263 int n, m, i;
2264 gchar *buf;
2265
2266 if (NULL != client.conn.playing
2267 && city_owner(pdialog->pcity) != client.conn.playing) {
2268 units = pdialog->pcity->client.info_units_present;
2269 } else {
2270 units = pdialog->pcity->tile->units;
2271 }
2272
2273 nodes = &pdialog->overview.present_units;
2274
2275 n = unit_list_size(units);
2276 m = unit_node_vector_size(nodes);
2277
2278 if (m > n) {
2279 i = 0;
2280 unit_node_vector_iterate(nodes, elt) {
2281 if (i++ >= n) {
2282 gtk_box_remove(GTK_BOX(pdialog->overview.present_unit_table),
2283 elt->cmd);
2284 }
2285 } unit_node_vector_iterate_end;
2286
2287 unit_node_vector_reserve(nodes, n);
2288 } else {
2289 for (i = m; i < n; i++) {
2290 GtkWidget *cmd, *pix;
2291 struct unit_node node;
2292
2293 cmd = gtk_button_new();
2294 node.cmd = cmd;
2295
2296 gtk_button_set_has_frame(GTK_BUTTON(cmd), FALSE);
2297
2298 pix = gtk_picture_new();
2299 node.pix = pix;
2300 node.height = tileset_full_tile_height(tileset);
2301
2302 gtk_button_set_child(GTK_BUTTON(cmd), pix);
2303
2304 gtk_box_append(GTK_BOX(pdialog->overview.present_unit_table),
2305 cmd);
2306
2307 node.left = NULL;
2308 node.middle = NULL;
2309 node.right = NULL;
2310
2311 unit_node_vector_append(nodes, node);
2312 }
2313 }
2314
2315 i = 0;
2316 unit_list_iterate(units, punit) {
2317 struct unit_node *pnode;
2318
2319 pnode = unit_node_vector_get(nodes, i);
2320 if (pnode) {
2321 GtkWidget *cmd, *pix;
2322 GtkEventController *controller;
2323 GtkGesture *gesture;
2324
2325 cmd = pnode->cmd;
2326 pix = pnode->pix;
2327
2328 put_unit_picture(punit, GTK_PICTURE(pix), pnode->height);
2329
2330 if (pnode->left != NULL) {
2331 gtk_widget_remove_controller(cmd, pnode->left);
2332 gtk_widget_remove_controller(cmd, pnode->middle);
2333 gtk_widget_remove_controller(cmd, pnode->right);
2334 }
2335
2336 gtk_widget_set_tooltip_text(cmd, unit_description(punit));
2337
2338 controller = GTK_EVENT_CONTROLLER(gtk_gesture_click_new());
2339 g_signal_connect(controller, "pressed",
2340 G_CALLBACK(present_unit_callback),
2341 GINT_TO_POINTER(punit->id));
2342 gtk_widget_add_controller(cmd, controller);
2343 pnode->left = controller;
2344 gesture = gtk_gesture_click_new();
2345 gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 2);
2346 controller = GTK_EVENT_CONTROLLER(gesture);
2347 g_signal_connect(controller, "released",
2348 G_CALLBACK(middle_present_unit_release),
2349 GINT_TO_POINTER(punit->id));
2350 gtk_widget_add_controller(cmd, controller);
2351 pnode->middle = controller;
2352 gesture = gtk_gesture_click_new();
2353 gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 3);
2354 controller = GTK_EVENT_CONTROLLER(gesture);
2355 g_signal_connect(controller, "released",
2356 G_CALLBACK(right_unit_release),
2357 GINT_TO_POINTER(punit->id));
2358 gtk_widget_add_controller(cmd, controller);
2359 pnode->right = controller;
2360
2361 if (city_owner(pdialog->pcity) != client.conn.playing) {
2362 gtk_widget_set_sensitive(cmd, FALSE);
2363 } else {
2364 gtk_widget_set_sensitive(cmd, TRUE);
2365 }
2366
2367 gtk_widget_set_visible(pix, TRUE);
2368 gtk_widget_set_visible(cmd, TRUE);
2369 }
2370 i++;
2371 } unit_list_iterate_end;
2372
2373 buf = g_strdup_printf(_("Present units %d"), n);
2374 gtk_frame_set_label(GTK_FRAME(pdialog->overview.present_units_frame), buf);
2375 g_free(buf);
2376}
2377
2378/***********************************************************************/
2385 static void city_dialog_update_prev_next(void)
2386{
2387 int count = 0;
2388 int city_number;
2389
2390 if (NULL != client.conn.playing) {
2391 city_number = city_list_size(client.conn.playing->cities);
2392 } else {
2393 city_number = FC_INFINITY; /* ? */
2394 }
2395
2396 /* The first time, we see if all the city dialogs are open */
2397 dialog_list_iterate(dialog_list, pdialog) {
2398 if (city_owner(pdialog->pcity) == client.conn.playing) {
2399 count++;
2400 }
2401 } dialog_list_iterate_end;
2402
2403 if (count == city_number) { /* All are open, shouldn't prev/next */
2404 dialog_list_iterate(dialog_list, pdialog) {
2405 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->prev_command), FALSE);
2406 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->next_command), FALSE);
2407 } dialog_list_iterate_end;
2408 } else {
2409 dialog_list_iterate(dialog_list, pdialog) {
2410 if (city_owner(pdialog->pcity) == client.conn.playing) {
2411 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->prev_command), TRUE);
2412 gtk_widget_set_sensitive(GTK_WIDGET(pdialog->next_command), TRUE);
2413 }
2414 } dialog_list_iterate_end;
2415 }
2416}
2417
2418/***********************************************************************/
2421 static void citydlg_response_callback(GtkDialog *dlg, gint response,
2422 void *data)
2423{
2424 switch (response) {
2425 case CDLGR_UNITS:
2426 show_units_response(data);
2427 break;
2428 }
2429}
2430
2431/***********************************************************************/
2434 static void show_units_response(void *data)
2435{
2436 struct city_dialog *pdialog = (struct city_dialog *) data;
2437 struct tile *ptile = pdialog->pcity->tile;
2438
2439 if (unit_list_size(ptile->units)) {
2440 unit_select_dialog_popup(ptile);
2441 }
2442}
2443
2444/***********************************************************************/
2454 static bool create_unit_menu(struct city_dialog *pdialog, struct unit *punit,
2455 GtkWidget *wdg, bool supported)
2456{
2457 GMenu *menu;
2458 GActionGroup *group;
2459 GSimpleAction *act;
2460
2461 if (!can_client_issue_orders()) {
2462 return FALSE;
2463 }
2464
2465 if (pdialog->popover != NULL) {
2466 close_citydlg_unit_popover(pdialog);
2467 }
2468
2469 group = G_ACTION_GROUP(g_simple_action_group_new());
2470 menu = g_menu_new();
2471
2472 if (supported) {
2473 act = g_simple_action_new("center", NULL);
2474 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2475 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2476 g_signal_connect(act, "activate", G_CALLBACK(unit_center_callback),
2477 GINT_TO_POINTER(punit->id));
2478 menu_item_append_unref(menu, g_menu_item_new(_("Cen_ter"), "win.center"));
2479 }
2480
2481 act = g_simple_action_new("activate", NULL);
2482 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2483 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2484 g_signal_connect(act, "activate", G_CALLBACK(unit_activate_callback),
2485 GINT_TO_POINTER(punit->id));
2486 menu_item_append_unref(menu, g_menu_item_new(_("_Activate unit"),
2487 "win.activate"));
2488
2489 act = g_simple_action_new("activate_close", NULL);
2490 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2491 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2492
2493 if (supported) {
2494 g_signal_connect(act, "activate",
2495 G_CALLBACK(supported_unit_activate_close_callback),
2496 GINT_TO_POINTER(punit->id));
2497 } else {
2498 g_signal_connect(act, "activate",
2499 G_CALLBACK(present_unit_activate_close_callback),
2500 GINT_TO_POINTER(punit->id));
2501 }
2502
2503 menu_item_append_unref(menu,
2504 g_menu_item_new(_("Activate unit, _close dialog"),
2505 "win.activate_close"));
2506
2507 if (!supported) {
2508 act = g_simple_action_new("load", NULL);
2509 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2510 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2511 g_signal_connect(act, "activate", G_CALLBACK(unit_load_callback),
2512 GINT_TO_POINTER(punit->id));
2513 g_simple_action_set_enabled(G_SIMPLE_ACTION(act), unit_can_load(punit));
2514 menu_item_append_unref(menu, g_menu_item_new(_("_Load unit"), "win.load"));
2515
2516 act = g_simple_action_new("unload", NULL);
2517 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2518 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2519 g_signal_connect(act, "activate", G_CALLBACK(unit_unload_callback),
2520 GINT_TO_POINTER(punit->id));
2521 g_simple_action_set_enabled(G_SIMPLE_ACTION(act),
2522 can_unit_unload(punit,
2523 unit_transport_get(punit))
2524 && can_unit_exist_at_tile(&(wld.map), punit,
2525 unit_tile(punit)));
2526 menu_item_append_unref(menu, g_menu_item_new(_("_Unload unit"),
2527 "win.unload"));
2528
2529 act = g_simple_action_new("sentry", NULL);
2530 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2531 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2532 g_signal_connect(act, "activate", G_CALLBACK(unit_sentry_callback),
2533 GINT_TO_POINTER(punit->id));
2534 g_simple_action_set_enabled(G_SIMPLE_ACTION(act),
2535 punit->activity != ACTIVITY_SENTRY
2536 && can_unit_do_activity_client(punit,
2537 ACTIVITY_SENTRY));
2538 menu_item_append_unref(menu, g_menu_item_new(_("_Sentry unit"),
2539 "win.sentry"));
2540
2541 act = g_simple_action_new("fortify", NULL);
2542 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2543 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2544 g_signal_connect(act, "activate", G_CALLBACK(unit_fortify_callback),
2545 GINT_TO_POINTER(punit->id));
2546 g_simple_action_set_enabled(G_SIMPLE_ACTION(act),
2547 punit->activity != ACTIVITY_FORTIFYING
2548 && can_unit_do_activity_client(punit,
2549 ACTIVITY_FORTIFYING));
2550 menu_item_append_unref(menu, g_menu_item_new(_("_Fortify unit"),
2551 "win.fortify"));
2552 }
2553
2554 act = g_simple_action_new("disband", NULL);
2555 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2556 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2557 g_signal_connect(act, "activate", G_CALLBACK(unit_disband_callback),
2558 GINT_TO_POINTER(punit->id));
2559 g_simple_action_set_enabled(G_SIMPLE_ACTION(act),
2560 unit_can_do_action(punit, ACTION_DISBAND_UNIT));
2561 menu_item_append_unref(menu, g_menu_item_new(_("_Disband unit"),
2562 "win.disband"));
2563
2564 if (!supported) {
2565 act = g_simple_action_new("rehome", NULL);
2566 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2567 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2568 g_signal_connect(act, "activate", G_CALLBACK(unit_homecity_callback),
2569 GINT_TO_POINTER(punit->id));
2570 g_simple_action_set_enabled(G_SIMPLE_ACTION(act),
2571 can_unit_change_homecity_to(punit,
2572 pdialog->pcity));
2573 menu_item_append_unref(menu,
2574 g_menu_item_new(action_id_name_translation(ACTION_HOME_CITY),
2575 "win.rehome"));
2576
2577 act = g_simple_action_new("upgrade", NULL);
2578 g_object_set_data(G_OBJECT(act), "dlg", pdialog);
2579 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2580 g_signal_connect(act, "activate", G_CALLBACK(unit_upgrade_callback),
2581 GINT_TO_POINTER(punit->id));
2582 g_simple_action_set_enabled(G_SIMPLE_ACTION(act),
2583 action_ever_possible(ACTION_UPGRADE_UNIT)
2584 && can_client_issue_orders()
2585 && can_upgrade_unittype(client_player(),
2586 unit_type_get(punit))
2587 != NULL);
2588 menu_item_append_unref(menu, g_menu_item_new(_("U_pgrade unit"),
2589 "win.upgrade"));
2590 }
2591
2592 pdialog->popover = gtk_popover_menu_new_from_model(G_MENU_MODEL(menu));
2593 g_object_ref(pdialog->popover);
2594 gtk_widget_insert_action_group(pdialog->popover, "win", group);
2595 gtk_widget_set_parent(pdialog->popover, wdg);
2596
2597
2598 gtk_popover_popup(GTK_POPOVER(pdialog->popover));
2599
2600 return TRUE;
2601}
2602
2603/***********************************************************************/
2606 static gboolean supported_unit_callback(GtkGestureClick *gesture, int n_press,
2607 double x, double y, gpointer data)
2608{
2609 struct city_dialog *pdialog;
2610 struct city *pcity;
2611 struct unit *punit =
2612 player_unit_by_number(client_player(), (size_t) data);
2613
2614 if (NULL != punit
2615 && NULL != (pcity = game_city_by_number(punit->homecity))
2616 && NULL != (pdialog = get_city_dialog(pcity))) {
2617
2618 return create_unit_menu(pdialog, punit,
2619 gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)),
2620 TRUE);
2621 }
2622
2623 return TRUE;
2624}
2625
2626/***********************************************************************/
2629 static gboolean present_unit_callback(GtkGestureClick *gesture, int n_press,
2630 double x, double y, gpointer data)
2631{
2632 struct city_dialog *pdialog;
2633 struct city *pcity;
2634 struct unit *punit =
2635 player_unit_by_number(client_player(), (size_t) data);
2636
2637 if (NULL != punit
2638 && NULL != (pcity = tile_city(unit_tile(punit)))
2639 && NULL != (pdialog = get_city_dialog(pcity))) {
2640
2641 return create_unit_menu(pdialog, punit,
2642 gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)),
2643 FALSE);
2644 }
2645
2646 return TRUE;
2647}
2648
2649/***********************************************************************/
2653 static gboolean middle_present_unit_release(GtkGestureClick *gesture,
2654 int n_press, double x, double y,
2655 gpointer data)
2656{
2657 struct city_dialog *pdialog;
2658 struct city *pcity;
2659 struct unit *punit =
2660 player_unit_by_number(client_player(), (size_t) data);
2661
2662 if (NULL != punit
2663 && NULL != (pcity = tile_city(unit_tile(punit)))
2664 && NULL != (pdialog = get_city_dialog(pcity))
2665 && can_client_issue_orders()) {
2666 unit_focus_set(punit);
2667 close_city_dialog(pdialog);
2668 }
2669
2670 return TRUE;
2671}
2672
2673/***********************************************************************/
2677 static gboolean middle_supported_unit_release(GtkGestureClick *gesture, int n_press,
2678 double x, double y, gpointer data)
2679{
2680 struct city_dialog *pdialog;
2681 struct city *pcity;
2682 struct unit *punit =
2683 player_unit_by_number(client_player(), (size_t) data);
2684
2685 if (NULL != punit
2686 && NULL != (pcity = game_city_by_number(punit->homecity))
2687 && NULL != (pdialog = get_city_dialog(pcity))
2688 && can_client_issue_orders()) {
2689 unit_focus_set(punit);
2690 close_city_dialog(pdialog);
2691 }
2692
2693 return TRUE;
2694}
2695
2696/***********************************************************************/
2699 static gboolean right_unit_release(GtkGestureClick *gesture, int n_press,
2700 double x, double y, gpointer data)
2701{
2702 struct unit *punit =
2703 player_unit_by_number(client_player(), (size_t) data);
2704
2705 if (NULL != punit
2706 && can_client_issue_orders()) {
2707 unit_focus_set(punit);
2708 }
2709
2710 return TRUE;
2711}
2712
2713/***********************************************************************/
2718 static void close_citydlg_unit_popover(struct city_dialog *pdialog)
2719{
2720 if (pdialog->popover != NULL) {
2721 gtk_widget_unparent(pdialog->popover);
2722 g_object_unref(pdialog->popover);
2723 pdialog->popover = NULL;
2724 }
2725}
2726
2727/***********************************************************************/
2730 static void unit_center_callback(GSimpleAction *action, GVariant *parameter,
2731 gpointer data)
2732{
2733 struct unit *punit =
2734 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2735
2736 if (NULL != punit) {
2737 center_tile_mapcanvas(unit_tile(punit));
2738 }
2739
2740 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2741}
2742
2743/***********************************************************************/
2746 static void unit_activate_callback(GSimpleAction *action, GVariant *parameter,
2747 gpointer data)
2748{
2749 struct unit *punit =
2750 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2751
2752 if (NULL != punit) {
2753 unit_focus_set(punit);
2754 }
2755
2756 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2757}
2758
2759/***********************************************************************/
2763 static void supported_unit_activate_close_callback(GSimpleAction *action,
2764 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) {
2771 struct city *pcity =
2772 player_city_by_number(client_player(), punit->homecity);
2773
2774 unit_focus_set(punit);
2775 if (NULL != pcity) {
2776 struct city_dialog *pdialog = get_city_dialog(pcity);
2777
2778 if (NULL != pdialog) {
2779 close_city_dialog(pdialog);
2780 }
2781 }
2782 }
2783
2784 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2785}
2786
2787/***********************************************************************/
2791 static void present_unit_activate_close_callback(GSimpleAction *action,
2792 GVariant *parameter,
2793 gpointer data)
2794{
2795 struct unit *punit =
2796 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2797
2798 if (NULL != punit) {
2799 struct city *pcity = tile_city(unit_tile(punit));
2800
2801 unit_focus_set(punit);
2802 if (NULL != pcity) {
2803 struct city_dialog *pdialog = get_city_dialog(pcity);
2804
2805 if (NULL != pdialog) {
2806 close_city_dialog(pdialog);
2807 }
2808 }
2809 }
2810
2811 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2812}
2813
2814/***********************************************************************/
2817 static void unit_load_callback(GSimpleAction *action, GVariant *parameter,
2818 gpointer data)
2819{
2820 struct unit *punit =
2821 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2822
2823 if (NULL != punit) {
2824 request_transport(punit, unit_tile(punit));
2825 }
2826
2827 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2828}
2829
2830/***********************************************************************/
2833 static void unit_unload_callback(GSimpleAction *action, GVariant *parameter,
2834 gpointer data)
2835{
2836 struct unit *punit =
2837 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2838
2839 if (NULL != punit) {
2840 request_unit_unload(punit);
2841 }
2842
2843 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2844}
2845
2846/***********************************************************************/
2849 static void unit_sentry_callback(GSimpleAction *action, GVariant *parameter,
2850 gpointer data)
2851{
2852 struct unit *punit =
2853 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2854
2855 if (NULL != punit) {
2856 request_unit_sentry(punit);
2857 }
2858
2859 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2860}
2861
2862/***********************************************************************/
2865 static void unit_fortify_callback(GSimpleAction *action, GVariant *parameter,
2866 gpointer data)
2867{
2868 struct unit *punit =
2869 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2870
2871 if (NULL != punit) {
2872 request_unit_fortify(punit);
2873 }
2874
2875 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2876}
2877
2878/***********************************************************************/
2881 static void unit_disband_callback(GSimpleAction *action, GVariant *parameter,
2882 gpointer data)
2883{
2884 struct unit_list *punits;
2885 struct unit *punit =
2886 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2887
2888 if (NULL == punit) {
2889 return;
2890 }
2891
2892 punits = unit_list_new();
2893 unit_list_append(punits, punit);
2894 popup_disband_dialog(punits);
2895 unit_list_destroy(punits);
2896
2897 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2898}
2899
2900/***********************************************************************/
2904 static void unit_homecity_callback(GSimpleAction *action, GVariant *parameter,
2905 gpointer data)
2906{
2907 struct unit *punit =
2908 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2909
2910 if (NULL != punit) {
2911 request_unit_change_homecity(punit);
2912 }
2913
2914 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2915}
2916
2917/***********************************************************************/
2920 static void unit_upgrade_callback(GSimpleAction *action, GVariant *parameter,
2921 gpointer data)
2922{
2923 struct unit_list *punits;
2924 struct unit *punit =
2925 player_unit_by_number(client_player(), GPOINTER_TO_INT(data));
2926
2927 if (NULL == punit) {
2928 return;
2929 }
2930
2931 punits = unit_list_new();
2932 unit_list_append(punits, punit);
2933 popup_upgrade_dialog(punits);
2934 unit_list_destroy(punits);
2935
2936 close_citydlg_unit_popover(g_object_get_data(G_OBJECT(action), "dlg"));
2937}
2938
2939/******** Callbacks for citizen bar, map funcs that are not update ********/
2940
2941/***********************************************************************/
2945 static gboolean citizens_callback(GtkGestureClick *gesture, int n_press,
2946 double x, double y, gpointer data)
2947{
2948 struct city_dialog *pdialog = data;
2949 struct city *pcity = pdialog->pcity;
2950 int citnum, tlen, len;
2951
2952 if (!can_client_issue_orders()) {
2953 return FALSE;
2954 }
2955
2956 tlen = tileset_small_sprite_width(tileset);
2957 len = (city_size_get(pcity) - 1) * pdialog->cwidth + tlen;
2958
2959 if (x > len) {
2960 /* No citizen that far to the right */
2961 return FALSE;
2962 }
2963 citnum = MIN(city_size_get(pcity) - 1, x / pdialog->cwidth);
2964
2965 city_rotate_specialist(pcity, citnum);
2966
2967 return TRUE;
2968}
2969
2970/***********************************************************************/
2973 static void set_city_workertask(GtkWidget *w, gpointer data)
2974{
2975 enum unit_activity act = (enum unit_activity)GPOINTER_TO_INT(data);
2976 struct city *pcity = workertask_req.owner;
2977 struct tile *ptile = workertask_req.loc;
2978 struct packet_worker_task task;
2979
2980 task.city_id = pcity->id;
2981
2982 if (act == ACTIVITY_LAST) {
2983 task.tgt = -1;
2984 task.want = 0;
2985 } else {
2986 enum extra_cause cause = activity_to_extra_cause(act);
2987 enum extra_rmcause rmcause = activity_to_extra_rmcause(act);
2988 struct extra_type *tgt;
2989
2990 if (cause != EC_NONE) {
2991 tgt = next_extra_for_tile(ptile, cause, city_owner(pcity), NULL);
2992 } else if (rmcause != ERM_NONE) {
2993 tgt = prev_extra_in_tile(ptile, rmcause, city_owner(pcity), NULL);
2994 } else {
2995 tgt = NULL;
2996 }
2997
2998 if (tgt == NULL) {
2999 struct terrain *pterr = tile_terrain(ptile);
3000
3001 if ((act != ACTIVITY_TRANSFORM
3002 || pterr->transform_result == NULL || pterr->transform_result == pterr)
3003 && (act != ACTIVITY_CULTIVATE || pterr->cultivate_result == NULL)
3004 && (act != ACTIVITY_PLANT || pterr->plant_result == NULL)) {
3005 /* No extra to order */
3006 output_window_append(ftc_client, _("There's no suitable extra to order."));
3007
3008 return;
3009 }
3010
3011 task.tgt = -1;
3012 } else {
3013 task.tgt = extra_index(tgt);
3014 }
3015
3016 task.want = 100;
3017 }
3018
3019 task.tile_id = ptile->index;
3020 task.activity = act;
3021
3022 send_packet_worker_task(&client.conn, &task);
3023}
3024
3025/***********************************************************************/
3028 static void workertask_dlg_destroy(GtkWidget *w, gpointer data)
3029{
3030 is_showing_workertask_dialog = FALSE;
3031}
3032
3033/***********************************************************************/
3036 static void popup_workertask_dlg(struct city *pcity, struct tile *ptile)
3037{
3038 if (!is_showing_workertask_dialog) {
3039 GtkWidget *shl;
3040 struct terrain *pterr = tile_terrain(ptile);
3041 struct universal for_terr = { .kind = VUT_TERRAIN,
3042 .value = { .terrain = pterr }};
3043 struct worker_task *ptask;
3044
3045 is_showing_workertask_dialog = TRUE;
3046 workertask_req.owner = pcity;
3047 workertask_req.loc = ptile;
3048
3049 shl = choice_dialog_start(GTK_WINDOW(toplevel),
3050 _("What Action to Request"),
3051 _("Select autoworker activity:"));
3052
3053 ptask = worker_task_list_get(pcity->task_reqs, 0);
3054 if (ptask != NULL) {
3055 choice_dialog_add(shl, _("Clear request"),
3056 G_CALLBACK(set_city_workertask),
3057 GINT_TO_POINTER(ACTIVITY_LAST), FALSE, NULL);
3058 }
3059
3060 if (action_id_univs_not_blocking(ACTION_MINE, NULL, &for_terr)) {
3061 choice_dialog_add(shl, Q_("?act:Mine"),
3062 G_CALLBACK(set_city_workertask),
3063 GINT_TO_POINTER(ACTIVITY_MINE), FALSE, NULL);
3064 }
3065 if (pterr->plant_result != NULL
3066 && action_id_univs_not_blocking(ACTION_PLANT,
3067 NULL, &for_terr)) {
3068 choice_dialog_add(shl, _("Plant"),
3069 G_CALLBACK(set_city_workertask),
3070 GINT_TO_POINTER(ACTIVITY_PLANT), FALSE, NULL);
3071 }
3072 if (action_id_univs_not_blocking(ACTION_IRRIGATE, NULL, &for_terr)) {
3073 choice_dialog_add(shl, _("Irrigate"),
3074 G_CALLBACK(set_city_workertask),
3075 GINT_TO_POINTER(ACTIVITY_IRRIGATE), FALSE, NULL);
3076 }
3077 if (pterr->cultivate_result != NULL
3078 && action_id_univs_not_blocking(ACTION_CULTIVATE,
3079 NULL, &for_terr)) {
3080 choice_dialog_add(shl, _("Cultivate"),
3081 G_CALLBACK(set_city_workertask),
3082 GINT_TO_POINTER(ACTIVITY_CULTIVATE), FALSE, NULL);
3083 }
3084 if (next_extra_for_tile(ptile, EC_ROAD, city_owner(pcity), NULL) != NULL) {
3085 choice_dialog_add(shl, _("Road"),
3086 G_CALLBACK(set_city_workertask),
3087 GINT_TO_POINTER(ACTIVITY_GEN_ROAD), FALSE, NULL);
3088 }
3089 if (pterr->transform_result != pterr && pterr->transform_result != NULL
3090 && action_id_univs_not_blocking(ACTION_TRANSFORM_TERRAIN,
3091 NULL, &for_terr)) {
3092 choice_dialog_add(shl, _("Transform"),
3093 G_CALLBACK(set_city_workertask),
3094 GINT_TO_POINTER(ACTIVITY_TRANSFORM), FALSE, NULL);
3095 }
3096 if (prev_extra_in_tile(ptile, ERM_CLEAN,
3097 city_owner(pcity), NULL) != NULL) {
3098 choice_dialog_add(shl, _("Clean"),
3099 G_CALLBACK(set_city_workertask),
3100 GINT_TO_POINTER(ACTIVITY_CLEAN), FALSE, NULL);
3101 }
3102
3103 choice_dialog_add(shl, _("_Cancel"), 0, 0, FALSE, NULL);
3104 choice_dialog_end(shl);
3105
3106 g_signal_connect(shl, "destroy", G_CALLBACK(workertask_dlg_destroy),
3107 NULL);
3108 }
3109}
3110
3111/***********************************************************************/
3114 static gboolean left_button_down_citymap(GtkGestureClick *gesture, int n_press,
3115 double x, double y, gpointer data)
3116{
3117 struct city_dialog *pdialog = data;
3118 int canvas_x, canvas_y, city_x, city_y;
3119
3120 if (!can_client_issue_orders()) {
3121 return FALSE;
3122 }
3123
3124 if (cma_is_city_under_agent(pdialog->pcity, NULL)) {
3125 return FALSE;
3126 }
3127
3128 canvas_x = x * (double)canvas_width / (double)CITYMAP_WIDTH;
3129 canvas_y = y * (double)canvas_height / (double)CITYMAP_HEIGHT;
3130
3131 if (canvas_to_city_pos(&city_x, &city_y,
3132 city_map_radius_sq_get(pdialog->pcity),
3133 canvas_x, canvas_y)) {
3134 city_toggle_worker(pdialog->pcity, city_x, city_y);
3135 }
3136
3137 return TRUE;
3138}
3139
3140/***********************************************************************/
3143 static gboolean right_button_down_citymap(GtkGestureClick *gesture, int n_press,
3144 double x, double y, gpointer data)
3145{
3146 struct city_dialog *pdialog = data;
3147 int canvas_x, canvas_y, city_x, city_y;
3148
3149 if (!can_client_issue_orders()) {
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 struct city *pcity = pdialog->pcity;
3160
3161 popup_workertask_dlg(pdialog->pcity,
3162 city_map_to_tile(&(wld.map), pcity->tile,
3163 city_map_radius_sq_get(pcity),
3164 city_x, city_y));
3165 }
3166
3167 return TRUE;
3168}
3169
3170/***********************************************************************/
3173 static void draw_map_canvas(struct city_dialog *pdialog)
3174{
3175 gtk_widget_queue_draw(pdialog->overview.map_canvas.darea);
3176 if (pdialog->happiness.map_canvas.darea) { /* in case of spy */
3177 gtk_widget_queue_draw(pdialog->happiness.map_canvas.darea);
3178 }
3179}
3180
3181/************** Callbacks for Buy, Change, Sell, Worklist *****************/
3182
3183/***********************************************************************/
3186 static void buy_callback_response(GtkWidget *w, gint response, gpointer data)
3187{
3188 struct city_dialog *pdialog = data;
3189
3190 if (response == GTK_RESPONSE_YES) {
3191 city_buy_production(pdialog->pcity);
3192 }
3193
3194 gtk_window_destroy(GTK_WINDOW(w));
3195}
3196
3197/***********************************************************************/
3200 static void buy_callback(GtkWidget *w, gpointer data)
3201{
3202 GtkWidget *shell;
3203 struct city_dialog *pdialog = data;
3204 const char *name = city_production_name_translation(pdialog->pcity);
3205 int value = pdialog->pcity->client.buy_cost;
3206 char buf[1024];
3207
3208 if (!can_client_issue_orders()) {
3209 return;
3210 }
3211
3212 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
3213 "Treasury contains %d gold.",
3214 client_player()->economic.gold),
3215 client_player()->economic.gold);
3216
3217 if (value <= client_player()->economic.gold) {
3218 shell = gtk_message_dialog_new(NULL,
3219 GTK_DIALOG_DESTROY_WITH_PARENT,
3220 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
3221 /* TRANS: Last %s is pre-pluralised "Treasury contains %d gold." */
3222 PL_("Buy %s for %d gold?\n%s",
3223 "Buy %s for %d gold?\n%s", value),
3224 name, value, buf);
3225 setup_dialog(shell, pdialog->shell);
3226 gtk_window_set_title(GTK_WINDOW(shell), _("Buy It!"));
3227 gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_NO);
3228 g_signal_connect(shell, "response", G_CALLBACK(buy_callback_response),
3229 pdialog);
3230 gtk_window_present(GTK_WINDOW(shell));
3231 } else {
3232 shell = gtk_message_dialog_new(NULL,
3233 GTK_DIALOG_DESTROY_WITH_PARENT,
3234 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
3235 /* TRANS: Last %s is pre-pluralised "Treasury contains %d gold." */
3236 PL_("%s costs %d gold.\n%s",
3237 "%s costs %d gold.\n%s", value),
3238 name, value, buf);
3239 setup_dialog(shell, pdialog->shell);
3240 gtk_window_set_title(GTK_WINDOW(shell), _("Buy It!"));
3241 g_signal_connect(shell, "response", G_CALLBACK(gtk_window_destroy),
3242 NULL);
3243 gtk_window_present(GTK_WINDOW(shell));
3244 }
3245}
3246
3247/***********************************************************************/
3250 static void change_production_callback(GtkComboBox *combo,
3251 struct city_dialog *pdialog)
3252{
3253 GtkTreeIter iter;
3254
3255 if (can_client_issue_orders()
3256 && gtk_combo_box_get_active_iter(combo, &iter)) {
3257 cid id;
3258 struct universal univ;
3259
3260 gtk_tree_model_get(gtk_combo_box_get_model(combo), &iter, 2, &id, -1);
3261 univ = cid_production(id);
3262 city_change_production(pdialog->pcity, &univ);
3263 }
3264}
3265
3266/***********************************************************************/
3269 static void sell_callback(struct impr_type *pimprove, gpointer data)
3270{
3271 GtkWidget *shl;
3272 struct city_dialog *pdialog = (struct city_dialog *) data;
3273 pdialog->sell_id = improvement_number(pimprove);
3274 int price;
3275
3276 if (!can_client_issue_orders()) {
3277 return;
3278 }
3279
3280 if (test_player_sell_building_now(client.conn.playing, pdialog->pcity,
3281 pimprove) != TR_SUCCESS) {
3282 return;
3283 }
3284
3285 price = impr_sell_gold(pimprove);
3286 shl = gtk_message_dialog_new(NULL,
3287 GTK_DIALOG_DESTROY_WITH_PARENT,
3288 GTK_MESSAGE_QUESTION,
3289 GTK_BUTTONS_YES_NO,
3290 PL_("Sell %s for %d gold?",
3291 "Sell %s for %d gold?", price),
3292 city_improvement_name_translation(pdialog->pcity, pimprove), price);
3293 setup_dialog(shl, pdialog->shell);
3294 pdialog->sell_shell = shl;
3295
3296 gtk_window_set_title(GTK_WINDOW(shl), _("Sell It!"));
3297
3298 g_signal_connect(shl, "response",
3299 G_CALLBACK(sell_callback_response), pdialog);
3300
3301 gtk_window_present(GTK_WINDOW(shl));
3302}
3303
3304/***********************************************************************/
3307 static void sell_callback_response(GtkWidget *w, gint response, gpointer data)
3308{
3309 struct city_dialog *pdialog = data;
3310
3311 if (response == GTK_RESPONSE_YES) {
3312 city_sell_improvement(pdialog->pcity, pdialog->sell_id);
3313 }
3314 gtk_window_destroy(GTK_WINDOW(w));
3315
3316 pdialog->sell_shell = NULL;
3317}
3318
3319/***********************************************************************/
3322 static void impr_callback(GtkTreeView *view, GtkTreePath *path,
3323 GtkTreeViewColumn *col, gpointer data)
3324{
3325 GtkTreeModel *model;
3326 GtkTreeIter it;
3327 GdkSeat *seat;
3328 GdkModifierType mask;
3329 struct impr_type *pimprove;
3330
3331 model = gtk_tree_view_get_model(view);
3332
3333 if (!gtk_tree_model_get_iter(model, &it, path)) {
3334 return;
3335 }
3336
3337 gtk_tree_model_get(model, &it, 0, &pimprove, -1);
3338
3339 seat = gdk_display_get_default_seat(gtk_widget_get_display(GTK_WIDGET(view)));
3340 mask = gdk_device_get_modifier_state(gdk_seat_get_keyboard(seat));
3341
3342 if (!(mask & GDK_CONTROL_MASK)) {
3343 sell_callback(pimprove, data);
3344 } else {
3345 if (is_great_wonder(pimprove)) {
3346 popup_help_dialog_typed(improvement_name_translation(pimprove), HELP_WONDER);
3347 } else {
3348 popup_help_dialog_typed(improvement_name_translation(pimprove), HELP_IMPROVEMENT);
3349 }
3350 }
3351}
3352
3353/************ Callbacks for stuff on the Misc. Settings page **************/
3354
3355/***********************************************************************/
3358 static void rename_callback(GtkWidget *w, gpointer data)
3359{
3360 struct city_dialog *pdialog;
3361
3362 pdialog = (struct city_dialog *) data;
3363
3364 pdialog->rename_shell = input_dialog_create(GTK_WINDOW(pdialog->shell),
3365 /* "shellrenamecity" */
3366 _("Rename City"),
3367 _("What should we rename the city to?"),
3368 city_name_get(pdialog->pcity),
3369 rename_popup_callback, pdialog);
3370}
3371
3372/***********************************************************************/
3375 static void rename_popup_callback(gpointer data, gint response,
3376 const char *input)
3377{
3378 struct city_dialog *pdialog = data;
3379
3380 if (pdialog) {
3381 if (response == GTK_RESPONSE_OK) {
3382 city_rename(pdialog->pcity, input);
3383 } /* else CANCEL or DELETE_EVENT */
3384
3385 pdialog->rename_shell = NULL;
3386 }
3387}
3388
3389/***********************************************************************/
3392 static void misc_whichtab_callback(GtkWidget *w, gpointer data)
3393{
3394 new_dialog_def_page = GPOINTER_TO_INT(data);
3395}
3396
3397/***********************************************************************/
3400 static void cityopt_callback(GtkWidget *w, gpointer data)
3401{
3402 struct city_dialog *pdialog = (struct city_dialog *) data;
3403
3404 if (!can_client_issue_orders()) {
3405 return;
3406 }
3407
3408 if (!pdialog->misc.block_signal) {
3409 struct city *pcity = pdialog->pcity;
3410 bv_city_options new_options;
3411
3412 fc_assert(CITYO_LAST == 3);
3413
3414 BV_CLR_ALL(new_options);
3415 if (gtk_check_button_get_active(GTK_CHECK_BUTTON(pdialog->misc.disband_on_settler))) {
3416 BV_SET(new_options, CITYO_DISBAND);
3417 }
3418 if (gtk_check_button_get_active(GTK_CHECK_BUTTON(pdialog->misc.new_citizens_radio[1]))) {
3419 BV_SET(new_options, CITYO_SCIENCE_SPECIALISTS);
3420 }
3421 if (gtk_check_button_get_active(GTK_CHECK_BUTTON(pdialog->misc.new_citizens_radio[2]))) {
3422 BV_SET(new_options, CITYO_GOLD_SPECIALISTS);
3423 }
3424
3425 dsend_packet_city_options_req(&client.conn, pcity->id,new_options);
3426 }
3427}
3428
3429/***********************************************************************/
3433 static void set_cityopt_values(struct city_dialog *pdialog)
3434{
3435 struct city *pcity = pdialog->pcity;
3436
3437 pdialog->misc.block_signal = 1;
3438
3439 gtk_check_button_set_active(GTK_CHECK_BUTTON(pdialog->misc.disband_on_settler),
3440 is_city_option_set(pcity, CITYO_DISBAND));
3441
3442 if (is_city_option_set(pcity, CITYO_SCIENCE_SPECIALISTS)) {
3443 gtk_check_button_set_active(GTK_CHECK_BUTTON
3444 (pdialog->misc.new_citizens_radio[1]), TRUE);
3445 } else if (is_city_option_set(pcity, CITYO_GOLD_SPECIALISTS)) {
3446 gtk_check_button_set_active(GTK_CHECK_BUTTON
3447 (pdialog->misc.new_citizens_radio[2]), TRUE);
3448 } else {
3449 gtk_check_button_set_active(GTK_CHECK_BUTTON
3450 (pdialog->misc.new_citizens_radio[0]), TRUE);
3451 }
3452 pdialog->misc.block_signal = 0;
3453}
3454
3455/******************** Callbacks for: Close, Prev, Next. *******************/
3456
3457/***********************************************************************/
3460 static void close_callback(GtkWidget *w, gpointer data)
3461{
3462 close_city_dialog((struct city_dialog *) data);
3463}
3464
3465/***********************************************************************/
3468 static void city_destroy_callback(GtkWidget *w, gpointer data)
3469{
3470 struct city_dialog *pdialog;
3471
3472 pdialog = (struct city_dialog *) data;
3473
3474 gtk_widget_set_visible(pdialog->shell, FALSE);
3475
3476 if (game.info.citizen_nationality) {
3477 citizens_dialog_close(pdialog->pcity);
3478 }
3479 close_happiness_dialog(pdialog->pcity);
3480 close_cma_dialog(pdialog->pcity);
3481
3482 /* Save size of the city dialog. */
3483 GUI_GTK_OPTION(citydlg_xsize)
3484 = CLIP(GUI_GTK4_CITYDLG_MIN_XSIZE,
3485 gtk_widget_get_allocated_width(pdialog->shell),
3486 GUI_GTK4_CITYDLG_MAX_XSIZE);
3487 GUI_GTK_OPTION(citydlg_ysize)
3488 = CLIP(GUI_GTK4_CITYDLG_MIN_XSIZE,
3489 gtk_widget_get_allocated_height(pdialog->shell),
3490 GUI_GTK4_CITYDLG_MAX_XSIZE);
3491
3492 last_page
3493 = gtk_notebook_get_current_page(GTK_NOTEBOOK(pdialog->notebook));
3494
3495 close_citydlg_unit_popover(pdialog);
3496 dialog_list_remove(dialog_list, pdialog);
3497
3498 unit_node_vector_free(&pdialog->overview.supported_units);
3499 unit_node_vector_free(&pdialog->overview.present_units);
3500
3501 if (pdialog->sell_shell) {
3502 gtk_window_destroy(GTK_WINDOW(pdialog->sell_shell));
3503 }
3504 if (pdialog->rename_shell) {
3505 gtk_window_destroy(GTK_WINDOW(pdialog->rename_shell));
3506 }
3507
3508 cairo_surface_destroy(pdialog->map_canvas_store_unscaled);
3509 cairo_surface_destroy(pdialog->citizen_surface);
3510
3511 free(pdialog);
3512
3513 /* Need to do this every time a new dialog is closed. */
3514 city_dialog_update_prev_next();
3515}
3516
3517/***********************************************************************/
3520 static void close_city_dialog(struct city_dialog *pdialog)
3521{
3522 gtk_window_destroy(GTK_WINDOW(pdialog->shell));
3523}
3524
3525/***********************************************************************/
3529 static void switch_city_callback(GtkWidget *w, gpointer data)
3530{
3531 struct city_dialog *pdialog = (struct city_dialog *) data;
3532 int i, j, dir, size;
3533 struct city *new_pcity = NULL;
3534
3535 if (client_is_global_observer()) {
3536 return;
3537 }
3538
3539 size = city_list_size(client.conn.playing->cities);
3540
3541 fc_assert_ret(city_dialogs_have_been_initialised);
3542 fc_assert_ret(size >= 1);
3543 fc_assert_ret(city_owner(pdialog->pcity) == client.conn.playing);
3544
3545 if (size == 1) {
3546 return;
3547 }
3548
3549 /* dir = 1 will advance to the city, dir = -1 will get previous */
3550 if (w == GTK_WIDGET(pdialog->next_command)) {
3551 dir = 1;
3552 } else if (w == GTK_WIDGET(pdialog->prev_command)) {
3553 dir = -1;
3554 } else {
3555 /* Always fails. */
3556 fc_assert_ret(w == GTK_WIDGET(pdialog->next_command)
3557 || w == GTK_WIDGET(pdialog->prev_command));
3558 dir = 1;
3559 }
3560
3561 for (i = 0; i < size; i++) {
3562 if (pdialog->pcity == city_list_get(client.conn.playing->cities, i)) {
3563 break;
3564 }
3565 }
3566
3567 fc_assert_ret(i < size);
3568
3569 for (j = 1; j < size; j++) {
3570 struct city *other_pcity = city_list_get(client.conn.playing->cities,
3571 (i + dir * j + size) % size);
3572 struct city_dialog *other_pdialog = get_city_dialog(other_pcity);
3573
3574 fc_assert_ret(other_pdialog != pdialog);
3575 if (!other_pdialog) {
3576 new_pcity = other_pcity;
3577 break;
3578 }
3579 }
3580
3581 if (!new_pcity) {
3582 /* Every other city has an open city dialog. */
3583 return;
3584 }
3585
3586 /* cleanup happiness dialog */
3587 if (game.info.citizen_nationality) {
3588 citizens_dialog_close(pdialog->pcity);
3589 }
3590 close_happiness_dialog(pdialog->pcity);
3591
3592 pdialog->pcity = new_pcity;
3593
3594 /* reinitialize happiness, and cma dialogs */
3595 if (game.info.citizen_nationality) {
3596 gtk_box_append(GTK_BOX(pdialog->happiness.citizens),
3597 citizens_dialog_display(pdialog->pcity));
3598 }
3599 gtk_box_append(GTK_BOX(pdialog->happiness.widget),
3600 get_top_happiness_display(pdialog->pcity, low_citydlg, pdialog->shell));
3601 if (!client_is_observer()) {
3602 fc_assert(pdialog->cma_editor != NULL);
3603 pdialog->cma_editor->pcity = new_pcity;
3604 }
3605
3606 reset_city_worklist(pdialog->production.worklist, pdialog->pcity);
3607
3608 can_slide = FALSE;
3609 center_tile_mapcanvas(pdialog->pcity->tile);
3610 can_slide = TRUE;
3611 if (!client_is_observer()) {
3612 set_cityopt_values(pdialog); /* Need not be in real_city_dialog_refresh */
3613 }
3614
3615 real_city_dialog_refresh(pdialog->pcity);
3616
3617 /* Recenter the city map(s) */
3618 city_dialog_map_recenter(pdialog->overview.map_canvas.sw);
3619 if (pdialog->happiness.map_canvas.sw) {
3620 city_dialog_map_recenter(pdialog->happiness.map_canvas.sw);
3621 }
3622}
3623
3624/***********************************************************************/
3627 void refresh_all_city_worklists(void)
3628{
3629 dialog_list_iterate(dialog_list, pdialog) {
3630 refresh_worklist(pdialog->production.worklist);
3631 } dialog_list_iterate_end;
3632}
action_id_name_translation
const char * action_id_name_translation(action_id act_id)
Definition actions.c:1215
action_ever_possible
bool action_ever_possible(action_id action)
Definition actions.c:7451
action_id_univs_not_blocking
#define action_id_univs_not_blocking(act_id, act_uni, tgt_uni)
Definition actions.h:685
n
#define n
Definition astring.c:77
bitvector.h
BV_CLR_ALL
#define BV_CLR_ALL(bv)
Definition bitvector.h:95
BV_SET
#define BV_SET(bv, bit)
Definition bitvector.h:81
height
struct canvas int int struct sprite int int int int height
Definition canvas_g.h:44
canvas_y
struct canvas int int canvas_y
Definition canvas_g.h:43
canvas_x
struct canvas int canvas_x
Definition canvas_g.h:43
width
struct canvas int int struct sprite int int int width
Definition canvas_g.h:44
output_window_append
void output_window_append(const struct ft_color color, const char *featured_text)
Definition chatline_common.c:104
chatline_common.h
city_improvement_name_translation
const char * city_improvement_name_translation(const struct city *pcity, const struct impr_type *pimprove)
Definition city.c:662
city_production_build_shield_cost
int city_production_build_shield_cost(const struct city *pcity)
Definition city.c:736
city_granary_size
int city_granary_size(int city_size)
Definition city.c:2123
can_city_build_now
bool can_city_build_now(const struct city *pcity, const struct universal *target)
Definition city.c:1006
city_unit_unhappiness
int city_unit_unhappiness(struct unit *punit, int *free_unhappy)
Definition city.c:3040
city_build_slots
int city_build_slots(const struct city *pcity)
Definition city.c:2923
city_map_to_tile
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:304
city_name_get
const char * city_name_get(const struct city *pcity)
Definition city.c:1128
city_improvement_upkeep
int city_improvement_upkeep(const struct city *pcity, const struct impr_type *b)
Definition city.c:1246
is_city_option_set
bool is_city_option_set(const struct city *pcity, enum city_options option)
Definition city.c:3376
city_population
int city_population(const struct city *pcity)
Definition city.c:1182
city_unhappy
bool city_unhappy(const struct city *pcity)
Definition city.c:1618
city_celebrating
bool city_celebrating(const struct city *pcity)
Definition city.c:1637
city_illness_calc
int city_illness_calc(const struct city *pcity, int *ill_base, int *ill_size, int *ill_trade, int *ill_pollution)
Definition city.c:2861
city_happy
bool city_happy(const struct city *pcity)
Definition city.c:1606
city_map_radius_sq_get
int city_map_radius_sq_get(const struct city *pcity)
Definition city.c:136
city_specialists
citizens city_specialists(const struct city *pcity)
Definition city.c:3305
city_turns_to_grow
int city_turns_to_grow(const struct city *pcity)
Definition city.c:1988
city_production_name_translation
const char * city_production_name_translation(const struct city *pcity)
Definition city.c:699
city.h
city_size_get
static citizens city_size_get(const struct city *pcity)
Definition city.h:569
citizen_category
citizen_category
Definition city.h:267
city_owner
#define city_owner(_pcity_)
Definition city.h:563
MAX_CITY_SIZE
#define MAX_CITY_SIZE
Definition city.h:106
FEELING_FINAL
@ FEELING_FINAL
Definition city.h:284
get_city_dialog_output_text
void get_city_dialog_output_text(const struct city *pcity, Output_type_id otype, char *buf, size_t bufsz)
Definition citydlg_common.c:749
get_city_dialog_production
void get_city_dialog_production(struct city *pcity, char *buffer, size_t buffer_len)
Definition citydlg_common.c:260
city_rename
int city_rename(struct city *pcity, const char *name)
Definition citydlg_common.c:1602
get_city_citizen_types
int get_city_citizen_types(struct city *pcity, enum citizen_feeling idx, enum citizen_category *categories)
Definition citydlg_common.c:1202
city_buy_production
int city_buy_production(struct city *pcity)
Definition citydlg_common.c:1552
city_toggle_worker
int city_toggle_worker(struct city *pcity, int city_x, int city_y)
Definition citydlg_common.c:1571
get_city_dialog_airlift_text
void get_city_dialog_airlift_text(const struct city *pcity, char *buf, size_t bufsz)
Definition citydlg_common.c:1070
city_change_production
int city_change_production(struct city *pcity, struct universal *target)
Definition citydlg_common.c:1289
city_rotate_specialist
void city_rotate_specialist(struct city *pcity, int citizen_index)
Definition citydlg_common.c:1240
get_citydlg_canvas_width
int get_citydlg_canvas_width(void)
Definition citydlg_common.c:51
canvas_to_city_pos
bool canvas_to_city_pos(int *city_x, int *city_y, int city_radius_sq, int canvas_x, int canvas_y)
Definition citydlg_common.c:115
get_city_dialog_airlift_value
void get_city_dialog_airlift_value(const struct city *pcity, char *buf, size_t bufsz)
Definition citydlg_common.c:1140
city_dialog_redraw_map
void city_dialog_redraw_map(struct city *pcity, struct canvas *pcanvas)
Definition citydlg_common.c:187
city_sell_improvement
int city_sell_improvement(struct city *pcity, Impr_type_id sell_id)
Definition citydlg_common.c:1544
get_city_dialog_pollution_text
void get_city_dialog_pollution_text(const struct city *pcity, char *buf, size_t bufsz)
Definition citydlg_common.c:994
get_city_dialog_culture_text
void get_city_dialog_culture_text(const struct city *pcity, char *buf, size_t bufsz)
Definition citydlg_common.c:1020
city_can_buy
bool city_can_buy(const struct city *pcity)
Definition citydlg_common.c:1524
get_citydlg_canvas_height
int get_citydlg_canvas_height(void)
Definition citydlg_common.c:59
get_city_dialog_illness_text
void get_city_dialog_illness_text(const struct city *pcity, char *buf, size_t bufsz)
Definition citydlg_common.c:922
city_report_dialog_update_city
void city_report_dialog_update_city(struct city *pcity)
Definition update_queue.c:641
client_is_global_observer
bool client_is_global_observer(void)
Definition client_main.c:1345
client_is_observer
bool client_is_observer(void)
Definition client_main.c:1083
client
struct civclient client
Definition client_main.c:150
can_client_issue_orders
bool can_client_issue_orders(void)
Definition client_main.c:1264
client_has_player
bool client_has_player(void)
Definition client_main.c:1364
client_main.h
client_player
#define client_player()
Definition client_main.h:106
climap.h
collect_eventually_buildable_targets
int collect_eventually_buildable_targets(struct universal *targets, struct city *pcity, bool advanced_tech)
Definition climisc.c:809
name_and_sort_items
void name_and_sort_items(struct universal *targets, int num_targets, struct item *items, bool show_cost, struct city *pcity)
Definition climisc.c:640
cid_encode
cid cid_encode(struct universal target)
Definition climisc.c:482
collect_already_built_targets
int collect_already_built_targets(struct universal *targets, struct city *pcity)
Definition climisc.c:902
MAX_NUM_PRODUCTION_TARGETS
#define MAX_NUM_PRODUCTION_TARGETS
Definition climisc.h:87
cid_production
#define cid_production
Definition climisc.h:71
cid
int cid
Definition climisc.h:31
cma_is_city_under_agent
bool cma_is_city_under_agent(const struct city *pcity, struct cm_parameter *parameter)
Definition cma_core.c:551
cma_fec.h
incite_cost
char * incite_cost
Definition comments.c:74
request_unit_fortify
void request_unit_fortify(struct unit *punit)
Definition control.c:2324
unit_focus_set
void unit_focus_set(struct unit *punit)
Definition control.c:501
request_unit_change_homecity
void request_unit_change_homecity(struct unit *punit)
Definition control.c:2065
request_unit_unload
void request_unit_unload(struct unit *pcargo)
Definition control.c:2165
request_unit_sentry
void request_unit_sentry(struct unit *punit)
Definition control.c:2313
control.h
can_unit_do_activity_client
#define can_unit_do_activity_client(_punit_, _act_)
Definition control.h:41
punit
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:74
cost
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:74
id
int int id
Definition editgui_g.h:28
editor
static struct editor_state * editor
Definition editor.c:100
get_city_bonus
int get_city_bonus(const struct city *pcity, enum effect_type effect_type)
Definition effects.c:846
next_extra_for_tile
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:765
prev_extra_in_tile
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:790
activity_to_extra_cause
enum extra_cause activity_to_extra_cause(enum unit_activity act)
Definition extras.c:1076
activity_to_extra_rmcause
enum extra_rmcause activity_to_extra_rmcause(enum unit_activity act)
Definition extras.c:1097
extra_index
#define extra_index(_e_)
Definition extras.h:183
Impr_type_id
int Impr_type_id
Definition fc_types.h:380
EC_NONE
#define EC_NONE
Definition fc_types.h:1123
TR_SUCCESS
@ TR_SUCCESS
Definition fc_types.h:1256
ERM_NONE
#define ERM_NONE
Definition fc_types.h:1146
O_SHIELD
@ O_SHIELD
Definition fc_types.h:101
O_FOOD
@ O_FOOD
Definition fc_types.h:101
O_TRADE
@ O_TRADE
Definition fc_types.h:101
O_SCIENCE
@ O_SCIENCE
Definition fc_types.h:101
O_LUXURY
@ O_LUXURY
Definition fc_types.h:101
O_GOLD
@ O_GOLD
Definition fc_types.h:101
fcintl.h
Q_
#define Q_(String)
Definition fcintl.h:70
PL_
#define PL_(String1, String2, n)
Definition fcintl.h:71
_
#define _(String)
Definition fcintl.h:67
N_
#define N_(String)
Definition fcintl.h:69
ftc_client
const struct ft_color ftc_client
Definition featured_text.c:78
population_to_text
const char * population_to_text(int thousand_citizen)
Definition game.c:740
game
struct civ_game game
Definition game.c:62
wld
struct world wld
Definition game.c:63
game_city_by_number
struct city * game_city_by_number(int id)
Definition game.c:107
game.h
FC_STATIC_CANVAS_INIT
#define FC_STATIC_CANVAS_INIT
Definition canvas.h:28
choice_dialog_start
GtkWidget * choice_dialog_start(GtkWindow *parent, const gchar *name, const gchar *text)
Definition choice_dialog.c:103
choice_dialog_end
void choice_dialog_end(GtkWidget *dshell)
Definition choice_dialog.c:194
choice_dialog_add
void choice_dialog_add(GtkWidget *dshell, const gchar *label, GCallback handler, gpointer data, bool meta, const gchar *tool_tip)
Definition choice_dialog.c:158
citizens_dialog_display
GtkWidget * citizens_dialog_display(const struct city *pcity)
Definition citizensinfo.c:385
citizens_dialog_refresh
void citizens_dialog_refresh(const struct city *pcity)
Definition citizensinfo.c:299
citizens_dialog_close
void citizens_dialog_close(const struct city *pcity)
Definition citizensinfo.c:366
unit_sentry_callback
static void unit_sentry_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2773
citydlg_response
citydlg_response
Definition citydlg.c:81
CDLGR_UNITS
@ CDLGR_UNITS
Definition citydlg.c:81
CDLGR_PREV
@ CDLGR_PREV
Definition citydlg.c:81
CDLGR_NEXT
@ CDLGR_NEXT
Definition citydlg.c:81
new_dialog_def_page
static int new_dialog_def_page
Definition citydlg.c:213
create_and_append_buildings_page
static void create_and_append_buildings_page(struct city_dialog *pdialog)
Definition citydlg.c:1230
unit_upgrade_callback
static void unit_upgrade_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2832
popup_workertask_dlg
static void popup_workertask_dlg(struct city *pcity, struct tile *ptile)
Definition citydlg.c:2943
city_dialog_update_citizens
static void city_dialog_update_citizens(struct city_dialog *pdialog)
Definition citydlg.c:1768
city_destroy_callback
static void city_destroy_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:3355
city_dialog_update_title
static void city_dialog_update_title(struct city_dialog *pdialog)
Definition citydlg.c:1729
last_page
static int last_page
Definition citydlg.c:214
init_citydlg_dimensions
static void init_citydlg_dimensions(void)
Definition citydlg.c:325
create_and_append_worklist_page
static void create_and_append_worklist_page(struct city_dialog *pdialog)
Definition citydlg.c:1264
loc
struct tile * loc
Definition citydlg.c:221
WORKLIST_PAGE
@ WORKLIST_PAGE
Definition citydlg.c:111
CMA_PAGE
@ CMA_PAGE
Definition citydlg.c:111
HAPPINESS_PAGE
@ HAPPINESS_PAGE
Definition citydlg.c:111
SETTINGS_PAGE
@ SETTINGS_PAGE
Definition citydlg.c:112
STICKY_PAGE
@ STICKY_PAGE
Definition citydlg.c:112
NUM_PAGES
@ NUM_PAGES
Definition citydlg.c:113
OVERVIEW_PAGE
@ OVERVIEW_PAGE
Definition citydlg.c:111
CITY_MAP_MIN_SIZE_X
#define CITY_MAP_MIN_SIZE_X
Definition citydlg.c:127
real_city_dialog_popup
void real_city_dialog_popup(struct city *pcity)
Definition citydlg.c:558
misc_whichtab_callback
static void misc_whichtab_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:3280
low_citydlg
static bool low_citydlg
Definition citydlg.c:224
workertask_req
static struct @141 workertask_req
city_dialog_is_open
bool city_dialog_is_open(struct city *pcity)
Definition citydlg.c:579
city_dialog_update_building
static void city_dialog_update_building(struct city_dialog *pdialog)
Definition citydlg.c:1968
citydlg_response_callback
static void citydlg_response_callback(GtkDialog *dlg, gint response, void *data)
Definition citydlg.c:2400
buy_callback_response
static void buy_callback_response(GtkWidget *w, gint response, gpointer data)
Definition citydlg.c:3071
real_city_dialog_refresh
void real_city_dialog_refresh(struct city *pcity)
Definition citydlg.c:480
unit_center_callback
static void unit_center_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2672
get_city_dialog
static struct city_dialog * get_city_dialog(struct city *pcity)
Definition citydlg.c:380
CITY_MAP_MIN_SIZE_Y
#define CITY_MAP_MIN_SIZE_Y
Definition citydlg.c:128
city_dialog_update_information
static void city_dialog_update_information(GtkWidget **info_ebox, GtkWidget **info_label, struct city_dialog *pdialog)
Definition citydlg.c:1831
create_citydlg_improvement_list
static GtkWidget * create_citydlg_improvement_list(struct city_dialog *pdialog, GtkWidget *vbox)
Definition citydlg.c:889
create_production_header
static void create_production_header(struct city_dialog *pdialog, GtkContainer *contain)
Definition citydlg.c:1197
workertask_dlg_destroy
static void workertask_dlg_destroy(GtkWidget *w, gpointer data)
Definition citydlg.c:2935
city_dialog_update_present_units
static void city_dialog_update_present_units(struct city_dialog *pdialog)
Definition citydlg.c:2254
CITYMAP_SCALE
#define CITYMAP_SCALE
Definition citydlg.c:75
citizens_callback
static gboolean citizens_callback(GtkWidget *w, GdkEventButton *ev, gpointer data)
Definition citydlg.c:2853
change_production_callback
static void change_production_callback(GtkComboBox *combo, struct city_dialog *pdialog)
Definition citydlg.c:3134
unit_load_callback
static void unit_load_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2747
set_cityopt_values
static void set_cityopt_values(struct city_dialog *pdialog)
Definition citydlg.c:3321
close_city_dialog
static void close_city_dialog(struct city_dialog *pdialog)
Definition citydlg.c:3410
show_info_popup
static gboolean show_info_popup(GtkWidget *w, GdkEventButton *ev, gpointer data)
Definition citydlg.c:653
create_and_append_overview_page
static void create_and_append_overview_page(struct city_dialog *pdialog)
Definition citydlg.c:948
create_and_append_happiness_page
static void create_and_append_happiness_page(struct city_dialog *pdialog)
Definition citydlg.c:1308
popdown_all_city_dialogs
void popdown_all_city_dialogs(void)
Definition citydlg.c:599
buy_callback
static void buy_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:3084
dialog_list_iterate_end
#define dialog_list_iterate_end
Definition citydlg.c:92
impr_callback
static void impr_callback(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data)
Definition citydlg.c:3207
create_and_append_map_page
static void create_and_append_map_page(struct city_dialog *pdialog)
Definition citydlg.c:1136
city_dialog_map_create
static void city_dialog_map_create(struct city_dialog *pdialog, struct city_map_canvas *cmap_canvas)
Definition citydlg.c:416
refresh_unit_city_dialogs
void refresh_unit_city_dialogs(struct unit *punit)
Definition citydlg.c:538
reset_city_dialogs
void reset_city_dialogs(void)
Definition citydlg.c:358
cityopt_callback
static void cityopt_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:3288
city_dialog_map_recenter
static void city_dialog_map_recenter(GtkWidget *map_canvas_sw)
Definition citydlg.c:455
draw_map_canvas
static void draw_map_canvas(struct city_dialog *pdialog)
Definition citydlg.c:3059
is_showing_workertask_dialog
static bool is_showing_workertask_dialog
Definition citydlg.c:216
unit_node_vector_iterate_end
#define unit_node_vector_iterate_end
Definition citydlg.c:107
sell_callback
static void sell_callback(struct impr_type *pimprove, gpointer data)
Definition citydlg.c:3153
dialog_list_iterate
#define dialog_list_iterate(dialoglist, pdialog)
Definition citydlg.c:90
supported_unit_activate_close_callback
static void supported_unit_activate_close_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2699
city_dialog_update_prev_next
static void city_dialog_update_prev_next(void)
Definition citydlg.c:2361
create_and_append_settings_page
static void create_and_append_settings_page(struct city_dialog *pdialog)
Definition citydlg.c:1401
city_dialogs_have_been_initialised
static bool city_dialogs_have_been_initialised
Definition citydlg.c:211
close_callback
static void close_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:3347
dialog_list
static struct dialog_list * dialog_list
Definition citydlg.c:210
sell_callback_response
static void sell_callback_response(GtkWidget *w, gint response, gpointer data)
Definition citydlg.c:3192
create_citydlg_main_map
static void create_citydlg_main_map(struct city_dialog *pdialog, GtkWidget *container)
Definition citydlg.c:872
NUM_CITIZENS_SHOWN
#define NUM_CITIZENS_SHOWN
Definition citydlg.c:109
CITYMAP_HEIGHT
#define CITYMAP_HEIGHT
Definition citydlg.c:74
unit_homecity_callback
static void unit_homecity_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2819
unit_fortify_callback
static void unit_fortify_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2786
present_unit_callback
static gboolean present_unit_callback(GtkWidget *w, GdkEventButton *ev, gpointer data)
Definition citydlg.c:2496
owner
struct city * owner
Definition citydlg.c:220
create_city_info_table
static GtkWidget * create_city_info_table(struct city_dialog *pdialog, GtkWidget **info_ebox, GtkWidget **info_label)
Definition citydlg.c:737
create_city_dialog
static struct city_dialog * create_city_dialog(struct city *pcity)
Definition citydlg.c:1543
target_drag_data_received
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:1159
unit_disband_callback
static void unit_disband_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2799
unit_node_vector_iterate
#define unit_node_vector_iterate(list, elt)
Definition citydlg.c:105
rename_callback
static void rename_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:3246
switch_city_callback
static void switch_city_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:3419
CITYMAP_WIDTH
#define CITYMAP_WIDTH
Definition citydlg.c:73
city_dialog_update_map
static void city_dialog_update_map(struct city_dialog *pdialog)
Definition citydlg.c:1946
unit_unload_callback
static void unit_unload_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2760
show_units_response
static void show_units_response(void *data)
Definition citydlg.c:2413
initialize_city_dialogs
static void initialize_city_dialogs(void)
Definition citydlg.c:334
canvas_height
static int canvas_height
Definition citydlg.c:212
canvas_width
static int canvas_width
Definition citydlg.c:212
TINYSCREEN_MAX_HEIGHT
#define TINYSCREEN_MAX_HEIGHT
Definition citydlg.c:77
city_dialog_update_supported_units
static void city_dialog_update_supported_units(struct city_dialog *pdialog)
Definition citydlg.c:2148
unit_activate_callback
static void unit_activate_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2685
present_unit_activate_close_callback
static void present_unit_activate_close_callback(GtkWidget *w, gpointer data)
Definition citydlg.c:2724
INFO_LUXURY
@ INFO_LUXURY
Definition citydlg.c:119
INFO_STEAL
@ INFO_STEAL
Definition citydlg.c:121
INFO_CORRUPTION
@ INFO_CORRUPTION
Definition citydlg.c:120
NUM_INFO_FIELDS
@ NUM_INFO_FIELDS
Definition citydlg.c:122
INFO_ILLNESS
@ INFO_ILLNESS
Definition citydlg.c:121
INFO_WASTE
@ INFO_WASTE
Definition citydlg.c:120
INFO_SIZE
@ INFO_SIZE
Definition citydlg.c:118
INFO_GROWTH
@ INFO_GROWTH
Definition citydlg.c:119
INFO_SHIELD
@ INFO_SHIELD
Definition citydlg.c:118
INFO_CULTURE
@ INFO_CULTURE
Definition citydlg.c:120
INFO_GOLD
@ INFO_GOLD
Definition citydlg.c:118
INFO_SCIENCE
@ INFO_SCIENCE
Definition citydlg.c:119
INFO_POLLUTION
@ INFO_POLLUTION
Definition citydlg.c:120
INFO_TRADE
@ INFO_TRADE
Definition citydlg.c:118
INFO_AIRLIFT
@ INFO_AIRLIFT
Definition citydlg.c:121
INFO_GRANARY
@ INFO_GRANARY
Definition citydlg.c:119
INFO_FOOD
@ INFO_FOOD
Definition citydlg.c:118
set_city_workertask
static void set_city_workertask(GtkWidget *w, gpointer data)
Definition citydlg.c:2880
rename_popup_callback
static void rename_popup_callback(gpointer data, gint response, const char *input)
Definition citydlg.c:3263
city_dialog_update_improvement_list
static void city_dialog_update_improvement_list(struct city_dialog *pdialog)
Definition citydlg.c:2091
create_and_append_cma_page
static void create_and_append_cma_page(struct city_dialog *pdialog)
Definition citydlg.c:1381
popdown_city_dialog
void popdown_city_dialog(struct city *pcity)
Definition citydlg.c:587
supported_unit_callback
static gboolean supported_unit_callback(GtkWidget *w, GdkEventButton *ev, gpointer data)
Definition citydlg.c:2434
close_cma_dialog
void close_cma_dialog(struct city *pcity)
Definition cma_fe.c:104
create_cma_dialog
struct cma_dialog * create_cma_dialog(struct city *pcity, bool tiny)
Definition cma_fe.c:214
refresh_cma_dialog
void refresh_cma_dialog(struct city *pcity, enum cma_refresh refresh)
Definition cma_fe.c:471
REFRESH_ALL
@ REFRESH_ALL
Definition cma_fe.h:26
unit_select_dialog_popup
void unit_select_dialog_popup(struct tile *ptile)
Definition dialogs.c:377
popup_upgrade_dialog
void popup_upgrade_dialog(struct unit_list *punits)
Definition dialogs.c:1435
popup_disband_dialog
void popup_disband_dialog(struct unit_list *punits)
Definition dialogs.c:1473
toplevel
GtkWidget * toplevel
Definition gui_main.c:125
map_canvas
GtkWidget * map_canvas
Definition gui_main.c:107
screen_height
int screen_height(void)
Definition gui_main.c:2615
GUI_GTK_OPTION
#define GUI_GTK_OPTION(optname)
Definition gui_main.h:25
icon_label_button_new
GtkWidget * icon_label_button_new(const gchar *icon_name, const gchar *label_text)
Definition gui_stuff.c:76
setup_dialog
void setup_dialog(GtkWidget *shell, GtkWidget *parent)
Definition gui_stuff.c:287
intl_slist
void intl_slist(int n, const char **s, bool *done)
Definition gui_stuff.c:111
close_happiness_dialog
void close_happiness_dialog(struct city *pcity)
Definition happiness.c:330
refresh_happiness_dialog
void refresh_happiness_dialog(struct city *pcity)
Definition happiness.c:317
get_top_happiness_display
GtkWidget * get_top_happiness_display(struct city *pcity, bool low_dlg, GtkWidget *win)
Definition happiness.c:356
popup_help_dialog_typed
void popup_help_dialog_typed(const char *item, enum help_page_type htype)
Definition helpdlg.c:196
input_dialog_create
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
shell
static struct gui_dialog * shell
Definition messagedlg.c:39
sprite_get_pixbuf
GdkPixbuf * sprite_get_pixbuf(struct sprite *sprite)
Definition sprite.c:402
request_transport
bool request_transport(struct unit *cargo, struct tile *ptile)
Definition transportdlg.c:82
refresh_worklist
void refresh_worklist(GtkWidget *editor)
Definition wldlg.c:1327
add_worklist_dnd_target
void add_worklist_dnd_target(GtkWidget *w)
Definition wldlg.c:339
reset_city_worklist
void reset_city_worklist(GtkWidget *editor, struct city *pcity)
Definition wldlg.c:1279
create_worklist
GtkWidget * create_worklist(void)
Definition wldlg.c:1054
refresh_all_city_worklists
void refresh_all_city_worklists(void)
Definition citydlg.c:3627
canvas_draw_cb
static void canvas_draw_cb(GtkDrawingArea *w, cairo_t *cr, int width, int height, gpointer data)
Definition citydlg.c:413
right_button_down_citymap
static gboolean right_button_down_citymap(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data)
Definition citydlg.c:3143
middle_present_unit_release
static gboolean middle_present_unit_release(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data)
Definition citydlg.c:2653
create_unit_menu
static bool create_unit_menu(struct city_dialog *pdialog, struct unit *punit, GtkWidget *wdg, bool supported)
Definition citydlg.c:2454
right_unit_release
static gboolean right_unit_release(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data)
Definition citydlg.c:2699
left_button_down_citymap
static gboolean left_button_down_citymap(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data)
Definition citydlg.c:3114
close_citydlg_unit_popover
static void close_citydlg_unit_popover(struct city_dialog *pdialog)
Definition citydlg.c:2718
middle_supported_unit_release
static gboolean middle_supported_unit_release(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data)
Definition citydlg.c:2677
citydlg_keyboard_handler
static gboolean citydlg_keyboard_handler(GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, gpointer data)
Definition citydlg.c:630
menu_item_append_unref
#define menu_item_append_unref(menu, item)
Definition gui_stuff.h:149
put_unit_picture_city_overlays
void put_unit_picture_city_overlays(struct unit *punit, GtkPicture *p, int height, int *upkeep_cost, int happy_cost)
Definition mapview.c:519
put_unit_picture
void put_unit_picture(struct unit *punit, GtkPicture *p, int height)
Definition mapview.c:494
picture_set_from_surface
void picture_set_from_surface(GtkPicture *pic, cairo_surface_t *surf)
Definition sprite.c:544
choice_dialog.h
citizensinfo.h
gui_stuff.h
happiness.h
inputdlg.h
info_label
static SDL_Surface * info_label
Definition widget.c:57
cma_fe.h
citydlg.h
cityrep.h
colors.h
dialogs.h
graphics.h
gui_main.h
helpdlg.h
mapview.h
wldlg.h
HELP_IMPROVEMENT
@ HELP_IMPROVEMENT
Definition helpdlg_g.h:20
HELP_WONDER
@ HELP_WONDER
Definition helpdlg_g.h:21
impr_sell_gold
int impr_sell_gold(const struct impr_type *pimprove)
Definition improvement.c:334
test_player_sell_building_now
enum test_result test_player_sell_building_now(struct player *pplayer, struct city *pcity, const struct impr_type *pimprove)
Definition improvement.c:1120
is_improvement_redundant
bool is_improvement_redundant(const struct city *pcity, const struct impr_type *pimprove)
Definition improvement.c:641
improvement_number
Impr_type_id improvement_number(const struct impr_type *pimprove)
Definition improvement.c:184
is_great_wonder
bool is_great_wonder(const struct impr_type *pimprove)
Definition improvement.c:772
improvement_name_translation
const char * improvement_name_translation(const struct impr_type *pimprove)
Definition improvement.c:243
is_small_wonder
bool is_small_wonder(const struct impr_type *pimprove)
Definition improvement.c:780
name
const char * name
Definition inputfile.c:127
log.h
fc_assert_ret
#define fc_assert_ret(condition)
Definition log.h:191
fc_assert
#define fc_assert(condition)
Definition log.h:176
fc_assert_action
#define fc_assert_action(condition, action)
Definition log.h:187
log_debug
#define log_debug(message,...)
Definition log.h:115
map.h
center_tile_mapcanvas
void center_tile_mapcanvas(const struct tile *ptile)
Definition mapview_common.c:1237
can_slide
bool can_slide
Definition mapview_common.c:76
mem.h
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
can_unit_exist_at_tile
bool can_unit_exist_at_tile(const struct civ_map *nmap, const struct unit *punit, const struct tile *ptile)
Definition movement.c:318
unit_can_load
bool unit_can_load(const struct unit *punit)
Definition movement.c:884
movement.h
options.h
GUI_GTK4_CITYDLG_MAX_XSIZE
#define GUI_GTK4_CITYDLG_MAX_XSIZE
Definition options.h:675
GUI_GTK4_CITYDLG_MIN_XSIZE
#define GUI_GTK4_CITYDLG_MIN_XSIZE
Definition options.h:674
packets.h
send_packet_worker_task
int send_packet_worker_task(struct connection *pc, const struct packet_worker_task *packet)
Definition packets_gen.c:22234
dsend_packet_city_options_req
int dsend_packet_city_options_req(struct connection *pc, int city_id, bv_city_options options)
Definition packets_gen.c:20503
len
int len
Definition packhand.c:127
player_unit_by_number
struct unit * player_unit_by_number(const struct player *pplayer, int unit_id)
Definition player.c:1229
player_city_by_number
struct city * player_city_by_number(const struct player *pplayer, int city_id)
Definition player.c:1203
player.h
are_universals_equal
bool are_universals_equal(const struct universal *psource1, const struct universal *psource2)
Definition requirements.c:6667
shared.h
CLIP
#define CLIP(lower, current, upper)
Definition shared.h:57
ARRAY_SIZE
#define ARRAY_SIZE(x)
Definition shared.h:85
MIN
#define MIN(x, y)
Definition shared.h:55
FC_INFINITY
#define FC_INFINITY
Definition shared.h:36
speclist.h
specvec.h
size
size_t size
Definition specvec.h:72
mask
struct sprite int int int int struct sprite * mask
Definition sprite_g.h:32
y
struct sprite int int y
Definition sprite_g.h:31
x
struct sprite int x
Definition sprite_g.h:31
action
Definition actions.h:106
canvas
Definition canvas.h:22
canvas::surface
cairo_surface_t * surface
Definition canvas.h:23
city_dialog
Definition citydlg.c:136
city_dialog::prev_command
GtkWidget * prev_command
Definition citydlg.c:202
city_dialog::happiness
struct city_dialog::@144 happiness
city_dialog::name_label
GtkWidget * name_label
Definition citydlg.c:140
city_dialog::overview
struct city_dialog::@142 overview
city_dialog::rename_shell
GtkWidget * rename_shell
Definition citydlg.c:199
city_dialog::misc
struct city_dialog::@145 misc
city_dialog::rename_command
GtkWidget * rename_command
Definition citydlg.c:190
city_dialog::production_bar
GtkWidget * production_bar
Definition citydlg.c:151
city_dialog::supported_units_frame
GtkWidget * supported_units_frame
Definition citydlg.c:156
city_dialog::sell_shell
GtkWidget * sell_shell
Definition citydlg.c:197
city_dialog::production_label
GtkWidget * production_label
Definition citydlg.c:172
city_dialog::cwidth
int cwidth
Definition citydlg.c:207
city_dialog::widget
GtkWidget * widget
Definition citydlg.c:181
city_dialog::supported_unit_table
GtkWidget * supported_unit_table
Definition citydlg.c:157
city_dialog::disband_on_settler
GtkWidget * disband_on_settler
Definition citydlg.c:192
city_dialog::map_canvas
struct city_map_canvas map_canvas
Definition citydlg.c:149
city_dialog::improvement_list
GtkWidget * improvement_list
Definition citydlg.c:154
city_dialog::buy_command
GtkWidget * buy_command
Definition citydlg.c:153
city_dialog::block_signal
short block_signal
Definition citydlg.c:194
city_dialog::whichtab_radio
GtkWidget * whichtab_radio[NUM_PAGES]
Definition citydlg.c:193
city_dialog::supported_units
struct unit_node_vector supported_units
Definition citydlg.c:162
city_dialog::map_canvas_store_unscaled
cairo_surface_t * map_canvas_store_unscaled
Definition citydlg.c:141
city_dialog::pcity
struct city * pcity
Definition citydlg.c:137
city_dialog::present_units
struct unit_node_vector present_units
Definition citydlg.c:163
city_dialog::view
city_map * view
Definition citydlg.h:450
city_dialog::popover
GtkWidget * popover
Definition citydlg.c:146
city_dialog::citizen_pics
GtkWidget * citizen_pics
Definition citydlg.c:147
city_dialog::citizens
GtkWidget * citizens
Definition citydlg.c:184
city_dialog::show_units_command
GtkWidget * show_units_command
Definition citydlg.c:201
city_dialog::sell_id
Impr_type_id sell_id
Definition citydlg.c:205
city_dialog::production_combo
GtkWidget * production_combo
Definition citydlg.c:152
city_dialog::cma_editor
struct cma_dialog * cma_editor
Definition citydlg.c:187
city_dialog::citizen_surface
cairo_surface_t * citizen_surface
Definition citydlg.c:146
city_dialog::page
enum city_dialog::@213 page
city_dialog::shell
GtkWidget * shell
Definition citydlg.c:139
city_dialog::worklist
GtkWidget * worklist
Definition citydlg.c:175
city_dialog::production
struct city_dialog::@143 production
city_dialog::present_units_frame
GtkWidget * present_units_frame
Definition citydlg.c:159
city_dialog::info_label
GtkWidget * info_label[NUM_INFO_FIELDS]
Definition citydlg.c:166
city_dialog::new_citizens_radio
GtkWidget * new_citizens_radio[3]
Definition citydlg.c:191
city_dialog::change_production_store
GtkListStore * change_production_store
Definition citydlg.c:168
city_dialog::present_unit_table
GtkWidget * present_unit_table
Definition citydlg.c:160
city_dialog::notebook
GtkWidget * notebook
Definition citydlg.c:142
city_dialog::next_command
GtkWidget * next_command
Definition citydlg.c:203
city_dialog::change_selection
GtkTreeSelection * change_selection
Definition citydlg.c:198
city_map_canvas
Definition citydlg.c:130
city_map_canvas::darea
GtkWidget * darea
Definition citydlg.c:133
city_map_canvas::sw
GtkWidget * sw
Definition citydlg.c:131
city
Definition city.h:320
city::task_reqs
struct worker_task_list * task_reqs
Definition city.h:412
city::surplus
int surplus[O_LAST]
Definition city.h:355
city::food_stock
int food_stock
Definition city.h:367
city::pollution
int pollution
Definition city.h:369
city::id
int id
Definition city.h:326
city::waste
int waste[O_LAST]
Definition city.h:356
city::info_units_present
struct unit_list * info_units_present
Definition city.h:474
city::owner
struct player * owner
Definition city.h:323
city::info_units_supported
struct unit_list * info_units_supported
Definition city.h:473
city::worklist
struct worklist worklist
Definition city.h:401
city::production
struct universal production
Definition city.h:396
city::steal
int steal
Definition city.h:414
city::size
citizens size
Definition city.h:332
city::illness
int illness
Definition city.h:434
city::culture
int culture
Definition city.h:465
city::buy_cost
int buy_cost
Definition city.h:466
city::tile
struct tile * tile
Definition city.h:322
city::shield_stock
int shield_stock
Definition city.h:368
city::prod
int prod[O_LAST]
Definition city.h:358
city::units_supported
struct unit_list * units_supported
Definition city.h:406
city::client
struct city::@17::@20 client
civ_game::info
struct packet_game_info info
Definition game.h:89
civclient::conn
struct connection conn
Definition client_main.h:96
cma_dialog
Definition cma_fe.h:31
cma_dialog::shell
GtkWidget * shell
Definition cma_fe.h:33
cma_dialog::pcity
struct city * pcity
Definition cma_fe.h:32
connection::playing
struct player * playing
Definition connection.h:151
extra_type
Definition extras.h:88
impr_type
Definition improvement.h:50
item
Definition climisc.h:80
item::item
struct universal item
Definition climisc.h:81
item::descr
char descr[MAX_LEN_NAME+40]
Definition climisc.h:82
packet_game_info::citizen_nationality
bool citizen_nationality
Definition packets_gen.h:146
packet_game_info::illness_on
bool illness_on
Definition packets_gen.h:187
packet_worker_task
Definition packets_gen.h:503
packet_worker_task::city_id
int city_id
Definition packets_gen.h:504
packet_worker_task::tile_id
int tile_id
Definition packets_gen.h:505
packet_worker_task::activity
enum unit_activity activity
Definition packets_gen.h:506
packet_worker_task::want
int want
Definition packets_gen.h:508
packet_worker_task::tgt
int tgt
Definition packets_gen.h:507
player
Definition player.h:249
player::cities
struct city_list * cities
Definition player.h:281
sprite
Definition sprite.h:22
terrain
Definition terrain.h:75
tile
Definition tile.h:50
tile::index
int index
Definition tile.h:51
tile::units
struct unit_list * units
Definition tile.h:58
tileset
Definition tilespec.c:481
unit_node
Definition citydlg.c:94
unit_node::height
int height
Definition citydlg.c:97
unit_node::right
GtkEventController * right
Definition citydlg.c:100
unit_node::cmd
GtkWidget * cmd
Definition citydlg.c:95
unit_node::pix
GtkWidget * pix
Definition citydlg.c:96
unit_node::middle
GtkEventController * middle
Definition citydlg.c:99
unit_node::left
GtkEventController * left
Definition citydlg.c:98
unit
Definition unit.h:140
unit::upkeep
int upkeep[O_LAST]
Definition unit.h:150
unit::activity
enum unit_activity activity
Definition unit.h:159
unit::id
int id
Definition unit.h:147
unit::homecity
int homecity
Definition unit.h:148
universal
Definition fc_types.h:908
universal::kind
enum universals_n kind
Definition fc_types.h:910
universal::value
universals_u value
Definition fc_types.h:909
view
Definition mapview_common.h:36
worker_task
Definition workertask.h:21
worker_task::ptile
struct tile * ptile
Definition workertask.h:22
worklist
Definition worklist.h:28
world::map
struct civ_map map
Definition world_object.h:38
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
support.h
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
unit_description
const char * unit_description(struct unit *punit)
Definition text.c:488
text.h
tile_city
struct city * tile_city(const struct tile *ptile)
Definition tile.c:83
tile_terrain
#define tile_terrain(_tile)
Definition tile.h:111
get_building_sprite
struct sprite * get_building_sprite(const struct tileset *t, const struct impr_type *pimprove)
Definition tilespec.c:6801
tileset_small_sprite_width
int tileset_small_sprite_width(const struct tileset *t)
Definition tilespec.c:901
tileset_full_tile_height
int tileset_full_tile_height(const struct tileset *t)
Definition tilespec.c:789
tileset_small_sprite_height
int tileset_small_sprite_height(const struct tileset *t)
Definition tilespec.c:937
tileset_unit_with_upkeep_height
int tileset_unit_with_upkeep_height(const struct tileset *t)
Definition tilespec.c:859
get_citizen_sprite
struct sprite * get_citizen_sprite(const struct tileset *t, enum citizen_category type, int citizen_index, const struct city *pcity)
Definition tilespec.c:6740
get_unittype_sprite
struct sprite * get_unittype_sprite(const struct tileset *t, const struct unit_type *punittype, enum unit_activity activity, enum direction8 facing)
Definition tilespec.c:6823
tilespec.h
universals_u::utype
const struct unit_type * utype
Definition fc_types.h:728
universals_u::building
const struct impr_type * building
Definition fc_types.h:721
can_unit_change_homecity_to
bool can_unit_change_homecity_to(const struct unit *punit, const struct city *pcity)
Definition unit.c:490
unit_transport_get
struct unit * unit_transport_get(const struct unit *pcargo)
Definition unit.c:2485
unit_can_do_action
bool unit_can_do_action(const struct unit *punit, const action_id act_id)
Definition unit.c:385
can_unit_unload
bool can_unit_unload(const struct unit *pcargo, const struct unit *ptrans)
Definition unit.c:772
unit_tile
#define unit_tile(_pu)
Definition unit.h:397
unitlist.h
unit_list_iterate
#define unit_list_iterate(unitlist, punit)
Definition unitlist.h:31
unit_list_iterate_end
#define unit_list_iterate_end
Definition unitlist.h:33
unit_type_get
const struct unit_type * unit_type_get(const struct unit *punit)
Definition unittype.c:123
can_upgrade_unittype
const struct unit_type * can_upgrade_unittype(const struct player *pplayer, const struct unit_type *punittype)
Definition unittype.c:1703
utype_name_translation
const char * utype_name_translation(const struct unit_type *punittype)
Definition unittype.c:1560
economy_report_dialog_update
void economy_report_dialog_update(void)
Definition update_queue.c:682
update_queue.h
worklist_is_empty
bool worklist_is_empty(const struct worklist *pwl)
Definition worklist.c:66