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 "client_main.h"
44 #include "colors.h"
45 #include "control.h"
46 #include "climap.h"
47 #include "options.h"
48 #include "text.h"
49 #include "tilespec.h"
50 
51 /* client/agents */
52 #include "cma_fec.h"
53 
54 /* client/gui-gtk-2.0 */
55 #include "citizensinfo.h"
56 #include "cityrep.h"
57 #include "cma_fe.h"
58 #include "dialogs.h"
59 #include "graphics.h"
60 #include "gui_main.h"
61 #include "gui_stuff.h"
62 #include "happiness.h"
63 #include "helpdlg.h"
64 #include "inputdlg.h"
65 #include "mapview.h"
66 #include "repodlgs.h"
67 #include "wldlg.h"
68 
69 #include "citydlg.h"
70 
71 #define CITYMAP_WIDTH MIN(512, canvas_width)
72 #define CITYMAP_HEIGHT (CITYMAP_WIDTH * canvas_height / canvas_width)
73 #define CITYMAP_SCALE ((double)CITYMAP_WIDTH / (double)canvas_width)
74 
75 struct city_dialog;
76 
77 /* get 'struct dialog_list' and related function */
78 #define SPECLIST_TAG dialog
79 #define SPECLIST_TYPE struct city_dialog
80 #include "speclist.h"
81 
82 #define dialog_list_iterate(dialoglist, pdialog) \
83     TYPED_LIST_ITERATE(struct city_dialog, dialoglist, pdialog)
84 #define dialog_list_iterate_end  LIST_ITERATE_END
85 
86 struct unit_node {
87   GtkWidget *cmd;
88   GtkWidget *pix;
89 };
90 
91 /* get 'struct unit_node' and related function */
92 #define SPECVEC_TAG unit_node
93 #define SPECVEC_TYPE struct unit_node
94 #include "specvec.h"
95 
96 #define unit_node_vector_iterate(list, elt) \
97     TYPED_VECTOR_ITERATE(struct unit_node, list, elt)
98 #define unit_node_vector_iterate_end  VECTOR_ITERATE_END
99 
100 enum { OVERVIEW_PAGE, WORKLIST_PAGE,
101   HAPPINESS_PAGE, CMA_PAGE, TRADE_PAGE, MISC_PAGE
102 };
103 
104 enum info_style { NORMAL, ORANGE, RED, NUM_INFO_STYLES };
105 
106 #define NUM_CITIZENS_SHOWN 30
107 #define NUM_INFO_FIELDS 14      /* number of fields in city_info */
108 #define NUM_PAGES 6             /* the number of pages in city dialog notebook
109                                  * (+1) if you change this, you must add an
110                                  * entry to misc_whichtab_label[] */
111 
112 /* minimal size for the city map scrolling windows*/
113 #define CITY_MAP_MIN_SIZE_X  200
114 #define CITY_MAP_MIN_SIZE_Y  150
115 
116 struct city_map_canvas {
117   GtkWidget *sw;
118   GtkWidget *ebox;
119   GtkWidget *pixmap;
120 };
121 
122 struct city_dialog {
123   struct city *pcity;
124 
125   GtkWidget *shell;
126   GtkWidget *name_label;
127   GdkPixbuf *map_canvas_store, *map_pixbuf_unscaled;
128   GdkPixmap *map_canvas_store_unscaled;
129   GtkWidget *notebook;
130 
131   GtkWidget *popup_menu;
132   GtkWidget *citizen_pixmap;
133 
134   struct {
135     struct city_map_canvas map_canvas;
136 
137     GtkWidget *production_bar;
138     GtkWidget *production_combo;
139     GtkWidget *buy_command;
140     GtkWidget *improvement_list;
141 
142     GtkWidget *supported_units_frame;
143     GtkWidget *supported_unit_table;
144 
145     GtkWidget *present_units_frame;
146     GtkWidget *present_unit_table;
147 
148     struct unit_node_vector supported_units;
149     struct unit_node_vector present_units;
150 
151     GtkWidget *info_ebox[NUM_INFO_FIELDS];
152     GtkWidget *info_label[NUM_INFO_FIELDS];
153 
154     GtkListStore* change_production_store;
155   } overview;
156 
157   struct {
158     GtkWidget *production_label;
159     GtkWidget *production_bar;
160     GtkWidget *buy_command;
161     GtkWidget *worklist;
162   } production;
163 
164   struct {
165     struct city_map_canvas map_canvas;
166 
167     GtkWidget *widget;
168     GtkWidget *info_ebox[NUM_INFO_FIELDS];
169     GtkWidget *info_label[NUM_INFO_FIELDS];
170     GtkWidget *citizens;
171   } happiness;
172 
173   struct cma_dialog *cma_editor;
174 
175   struct {
176     GtkWidget *rename_command;
177     GtkWidget *new_citizens_radio[3];
178     GtkWidget *disband_on_settler;
179     GtkWidget *whichtab_radio[NUM_PAGES];
180     short block_signal;
181   } misc;
182 
183   GtkWidget *buy_shell, *sell_shell;
184   GtkTreeSelection *change_selection;
185   GtkWidget *rename_shell, *rename_input;
186 
187   GtkWidget *show_units_command;
188   GtkWidget *prev_command, *next_command;
189 
190   Impr_type_id sell_id;
191 
192   int cwidth;
193 };
194 
195 static GtkRcStyle *info_label_style[NUM_INFO_STYLES] = { NULL, NULL, NULL };
196 
197 static struct dialog_list *dialog_list;
198 static bool city_dialogs_have_been_initialised = FALSE;
199 static int canvas_width, canvas_height;
200 static int new_dialog_def_page = OVERVIEW_PAGE;
201 static int last_page = OVERVIEW_PAGE;
202 
203 /****************************************/
204 
205 static void initialize_city_dialogs(void);
206 static void city_dialog_map_create(struct city_dialog *pdialog,
207                                    struct city_map_canvas *cmap_canvas);
208 static void city_dialog_map_recenter(GtkWidget *map_canvas_sw);
209 
210 static struct city_dialog *get_city_dialog(struct city *pcity);
211 static gboolean keyboard_handler(GtkWidget * widget, GdkEventKey * event,
212 				 struct city_dialog *pdialog);
213 
214 static GtkWidget *create_city_info_table(struct city_dialog *pdialog,
215     					 GtkWidget **info_ebox,
216 					 GtkWidget **info_label);
217 static void create_and_append_overview_page(struct city_dialog *pdialog);
218 static void create_and_append_worklist_page(struct city_dialog *pdialog);
219 static void create_and_append_happiness_page(struct city_dialog *pdialog);
220 static void create_and_append_cma_page(struct city_dialog *pdialog);
221 static void create_and_append_settings_page(struct city_dialog *pdialog);
222 
223 static struct city_dialog *create_city_dialog(struct city *pcity);
224 
225 static void city_dialog_update_title(struct city_dialog *pdialog);
226 static void city_dialog_update_citizens(struct city_dialog *pdialog);
227 static void city_dialog_update_information(GtkWidget **info_ebox,
228 					   GtkWidget **info_label,
229                                            struct city_dialog *pdialog);
230 static void city_dialog_update_map(struct city_dialog *pdialog);
231 static void city_dialog_update_building(struct city_dialog *pdialog);
232 static void city_dialog_update_improvement_list(struct city_dialog
233 						*pdialog);
234 static void city_dialog_update_supported_units(struct city_dialog
235 					       *pdialog);
236 static void city_dialog_update_present_units(struct city_dialog *pdialog);
237 static void city_dialog_update_prev_next(void);
238 
239 static void show_units_callback(GtkWidget * w, gpointer data);
240 
241 static gboolean supported_unit_callback(GtkWidget * w, GdkEventButton * ev,
242 				        gpointer data);
243 static gboolean present_unit_callback(GtkWidget * w, GdkEventButton * ev,
244 				      gpointer data);
245 static gboolean supported_unit_middle_callback(GtkWidget * w,
246 					       GdkEventButton * ev,
247 					       gpointer data);
248 static gboolean present_unit_middle_callback(GtkWidget * w,
249 					     GdkEventButton * ev,
250 					     gpointer data);
251 
252 static void unit_center_callback(GtkWidget * w, gpointer data);
253 static void unit_activate_callback(GtkWidget * w, gpointer data);
254 static void supported_unit_activate_close_callback(GtkWidget * w,
255 						   gpointer data);
256 static void present_unit_activate_close_callback(GtkWidget * w,
257 						 gpointer data);
258 static void unit_load_callback(GtkWidget * w, gpointer data);
259 static void unit_unload_callback(GtkWidget * w, gpointer data);
260 static void unit_sentry_callback(GtkWidget * w, gpointer data);
261 static void unit_fortify_callback(GtkWidget * w, gpointer data);
262 static void unit_disband_callback(GtkWidget * w, gpointer data);
263 static void unit_homecity_callback(GtkWidget * w, gpointer data);
264 static void unit_upgrade_callback(GtkWidget * w, gpointer data);
265 
266 static gboolean citizens_callback(GtkWidget * w, GdkEventButton * ev,
267 			      gpointer data);
268 static gboolean button_down_citymap(GtkWidget * w, GdkEventButton * ev,
269 				    gpointer data);
270 static void draw_map_canvas(struct city_dialog *pdialog);
271 
272 static void buy_callback(GtkWidget * w, gpointer data);
273 static void change_production_callback(GtkComboBox *combo,
274                                        struct city_dialog *pdialog);
275 
276 static void sell_callback(struct impr_type *pimprove, gpointer data);
277 static void sell_callback_response(GtkWidget *w, gint response, gpointer data);
278 
279 static void impr_callback(GtkTreeView *view, GtkTreePath *path,
280 			  GtkTreeViewColumn *col, gpointer data);
281 
282 static void rename_callback(GtkWidget * w, gpointer data);
283 static void rename_popup_callback(gpointer data, gint response,
284                                   const char *input);
285 static void set_cityopt_values(struct city_dialog *pdialog);
286 static void cityopt_callback(GtkWidget * w, gpointer data);
287 static void misc_whichtab_callback(GtkWidget * w, gpointer data);
288 
289 static void city_destroy_callback(GtkWidget *w, gpointer data);
290 static void close_city_dialog(struct city_dialog *pdialog);
291 static void close_callback(GtkWidget *w, gpointer data);
292 static void switch_city_callback(GtkWidget * w, gpointer data);
293 
294 /****************************************************************
295   Called to set the dimensions of the city dialog, both on
296   startup and if the tileset is changed.
297 *****************************************************************/
init_citydlg_dimensions(void)298 static void init_citydlg_dimensions(void)
299 {
300   canvas_width = get_citydlg_canvas_width();
301   canvas_height = get_citydlg_canvas_height();
302 }
303 
304 /****************************************************************
305   Initialize stuff needed for city dialogs
306 *****************************************************************/
initialize_city_dialogs(void)307 static void initialize_city_dialogs(void)
308 {
309   int i;
310   GdkColor orange = { 0, 65535, 32768, 0 };	/* not currently used */
311   GdkColor red = { 0, 65535, 0, 0 };
312 
313   fc_assert_ret(!city_dialogs_have_been_initialised);
314 
315   dialog_list = dialog_list_new();
316   init_citydlg_dimensions();
317 
318   /* make the styles */
319 
320   for (i = 0; i < NUM_INFO_STYLES; i++) {
321     info_label_style[i] = gtk_rc_style_new();
322   }
323   /* info_syle[NORMAL] is normal, don't change it */
324   info_label_style[ORANGE]->color_flags[GTK_STATE_NORMAL] |= GTK_RC_FG;
325   info_label_style[ORANGE]->fg[GTK_STATE_NORMAL] = orange;
326   info_label_style[RED]->color_flags[GTK_STATE_NORMAL] |= GTK_RC_FG;
327   info_label_style[RED]->fg[GTK_STATE_NORMAL] = red;
328 
329   city_dialogs_have_been_initialised = TRUE;
330 }
331 
332 /****************************************************************
333   Called when the tileset changes.
334 *****************************************************************/
reset_city_dialogs(void)335 void reset_city_dialogs(void)
336 {
337   if (!city_dialogs_have_been_initialised) {
338     return;
339   }
340 
341   init_citydlg_dimensions();
342 
343   dialog_list_iterate(dialog_list, pdialog) {
344     /* There's no reasonable way to resize a GtkPixcomm, so we don't try.
345        Instead we just redraw the overview within the existing area.  The
346        player has to close and reopen the dialog to fix this. */
347     city_dialog_update_map(pdialog);
348   } dialog_list_iterate_end;
349 
350   popdown_all_city_dialogs();
351 }
352 
353 /****************************************************************
354   Return city dialog of the given city, or NULL is it doesn't
355   already exist
356 *****************************************************************/
get_city_dialog(struct city * pcity)357 static struct city_dialog *get_city_dialog(struct city *pcity)
358 {
359   if (!city_dialogs_have_been_initialised) {
360     initialize_city_dialogs();
361   }
362 
363   dialog_list_iterate(dialog_list, pdialog) {
364     if (pdialog->pcity == pcity)
365       return pdialog;
366   }
367   dialog_list_iterate_end;
368   return NULL;
369 }
370 
371 /***************************************************************************
372   Create a city map widget; used in the overview and in the happiness page.
373 ****************************************************************************/
city_dialog_map_create(struct city_dialog * pdialog,struct city_map_canvas * cmap_canvas)374 static void city_dialog_map_create(struct city_dialog *pdialog,
375                                    struct city_map_canvas *cmap_canvas)
376 {
377   GtkWidget *sw, *align, *ebox, *pixmap;
378 
379   sw = gtk_scrolled_window_new(NULL, NULL);
380   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
381                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
382   gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
383                                       GTK_SHADOW_NONE);
384 
385   align = gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
386   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), align);
387 
388   ebox = gtk_event_box_new();
389   gtk_widget_add_events(ebox, GDK_BUTTON_PRESS_MASK);
390   gtk_container_add(GTK_CONTAINER(align), ebox);
391 
392   pixmap = gtk_image_new_from_pixbuf(pdialog->map_canvas_store);
393   g_signal_connect(ebox, "button_press_event",
394                    G_CALLBACK(button_down_citymap), pdialog);
395   gtk_container_add(GTK_CONTAINER(ebox), pixmap);
396 
397   /* save all widgets for the city map */
398   cmap_canvas->sw = sw;
399   cmap_canvas->ebox = ebox;
400   cmap_canvas->pixmap = pixmap;
401 }
402 
403 /****************************************************************
404   Center city dialog map.
405 *****************************************************************/
city_dialog_map_recenter(GtkWidget * map_canvas_sw)406 static void city_dialog_map_recenter(GtkWidget *map_canvas_sw) {
407   GtkAdjustment *adjust = NULL;
408   gdouble value;
409 
410   fc_assert_ret(map_canvas_sw != NULL);
411 
412   adjust = gtk_scrolled_window_get_hadjustment(
413     GTK_SCROLLED_WINDOW(map_canvas_sw));
414   value = (adjust->lower + adjust->upper - adjust->page_size) / 2;
415   gtk_adjustment_set_value(adjust, value);
416   gtk_adjustment_value_changed(adjust);
417 
418   adjust = gtk_scrolled_window_get_vadjustment(
419     GTK_SCROLLED_WINDOW(map_canvas_sw));
420   value = (adjust->lower + adjust->upper - adjust->page_size) / 2;
421   gtk_adjustment_set_value(adjust, value);
422   gtk_adjustment_value_changed(adjust);
423 }
424 
425 /****************************************************************
426   Refresh city dialog of the given city
427 *****************************************************************/
real_city_dialog_refresh(struct city * pcity)428 void real_city_dialog_refresh(struct city *pcity)
429 {
430   struct city_dialog *pdialog = get_city_dialog(pcity);
431 
432   log_debug("CITYMAP_WIDTH:  %d", CITYMAP_WIDTH);
433   log_debug("CITYMAP_HEIGHT: %d", CITYMAP_HEIGHT);
434   log_debug("CITYMAP_SCALE:  %.3f", CITYMAP_SCALE);
435 
436   if (city_owner(pcity) == client.conn.playing) {
437     city_report_dialog_update_city(pcity);
438     economy_report_dialog_update();
439   }
440 
441   if (!pdialog)
442     return;
443 
444   city_dialog_update_title(pdialog);
445   city_dialog_update_citizens(pdialog);
446   city_dialog_update_information(pdialog->overview.info_ebox,
447 				 pdialog->overview.info_label, pdialog);
448   city_dialog_update_map(pdialog);
449   city_dialog_update_building(pdialog);
450   city_dialog_update_improvement_list(pdialog);
451   city_dialog_update_supported_units(pdialog);
452   city_dialog_update_present_units(pdialog);
453 
454   if (!client_has_player() || city_owner(pcity) == client_player()) {
455     bool have_present_units = (unit_list_size(pcity->tile->units) > 0);
456 
457     refresh_worklist(pdialog->production.worklist);
458 
459     city_dialog_update_information(pdialog->happiness.info_ebox,
460 				   pdialog->happiness.info_label, pdialog);
461     refresh_happiness_dialog(pdialog->pcity);
462     if (game.info.citizen_nationality) {
463       citizens_dialog_refresh(pdialog->pcity);
464     }
465 
466     if (!client_is_observer()) {
467       refresh_cma_dialog(pdialog->pcity, REFRESH_ALL);
468     }
469 
470     gtk_widget_set_sensitive(pdialog->show_units_command,
471 			     can_client_issue_orders() &&
472 			     have_present_units);
473   } else {
474     /* Set the buttons we do not want live while a Diplomat investigates */
475     gtk_widget_set_sensitive(pdialog->show_units_command, FALSE);
476   }
477 }
478 
479 /****************************************************************
480   Refresh city dialogs of unit's homecity and city where unit
481   currently is.
482 *****************************************************************/
refresh_unit_city_dialogs(struct unit * punit)483 void refresh_unit_city_dialogs(struct unit *punit)
484 {
485   struct city *pcity_sup, *pcity_pre;
486   struct city_dialog *pdialog;
487 
488   pcity_sup = game_city_by_number(punit->homecity);
489   pcity_pre = tile_city(unit_tile(punit));
490 
491   if (pcity_sup && (pdialog = get_city_dialog(pcity_sup)))
492     city_dialog_update_supported_units(pdialog);
493 
494   if (pcity_pre && (pdialog = get_city_dialog(pcity_pre)))
495     city_dialog_update_present_units(pdialog);
496 }
497 
498 /****************************************************************
499 popup the dialog 10% inside the main-window
500 *****************************************************************/
real_city_dialog_popup(struct city * pcity)501 void real_city_dialog_popup(struct city *pcity)
502 {
503   struct city_dialog *pdialog;
504 
505   if (!(pdialog = get_city_dialog(pcity))) {
506     pdialog = create_city_dialog(pcity);
507   }
508 
509   gtk_window_present(GTK_WINDOW(pdialog->shell));
510 
511   /* center the city map(s); this must be *after* the city dialog was drawn
512    * else the size information is missing! */
513   city_dialog_map_recenter(pdialog->overview.map_canvas.sw);
514   if (pdialog->happiness.map_canvas.sw) {
515     city_dialog_map_recenter(pdialog->happiness.map_canvas.sw);
516   }
517 }
518 
519 /****************************************************************
520   Return whether city dialog for given city is open
521 *****************************************************************/
city_dialog_is_open(struct city * pcity)522 bool city_dialog_is_open(struct city *pcity)
523 {
524   return get_city_dialog(pcity) != NULL;
525 }
526 
527 /****************************************************************
528 popdown the dialog
529 *****************************************************************/
popdown_city_dialog(struct city * pcity)530 void popdown_city_dialog(struct city *pcity)
531 {
532   struct city_dialog *pdialog = get_city_dialog(pcity);
533 
534   if (pdialog) {
535     close_city_dialog(pdialog);
536   }
537 }
538 
539 /****************************************************************
540 popdown all dialogs
541 *****************************************************************/
popdown_all_city_dialogs(void)542 void popdown_all_city_dialogs(void)
543 {
544   int i;
545 
546   if (!city_dialogs_have_been_initialised) {
547     return;
548   }
549 
550   while (dialog_list_size(dialog_list)) {
551     close_city_dialog(dialog_list_get(dialog_list, 0));
552   }
553   dialog_list_destroy(dialog_list);
554 
555   for (i = 0; i < NUM_INFO_STYLES; i++) {
556     g_object_unref(info_label_style[i]);
557   }
558 
559   city_dialogs_have_been_initialised = FALSE;
560 }
561 
562 /**************************************************************************
563   Keyboard handler for city dialog
564 **************************************************************************/
keyboard_handler(GtkWidget * widget,GdkEventKey * event,struct city_dialog * pdialog)565 static gboolean keyboard_handler(GtkWidget * widget, GdkEventKey * event,
566 				 struct city_dialog *pdialog)
567 {
568   if (event->state & GDK_CONTROL_MASK) {
569     switch (event->keyval) {
570     case GDK_Left:
571       gtk_notebook_prev_page(GTK_NOTEBOOK(pdialog->notebook));
572       return TRUE;
573 
574     case GDK_Right:
575       gtk_notebook_next_page(GTK_NOTEBOOK(pdialog->notebook));
576       return TRUE;
577 
578     default:
579       break;
580     }
581   }
582 
583   return FALSE;
584 }
585 
586 /**************************************************************************
587   Destroy info popup dialog when button released
588 **************************************************************************/
show_info_button_release(GtkWidget * w,GdkEventButton * ev,gpointer data)589 static gboolean show_info_button_release(GtkWidget *w, GdkEventButton *ev,
590 					 gpointer data)
591 {
592   gtk_grab_remove(w);
593   gdk_pointer_ungrab(GDK_CURRENT_TIME);
594   gtk_widget_destroy(w);
595   return FALSE;
596 }
597 
598 enum { FIELD_FOOD, FIELD_SHIELD, FIELD_TRADE, FIELD_GOLD, FIELD_LUXURY,
599        FIELD_SCIENCE, FIELD_GRANARY, FIELD_GROWTH, FIELD_CORRUPTION,
600        FIELD_WASTE, FIELD_CULTURE, FIELD_POLLUTION, FIELD_ILLNESS,
601        FIELD_AIRLIFT,
602 };
603 
604 /****************************************************************
605   Popup info dialog
606 *****************************************************************/
show_info_popup(GtkWidget * w,GdkEventButton * ev,gpointer data)607 static gboolean show_info_popup(GtkWidget *w, GdkEventButton *ev,
608     				gpointer data)
609 {
610   struct city_dialog *pdialog = g_object_get_data(G_OBJECT(w), "pdialog");
611 
612   if (ev->button == 1) {
613     GtkWidget *p, *label, *frame;
614     char buf[1024];
615 
616     switch (GPOINTER_TO_UINT(data)) {
617     case FIELD_FOOD:
618       get_city_dialog_output_text(pdialog->pcity, O_FOOD, buf, sizeof(buf));
619       break;
620     case FIELD_SHIELD:
621       get_city_dialog_output_text(pdialog->pcity, O_SHIELD,
622 				  buf, sizeof(buf));
623       break;
624     case FIELD_TRADE:
625       get_city_dialog_output_text(pdialog->pcity, O_TRADE, buf, sizeof(buf));
626       break;
627     case FIELD_GOLD:
628       get_city_dialog_output_text(pdialog->pcity, O_GOLD, buf, sizeof(buf));
629       break;
630     case FIELD_SCIENCE:
631       get_city_dialog_output_text(pdialog->pcity, O_SCIENCE,
632 				  buf, sizeof(buf));
633       break;
634     case FIELD_LUXURY:
635       get_city_dialog_output_text(pdialog->pcity, O_LUXURY,
636 				  buf, sizeof(buf));
637       break;
638     case FIELD_CULTURE:
639       get_city_dialog_culture_text(pdialog->pcity, buf, sizeof(buf));
640       break;
641     case FIELD_POLLUTION:
642       get_city_dialog_pollution_text(pdialog->pcity, buf, sizeof(buf));
643       break;
644     case FIELD_ILLNESS:
645       get_city_dialog_illness_text(pdialog->pcity, buf, sizeof(buf));
646       break;
647     case FIELD_AIRLIFT:
648       get_city_dialog_airlift_text(pdialog->pcity, buf, sizeof(buf));
649       break;
650     default:
651       return TRUE;
652     }
653 
654     p = gtk_window_new(GTK_WINDOW_POPUP);
655     gtk_widget_set_name(p, "Freeciv");
656     gtk_container_set_border_width(GTK_CONTAINER(p), 2);
657     gtk_window_set_position(GTK_WINDOW(p), GTK_WIN_POS_MOUSE);
658 
659     frame = gtk_frame_new(NULL);
660     gtk_container_add(GTK_CONTAINER(p), frame);
661 
662     label = gtk_label_new(buf);
663     gtk_widget_set_name(label, "city_label");
664     gtk_misc_set_padding(GTK_MISC(label), 4, 4);
665     gtk_container_add(GTK_CONTAINER(frame), label);
666     gtk_widget_show_all(p);
667 
668     gdk_pointer_grab(p->window, TRUE, GDK_BUTTON_RELEASE_MASK,
669 		     NULL, NULL, ev->time);
670     gtk_grab_add(p);
671 
672     g_signal_connect_after(p, "button_release_event",
673                            G_CALLBACK(show_info_button_release), NULL);
674   }
675   return TRUE;
676 }
677 /****************************************************************
678  used once in the overview page and once in the happiness page
679  **info_label points to the info_label in the respective struct
680 ****************************************************************/
create_city_info_table(struct city_dialog * pdialog,GtkWidget ** info_ebox,GtkWidget ** info_label)681 static GtkWidget *create_city_info_table(struct city_dialog *pdialog,
682     					 GtkWidget **info_ebox,
683 					 GtkWidget **info_label)
684 {
685   int i;
686   GtkWidget *hbox, *table, *label, *ebox;
687 
688   static const char *output_label[NUM_INFO_FIELDS] = { N_("Food:"),
689     N_("Prod:"),
690     N_("Trade:"),
691     N_("Gold:"),
692     N_("Luxury:"),
693     N_("Science:"),
694     N_("Granary:"),
695     N_("Change in:"),
696     N_("Corruption:"),
697     N_("Waste:"),
698     N_("Culture:"),
699     N_("Pollution:"),
700     N_("Plague risk:"),
701     N_("Airlift:"),
702   };
703   static bool output_label_done;
704 
705   hbox = gtk_hbox_new(TRUE, 0);	/* to give the table padding inside the frame */
706 
707   table = gtk_table_new(NUM_INFO_FIELDS, 2, FALSE);
708   gtk_table_set_row_spacing(GTK_TABLE(table), 2, 10);
709   gtk_table_set_row_spacing(GTK_TABLE(table), 5, 10);
710   gtk_table_set_row_spacing(GTK_TABLE(table), 7, 10);
711   gtk_table_set_col_spacing(GTK_TABLE(table), 0, 5);
712   gtk_box_pack_start(GTK_BOX(hbox), table, FALSE, FALSE, 4);
713 
714   intl_slist(ARRAY_SIZE(output_label), output_label, &output_label_done);
715 
716   for (i = 0; i < NUM_INFO_FIELDS; i++) {
717     label = gtk_label_new(output_label[i]);
718     gtk_widget_set_name(label, "city_label");	/* for font style? */
719     gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
720     gtk_table_attach(GTK_TABLE(table), label, 0, 1, i, i + 1, GTK_FILL, 0,
721 		     0, 0);
722 
723     ebox = gtk_event_box_new();
724     g_object_set_data(G_OBJECT(ebox), "pdialog", pdialog);
725     g_signal_connect(ebox, "button_press_event",
726 	G_CALLBACK(show_info_popup), GUINT_TO_POINTER(i));
727     info_ebox[i] = ebox;
728 
729     label = gtk_label_new("");
730     info_label[i] = label;
731     gtk_widget_set_name(label, "city_label");	/* ditto */
732     gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
733 
734     gtk_container_add(GTK_CONTAINER(ebox), label);
735 
736     gtk_table_attach(GTK_TABLE(table), ebox, 1, 2, i, i + 1, GTK_FILL, 0,
737 		     0, 0);
738   }
739 
740   gtk_widget_show_all(hbox);
741   return hbox;
742 }
743 
744 /****************************************************************
745                   **** Overview page ****
746  +- GtkWidget *page ------------------------------------------+
747  | +- GtkWidget *middle -----------+------------------------+ |
748  | | City map                      |  Production            | |
749  | +-------------------------------+------------------------+ |
750  +------------------------------------------------------------+
751  | +- GtkWidget *bottom -------+----------------------------+ |
752  | | Info                      | +- GtkWidget *right -----+ | |
753  | |                           | | supported units        | | |
754  | |                           | +------------------------+ | |
755  | |                           | | present units          | | |
756  | |                           | +------------------------+ | |
757  | +---------------------------+----------------------------+ |
758  +------------------------------------------------------------+
759 *****************************************************************/
create_and_append_overview_page(struct city_dialog * pdialog)760 static void create_and_append_overview_page(struct city_dialog *pdialog)
761 {
762   GtkWidget *page, *middle, *bottom;
763   GtkWidget *hbox, *right, *vbox, *align, *frame, *table;
764   GtkWidget *label, *sw, *view, *bar, *production_combo;
765   GtkCellRenderer *rend;
766   GtkListStore *store;
767   GtkListStore *production_store;
768   /* TRANS: Overview tab in city dialog */
769   const char *tab_title = _("_Overview");
770   int unit_height = tileset_unit_with_upkeep_height(tileset);
771 
772   /* main page */
773   page = gtk_vbox_new(FALSE, 0);
774   gtk_container_set_border_width(GTK_CONTAINER(page), 8);
775   label = gtk_label_new_with_mnemonic(tab_title);
776   gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), page, label);
777 
778   /* middle: city map, improvements */
779   middle = gtk_hbox_new(TRUE, 6);
780   gtk_box_pack_start(GTK_BOX(page), middle, TRUE, TRUE, 0);
781 
782   /* city map */
783   frame = gtk_frame_new(_("City map"));
784   gtk_widget_set_size_request(frame, CITY_MAP_MIN_SIZE_X,
785                               CITY_MAP_MIN_SIZE_Y);
786   gtk_box_pack_start(GTK_BOX(middle), frame, FALSE, TRUE, 0);
787 
788   city_dialog_map_create(pdialog, &pdialog->overview.map_canvas);
789   gtk_container_add(GTK_CONTAINER(frame), pdialog->overview.map_canvas.sw);
790 
791   /* improvements */
792   vbox = gtk_vbox_new(FALSE, 0);
793   gtk_box_pack_start(GTK_BOX(middle), vbox, TRUE, TRUE, 0);
794 
795   /* gtk list store columns: 0 - sell value, 1 - sprite,
796   2 - description, 3 - upkeep, 4 - is redundant, 5 - tooltip */
797   store = gtk_list_store_new(6, G_TYPE_POINTER, GDK_TYPE_PIXBUF,
798                              G_TYPE_STRING, G_TYPE_INT, G_TYPE_BOOLEAN,
799                              G_TYPE_STRING);
800 
801   view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
802   g_object_unref(store);
803   gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
804   gtk_widget_set_name(view, "small_font");
805   pdialog->overview.improvement_list = view;
806 
807   rend = gtk_cell_renderer_pixbuf_new();
808   gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, NULL,
809                                               rend, "pixbuf", 1, NULL);
810   rend = gtk_cell_renderer_text_new();
811   gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, NULL,
812                                               rend, "text", 2,
813                                               "strikethrough", 4, NULL);
814   rend = gtk_cell_renderer_text_new();
815   g_object_set(rend, "xalign", 1.0, NULL);
816   gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, NULL,
817                                               rend, "text", 3,
818                                               "strikethrough", 4, NULL);
819 
820   gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(view), 5);
821 
822   g_signal_connect(view, "row_activated", G_CALLBACK(impr_callback),
823                    pdialog);
824 
825   label = g_object_new(GTK_TYPE_LABEL, "label", _("Production:"),
826                        "xalign", 0.0, "yalign", 0.5, NULL);
827   gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
828 
829   hbox = gtk_hbox_new(FALSE, 10);
830   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
831 
832   production_store = gtk_list_store_new(4, GDK_TYPE_PIXBUF, G_TYPE_STRING,
833                                         G_TYPE_INT, G_TYPE_BOOLEAN);
834   pdialog->overview.change_production_store = production_store;
835 
836   production_combo =
837     gtk_combo_box_new_with_model(GTK_TREE_MODEL(production_store));
838   pdialog->overview.production_combo = production_combo;
839   gtk_box_pack_start(GTK_BOX(hbox), production_combo, TRUE, TRUE, 0);
840   g_object_unref(production_store);
841   g_signal_connect(production_combo, "changed",
842                    G_CALLBACK(change_production_callback), pdialog);
843 
844   gtk_cell_layout_clear(GTK_CELL_LAYOUT(production_combo));
845   rend = gtk_cell_renderer_pixbuf_new();
846   gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(production_combo), rend, TRUE);
847   gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(production_combo),
848                                  rend, "pixbuf", 0, NULL);
849   g_object_set(rend, "xalign", 0.0, NULL);
850 
851   rend = gtk_cell_renderer_text_new();
852   gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(production_combo), rend, TRUE);
853   gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(production_combo),
854                                  rend, "text", 1, "strikethrough", 3, NULL);
855 
856   bar = gtk_progress_bar_new();
857   pdialog->overview.production_bar = bar;
858   gtk_container_add(GTK_CONTAINER(production_combo), bar);
859   gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(production_combo), 3);
860 
861   gtk_progress_bar_set_text(GTK_PROGRESS_BAR(bar), _("%d/%d %d turns"));
862 
863   pdialog->overview.buy_command = gtk_stockbutton_new(GTK_STOCK_EXECUTE,
864                                                       _("_Buy"));
865   gtk_box_pack_start(GTK_BOX(hbox), pdialog->overview.buy_command,
866                      FALSE, FALSE, 0);
867   g_signal_connect(pdialog->overview.buy_command, "clicked",
868                    G_CALLBACK(buy_callback), pdialog);
869 
870   label = g_object_new(GTK_TYPE_LABEL, "use-underline", TRUE,
871                        "mnemonic-widget", view,
872                        "label", _("I_mprovements:"),
873                        "xalign", 0.0, "yalign", 0.5, NULL);
874   gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
875 
876   sw = gtk_scrolled_window_new(NULL, NULL);
877   gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
878                                       GTK_SHADOW_ETCHED_IN);
879   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
880                                  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
881   gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
882 
883   gtk_container_add(GTK_CONTAINER(sw), view);
884 
885   /* bottom: info, units */
886   bottom = gtk_hbox_new(FALSE, 6);
887   gtk_box_pack_start(GTK_BOX(page), bottom, FALSE, TRUE, 0);
888 
889   /* info */
890   frame = gtk_frame_new(_("Info"));
891   gtk_box_pack_start(GTK_BOX(bottom), frame, FALSE, TRUE, 0);
892 
893   align = gtk_alignment_new(0.5, 0.5, 0, 0);
894   gtk_container_add(GTK_CONTAINER(frame), align);
895 
896   table = create_city_info_table(pdialog,
897                                  pdialog->overview.info_ebox,
898                                  pdialog->overview.info_label);
899   gtk_container_add(GTK_CONTAINER(align), table);
900 
901   /* right: present and supported units (overview page) */
902   right = gtk_vbox_new(FALSE, 0);
903   gtk_box_pack_start(GTK_BOX(bottom), right, TRUE, TRUE, 0);
904 
905   pdialog->overview.supported_units_frame = gtk_frame_new("");
906   gtk_box_pack_start(GTK_BOX(right), pdialog->overview.supported_units_frame,
907                      TRUE, TRUE, 0);
908   pdialog->overview.present_units_frame = gtk_frame_new("");
909   gtk_box_pack_start(GTK_BOX(right), pdialog->overview.present_units_frame,
910                      TRUE, TRUE, 0);
911 
912   /* supported units */
913   sw = gtk_scrolled_window_new(NULL, NULL);
914   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
915                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
916   gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
917                                       GTK_SHADOW_NONE);
918   gtk_container_add(GTK_CONTAINER(pdialog->overview.supported_units_frame),
919                                   sw);
920 
921   align = gtk_alignment_new(0.0, 0.0, 0.0, 0.0);
922   gtk_widget_set_size_request(align, -1, unit_height);
923   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), align);
924 
925   table = gtk_table_new(0, 0, FALSE);
926   gtk_table_set_col_spacings(GTK_TABLE(table), 2);
927   gtk_container_add(GTK_CONTAINER(align), table);
928 
929   gtk_container_set_focus_hadjustment(GTK_CONTAINER(table),
930     gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(sw)));
931   gtk_container_set_focus_vadjustment(GTK_CONTAINER(table),
932     gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(sw)));
933 
934   pdialog->overview.supported_unit_table = table;
935   unit_node_vector_init(&pdialog->overview.supported_units);
936 
937   /* present units */
938   sw = gtk_scrolled_window_new(NULL, NULL);
939   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
940                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
941   gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
942                                       GTK_SHADOW_NONE);
943   gtk_container_add(GTK_CONTAINER(pdialog->overview.present_units_frame), sw);
944 
945   align = gtk_alignment_new(0.0, 0.0, 0.0, 0.0);
946   gtk_widget_set_size_request(align, -1, unit_height);
947   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), align);
948 
949   table = gtk_table_new(0, 0, FALSE);
950   gtk_table_set_col_spacings(GTK_TABLE(table), 2);
951   gtk_container_add(GTK_CONTAINER(align), table);
952 
953   gtk_container_set_focus_hadjustment(GTK_CONTAINER(table),
954     gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(sw)));
955   gtk_container_set_focus_vadjustment(GTK_CONTAINER(table),
956     gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(sw)));
957 
958   pdialog->overview.present_unit_table = table;
959   unit_node_vector_init(&pdialog->overview.present_units);
960 
961   /* show page */
962   gtk_widget_show_all(page);
963 }
964 
965 
966 /****************************************************************
967   Something dragged to worklist dialog
968 *****************************************************************/
969 static void
target_drag_data_received(GtkWidget * w,GdkDragContext * context,gint x,gint y,GtkSelectionData * data,guint info,guint time,gpointer user_data)970 target_drag_data_received(GtkWidget *w, GdkDragContext *context,
971 			  gint x, gint y, GtkSelectionData *data,
972 			  guint info, guint time, gpointer user_data)
973 {
974   struct city_dialog *pdialog = (struct city_dialog *) user_data;
975   GtkTreeModel *model;
976   GtkTreePath *path;
977 
978   if (NULL != client.conn.playing
979       && city_owner(pdialog->pcity) != client.conn.playing) {
980     gtk_drag_finish(context, FALSE, FALSE, time);
981   }
982 
983   if (gtk_tree_get_row_drag_data(data, &model, &path)) {
984     GtkTreeIter it;
985 
986     if (gtk_tree_model_get_iter(model, &it, path)) {
987       cid id;
988       struct universal univ;
989 
990       gtk_tree_model_get(model, &it, 0, &id, -1);
991       univ = cid_production(id);
992       city_change_production(pdialog->pcity, &univ);
993       gtk_drag_finish(context, TRUE, FALSE, time);
994     }
995     gtk_tree_path_free(path);
996   }
997 
998   gtk_drag_finish(context, FALSE, FALSE, time);
999 }
1000 
1001 /****************************************************************
1002                     **** Production Page ****
1003 *****************************************************************/
create_and_append_worklist_page(struct city_dialog * pdialog)1004 static void create_and_append_worklist_page(struct city_dialog *pdialog)
1005 {
1006   const char *tab_title = _("P_roduction");
1007   GtkWidget *label = gtk_label_new_with_mnemonic(tab_title);
1008   GtkWidget *page, *hbox, *editor, *bar;
1009 
1010   page = gtk_vbox_new(FALSE, 0);
1011   gtk_container_set_border_width(GTK_CONTAINER(page), 8);
1012   gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), page, label);
1013 
1014   /* stuff that's being currently built */
1015 
1016   label = g_object_new(GTK_TYPE_LABEL,
1017 		       "label", _("Production:"),
1018 		       "xalign", 0.0, "yalign", 0.5, NULL);
1019   pdialog->production.production_label = label;
1020   gtk_box_pack_start(GTK_BOX(page), label, FALSE, FALSE, 0);
1021 
1022   hbox = gtk_hbox_new(FALSE, 10);
1023   gtk_box_pack_start(GTK_BOX(page), hbox, FALSE, FALSE, 2);
1024 
1025   /* The label is set in city_dialog_update_building() */
1026   bar = gtk_progress_bar_new();
1027   pdialog->production.production_bar = bar;
1028   gtk_box_pack_start(GTK_BOX(hbox), bar, TRUE, TRUE, 0);
1029   gtk_progress_bar_set_text(GTK_PROGRESS_BAR(bar), _("%d/%d %d turns"));
1030 
1031   add_worklist_dnd_target(bar);
1032   g_signal_connect(bar, "drag_data_received",
1033 		   G_CALLBACK(target_drag_data_received), pdialog);
1034 
1035   pdialog->production.buy_command = gtk_stockbutton_new(GTK_STOCK_EXECUTE,
1036 						      _("_Buy"));
1037   gtk_box_pack_start(GTK_BOX(hbox), pdialog->production.buy_command,
1038 		     FALSE, FALSE, 0);
1039 
1040   g_signal_connect(pdialog->production.buy_command, "clicked",
1041 		   G_CALLBACK(buy_callback), pdialog);
1042 
1043 
1044   editor = create_worklist();
1045   reset_city_worklist(editor, pdialog->pcity);
1046   gtk_box_pack_start(GTK_BOX(page), editor, TRUE, TRUE, 6);
1047   pdialog->production.worklist = editor;
1048 
1049   gtk_widget_show_all(page);
1050 }
1051 
1052 /***************************************************************************
1053                      **** Happiness Page ****
1054  +- GtkWidget *page ----------+-------------------------------------------+
1055  | +- GtkWidget *left ------+ | +- GtkWidget *right --------------------+ |
1056  | | Info                   | | | City map                              | |
1057  | +- GtkWidget *citizens --+ | +- GtkWidget pdialog->happiness.widget -+ |
1058  | | Citizens data          | | | Happiness                             | |
1059  | +------------------------+ | +---------------------------------------+ |
1060  +----------------------------+-------------------------------------------+
1061 ****************************************************************************/
create_and_append_happiness_page(struct city_dialog * pdialog)1062 static void create_and_append_happiness_page(struct city_dialog *pdialog)
1063 {
1064   GtkWidget *page, *label, *table, *align, *right, *left, *frame;
1065   const char *tab_title = _("Happ_iness");
1066 
1067   /* main page */
1068   page = gtk_hbox_new(FALSE, 6);
1069   gtk_container_set_border_width(GTK_CONTAINER(page), 8);
1070   label = gtk_label_new_with_mnemonic(tab_title);
1071   gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), page, label);
1072 
1073   /* left: info, citizens */
1074   left = gtk_vbox_new(FALSE, 0);
1075   gtk_box_pack_start(GTK_BOX(page), left, FALSE, TRUE, 0);
1076 
1077   /* upper left: info */
1078   frame = gtk_frame_new(_("Info"));
1079   gtk_box_pack_start(GTK_BOX(left), frame, FALSE, TRUE, 0);
1080 
1081   align = gtk_alignment_new(0.5, 0, 0, 0);
1082   gtk_container_add(GTK_CONTAINER(frame), align);
1083 
1084   table = create_city_info_table(pdialog,
1085                                  pdialog->happiness.info_ebox,
1086                                  pdialog->happiness.info_label);
1087   gtk_container_add(GTK_CONTAINER(align), table);
1088 
1089   /* lower left: citizens */
1090   if (game.info.citizen_nationality) {
1091     pdialog->happiness.citizens = gtk_vbox_new(FALSE, 0);
1092     gtk_box_pack_start(GTK_BOX(left), pdialog->happiness.citizens,
1093                        TRUE, TRUE, 0);
1094     gtk_box_pack_start(GTK_BOX(pdialog->happiness.citizens),
1095                        citizens_dialog_display(pdialog->pcity),
1096                        TRUE, TRUE, 0);
1097   }
1098 
1099   /* right: city map, happiness */
1100   right = gtk_vbox_new(FALSE, 0);
1101   gtk_box_pack_start(GTK_BOX(page), right, TRUE, TRUE, 0);
1102 
1103   /* upper right: city map */
1104   frame = gtk_frame_new(_("City map"));
1105   gtk_widget_set_size_request(frame, CITY_MAP_MIN_SIZE_X,
1106                               CITY_MAP_MIN_SIZE_Y);
1107   gtk_box_pack_start(GTK_BOX(right), frame, TRUE, TRUE, 0);
1108 
1109   city_dialog_map_create(pdialog, &pdialog->happiness.map_canvas);
1110   gtk_container_add(GTK_CONTAINER(frame), pdialog->happiness.map_canvas.sw);
1111 
1112   /* lower right: happiness */
1113   pdialog->happiness.widget = gtk_vbox_new(FALSE, 0);
1114   gtk_box_pack_start(GTK_BOX(right), pdialog->happiness.widget, FALSE, TRUE, 0);
1115   gtk_box_pack_start(GTK_BOX(pdialog->happiness.widget),
1116                      get_top_happiness_display(pdialog->pcity), TRUE, TRUE, 0);
1117 
1118   /* show page */
1119   gtk_widget_show_all(page);
1120 }
1121 
1122 /****************************************************************
1123             **** Citizen Management Agent (CMA) Page ****
1124 *****************************************************************/
create_and_append_cma_page(struct city_dialog * pdialog)1125 static void create_and_append_cma_page(struct city_dialog *pdialog)
1126 {
1127   GtkWidget *page, *label;
1128   const char *tab_title = _("_Governor");
1129 
1130   page = gtk_vbox_new(FALSE, 0);
1131 
1132   label = gtk_label_new_with_mnemonic(tab_title);
1133 
1134   gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), page, label);
1135 
1136   pdialog->cma_editor = create_cma_dialog(pdialog->pcity);
1137   gtk_box_pack_start(GTK_BOX(page), pdialog->cma_editor->shell, TRUE, TRUE, 0);
1138 
1139   gtk_widget_show(page);
1140 }
1141 
1142 /****************************************************************
1143                     **** Misc. Settings Page ****
1144 *****************************************************************/
create_and_append_settings_page(struct city_dialog * pdialog)1145 static void create_and_append_settings_page(struct city_dialog *pdialog)
1146 {
1147   int i;
1148   GtkWidget *vbox, *vbox2, *page, *frame, *label, *button;
1149   GtkSizeGroup *size;
1150   GSList *group;
1151   const char *tab_title = _("_Settings");
1152 
1153   static const char *new_citizens_label[] = {
1154     N_("Entertainers"),
1155     N_("Scientists"),
1156     N_("Taxmen")
1157   };
1158 
1159   static const char *disband_label
1160     = N_("Allow unit production to disband city");
1161 
1162   static const char *misc_whichtab_label[NUM_PAGES] = {
1163     N_("Overview page"),
1164     N_("Production page"),
1165     N_("Happiness page"),
1166     N_("Governor page"),
1167     N_("This Settings page"),
1168     N_("Last active page")
1169   };
1170 
1171   static bool new_citizens_label_done;
1172   static bool misc_whichtab_label_done;
1173 
1174   /* initialize signal_blocker */
1175   pdialog->misc.block_signal = 0;
1176 
1177 
1178   page = gtk_table_new(2, 2, FALSE);
1179   gtk_table_set_col_spacings(GTK_TABLE(page), 18);
1180   gtk_container_set_border_width(GTK_CONTAINER(page), 8);
1181 
1182   size = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
1183 
1184   label = gtk_label_new_with_mnemonic(tab_title);
1185 
1186   gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), page, label);
1187 
1188   vbox = gtk_vbox_new(FALSE, 12);
1189   gtk_table_attach(GTK_TABLE(page), vbox, 0, 1, 0, 1,
1190 		   GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
1191   gtk_size_group_add_widget(size, vbox);
1192 
1193   /* new_citizens radio */
1194   frame = gtk_frame_new(_("New citizens are"));
1195   gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
1196 
1197   vbox2 = gtk_vbox_new(TRUE, 0);
1198   gtk_container_add(GTK_CONTAINER(frame), vbox2);
1199 
1200   intl_slist(ARRAY_SIZE(new_citizens_label), new_citizens_label,
1201              &new_citizens_label_done);
1202 
1203   group = NULL;
1204   for (i = 0; i < ARRAY_SIZE(new_citizens_label); i++) {
1205     button = gtk_radio_button_new_with_mnemonic(group, new_citizens_label[i]);
1206     pdialog->misc.new_citizens_radio[i] = button;
1207     gtk_container_add(GTK_CONTAINER(vbox2), button);
1208     g_signal_connect(button, "toggled",
1209 		     G_CALLBACK(cityopt_callback), pdialog);
1210     group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button));
1211   }
1212 
1213   /* next is the next-time-open radio group in the right column */
1214   frame = gtk_frame_new(_("Next time open"));
1215   gtk_table_attach(GTK_TABLE(page), frame, 1, 2, 0, 1,
1216 		   GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
1217   gtk_size_group_add_widget(size, frame);
1218 
1219   vbox2 = gtk_vbox_new(TRUE, 0);
1220   gtk_container_add(GTK_CONTAINER(frame), vbox2);
1221 
1222   intl_slist(ARRAY_SIZE(misc_whichtab_label), misc_whichtab_label,
1223              &misc_whichtab_label_done);
1224 
1225   group = NULL;
1226   for (i = 0; i < ARRAY_SIZE(misc_whichtab_label); i++) {
1227     button = gtk_radio_button_new_with_mnemonic(group, misc_whichtab_label[i]);
1228     pdialog->misc.whichtab_radio[i] = button;
1229     gtk_container_add(GTK_CONTAINER(vbox2), button);
1230     g_signal_connect(button, "toggled",
1231 		     G_CALLBACK(misc_whichtab_callback), GINT_TO_POINTER(i));
1232     group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button));
1233   }
1234 
1235   /* now we go back and fill the hbox rename */
1236   frame = gtk_frame_new(_("City"));
1237   gtk_table_attach(GTK_TABLE(page), frame, 0, 1, 1, 2,
1238 		   GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 12);
1239 
1240   vbox2 = gtk_vbox_new(TRUE, 0);
1241   gtk_container_add(GTK_CONTAINER(frame), vbox2);
1242 
1243   button = gtk_button_new_with_mnemonic(_("R_ename..."));
1244   pdialog->misc.rename_command = button;
1245   gtk_container_add(GTK_CONTAINER(vbox2), button);
1246   g_signal_connect(button, "clicked",
1247 		   G_CALLBACK(rename_callback), pdialog);
1248 
1249   gtk_widget_set_sensitive(button, can_client_issue_orders());
1250 
1251   /* the disband-city-on-unit-production button */
1252   button = gtk_check_button_new_with_mnemonic(_(disband_label));
1253   pdialog->misc.disband_on_settler = button;
1254   gtk_container_add(GTK_CONTAINER(vbox2), button);
1255   g_signal_connect(button, "toggled",
1256 		   G_CALLBACK(cityopt_callback), pdialog);
1257 
1258   /* we choose which page to popup by default */
1259   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
1260 			       (pdialog->
1261 				misc.whichtab_radio[new_dialog_def_page]),
1262 			       TRUE);
1263 
1264   set_cityopt_values(pdialog);
1265 
1266   gtk_widget_show_all(page);
1267 
1268   if (new_dialog_def_page == (NUM_PAGES - 1)) {
1269     gtk_notebook_set_current_page(GTK_NOTEBOOK(pdialog->notebook),
1270 				  last_page);
1271   } else {
1272     gtk_notebook_set_current_page(GTK_NOTEBOOK(pdialog->notebook),
1273 				  new_dialog_def_page);
1274   }
1275 }
1276 
1277 
1278 
1279 
1280 /****************************************************************
1281                      **** Main City Dialog ****
1282  +----------------------------+-------------------------------+
1283  | GtkWidget *top: Citizens   | city name                     |
1284  +----------------------------+-------------------------------+
1285  | <notebook tab>                                             |
1286  +------------------------------------------------------------+
1287 *****************************************************************/
create_city_dialog(struct city * pcity)1288 static struct city_dialog *create_city_dialog(struct city *pcity)
1289 {
1290   struct city_dialog *pdialog;
1291 
1292   GtkWidget *close_command;
1293   GtkWidget *vbox, *hbox, *cbox, *ebox;
1294 
1295   if (!city_dialogs_have_been_initialised) {
1296     initialize_city_dialogs();
1297   }
1298 
1299   pdialog = fc_malloc(sizeof(struct city_dialog));
1300   pdialog->pcity = pcity;
1301   pdialog->buy_shell = NULL;
1302   pdialog->sell_shell = NULL;
1303   pdialog->rename_shell = NULL;
1304   pdialog->happiness.map_canvas.sw = NULL;      /* make sure NULL if spy */
1305   pdialog->happiness.map_canvas.ebox = NULL;    /* ditto */
1306   pdialog->happiness.map_canvas.pixmap = NULL;  /* ditto */
1307   pdialog->happiness.citizens = NULL;           /* ditto */
1308   pdialog->cma_editor = NULL;
1309   pdialog->map_canvas_store = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
1310 					     CITYMAP_WIDTH, CITYMAP_HEIGHT);
1311   pdialog->map_pixbuf_unscaled = NULL;
1312   pdialog->map_canvas_store_unscaled
1313     = gdk_pixmap_new(root_window, canvas_width, canvas_height, -1);
1314 
1315   pdialog->shell = gtk_dialog_new_with_buttons(city_name_get(pcity),
1316 	NULL,
1317   	0,
1318 	NULL);
1319   setup_dialog(pdialog->shell, toplevel);
1320   gtk_window_set_role(GTK_WINDOW(pdialog->shell), "city");
1321 
1322   g_signal_connect(pdialog->shell, "destroy",
1323 		   G_CALLBACK(city_destroy_callback), pdialog);
1324   gtk_window_set_position(GTK_WINDOW(pdialog->shell), GTK_WIN_POS_MOUSE);
1325   gtk_widget_set_name(pdialog->shell, "Freeciv");
1326 
1327   gtk_widget_realize(pdialog->shell);
1328 
1329   /* keep the icon of the executable on Windows (see PR#36491) */
1330 #ifndef WIN32_NATIVE
1331   gtk_window_set_icon(GTK_WINDOW(pdialog->shell),
1332 		sprite_get_pixbuf(get_icon_sprite(tileset, ICON_CITYDLG)));
1333 #endif /* WIN32_NATIVE */
1334 
1335   /* Restore size of the city dialog. */
1336   gtk_window_set_default_size(GTK_WINDOW(pdialog->shell),
1337                               gui_options.gui_gtk2_citydlg_xsize,
1338                               gui_options.gui_gtk2_citydlg_ysize);
1339 
1340   pdialog->popup_menu = gtk_menu_new();
1341 
1342   vbox = GTK_DIALOG(pdialog->shell)->vbox;
1343   hbox = gtk_hbox_new(TRUE, 0);
1344   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1345 
1346   /**** Citizens bar here ****/
1347   cbox = gtk_hbox_new(FALSE, 0);
1348   gtk_box_pack_start(GTK_BOX(hbox), cbox, TRUE, TRUE, 0);
1349 
1350   ebox = gtk_event_box_new();
1351   gtk_widget_add_events(ebox, GDK_BUTTON_PRESS_MASK);
1352   gtk_box_pack_start(GTK_BOX(cbox), ebox, FALSE, FALSE, 0);
1353   pdialog->citizen_pixmap =
1354       gtk_pixcomm_new(tileset_small_sprite_width(tileset)
1355                       * NUM_CITIZENS_SHOWN / tileset_scale(tileset),
1356                       tileset_small_sprite_height(tileset)
1357                       / tileset_scale(tileset));
1358   gtk_misc_set_padding(GTK_MISC(pdialog->citizen_pixmap), 2, 2);
1359   gtk_misc_set_alignment(GTK_MISC(pdialog->citizen_pixmap), 0.0f, 0.5f);
1360   gtk_container_add(GTK_CONTAINER(ebox), pdialog->citizen_pixmap);
1361   g_signal_connect(GTK_OBJECT(ebox), "button_press_event",
1362                    GTK_SIGNAL_FUNC(citizens_callback), pdialog);
1363 
1364   /**** City name label here ****/
1365   pdialog->name_label = gtk_label_new(NULL);
1366   gtk_misc_set_alignment(GTK_MISC(pdialog->name_label), 0.0f, 0.5f);
1367   gtk_box_pack_start(GTK_BOX(hbox), pdialog->name_label, TRUE, TRUE, 0);
1368 
1369   /**** -Start of Notebook- ****/
1370 
1371   pdialog->notebook = gtk_notebook_new();
1372   gtk_notebook_set_tab_pos(GTK_NOTEBOOK(pdialog->notebook),
1373 			   GTK_POS_BOTTOM);
1374   gtk_box_pack_start(GTK_BOX(vbox), pdialog->notebook, TRUE, TRUE, 0);
1375 
1376   create_and_append_overview_page(pdialog);
1377   create_and_append_worklist_page(pdialog);
1378 
1379   /* only create these tabs if not a spy */
1380   if (!client_has_player() || city_owner(pcity) == client_player()) {
1381     create_and_append_happiness_page(pdialog);
1382   }
1383 
1384   if (city_owner(pcity) == client_player()
1385       && !client_is_observer()) {
1386     create_and_append_cma_page(pdialog);
1387     create_and_append_settings_page(pdialog);
1388   } else {
1389     gtk_notebook_set_current_page(GTK_NOTEBOOK(pdialog->notebook),
1390                                   OVERVIEW_PAGE);
1391   }
1392 
1393   /**** End of Notebook ****/
1394 
1395   /* bottom buttons */
1396 
1397   pdialog->show_units_command =
1398 	gtk_button_new_with_mnemonic(_("_List present units..."));
1399   gtk_container_add(GTK_CONTAINER(GTK_DIALOG(pdialog->shell)->action_area),
1400 		    pdialog->show_units_command);
1401   gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(GTK_DIALOG(pdialog->shell)->action_area),
1402       pdialog->show_units_command, TRUE);
1403   g_signal_connect(pdialog->show_units_command,
1404 		   "clicked",
1405 		   G_CALLBACK(show_units_callback), pdialog);
1406 
1407   pdialog->prev_command = gtk_stockbutton_new(GTK_STOCK_GO_BACK,
1408                                               _("_Prev city"));
1409   gtk_dialog_add_action_widget(GTK_DIALOG(pdialog->shell),
1410                                pdialog->prev_command, 1);
1411 
1412   pdialog->next_command = gtk_stockbutton_new(GTK_STOCK_GO_FORWARD,
1413                                               _("_Next city"));
1414   gtk_dialog_add_action_widget(GTK_DIALOG(pdialog->shell),
1415                                pdialog->next_command, 2);
1416 
1417   if (city_owner(pcity) != client.conn.playing) {
1418     gtk_widget_set_sensitive(pdialog->prev_command, FALSE);
1419     gtk_widget_set_sensitive(pdialog->next_command, FALSE);
1420   }
1421 
1422   close_command = gtk_dialog_add_button(GTK_DIALOG(pdialog->shell),
1423 					GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
1424 
1425   gtk_dialog_set_default_response(GTK_DIALOG(pdialog->shell),
1426 	GTK_RESPONSE_CLOSE);
1427 
1428   g_signal_connect(close_command, "clicked",
1429 		   G_CALLBACK(close_callback), pdialog);
1430 
1431   g_signal_connect(pdialog->prev_command, "clicked",
1432                    G_CALLBACK(switch_city_callback), pdialog);
1433 
1434   g_signal_connect(pdialog->next_command, "clicked",
1435                    G_CALLBACK(switch_city_callback), pdialog);
1436 
1437   /* some other things we gotta do */
1438 
1439   g_signal_connect(pdialog->shell, "key_press_event",
1440 		   G_CALLBACK(keyboard_handler), pdialog);
1441 
1442   dialog_list_prepend(dialog_list, pdialog);
1443 
1444   real_city_dialog_refresh(pdialog->pcity);
1445 
1446   /* need to do this every time a new dialog is opened. */
1447   city_dialog_update_prev_next();
1448 
1449   gtk_widget_show_all(GTK_DIALOG(pdialog->shell)->vbox);
1450   gtk_widget_show_all(GTK_DIALOG(pdialog->shell)->action_area);
1451 
1452   gtk_window_set_focus(GTK_WINDOW(pdialog->shell), close_command);
1453 
1454   return pdialog;
1455 }
1456 
1457 /*********** Functions to update parts of the dialog ************/
1458 /****************************************************************
1459   Update title of city dialog.
1460 *****************************************************************/
city_dialog_update_title(struct city_dialog * pdialog)1461 static void city_dialog_update_title(struct city_dialog *pdialog)
1462 {
1463   gchar *buf;
1464   const gchar *now;
1465 
1466   if (city_unhappy(pdialog->pcity)) {
1467     /* TRANS: city dialog title */
1468     buf = g_strdup_printf(_("<b>%s</b> - %s citizens - DISORDER"),
1469                           city_name_get(pdialog->pcity),
1470                           population_to_text(city_population(pdialog->pcity)));
1471   } else if (city_celebrating(pdialog->pcity)) {
1472     /* TRANS: city dialog title */
1473     buf = g_strdup_printf(_("<b>%s</b> - %s citizens - celebrating"),
1474                           city_name_get(pdialog->pcity),
1475                           population_to_text(city_population(pdialog->pcity)));
1476   } else if (city_happy(pdialog->pcity)) {
1477     /* TRANS: city dialog title */
1478     buf = g_strdup_printf(_("<b>%s</b> - %s citizens - happy"),
1479                           city_name_get(pdialog->pcity),
1480                           population_to_text(city_population(pdialog->pcity)));
1481   } else {
1482     /* TRANS: city dialog title */
1483     buf = g_strdup_printf(_("<b>%s</b> - %s citizens"),
1484                           city_name_get(pdialog->pcity),
1485                           population_to_text(city_population(pdialog->pcity)));
1486   }
1487 
1488   now = gtk_label_get_text(GTK_LABEL(pdialog->name_label));
1489   if (strcmp(now, buf) != 0) {
1490     gtk_window_set_title(GTK_WINDOW(pdialog->shell), city_name_get(pdialog->pcity));
1491     gtk_label_set_markup(GTK_LABEL(pdialog->name_label), buf);
1492   }
1493 
1494   g_free(buf);
1495 }
1496 
1497 /****************************************************************
1498   Update citizens in city dialog
1499 *****************************************************************/
city_dialog_update_citizens(struct city_dialog * pdialog)1500 static void city_dialog_update_citizens(struct city_dialog *pdialog)
1501 {
1502   enum citizen_category categories[MAX_CITY_SIZE];
1503   int i, width, size;
1504   struct city *pcity = pdialog->pcity;
1505   int num_citizens = get_city_citizen_types(pcity, FEELING_FINAL, categories);
1506 
1507   /* If there is not enough space we stack the icons. We draw from left to */
1508   /* right. width is how far we go to the right for each drawn pixmap. The */
1509   /* last icon is always drawn in full, and so has reserved                */
1510   /* tileset_small_sprite_width(tileset) pixels.                           */
1511 
1512   if (num_citizens > 1) {
1513     width = MIN(tileset_small_sprite_width(tileset)  / tileset_scale(tileset),
1514         ((NUM_CITIZENS_SHOWN - 1) * (tileset_small_sprite_width(tileset))
1515         / tileset_scale(tileset)) / (num_citizens - 1));
1516   } else {
1517     width = tileset_small_sprite_width(tileset) / tileset_scale(tileset);
1518   }
1519   pdialog->cwidth = width;
1520 
1521   /* overview page */
1522   gtk_pixcomm_freeze(GTK_PIXCOMM(pdialog->citizen_pixmap));
1523   gtk_pixcomm_clear(GTK_PIXCOMM(pdialog->citizen_pixmap));
1524 
1525   size = (num_citizens - 1) * width + tileset_small_sprite_width(tileset) +
1526          2 * GTK_MISC(pdialog->citizen_pixmap)->xpad;
1527   gtk_widget_set_size_request(GTK_WIDGET(pdialog->citizen_pixmap), size, -1);
1528 
1529   for (i = 0; i < num_citizens; i++) {
1530     gtk_pixcomm_copyto(GTK_PIXCOMM(pdialog->citizen_pixmap),
1531                        get_citizen_sprite(tileset, categories[i], i, pcity),
1532                        i * width, 0);
1533   }
1534   gtk_pixcomm_thaw(GTK_PIXCOMM(pdialog->citizen_pixmap));
1535 }
1536 
1537 /****************************************************************
1538   Update textual info fields in city dialog
1539 *****************************************************************/
city_dialog_update_information(GtkWidget ** info_ebox,GtkWidget ** info_label,struct city_dialog * pdialog)1540 static void city_dialog_update_information(GtkWidget **info_ebox,
1541 					   GtkWidget **info_label,
1542                                            struct city_dialog *pdialog)
1543 {
1544   int i, style, illness = 0;
1545   char buf[NUM_INFO_FIELDS][512];
1546   struct city *pcity = pdialog->pcity;
1547   int granaryturns;
1548 
1549   enum { FOOD, SHIELD, TRADE, GOLD, LUXURY, SCIENCE,
1550          GRANARY, GROWTH, CORRUPTION, WASTE, CULTURE,
1551          POLLUTION, ILLNESS, AIRLIFT,
1552   };
1553 
1554   /* fill the buffers with the necessary info */
1555   fc_snprintf(buf[FOOD], sizeof(buf[FOOD]), "%3d (%+4d)",
1556               pcity->prod[O_FOOD], pcity->surplus[O_FOOD]);
1557   fc_snprintf(buf[SHIELD], sizeof(buf[SHIELD]), "%3d (%+4d)",
1558               pcity->prod[O_SHIELD] + pcity->waste[O_SHIELD],
1559               pcity->surplus[O_SHIELD]);
1560   fc_snprintf(buf[TRADE], sizeof(buf[TRADE]), "%3d (%+4d)",
1561               pcity->surplus[O_TRADE] + pcity->waste[O_TRADE],
1562               pcity->surplus[O_TRADE]);
1563   fc_snprintf(buf[GOLD], sizeof(buf[GOLD]), "%3d (%+4d)",
1564               pcity->prod[O_GOLD], pcity->surplus[O_GOLD]);
1565   fc_snprintf(buf[LUXURY], sizeof(buf[LUXURY]), "%3d",
1566               pcity->prod[O_LUXURY]);
1567   fc_snprintf(buf[SCIENCE], sizeof(buf[SCIENCE]), "%3d",
1568               pcity->prod[O_SCIENCE]);
1569   fc_snprintf(buf[GRANARY], sizeof(buf[GRANARY]), "%4d/%-4d",
1570               pcity->food_stock, city_granary_size(city_size_get(pcity)));
1571 
1572   granaryturns = city_turns_to_grow(pcity);
1573   if (granaryturns == 0) {
1574     /* TRANS: city growth is blocked.  Keep short. */
1575     fc_snprintf(buf[GROWTH], sizeof(buf[GROWTH]), _("blocked"));
1576   } else if (granaryturns == FC_INFINITY) {
1577     /* TRANS: city is not growing.  Keep short. */
1578     fc_snprintf(buf[GROWTH], sizeof(buf[GROWTH]), _("never"));
1579   } else {
1580     /* A negative value means we'll have famine in that many turns.
1581        But that's handled down below. */
1582     /* TRANS: city growth turns.  Keep short. */
1583     fc_snprintf(buf[GROWTH], sizeof(buf[GROWTH]),
1584                 PL_("%d turn", "%d turns", abs(granaryturns)),
1585                 abs(granaryturns));
1586   }
1587   fc_snprintf(buf[CORRUPTION], sizeof(buf[CORRUPTION]), "%4d",
1588               pcity->waste[O_TRADE]);
1589   fc_snprintf(buf[WASTE], sizeof(buf[WASTE]), "%4d",
1590               pcity->waste[O_SHIELD]);
1591   fc_snprintf(buf[CULTURE], sizeof(buf[CULTURE]), "%4d",
1592               pcity->client.culture);
1593   fc_snprintf(buf[POLLUTION], sizeof(buf[POLLUTION]), "%4d",
1594               pcity->pollution);
1595   if (!game.info.illness_on) {
1596     fc_snprintf(buf[ILLNESS], sizeof(buf[ILLNESS]), "  -.-");
1597   } else {
1598     illness = city_illness_calc(pcity, NULL, NULL, NULL, NULL);
1599     /* illness is in tenth of percent */
1600     fc_snprintf(buf[ILLNESS], sizeof(buf[ILLNESS]), "%5.1f%%",
1601                 (float)illness / 10.0);
1602   }
1603 
1604   get_city_dialog_airlift_value(pcity, buf[AIRLIFT], sizeof(buf[AIRLIFT]));
1605 
1606   /* stick 'em in the labels */
1607 
1608   for (i = 0; i < NUM_INFO_FIELDS; i++) {
1609     gtk_label_set_text(GTK_LABEL(info_label[i]), buf[i]);
1610   }
1611 
1612   /*
1613    * Special style stuff for granary, growth, pollution, and plague below.
1614    * For starvation, the "4" below is arbitrary. 3 turns should be enough
1615    * of a warning.
1616    */
1617   style = (granaryturns > -4 && granaryturns < 0) ? RED : NORMAL;
1618   gtk_widget_modify_style(info_label[GRANARY], info_label_style[style]);
1619 
1620   style = (granaryturns == 0 || pcity->surplus[O_FOOD] < 0) ? RED : NORMAL;
1621   gtk_widget_modify_style(info_label[GROWTH], info_label_style[style]);
1622 
1623   /* someone could add the info_label_style[ORANGE]
1624    * style for better granularity here */
1625 
1626   style = (pcity->pollution >= 10) ? RED : NORMAL;
1627   gtk_widget_modify_style(info_label[POLLUTION], info_label_style[style]);
1628 
1629   /* illness is in tenth of percent, i.e 100 == 10.0% */
1630   style = (illness >= 100) ? RED : NORMAL;
1631   gtk_widget_modify_style(info_label[ILLNESS], info_label_style[style]);
1632 }
1633 
1634 /****************************************************************
1635   Update map display of city dialog
1636 *****************************************************************/
city_dialog_update_map(struct city_dialog * pdialog)1637 static void city_dialog_update_map(struct city_dialog *pdialog)
1638 {
1639   struct canvas store = {
1640     .type = CANVAS_PIXMAP,
1641     .v = {.pixmap = pdialog->map_canvas_store_unscaled}
1642   };
1643 
1644   /* The drawing is done in three steps.
1645    *   1.  First we render to a pixmap with the appropriate canvas size.
1646    *   2.  Then the pixmap is rendered into a pixbuf of equal size.
1647    *   3.  Finally this pixbuf is composited and scaled onto the GtkImage's
1648    *       target pixbuf.
1649    */
1650 
1651   city_dialog_redraw_map(pdialog->pcity, &store);
1652   pdialog->map_pixbuf_unscaled
1653     = gdk_pixbuf_get_from_drawable(pdialog->map_pixbuf_unscaled,
1654 				   pdialog->map_canvas_store_unscaled,
1655 				   NULL,
1656 				   0, 0, 0, 0,
1657 				   canvas_width, canvas_height);
1658   gdk_pixbuf_composite(pdialog->map_pixbuf_unscaled,
1659 		       pdialog->map_canvas_store,
1660 		       0, 0, CITYMAP_WIDTH, CITYMAP_HEIGHT,
1661 		       0.0, 0.0,
1662 		       (double)CITYMAP_WIDTH / (double)canvas_width,
1663 		       (double)CITYMAP_HEIGHT / (double)canvas_height,
1664 		       GDK_INTERP_BILINEAR, 255);
1665 
1666   /* draw to real window */
1667   draw_map_canvas(pdialog);
1668 
1669   if (cma_is_city_under_agent(pdialog->pcity, NULL)) {
1670     gtk_widget_set_sensitive(pdialog->overview.map_canvas.ebox, FALSE);
1671     if (pdialog->happiness.map_canvas.ebox) {
1672       gtk_widget_set_sensitive(pdialog->happiness.map_canvas.ebox, FALSE);
1673     }
1674   } else {
1675     gtk_widget_set_sensitive(pdialog->overview.map_canvas.ebox, TRUE);
1676     if (pdialog->happiness.map_canvas.ebox) {
1677       gtk_widget_set_sensitive(pdialog->happiness.map_canvas.ebox, TRUE);
1678     }
1679   }
1680 }
1681 
1682 /****************************************************************
1683   Update what city is building and buy cost in city dialog
1684 *****************************************************************/
city_dialog_update_building(struct city_dialog * pdialog)1685 static void city_dialog_update_building(struct city_dialog *pdialog)
1686 {
1687   char buf[32], buf2[200];
1688   gdouble pct;
1689 
1690   GtkListStore* store;
1691   GtkTreeIter iter;
1692   struct universal targets[MAX_NUM_PRODUCTION_TARGETS];
1693   struct item items[MAX_NUM_PRODUCTION_TARGETS];
1694   int targets_used, item;
1695   struct city *pcity = pdialog->pcity;
1696   gboolean sensitive = city_can_buy(pcity);
1697   const char *descr = city_production_name_translation(pcity);
1698   int cost = city_production_build_shield_cost(pcity);
1699 
1700   gtk_widget_set_sensitive(pdialog->overview.buy_command, sensitive);
1701   gtk_widget_set_sensitive(pdialog->production.buy_command, sensitive);
1702 
1703   /* Make sure build slots info is up to date */
1704   {
1705     int build_slots = city_build_slots(pcity);
1706     /* Only display extra info if more than one slot is available */
1707     if (build_slots > 1) {
1708       fc_snprintf(buf2, sizeof(buf2),
1709                   /* TRANS: never actually used with built_slots<=1 */
1710                   PL_("Production (up to %d unit per turn):",
1711                       "Production (up to %d units per turn):", build_slots),
1712                   build_slots);
1713       gtk_label_set_text(
1714         GTK_LABEL(pdialog->production.production_label), buf2);
1715     } else {
1716       gtk_label_set_text(
1717         GTK_LABEL(pdialog->production.production_label), _("Production:"));
1718     }
1719   }
1720 
1721   /* Update what the city is working on */
1722   get_city_dialog_production(pcity, buf, sizeof(buf));
1723 
1724   if (cost > 0) {
1725     pct = (gdouble) pcity->shield_stock / (gdouble) cost;
1726     pct = CLAMP(pct, 0.0, 1.0);
1727   } else {
1728     pct = 1.0;
1729   }
1730 
1731   fc_snprintf(buf2, sizeof(buf2), "%s%s\n%s", descr,
1732               worklist_is_empty(&pcity->worklist) ? "" : " (+)", buf);
1733   gtk_progress_bar_set_text(
1734     GTK_PROGRESS_BAR(pdialog->overview.production_bar), buf2);
1735   gtk_progress_bar_set_fraction(
1736     GTK_PROGRESS_BAR(pdialog->overview.production_bar), pct);
1737 
1738   fc_snprintf(buf2, sizeof(buf2), "%s%s: %s", descr,
1739               worklist_is_empty(&pcity->worklist) ? "" : " (+)", buf);
1740   gtk_progress_bar_set_text(
1741     GTK_PROGRESS_BAR(pdialog->production.production_bar), buf2);
1742   gtk_progress_bar_set_fraction(
1743     GTK_PROGRESS_BAR(pdialog->production.production_bar), pct);
1744 
1745   store = pdialog->overview.change_production_store;
1746   gtk_combo_box_set_active(GTK_COMBO_BOX(pdialog->overview.production_combo),
1747                            -1);
1748   gtk_list_store_clear(store);
1749 
1750   targets_used
1751     = collect_eventually_buildable_targets(targets, pdialog->pcity, FALSE);
1752   name_and_sort_items(targets, targets_used, items, FALSE, pcity);
1753 
1754   for (item = 0; item < targets_used; item++) {
1755     if (can_city_build_now(pcity, &items[item].item)) {
1756       const char* name;
1757       struct sprite* sprite;
1758       struct universal target = items[item].item;
1759       bool useless;
1760 
1761       if (VUT_UTYPE == target.kind) {
1762 	name = utype_name_translation(target.value.utype);
1763 	sprite = get_unittype_sprite(tileset, target.value.utype,
1764                                      direction8_invalid(), TRUE);
1765         useless = FALSE;
1766       } else {
1767 	name = improvement_name_translation(target.value.building);
1768 	sprite = get_building_sprite(tileset, target.value.building);
1769         useless = is_improvement_redundant(pcity, target.value.building);
1770       }
1771       gtk_list_store_append(store, &iter);
1772       gtk_list_store_set(store, &iter, 0, sprite_get_pixbuf(sprite),
1773                          1, name, 3, useless,
1774                          2, (gint)cid_encode(items[item].item),-1);
1775     }
1776   }
1777 
1778   /* work around GTK+ refresh bug. */
1779   gtk_widget_queue_resize(pdialog->overview.production_bar);
1780   gtk_widget_queue_resize(pdialog->production.production_bar);
1781 }
1782 
1783 /****************************************************************
1784   Update list of improvements in city dialog
1785 *****************************************************************/
city_dialog_update_improvement_list(struct city_dialog * pdialog)1786 static void city_dialog_update_improvement_list(struct city_dialog *pdialog)
1787 {
1788   int item, targets_used;
1789   struct universal targets[MAX_NUM_PRODUCTION_TARGETS];
1790   struct item items[MAX_NUM_PRODUCTION_TARGETS];
1791   GtkTreeModel *model;
1792   GtkListStore *store;
1793 
1794   const char *tooltip_sellable = _("Press <b>ENTER</b> or double-click to "
1795                                    "sell an improvement.");
1796   const char *tooltip_great_wonder = _("Great Wonder - cannot be sold.");
1797   const char *tooltip_small_wonder = _("Small Wonder - cannot be sold.");
1798 
1799   model =
1800     gtk_tree_view_get_model(GTK_TREE_VIEW(pdialog->overview.improvement_list));
1801   store = GTK_LIST_STORE(model);
1802 
1803   targets_used = collect_already_built_targets(targets, pdialog->pcity);
1804   name_and_sort_items(targets, targets_used, items, FALSE, pdialog->pcity);
1805 
1806   gtk_list_store_clear(store);
1807 
1808   for (item = 0; item < targets_used; item++) {
1809     GtkTreeIter it;
1810     int upkeep;
1811     struct sprite *sprite;
1812     struct universal target = items[item].item;
1813 
1814     fc_assert_action(VUT_IMPROVEMENT == target.kind, continue);
1815     /* This takes effects (like Adam Smith's) into account. */
1816     upkeep = city_improvement_upkeep(pdialog->pcity, target.value.building);
1817     sprite = get_building_sprite(tileset, target.value.building);
1818 
1819     gtk_list_store_append(store, &it);
1820     gtk_list_store_set(store, &it,
1821                        0, target.value.building,
1822                        1, sprite_get_pixbuf(sprite),
1823                        2, items[item].descr,
1824                        3, upkeep,
1825                        4,
1826                        is_improvement_redundant(pdialog->pcity,
1827                                                 target.value.building),
1828                        5,
1829                        is_great_wonder(target.value.building) ?
1830                          tooltip_great_wonder :
1831                            (is_small_wonder(target.value.building) ?
1832                              tooltip_small_wonder : tooltip_sellable),
1833                        -1);
1834   }
1835 }
1836 
1837 /****************************************************************
1838   Update list of supported units in city dialog
1839 *****************************************************************/
city_dialog_update_supported_units(struct city_dialog * pdialog)1840 static void city_dialog_update_supported_units(struct city_dialog *pdialog)
1841 {
1842   struct unit_list *units;
1843   struct unit_node_vector *nodes;
1844   int n, m, i;
1845   gchar *buf;
1846   int free_unhappy = get_city_bonus(pdialog->pcity, EFT_MAKE_CONTENT_MIL);
1847 
1848   if (NULL != client.conn.playing
1849       && city_owner(pdialog->pcity) != client.conn.playing) {
1850     units = pdialog->pcity->client.info_units_supported;
1851   } else {
1852     units = pdialog->pcity->units_supported;
1853   }
1854 
1855   nodes = &pdialog->overview.supported_units;
1856 
1857   n = unit_list_size(units);
1858   m = unit_node_vector_size(nodes);
1859 
1860   gtk_table_resize(GTK_TABLE(pdialog->overview.supported_unit_table),
1861 		   1, MAX(n, 1));
1862 
1863   if (m > n) {
1864     i = 0;
1865     unit_node_vector_iterate(nodes, elt) {
1866       if (i++ >= n) {
1867 	gtk_widget_destroy(elt->cmd);
1868       }
1869     } unit_node_vector_iterate_end;
1870 
1871     unit_node_vector_reserve(nodes, n);
1872   } else {
1873     for (i = m; i < n; i++) {
1874       GtkWidget *cmd, *pix;
1875       struct unit_node node;
1876       int unit_height = tileset_unit_with_upkeep_height(tileset);
1877 
1878       cmd = gtk_button_new();
1879       node.cmd = cmd;
1880 
1881       gtk_button_set_relief(GTK_BUTTON(cmd), GTK_RELIEF_NONE);
1882       gtk_widget_add_events(cmd,
1883 	  GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
1884 
1885       pix = gtk_pixcomm_new(tileset_full_tile_width(tileset), unit_height);
1886       node.pix = pix;
1887 
1888       gtk_container_add(GTK_CONTAINER(cmd), pix);
1889 
1890       gtk_table_attach_defaults(
1891 	  GTK_TABLE(pdialog->overview.supported_unit_table),
1892 	  cmd, i, i+1, 0, 1);
1893       unit_node_vector_append(nodes, node);
1894     }
1895   }
1896 
1897   i = 0;
1898   unit_list_iterate(units, punit) {
1899     struct unit_node *pnode;
1900     int happy_cost = city_unit_unhappiness(punit, &free_unhappy);
1901 
1902     pnode = unit_node_vector_get(nodes, i);
1903     if (pnode) {
1904       GtkWidget *cmd, *pix;
1905 
1906       cmd = pnode->cmd;
1907       pix = pnode->pix;
1908 
1909       gtk_pixcomm_freeze(GTK_PIXCOMM(pix));
1910       put_unit_gpixmap(punit, GTK_PIXCOMM(pix));
1911       put_unit_gpixmap_city_overlays(punit, GTK_PIXCOMM(pix), punit->upkeep,
1912                                      happy_cost);
1913       gtk_pixcomm_thaw(GTK_PIXCOMM(pix));
1914 
1915       g_signal_handlers_disconnect_matched(cmd,
1916 	  G_SIGNAL_MATCH_FUNC,
1917 	  0, 0, NULL, supported_unit_callback, NULL);
1918 
1919       g_signal_handlers_disconnect_matched(cmd,
1920 	  G_SIGNAL_MATCH_FUNC,
1921 	  0, 0, NULL, supported_unit_middle_callback, NULL);
1922 
1923       gtk_widget_set_tooltip_text(cmd, unit_description(punit));
1924 
1925       g_signal_connect(cmd, "button_press_event",
1926 	  G_CALLBACK(supported_unit_callback),
1927 	  GINT_TO_POINTER(punit->id));
1928 
1929       g_signal_connect(cmd, "button_release_event",
1930 	  G_CALLBACK(supported_unit_middle_callback),
1931 	  GINT_TO_POINTER(punit->id));
1932 
1933       if (city_owner(pdialog->pcity) != client.conn.playing) {
1934 	gtk_widget_set_sensitive(cmd, FALSE);
1935       } else {
1936 	gtk_widget_set_sensitive(cmd, TRUE);
1937       }
1938 
1939       gtk_widget_show(pix);
1940       gtk_widget_show(cmd);
1941     }
1942     i++;
1943   } unit_list_iterate_end;
1944 
1945   buf = g_strdup_printf(_("Supported units %d"), n);
1946   gtk_frame_set_label(GTK_FRAME(pdialog->overview.supported_units_frame), buf);
1947   g_free(buf);
1948 }
1949 
1950 /****************************************************************
1951   Update list of present units in city dialog
1952 *****************************************************************/
city_dialog_update_present_units(struct city_dialog * pdialog)1953 static void city_dialog_update_present_units(struct city_dialog *pdialog)
1954 {
1955   struct unit_list *units;
1956   struct unit_node_vector *nodes;
1957   int n, m, i;
1958   gchar *buf;
1959 
1960   if (NULL != client.conn.playing
1961       && city_owner(pdialog->pcity) != client.conn.playing) {
1962     units = pdialog->pcity->client.info_units_present;
1963   } else {
1964     units = pdialog->pcity->tile->units;
1965   }
1966 
1967   nodes = &pdialog->overview.present_units;
1968 
1969   n = unit_list_size(units);
1970   m = unit_node_vector_size(nodes);
1971 
1972   gtk_table_resize(GTK_TABLE(pdialog->overview.present_unit_table),
1973 		   1, MAX(n, 1));
1974 
1975   if (m > n) {
1976     i = 0;
1977     unit_node_vector_iterate(nodes, elt) {
1978       if (i++ >= n) {
1979 	gtk_widget_destroy(elt->cmd);
1980       }
1981     } unit_node_vector_iterate_end;
1982 
1983     unit_node_vector_reserve(nodes, n);
1984   } else {
1985     for (i = m; i < n; i++) {
1986       GtkWidget *cmd, *pix;
1987       struct unit_node node;
1988 
1989       cmd = gtk_button_new();
1990       node.cmd = cmd;
1991 
1992       gtk_button_set_relief(GTK_BUTTON(cmd), GTK_RELIEF_NONE);
1993       gtk_widget_add_events(cmd,
1994 	  GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
1995 
1996       pix = gtk_pixcomm_new(tileset_full_tile_width(tileset),
1997                             tileset_full_tile_height(tileset));
1998       node.pix = pix;
1999 
2000       gtk_container_add(GTK_CONTAINER(cmd), pix);
2001 
2002       gtk_table_attach_defaults(
2003 	  GTK_TABLE(pdialog->overview.present_unit_table),
2004 	  cmd, i, i+1, 0, 1);
2005       unit_node_vector_append(nodes, node);
2006     }
2007   }
2008 
2009   i = 0;
2010   unit_list_iterate(units, punit) {
2011     struct unit_node *pnode;
2012 
2013     pnode = unit_node_vector_get(nodes, i);
2014     if (pnode) {
2015       GtkWidget *cmd, *pix;
2016 
2017       cmd = pnode->cmd;
2018       pix = pnode->pix;
2019 
2020       put_unit_gpixmap(punit, GTK_PIXCOMM(pix));
2021 
2022       g_signal_handlers_disconnect_matched(cmd,
2023 	  G_SIGNAL_MATCH_FUNC,
2024 	  0, 0, NULL, present_unit_callback, NULL);
2025 
2026       g_signal_handlers_disconnect_matched(cmd,
2027 	  G_SIGNAL_MATCH_FUNC,
2028 	  0, 0, NULL, present_unit_middle_callback, NULL);
2029 
2030       gtk_widget_set_tooltip_text(cmd, unit_description(punit));
2031 
2032       g_signal_connect(cmd, "button_press_event",
2033 	  G_CALLBACK(present_unit_callback),
2034 	  GINT_TO_POINTER(punit->id));
2035 
2036       g_signal_connect(cmd, "button_release_event",
2037 	  G_CALLBACK(present_unit_middle_callback),
2038 	  GINT_TO_POINTER(punit->id));
2039 
2040       if (city_owner(pdialog->pcity) != client.conn.playing) {
2041 	gtk_widget_set_sensitive(cmd, FALSE);
2042       } else {
2043 	gtk_widget_set_sensitive(cmd, TRUE);
2044       }
2045 
2046       gtk_widget_show(pix);
2047       gtk_widget_show(cmd);
2048     }
2049     i++;
2050   } unit_list_iterate_end;
2051 
2052   buf = g_strdup_printf(_("Present units %d"), n);
2053   gtk_frame_set_label(GTK_FRAME(pdialog->overview.present_units_frame), buf);
2054   g_free(buf);
2055 }
2056 
2057 /****************************************************************
2058   Updates the sensitivity of the the prev and next buttons.
2059   this does not need pdialog as a parameter, since it iterates
2060   over all the open dialogs.
2061   note: we still need the sensitivity code in create_city_dialog()
2062   for the spied dialogs.
2063 *****************************************************************/
city_dialog_update_prev_next(void)2064 static void city_dialog_update_prev_next(void)
2065 {
2066   int count = 0;
2067   int city_number;
2068 
2069   if (client_is_global_observer()) {
2070     return; /* Keep them insensitive as initially set */
2071   }
2072 
2073   city_number = city_list_size(client.conn.playing->cities);
2074 
2075   /* the first time, we see if all the city dialogs are open */
2076   dialog_list_iterate(dialog_list, pdialog) {
2077     if (city_owner(pdialog->pcity) == client.conn.playing) {
2078       count++;
2079     }
2080   } dialog_list_iterate_end;
2081 
2082   if (count == city_number) {	/* all are open, shouldn't prev/next */
2083     dialog_list_iterate(dialog_list, pdialog) {
2084       gtk_widget_set_sensitive(pdialog->prev_command, FALSE);
2085       gtk_widget_set_sensitive(pdialog->next_command, FALSE);
2086     } dialog_list_iterate_end;
2087   } else {
2088     dialog_list_iterate(dialog_list, pdialog) {
2089       if (city_owner(pdialog->pcity) == client.conn.playing) {
2090 	gtk_widget_set_sensitive(pdialog->prev_command, TRUE);
2091 	gtk_widget_set_sensitive(pdialog->next_command, TRUE);
2092       }
2093     } dialog_list_iterate_end;
2094   }
2095 }
2096 
2097 /****************************************************************
2098   User has clicked show units
2099 *****************************************************************/
show_units_callback(GtkWidget * w,gpointer data)2100 static void show_units_callback(GtkWidget * w, gpointer data)
2101 {
2102   struct city_dialog *pdialog = (struct city_dialog *) data;
2103   struct tile *ptile = pdialog->pcity->tile;
2104 
2105   if (unit_list_size(ptile->units))
2106     unit_select_dialog_popup(ptile);
2107 }
2108 
2109 /****************************************************************
2110   Set city menu position
2111 *****************************************************************/
city_menu_position(GtkMenu * menu,gint * x,gint * y,gboolean * push_in,gpointer data)2112 static void city_menu_position(GtkMenu *menu, gint *x, gint *y,
2113                                gboolean *push_in, gpointer data)
2114 {
2115   GtkWidget *widget;
2116   GtkRequisition requisition;
2117   gint xpos;
2118   gint ypos;
2119 
2120   fc_assert_ret(GTK_IS_BUTTON(data));
2121 
2122   widget = GTK_WIDGET(data);
2123 
2124   gtk_widget_get_child_requisition(GTK_WIDGET(menu), &requisition);
2125 
2126   gdk_window_get_origin(widget->window, &xpos, &ypos);
2127 
2128   xpos += widget->allocation.x;
2129   ypos += widget->allocation.y;
2130 
2131   *x = xpos;
2132   *y = ypos;
2133   *push_in = TRUE;
2134 }
2135 
2136 /****************************************************************
2137   Destroy widget -callback
2138 *****************************************************************/
destroy_func(GtkWidget * w,gpointer data)2139 static void destroy_func(GtkWidget *w, gpointer data)
2140 {
2141   gtk_widget_destroy(w);
2142 }
2143 
2144 /****************************************************************
2145 Pop-up menu to change attributes of supported units
2146 *****************************************************************/
supported_unit_callback(GtkWidget * w,GdkEventButton * ev,gpointer data)2147 static gboolean supported_unit_callback(GtkWidget * w, GdkEventButton * ev,
2148 				        gpointer data)
2149 {
2150   GtkWidget *menu, *item;
2151   struct city_dialog *pdialog;
2152   struct city *pcity;
2153   struct unit *punit =
2154     player_unit_by_number(client_player(), (size_t) data);
2155 
2156   if (NULL != punit
2157    && NULL != (pcity = game_city_by_number(punit->homecity))
2158    && NULL != (pdialog = get_city_dialog(pcity))) {
2159 
2160     if (ev->type != GDK_BUTTON_PRESS || ev->button == 2 || ev->button == 3
2161 	|| !can_client_issue_orders()) {
2162       return FALSE;
2163     }
2164 
2165     menu = pdialog->popup_menu;
2166 
2167     gtk_menu_popdown(GTK_MENU(menu));
2168     gtk_container_foreach(GTK_CONTAINER(menu), destroy_func, NULL);
2169 
2170     item = gtk_menu_item_new_with_mnemonic(_("Cen_ter"));
2171     g_signal_connect(item, "activate",
2172       G_CALLBACK(unit_center_callback),
2173       GINT_TO_POINTER(punit->id));
2174     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2175 
2176     item = gtk_menu_item_new_with_mnemonic(_("_Activate unit"));
2177     g_signal_connect(item, "activate",
2178       G_CALLBACK(unit_activate_callback),
2179       GINT_TO_POINTER(punit->id));
2180     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2181 
2182     item = gtk_menu_item_new_with_mnemonic(_("Activate unit, _close dialog"));
2183     g_signal_connect(item, "activate",
2184       G_CALLBACK(supported_unit_activate_close_callback),
2185       GINT_TO_POINTER(punit->id));
2186     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2187 
2188     item = gtk_menu_item_new_with_mnemonic(_("_Disband unit"));
2189     g_signal_connect(item, "activate",
2190       G_CALLBACK(unit_disband_callback),
2191       GINT_TO_POINTER(punit->id));
2192     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2193 
2194     if (unit_has_type_flag(punit, UTYF_UNDISBANDABLE)) {
2195       gtk_widget_set_sensitive(item, FALSE);
2196     }
2197 
2198     gtk_widget_show_all(menu);
2199 
2200     gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
2201       city_menu_position, w, ev->button, ev->time);
2202 
2203 
2204   }
2205   return TRUE;
2206 }
2207 
2208 /****************************************************************
2209 Pop-up menu to change attributes of units, ex. change homecity.
2210 *****************************************************************/
present_unit_callback(GtkWidget * w,GdkEventButton * ev,gpointer data)2211 static gboolean present_unit_callback(GtkWidget * w, GdkEventButton * ev,
2212 				      gpointer data)
2213 {
2214   GtkWidget *menu, *item;
2215   struct city_dialog *pdialog;
2216   struct city *pcity;
2217   struct unit *punit =
2218     player_unit_by_number(client_player(), (size_t) data);
2219 
2220   if (NULL != punit
2221    && NULL != (pcity = tile_city(unit_tile(punit)))
2222    && NULL != (pdialog = get_city_dialog(pcity))) {
2223 
2224     if (ev->type != GDK_BUTTON_PRESS || ev->button == 2 || ev->button == 3
2225 	|| !can_client_issue_orders()) {
2226       return FALSE;
2227     }
2228 
2229     menu = pdialog->popup_menu;
2230 
2231     gtk_menu_popdown(GTK_MENU(menu));
2232     gtk_container_foreach(GTK_CONTAINER(menu), destroy_func, NULL);
2233 
2234     item = gtk_menu_item_new_with_mnemonic(_("_Activate unit"));
2235     g_signal_connect(item, "activate",
2236       G_CALLBACK(unit_activate_callback),
2237       GINT_TO_POINTER(punit->id));
2238     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2239 
2240     item = gtk_menu_item_new_with_mnemonic(_("Activate unit, _close dialog"));
2241     g_signal_connect(item, "activate",
2242       G_CALLBACK(present_unit_activate_close_callback),
2243       GINT_TO_POINTER(punit->id));
2244     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2245 
2246     item = gtk_menu_item_new_with_mnemonic(_("_Load unit"));
2247     g_signal_connect(item, "activate",
2248       G_CALLBACK(unit_load_callback),
2249       GINT_TO_POINTER(punit->id));
2250     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2251 
2252     if (!unit_can_load(punit)) {
2253       gtk_widget_set_sensitive(item, FALSE);
2254     }
2255 
2256     item = gtk_menu_item_new_with_mnemonic(_("_Unload unit"));
2257     g_signal_connect(item, "activate",
2258       G_CALLBACK(unit_unload_callback),
2259       GINT_TO_POINTER(punit->id));
2260     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2261 
2262     if (!can_unit_unload(punit, unit_transport_get(punit))
2263         || !can_unit_exist_at_tile(punit, unit_tile(punit))) {
2264       gtk_widget_set_sensitive(item, FALSE);
2265     }
2266 
2267     item = gtk_menu_item_new_with_mnemonic(_("_Sentry unit"));
2268     g_signal_connect(item, "activate",
2269       G_CALLBACK(unit_sentry_callback),
2270       GINT_TO_POINTER(punit->id));
2271     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2272 
2273     if (punit->activity == ACTIVITY_SENTRY
2274 	|| !can_unit_do_activity(punit, ACTIVITY_SENTRY)) {
2275       gtk_widget_set_sensitive(item, FALSE);
2276     }
2277 
2278     item = gtk_menu_item_new_with_mnemonic(_("_Fortify unit"));
2279     g_signal_connect(item, "activate",
2280       G_CALLBACK(unit_fortify_callback),
2281       GINT_TO_POINTER(punit->id));
2282     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2283 
2284     if (punit->activity == ACTIVITY_FORTIFYING
2285 	|| !can_unit_do_activity(punit, ACTIVITY_FORTIFYING)) {
2286       gtk_widget_set_sensitive(item, FALSE);
2287     }
2288 
2289     item = gtk_menu_item_new_with_mnemonic(_("_Disband unit"));
2290     g_signal_connect(item, "activate",
2291       G_CALLBACK(unit_disband_callback),
2292       GINT_TO_POINTER(punit->id));
2293     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2294 
2295     if (unit_has_type_flag(punit, UTYF_UNDISBANDABLE)) {
2296       gtk_widget_set_sensitive(item, FALSE);
2297     }
2298 
2299     item = gtk_menu_item_new_with_mnemonic(_("Set _Home City"));
2300     g_signal_connect(item, "activate",
2301       G_CALLBACK(unit_homecity_callback),
2302       GINT_TO_POINTER(punit->id));
2303     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2304     gtk_widget_set_sensitive(item, can_unit_change_homecity_to(punit, pcity));
2305 
2306     item = gtk_menu_item_new_with_mnemonic(_("U_pgrade unit"));
2307     g_signal_connect(item, "activate",
2308       G_CALLBACK(unit_upgrade_callback),
2309       GINT_TO_POINTER(punit->id));
2310     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2311 
2312     if (!can_client_issue_orders()
2313 	|| NULL == can_upgrade_unittype(client.conn.playing,
2314                                         unit_type_get(punit))) {
2315       gtk_widget_set_sensitive(item, FALSE);
2316     }
2317 
2318     gtk_widget_show_all(menu);
2319 
2320     gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
2321       city_menu_position, w, ev->button, ev->time);
2322   }
2323   return TRUE;
2324 }
2325 
2326 /****************************************************************
2327  if user middle-clicked on a unit, activate it and close dialog
2328 *****************************************************************/
present_unit_middle_callback(GtkWidget * w,GdkEventButton * ev,gpointer data)2329 static gboolean present_unit_middle_callback(GtkWidget * w,
2330 					     GdkEventButton * ev,
2331 					     gpointer data)
2332 {
2333   struct city_dialog *pdialog;
2334   struct city *pcity;
2335   struct unit *punit =
2336     player_unit_by_number(client_player(), (size_t) data);
2337 
2338   if (NULL != punit
2339    && NULL != (pcity = tile_city(unit_tile(punit)))
2340    && NULL != (pdialog = get_city_dialog(pcity))
2341    && can_client_issue_orders()) {
2342 
2343     if (ev->button == 3) {
2344       unit_focus_set(punit);
2345     } else if (ev->button == 2) {
2346       unit_focus_set(punit);
2347       close_city_dialog(pdialog);
2348     }
2349   }
2350 
2351   return TRUE;
2352 }
2353 
2354 /****************************************************************
2355  if user middle-clicked on a unit, activate it and close dialog
2356 *****************************************************************/
supported_unit_middle_callback(GtkWidget * w,GdkEventButton * ev,gpointer data)2357 static gboolean supported_unit_middle_callback(GtkWidget * w,
2358 					       GdkEventButton * ev,
2359 					       gpointer data)
2360 {
2361   struct city_dialog *pdialog;
2362   struct city *pcity;
2363   struct unit *punit =
2364     player_unit_by_number(client_player(), (size_t) data);
2365 
2366   if (NULL != punit
2367    && NULL != (pcity = game_city_by_number(punit->homecity))
2368    && NULL != (pdialog = get_city_dialog(pcity))
2369    && can_client_issue_orders()) {
2370 
2371     if (ev->button == 3) {
2372       unit_focus_set(punit);
2373     } else if (ev->button == 2) {
2374       unit_focus_set(punit);
2375       close_city_dialog(pdialog);
2376     }
2377   }
2378 
2379   return TRUE;
2380 }
2381 
2382 /****************************************************************
2383   User has requested centering to unit
2384 *****************************************************************/
unit_center_callback(GtkWidget * w,gpointer data)2385 static void unit_center_callback(GtkWidget * w, gpointer data)
2386 {
2387   struct unit *punit =
2388     player_unit_by_number(client_player(), (size_t)data);
2389 
2390   if (NULL != punit) {
2391     center_tile_mapcanvas(unit_tile(punit));
2392   }
2393 }
2394 
2395 /****************************************************************
2396   User has requested unit activation
2397 *****************************************************************/
unit_activate_callback(GtkWidget * w,gpointer data)2398 static void unit_activate_callback(GtkWidget * w, gpointer data)
2399 {
2400   struct unit *punit =
2401     player_unit_by_number(client_player(), (size_t)data);
2402 
2403   if (NULL != punit) {
2404     unit_focus_set(punit);
2405   }
2406 }
2407 
2408 /****************************************************************
2409   User has requested some supported unit to be activated and
2410   city dialog to be closed
2411 *****************************************************************/
supported_unit_activate_close_callback(GtkWidget * w,gpointer data)2412 static void supported_unit_activate_close_callback(GtkWidget * w,
2413 						   gpointer data)
2414 {
2415   struct unit *punit =
2416     player_unit_by_number(client_player(), (size_t)data);
2417 
2418   if (NULL != punit) {
2419     struct city *pcity =
2420       player_city_by_number(client_player(), punit->homecity);
2421 
2422     unit_focus_set(punit);
2423     if (NULL != pcity) {
2424       struct city_dialog *pdialog = get_city_dialog(pcity);
2425 
2426       if (NULL != pdialog) {
2427 	close_city_dialog(pdialog);
2428       }
2429     }
2430   }
2431 }
2432 
2433 /****************************************************************
2434   User has requested some present unit to be activated and
2435   city dialog to be closed
2436 *****************************************************************/
present_unit_activate_close_callback(GtkWidget * w,gpointer data)2437 static void present_unit_activate_close_callback(GtkWidget * w,
2438 						 gpointer data)
2439 {
2440   struct unit *punit =
2441     player_unit_by_number(client_player(), (size_t)data);
2442 
2443   if (NULL != punit) {
2444     struct city *pcity = tile_city(unit_tile(punit));
2445 
2446     unit_focus_set(punit);
2447     if (NULL != pcity) {
2448       struct city_dialog *pdialog = get_city_dialog(pcity);
2449 
2450       if (NULL != pdialog) {
2451 	close_city_dialog(pdialog);
2452       }
2453     }
2454   }
2455 }
2456 
2457 /****************************************************************
2458   User has requested unit to be loaded to transport
2459 *****************************************************************/
unit_load_callback(GtkWidget * w,gpointer data)2460 static void unit_load_callback(GtkWidget * w, gpointer data)
2461 {
2462   struct unit *punit =
2463     player_unit_by_number(client_player(), (size_t)data);
2464 
2465   if (NULL != punit) {
2466     request_unit_load(punit, NULL, unit_tile(punit));
2467   }
2468 }
2469 
2470 /****************************************************************
2471   User has requested unit to be unloaded from transport
2472 *****************************************************************/
unit_unload_callback(GtkWidget * w,gpointer data)2473 static void unit_unload_callback(GtkWidget * w, gpointer data)
2474 {
2475   struct unit *punit =
2476     player_unit_by_number(client_player(), (size_t)data);
2477 
2478   if (NULL != punit) {
2479     request_unit_unload(punit);
2480   }
2481 }
2482 
2483 /****************************************************************
2484   User has requested unit to be sentried
2485 *****************************************************************/
unit_sentry_callback(GtkWidget * w,gpointer data)2486 static void unit_sentry_callback(GtkWidget * w, gpointer data)
2487 {
2488   struct unit *punit =
2489     player_unit_by_number(client_player(), (size_t)data);
2490 
2491   if (NULL != punit) {
2492     request_unit_sentry(punit);
2493   }
2494 }
2495 
2496 /****************************************************************
2497   User has requested unit to be fortified
2498 *****************************************************************/
unit_fortify_callback(GtkWidget * w,gpointer data)2499 static void unit_fortify_callback(GtkWidget * w, gpointer data)
2500 {
2501   struct unit *punit =
2502     player_unit_by_number(client_player(), (size_t)data);
2503 
2504   if (NULL != punit) {
2505     request_unit_fortify(punit);
2506   }
2507 }
2508 
2509 /****************************************************************
2510   User has requested unit to be disbanded
2511 *****************************************************************/
unit_disband_callback(GtkWidget * w,gpointer data)2512 static void unit_disband_callback(GtkWidget * w, gpointer data)
2513 {
2514   struct unit_list *punits;
2515   struct unit *punit =
2516     player_unit_by_number(client_player(), (size_t)data);
2517 
2518   if (NULL == punit) {
2519     return;
2520   }
2521 
2522   punits = unit_list_new();
2523   unit_list_append(punits, punit);
2524   popup_disband_dialog(punits);
2525   unit_list_destroy(punits);
2526 }
2527 
2528 /****************************************************************
2529   User has requested unit to change homecity to city where it
2530   currently is
2531 *****************************************************************/
unit_homecity_callback(GtkWidget * w,gpointer data)2532 static void unit_homecity_callback(GtkWidget * w, gpointer data)
2533 {
2534   struct unit *punit =
2535     player_unit_by_number(client_player(), (size_t)data);
2536 
2537   if (NULL != punit) {
2538     request_unit_change_homecity(punit);
2539   }
2540 }
2541 
2542 /****************************************************************
2543   User has requested unit to be upgraded
2544 *****************************************************************/
unit_upgrade_callback(GtkWidget * w,gpointer data)2545 static void unit_upgrade_callback(GtkWidget *w, gpointer data)
2546 {
2547   struct unit_list *punits;
2548   struct unit *punit =
2549     player_unit_by_number(client_player(), (size_t)data);
2550 
2551   if (NULL == punit) {
2552     return;
2553   }
2554 
2555   punits = unit_list_new();
2556   unit_list_append(punits, punit);
2557   popup_upgrade_dialog(punits);
2558   unit_list_destroy(punits);
2559 }
2560 
2561 /*** Callbacks for citizen bar, map funcs that are not update ***/
2562 /****************************************************************
2563 Somebody clicked our list of citizens. If they clicked a specialist
2564 then change the type of him, else do nothing.
2565 *****************************************************************/
citizens_callback(GtkWidget * w,GdkEventButton * ev,gpointer data)2566 static gboolean citizens_callback(GtkWidget * w, GdkEventButton * ev,
2567 			      gpointer data)
2568 {
2569   struct city_dialog *pdialog = data;
2570   struct city *pcity = pdialog->pcity;
2571   int citnum, tlen, len;
2572 
2573   if (!can_client_issue_orders()) {
2574     return FALSE;
2575   }
2576 
2577   tlen = tileset_small_sprite_width(tileset) / tileset_scale(tileset);
2578   len = (city_size_get(pcity) - 1) * pdialog->cwidth + tlen;
2579   if (ev->x > len) {
2580     return FALSE;		/* no citizen that far to the right */
2581   }
2582   citnum = MIN(city_size_get(pcity) - 1, ev->x / pdialog->cwidth);
2583 
2584   city_rotate_specialist(pcity, citnum);
2585 
2586   return TRUE;
2587 }
2588 
2589 /**************************************************************************
2590   User has pressed button on citymap
2591 **************************************************************************/
button_down_citymap(GtkWidget * w,GdkEventButton * ev,gpointer data)2592 static gboolean button_down_citymap(GtkWidget * w, GdkEventButton * ev,
2593 				    gpointer data)
2594 {
2595   struct city_dialog *pdialog = data;
2596   int canvas_x, canvas_y, city_x, city_y;
2597 
2598   if (!can_client_issue_orders()) {
2599     return FALSE;
2600   }
2601 
2602   canvas_x = ev->x * (double)canvas_width / (double)CITYMAP_WIDTH;
2603   canvas_y = ev->y * (double)canvas_height / (double)CITYMAP_HEIGHT;
2604 
2605   if (canvas_to_city_pos(&city_x, &city_y,
2606                          city_map_radius_sq_get(pdialog->pcity),
2607                          canvas_x, canvas_y)) {
2608     city_toggle_worker(pdialog->pcity, city_x, city_y);
2609   }
2610 
2611   return TRUE;
2612 }
2613 
2614 /****************************************************************
2615   Set map canvas to be drawn
2616 *****************************************************************/
draw_map_canvas(struct city_dialog * pdialog)2617 static void draw_map_canvas(struct city_dialog *pdialog)
2618 {
2619   gtk_widget_queue_draw(pdialog->overview.map_canvas.pixmap);
2620   if (pdialog->happiness.map_canvas.pixmap) {	/* in case of spy */
2621     gtk_widget_queue_draw(pdialog->happiness.map_canvas.pixmap);
2622   }
2623 }
2624 
2625 /********* Callbacks for Buy, Change, Sell, Worklist ************/
2626 /****************************************************************
2627   User has answered buy cost dialog
2628 *****************************************************************/
buy_callback_response(GtkWidget * w,gint response,gpointer data)2629 static void buy_callback_response(GtkWidget *w, gint response, gpointer data)
2630 {
2631   struct city_dialog *pdialog = data;
2632 
2633   if (response == GTK_RESPONSE_YES) {
2634     city_buy_production(pdialog->pcity);
2635   }
2636   gtk_widget_destroy(w);
2637 }
2638 
2639 /****************************************************************
2640   User has clicked buy-button
2641 *****************************************************************/
buy_callback(GtkWidget * w,gpointer data)2642 static void buy_callback(GtkWidget *w, gpointer data)
2643 {
2644   GtkWidget *shell;
2645   struct city_dialog *pdialog = data;
2646   const char *name = city_production_name_translation(pdialog->pcity);
2647   int value = city_production_buy_gold_cost(pdialog->pcity);
2648   char buf[1024];
2649 
2650   if (!can_client_issue_orders()) {
2651     return;
2652   }
2653 
2654   fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
2655                                         "Treasury contains %d gold.",
2656                                         client_player()->economic.gold),
2657               client_player()->economic.gold);
2658 
2659   if (value <= client_player()->economic.gold) {
2660     shell = gtk_message_dialog_new(NULL,
2661         GTK_DIALOG_DESTROY_WITH_PARENT,
2662         GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
2663         /* TRANS: Last %s is pre-pluralised "Treasury contains %d gold." */
2664         PL_("Buy %s for %d gold?\n%s",
2665             "Buy %s for %d gold?\n%s", value),
2666         name, value, buf);
2667     setup_dialog(shell, pdialog->shell);
2668     gtk_window_set_title(GTK_WINDOW(shell), _("Buy It!"));
2669     gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_NO);
2670     g_signal_connect(shell, "response", G_CALLBACK(buy_callback_response),
2671 	pdialog);
2672     gtk_window_present(GTK_WINDOW(shell));
2673   } else {
2674     shell = gtk_message_dialog_new(NULL,
2675         GTK_DIALOG_DESTROY_WITH_PARENT,
2676         GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
2677         /* TRANS: Last %s is pre-pluralised "Treasury contains %d gold." */
2678         PL_("%s costs %d gold.\n%s",
2679             "%s costs %d gold.\n%s", value),
2680         name, value, buf);
2681     setup_dialog(shell, pdialog->shell);
2682     gtk_window_set_title(GTK_WINDOW(shell), _("Buy It!"));
2683     g_signal_connect(shell, "response", G_CALLBACK(gtk_widget_destroy),
2684       NULL);
2685     gtk_window_present(GTK_WINDOW(shell));
2686   }
2687 }
2688 
2689 /****************************************************************************
2690   Callback for the dropdown production menu.
2691 ****************************************************************************/
change_production_callback(GtkComboBox * combo,struct city_dialog * pdialog)2692 static void change_production_callback(GtkComboBox *combo,
2693                                        struct city_dialog *pdialog)
2694 {
2695   GtkTreeIter iter;
2696 
2697   if (can_client_issue_orders()
2698       && gtk_combo_box_get_active_iter(combo, &iter)) {
2699     cid id;
2700     struct universal univ;
2701 
2702     gtk_tree_model_get(gtk_combo_box_get_model(combo), &iter, 2, &id, -1);
2703     univ = cid_production(id);
2704     city_change_production(pdialog->pcity, &univ);
2705   }
2706 }
2707 
2708 /****************************************************************
2709   User has clicked sell-button
2710 *****************************************************************/
sell_callback(struct impr_type * pimprove,gpointer data)2711 static void sell_callback(struct impr_type *pimprove, gpointer data)
2712 {
2713   GtkWidget *shl;
2714   struct city_dialog *pdialog = (struct city_dialog *) data;
2715   pdialog->sell_id = improvement_number(pimprove);
2716   int price;
2717 
2718   if (!can_client_issue_orders()) {
2719     return;
2720   }
2721 
2722   if (test_player_sell_building_now(client.conn.playing, pdialog->pcity,
2723                                     pimprove) != TR_SUCCESS) {
2724     return;
2725   }
2726 
2727   price = impr_sell_gold(pimprove);
2728   shl = gtk_message_dialog_new(NULL,
2729     GTK_DIALOG_DESTROY_WITH_PARENT,
2730     GTK_MESSAGE_QUESTION,
2731     GTK_BUTTONS_YES_NO,
2732     PL_("Sell %s for %d gold?",
2733         "Sell %s for %d gold?", price),
2734     city_improvement_name_translation(pdialog->pcity, pimprove), price);
2735   setup_dialog(shl, pdialog->shell);
2736   pdialog->sell_shell = shl;
2737 
2738   gtk_window_set_title(GTK_WINDOW(shl), _("Sell It!"));
2739   gtk_window_set_position(GTK_WINDOW(shl), GTK_WIN_POS_CENTER_ON_PARENT);
2740 
2741   g_signal_connect(shl, "response",
2742 		   G_CALLBACK(sell_callback_response), pdialog);
2743 
2744   gtk_window_present(GTK_WINDOW(shl));
2745 }
2746 
2747 /****************************************************************
2748   User has responded to sell price dialog
2749 *****************************************************************/
sell_callback_response(GtkWidget * w,gint response,gpointer data)2750 static void sell_callback_response(GtkWidget *w, gint response, gpointer data)
2751 {
2752   struct city_dialog *pdialog = data;
2753 
2754   if (response == GTK_RESPONSE_YES) {
2755     city_sell_improvement(pdialog->pcity, pdialog->sell_id);
2756   }
2757   gtk_widget_destroy(w);
2758 
2759   pdialog->sell_shell = NULL;
2760 }
2761 
2762 /****************************************************************
2763  this is here because it's closely related to the sell stuff
2764 *****************************************************************/
impr_callback(GtkTreeView * view,GtkTreePath * path,GtkTreeViewColumn * col,gpointer data)2765 static void impr_callback(GtkTreeView *view, GtkTreePath *path,
2766 			  GtkTreeViewColumn *col, gpointer data)
2767 {
2768   GtkTreeModel *model;
2769   GtkTreeIter it;
2770   GdkModifierType mask;
2771   struct impr_type *pimprove;
2772 
2773   model = gtk_tree_view_get_model(view);
2774 
2775   if (!gtk_tree_model_get_iter(model, &it, path)) {
2776     return;
2777   }
2778 
2779   gtk_tree_model_get(model, &it, 0, &pimprove, -1);
2780   gdk_window_get_pointer(NULL, NULL, NULL, &mask);
2781 
2782   if (!(mask & GDK_CONTROL_MASK)) {
2783     sell_callback(pimprove, data);
2784   } else {
2785     if (is_great_wonder(pimprove)) {
2786       popup_help_dialog_typed(improvement_name_translation(pimprove), HELP_WONDER);
2787     } else {
2788       popup_help_dialog_typed(improvement_name_translation(pimprove), HELP_IMPROVEMENT);
2789     }
2790   }
2791 }
2792 
2793 /******* Callbacks for stuff on the Misc. Settings page *********/
2794 /****************************************************************
2795   Called when Rename button pressed
2796 *****************************************************************/
rename_callback(GtkWidget * w,gpointer data)2797 static void rename_callback(GtkWidget *w, gpointer data)
2798 {
2799   struct city_dialog *pdialog;
2800 
2801   pdialog = (struct city_dialog *) data;
2802 
2803   pdialog->rename_shell = input_dialog_create(GTK_WINDOW(pdialog->shell),
2804                                               /* "shellrenamecity" */
2805                                               _("Rename City"),
2806                                               _("What should we rename the city to?"),
2807                                               city_name_get(pdialog->pcity),
2808                                               rename_popup_callback, pdialog);
2809 }
2810 
2811 /****************************************************************
2812   Called when user has finished with "Rename City" popup
2813 *****************************************************************/
rename_popup_callback(gpointer data,gint response,const char * input)2814 static void rename_popup_callback(gpointer data, gint response,
2815                                   const char *input)
2816 {
2817   struct city_dialog *pdialog = data;
2818 
2819   if (pdialog) {
2820     if (response == GTK_RESPONSE_OK) {
2821       city_rename(pdialog->pcity, input);
2822     } /* else CANCEL or DELETE_EVENT */
2823 
2824     pdialog->rename_shell = NULL;
2825   }
2826 }
2827 
2828 /****************************************************************
2829  Sets which page will be set on reopen of dialog
2830 *****************************************************************/
misc_whichtab_callback(GtkWidget * w,gpointer data)2831 static void misc_whichtab_callback(GtkWidget * w, gpointer data)
2832 {
2833   new_dialog_def_page = GPOINTER_TO_INT(data);
2834 }
2835 
2836 /**************************************************************************
2837 City options callbacks
2838 **************************************************************************/
cityopt_callback(GtkWidget * w,gpointer data)2839 static void cityopt_callback(GtkWidget * w, gpointer data)
2840 {
2841   struct city_dialog *pdialog = (struct city_dialog *) data;
2842 
2843   if (!can_client_issue_orders()) {
2844     return;
2845   }
2846 
2847   if(!pdialog->misc.block_signal){
2848     struct city *pcity = pdialog->pcity;
2849     bv_city_options new_options;
2850 
2851     fc_assert(CITYO_LAST == 3);
2852 
2853     BV_CLR_ALL(new_options);
2854     if (GTK_TOGGLE_BUTTON(pdialog->misc.disband_on_settler)->active) {
2855       BV_SET(new_options, CITYO_DISBAND);
2856     }
2857     if (GTK_TOGGLE_BUTTON(pdialog->misc.new_citizens_radio[1])->active) {
2858       BV_SET(new_options, CITYO_NEW_EINSTEIN);
2859     }
2860     if (GTK_TOGGLE_BUTTON(pdialog->misc.new_citizens_radio[2])->active) {
2861       BV_SET(new_options, CITYO_NEW_TAXMAN);
2862     }
2863 
2864     dsend_packet_city_options_req(&client.conn, pcity->id,new_options);
2865   }
2866 }
2867 
2868 /**************************************************************************
2869  refresh the city options (auto_[land, air, sea, helicopter] and
2870  disband-is-size-1) in the misc page.
2871 **************************************************************************/
set_cityopt_values(struct city_dialog * pdialog)2872 static void set_cityopt_values(struct city_dialog *pdialog)
2873 {
2874   struct city *pcity = pdialog->pcity;
2875 
2876   pdialog->misc.block_signal = 1;
2877 
2878   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pdialog->misc.disband_on_settler),
2879 			       is_city_option_set(pcity, CITYO_DISBAND));
2880 
2881   if (is_city_option_set(pcity, CITYO_NEW_EINSTEIN)) {
2882     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
2883 				 (pdialog->misc.new_citizens_radio[1]), TRUE);
2884   } else if (is_city_option_set(pcity, CITYO_NEW_TAXMAN)) {
2885     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
2886 				 (pdialog->misc.new_citizens_radio[2]), TRUE);
2887   } else {
2888     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
2889 				 (pdialog->misc.new_citizens_radio[0]), TRUE);
2890   }
2891   pdialog->misc.block_signal = 0;
2892 }
2893 
2894 /*************** Callbacks for: Close, Prev, Next. **************/
2895 /****************************************************************
2896   User has clicked rename city-button
2897 *****************************************************************/
close_callback(GtkWidget * w,gpointer data)2898 static void close_callback(GtkWidget *w, gpointer data)
2899 {
2900   close_city_dialog((struct city_dialog *) data);
2901 }
2902 
2903 /****************************************************************
2904   User has closed rename city dialog
2905 *****************************************************************/
city_destroy_callback(GtkWidget * w,gpointer data)2906 static void city_destroy_callback(GtkWidget *w, gpointer data)
2907 {
2908   struct city_dialog *pdialog;
2909 
2910   pdialog = (struct city_dialog *) data;
2911 
2912   gtk_widget_hide(pdialog->shell);
2913 
2914   if (game.info.citizen_nationality) {
2915     citizens_dialog_close(pdialog->pcity);
2916   }
2917   close_happiness_dialog(pdialog->pcity);
2918   close_cma_dialog(pdialog->pcity);
2919 
2920   /* Save size of the city dialog. */
2921   gui_options.gui_gtk2_citydlg_xsize
2922     = CLIP(GUI_GTK2_CITYDLG_MIN_XSIZE,
2923            pdialog->shell->allocation.width,
2924            GUI_GTK2_CITYDLG_MAX_XSIZE);
2925   gui_options.gui_gtk2_citydlg_ysize
2926     = CLIP(GUI_GTK2_CITYDLG_MIN_XSIZE,
2927            pdialog->shell->allocation.height,
2928            GUI_GTK2_CITYDLG_MAX_XSIZE);
2929 
2930   last_page
2931     = gtk_notebook_get_current_page(GTK_NOTEBOOK(pdialog->notebook));
2932 
2933   if (pdialog->popup_menu) {
2934     gtk_widget_destroy(pdialog->popup_menu);
2935   }
2936 
2937   dialog_list_remove(dialog_list, pdialog);
2938 
2939   unit_node_vector_free(&pdialog->overview.supported_units);
2940   unit_node_vector_free(&pdialog->overview.present_units);
2941 
2942   if (pdialog->buy_shell) {
2943     gtk_widget_destroy(pdialog->buy_shell);
2944   }
2945   if (pdialog->sell_shell) {
2946     gtk_widget_destroy(pdialog->sell_shell);
2947   }
2948   if (pdialog->rename_shell) {
2949     gtk_widget_destroy(pdialog->rename_shell);
2950   }
2951 
2952   g_object_unref(pdialog->map_canvas_store);
2953   if (pdialog->map_pixbuf_unscaled) {
2954     g_object_unref(pdialog->map_pixbuf_unscaled);
2955   }
2956 
2957   free(pdialog);
2958 
2959   /* need to do this every time a new dialog is closed. */
2960   city_dialog_update_prev_next();
2961 }
2962 
2963 /************************************************************************
2964   Close city dialog
2965 *************************************************************************/
close_city_dialog(struct city_dialog * pdialog)2966 static void close_city_dialog(struct city_dialog *pdialog)
2967 {
2968   gtk_widget_destroy(pdialog->shell);
2969 }
2970 
2971 /************************************************************************
2972   Callback for the prev/next buttons. Switches to the previous/next
2973   city.
2974 *************************************************************************/
switch_city_callback(GtkWidget * w,gpointer data)2975 static void switch_city_callback(GtkWidget *w, gpointer data)
2976 {
2977   struct city_dialog *pdialog = (struct city_dialog *) data;
2978   int i, j, dir, size;
2979   struct city *new_pcity = NULL;
2980 
2981   if (client_is_global_observer()) {
2982     return;
2983   }
2984 
2985   size = city_list_size(client.conn.playing->cities);
2986 
2987   fc_assert_ret(city_dialogs_have_been_initialised);
2988   fc_assert_ret(size >= 1);
2989   fc_assert_ret(city_owner(pdialog->pcity) == client.conn.playing);
2990 
2991   if (size == 1) {
2992     return;
2993   }
2994 
2995   /* dir = 1 will advance to the city, dir = -1 will get previous */
2996   if (w == pdialog->next_command) {
2997     dir = 1;
2998   } else if (w == pdialog->prev_command) {
2999     dir = -1;
3000   } else {
3001     /* Always fails. */
3002     fc_assert_ret(w == pdialog->next_command
3003                   || w == pdialog->prev_command);
3004     dir = 1;
3005   }
3006 
3007   for (i = 0; i < size; i++) {
3008     if (pdialog->pcity == city_list_get(client.conn.playing->cities, i)) {
3009       break;
3010     }
3011   }
3012 
3013   fc_assert_ret(i < size);
3014 
3015   for (j = 1; j < size; j++) {
3016     struct city *other_pcity = city_list_get(client.conn.playing->cities,
3017 					     (i + dir * j + size) % size);
3018     struct city_dialog *other_pdialog = get_city_dialog(other_pcity);
3019 
3020     fc_assert_ret(other_pdialog != pdialog);
3021     if (!other_pdialog) {
3022       new_pcity = other_pcity;
3023       break;
3024     }
3025   }
3026 
3027   if (!new_pcity) {
3028     /* Every other city has an open city dialog. */
3029     return;
3030   }
3031 
3032   /* cleanup happiness dialog */
3033   if (game.info.citizen_nationality) {
3034     citizens_dialog_close(pdialog->pcity);
3035   }
3036   close_happiness_dialog(pdialog->pcity);
3037 
3038   pdialog->pcity = new_pcity;
3039 
3040   /* reinitialize happiness, and cma dialogs */
3041   if (game.info.citizen_nationality) {
3042     gtk_box_pack_start(GTK_BOX(pdialog->happiness.citizens),
3043                        citizens_dialog_display(pdialog->pcity),
3044                        TRUE, TRUE, 0);
3045   }
3046   gtk_box_pack_start(GTK_BOX(pdialog->happiness.widget),
3047                      get_top_happiness_display(pdialog->pcity), TRUE, TRUE, 0);
3048   if (!client_is_observer()) {
3049     fc_assert(pdialog->cma_editor != NULL);
3050     pdialog->cma_editor->pcity = new_pcity;
3051   }
3052 
3053   reset_city_worklist(pdialog->production.worklist, pdialog->pcity);
3054 
3055   can_slide = FALSE;
3056   center_tile_mapcanvas(pdialog->pcity->tile);
3057   can_slide = TRUE;
3058   if (!client_is_observer()) {
3059     set_cityopt_values(pdialog);  /* need not be in real_city_dialog_refresh */
3060   }
3061 
3062   real_city_dialog_refresh(pdialog->pcity);
3063 
3064   /* recenter the city map(s) */
3065   city_dialog_map_recenter(pdialog->overview.map_canvas.sw);
3066   if (pdialog->happiness.map_canvas.sw) {
3067     city_dialog_map_recenter(pdialog->happiness.map_canvas.sw);
3068   }
3069 }
3070 
3071 /**************************************************************************
3072   City is about to disappear from client
3073 **************************************************************************/
city_to_disappear(struct city * pcity)3074 void city_to_disappear(struct city *pcity)
3075 {
3076 }
3077