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)
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 ***********************************************************************/
15 #include <fc_config.h>
23 #include <gdk/gdkkeysyms.h>
41 #include "citydlg_common.h"
42 #include "cityrepdata.h"
43 #include "client_main.h"
45 #include "global_worklist.h"
46 #include "mapview_common.h"
49 /* client/gui-gtk-3.0 */
53 #include "gui_stuff.h"
55 #include "mapctrl.h" /* is_city_hilited() */
56 #include "optiondlg.h"
61 #define NEG_VAL(x) ((x)<0 ? (x) : (-x))
63 /* Some versions of gcc have problems with negative values here (PR#39722). */
64 #define CMA_NONE (10000)
65 #define CMA_CUSTOM (10001)
68 int count
; /* Number of cities. */
69 int gold
; /* Amount of gold. */
70 struct impr_type
*target
; /* The target for selling. */
73 enum city_operation_type
{
74 CO_CHANGE
, CO_LAST
, CO_NEXT
, CO_FIRST
, CO_NEXT_TO_LAST
, CO_SELL
, CO_NONE
77 /******************************************************************/
78 static void create_city_report_dialog(bool make_modal
);
80 static void city_activated_callback(GtkTreeView
*view
, GtkTreePath
*path
,
81 GtkTreeViewColumn
*col
, gpointer data
);
83 static void city_command_callback(struct gui_dialog
*dlg
, int response
,
86 static void city_selection_changed_callback(GtkTreeSelection
*selection
);
87 static void city_clear_worklist_callback(GtkMenuItem
*item
, gpointer data
);
88 static void update_total_buy_cost(void);
90 static void create_select_menu(GtkWidget
*item
);
91 static void create_change_menu(GtkWidget
*item
);
92 static void create_last_menu(GtkWidget
*item
);
93 static void create_first_menu(GtkWidget
*item
);
94 static void create_next_menu(GtkWidget
*item
);
95 static void create_next_to_last_menu(GtkWidget
*item
);
96 static void create_sell_menu(GtkWidget
*item
);
98 static struct gui_dialog
*city_dialog_shell
= NULL
;
101 CITY_CENTER
= 1, CITY_POPUP
, CITY_BUY
104 static GtkWidget
*city_view
;
105 static GtkTreeSelection
*city_selection
;
106 static GtkListStore
*city_model
;
107 #define CRD_COL_CITY_ID (0 + NUM_CREPORT_COLS)
109 static void popup_select_menu(GtkMenuShell
*menu
, gpointer data
);
110 static void popup_change_menu(GtkMenuShell
*menu
, gpointer data
);
111 static void popup_last_menu(GtkMenuShell
*menu
, gpointer data
);
112 static void popup_first_menu(GtkMenuShell
*menu
, gpointer data
);
113 static void popup_next_menu(GtkMenuShell
*menu
, gpointer data
);
114 static void popup_next_to_last_menu(GtkMenuShell
*menu
, gpointer data
);
116 static void recreate_sell_menu(void);
118 static GtkWidget
*city_center_command
;
119 static GtkWidget
*city_popup_command
;
120 static GtkWidget
*city_buy_command
;
121 static GtkWidget
*city_production_command
;
122 static GtkWidget
*city_governor_command
;
123 static GtkWidget
*city_sell_command
;
124 static GtkWidget
*city_total_buy_cost_label
;
126 static GtkWidget
*change_improvements_item
;
127 static GtkWidget
*change_units_item
;
128 static GtkWidget
*change_wonders_item
;
130 static GtkWidget
*last_improvements_item
;
131 static GtkWidget
*last_units_item
;
132 static GtkWidget
*last_wonders_item
;
134 static GtkWidget
*first_improvements_item
;
135 static GtkWidget
*first_units_item
;
136 static GtkWidget
*first_wonders_item
;
138 static GtkWidget
*next_improvements_item
;
139 static GtkWidget
*next_units_item
;
140 static GtkWidget
*next_wonders_item
;
142 static GtkWidget
*next_to_last_improvements_item
;
143 static GtkWidget
*next_to_last_units_item
;
144 static GtkWidget
*next_to_last_wonders_item
;
146 static GtkWidget
*select_island_item
;
148 static GtkWidget
*select_bunit_item
;
149 static GtkWidget
*select_bimprovement_item
;
150 static GtkWidget
*select_bwonder_item
;
152 static GtkWidget
*select_supported_item
;
153 static GtkWidget
*select_present_item
;
154 static GtkWidget
*select_built_improvements_item
;
155 static GtkWidget
*select_built_wonders_item
;
157 static GtkWidget
*select_improvements_item
;
158 static GtkWidget
*select_units_item
;
159 static GtkWidget
*select_wonders_item
;
160 static GtkWidget
*select_cma_item
;
162 static int city_dialog_shell_is_modal
;
164 bool select_menu_cached
;
166 /****************************************************************
167 Return text line for the column headers for the city report
168 *****************************************************************/
169 static void get_city_table_header(char **text
, int n
)
171 struct city_report_spec
*spec
;
174 for (i
= 0, spec
= city_report_specs
; i
< NUM_CREPORT_COLS
; i
++, spec
++) {
175 fc_snprintf(text
[i
], n
, "%*s\n%*s",
176 NEG_VAL(spec
->width
), spec
->title1
? spec
->title1
: "",
177 NEG_VAL(spec
->width
), spec
->title2
? spec
->title2
: "");
181 /****************************************************************************
183 ****************************************************************************/
185 /****************************************************************************
186 Returns a new tree model for the city report.
187 ****************************************************************************/
188 static GtkListStore
*city_report_dialog_store_new(void)
190 GType model_types
[NUM_CREPORT_COLS
+ 1];
193 /* City report data. */
194 for (i
= 0; i
< NUM_CREPORT_COLS
; i
++) {
195 model_types
[i
] = G_TYPE_STRING
;
198 /* Specific gtk client data. */
199 model_types
[i
++] = G_TYPE_INT
; /* CRD_COL_CITY_ID */
201 return gtk_list_store_newv(i
, model_types
);
204 /****************************************************************************
205 Set the values of the iterator.
206 ****************************************************************************/
207 static void city_model_set(GtkListStore
*store
, GtkTreeIter
*iter
,
210 struct city_report_spec
*spec
;
214 for (i
= 0; i
< NUM_CREPORT_COLS
; i
++) {
215 spec
= city_report_specs
+ i
;
216 fc_snprintf(buf
, sizeof(buf
), "%*s", NEG_VAL(spec
->width
),
217 spec
->func(pcity
, spec
->data
));
218 gtk_list_store_set(store
, iter
, i
, buf
, -1);
220 gtk_list_store_set(store
, iter
, CRD_COL_CITY_ID
, pcity
->id
, -1);
223 /****************************************************************************
224 Set the values of the iterator.
225 ****************************************************************************/
226 static struct city
*city_model_get(GtkTreeModel
*model
, GtkTreeIter
*iter
)
231 gtk_tree_model_get(model
, iter
, CRD_COL_CITY_ID
, &id
, -1);
232 pcity
= game_city_by_number(id
);
233 return ((NULL
!= pcity
234 && client_has_player()
235 && city_owner(pcity
) != client_player())
239 /****************************************************************************
240 Return TRUE if 'iter' has been set to the city row.
241 ****************************************************************************/
242 static gboolean
city_model_find(GtkTreeModel
*model
, GtkTreeIter
*iter
,
243 const struct city
*pcity
)
245 const int searched
= pcity
->id
;
248 if (gtk_tree_model_get_iter_first(model
, iter
)) {
250 gtk_tree_model_get(model
, iter
, CRD_COL_CITY_ID
, &id
, -1);
251 if (searched
== id
) {
254 } while (gtk_tree_model_iter_next(model
, iter
));
259 /****************************************************************************
260 Fill the model with the current configuration.
261 ****************************************************************************/
262 static void city_model_fill(GtkListStore
*store
,
263 GtkTreeSelection
*selection
, GHashTable
*select
)
267 if (client_has_player()) {
268 city_list_iterate(client_player()->cities
, pcity
) {
269 gtk_list_store_append(store
, &iter
);
270 city_model_set(store
, &iter
, pcity
);
272 && g_hash_table_remove(select
, GINT_TO_POINTER(pcity
->id
))) {
273 gtk_tree_selection_select_iter(selection
, &iter
);
275 } city_list_iterate_end
;
277 /* Global observer case. */
278 cities_iterate(pcity
) {
279 gtk_list_store_append(store
, &iter
);
280 city_model_set(store
, &iter
, pcity
);
282 && g_hash_table_remove(select
, GINT_TO_POINTER(pcity
->id
))) {
283 gtk_tree_selection_select_iter(selection
, &iter
);
285 } cities_iterate_end
;
289 /****************************************************************
290 Popup the city report dialog, and optionally raise it.
291 ****************************************************************/
292 void city_report_dialog_popup(bool raise
)
294 if(!city_dialog_shell
) {
295 city_dialog_shell_is_modal
= FALSE
;
297 create_city_report_dialog(FALSE
);
299 select_menu_cached
= FALSE
;
302 gui_dialog_present(city_dialog_shell
);
303 hilite_cities_from_canvas();
305 gui_dialog_raise(city_dialog_shell
);
309 /****************************************************************
310 Closes the city report dialog.
311 ****************************************************************/
312 void city_report_dialog_popdown(void)
314 if (city_dialog_shell
) {
315 gui_dialog_destroy(city_dialog_shell
);
319 /****************************************************************
320 Make submenu listing possible build targets
321 *****************************************************************/
322 static void append_impr_or_unit_to_menu_item(GtkMenuItem
*parent_item
,
325 enum city_operation_type
327 TestCityFunc test_func
,
332 struct universal targets
[MAX_NUM_PRODUCTION_TARGETS
];
333 struct item items
[MAX_NUM_PRODUCTION_TARGETS
];
334 int i
, item
, targets_used
;
338 GtkSizeGroup
*group
[3];
339 const char *markup
[3] = {
345 menu
= gtk_menu_new();
346 gtk_menu_item_set_submenu(parent_item
, menu
);
348 if (city_operation
!= CO_NONE
) {
351 int num_selected
= 0;
352 GtkTreeModel
*model
= GTK_TREE_MODEL(city_model
);
355 selected
= g_ptr_array_sized_new(size
);
357 for (itree_begin(model
, &it
); !itree_end(&it
); itree_next(&it
)) {
360 if (!itree_is_selected(city_selection
, &it
)
361 || !(pcity
= city_model_get(model
, TREE_ITER_PTR(it
)))) {
365 g_ptr_array_add(selected
, pcity
);
369 data
= (struct city
**)g_ptr_array_free(selected
, FALSE
);
371 = collect_production_targets(targets
, data
, num_selected
, append_units
,
372 append_wonders
, TRUE
, test_func
);
375 targets_used
= collect_production_targets(targets
, NULL
, 0, append_units
,
376 append_wonders
, FALSE
,
380 name_and_sort_items(targets
, targets_used
, items
,
381 city_operation
!= CO_NONE
, NULL
);
383 for (i
= 0; i
< 4; i
++) {
387 g_object_set_data(G_OBJECT(menu
), "freeciv_test_func", test_func
);
388 g_object_set_data(G_OBJECT(menu
), "freeciv_city_operation",
389 GINT_TO_POINTER(city_operation
));
391 for (i
= 0; i
< 3; i
++) {
392 group
[i
] = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL
);
395 for (item
= 0; item
< targets_used
; item
++) {
396 struct universal target
= items
[item
].item
;
397 GtkWidget
*menu_item
, *hbox
, *label
;
400 get_city_dialog_production_row(row
, sizeof(buf
[0]), &target
, NULL
);
402 menu_item
= gtk_menu_item_new();
403 hbox
= gtk_grid_new();
404 gtk_grid_set_column_spacing(GTK_GRID(hbox
), 18);
405 gtk_container_add(GTK_CONTAINER(menu_item
), hbox
);
407 for (i
= 0; i
< 3; i
++) {
408 if (row
[i
][0] == '\0') {
412 if (city_operation
== CO_SELL
&& i
!= 0) {
416 fc_snprintf(txt
, ARRAY_SIZE(txt
), "<span %s>%s</span>",
419 label
= gtk_label_new(NULL
);
420 gtk_label_set_markup(GTK_LABEL(label
), txt
);
424 gtk_widget_set_halign(label
, GTK_ALIGN_START
);
425 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
428 gtk_widget_set_halign(label
, GTK_ALIGN_END
);
429 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
435 gtk_container_add(GTK_CONTAINER(hbox
), label
);
436 gtk_size_group_add_widget(group
[i
], label
);
439 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), menu_item
);
440 g_signal_connect(menu_item
, "activate", callback
,
441 GINT_TO_POINTER(cid_encode(target
)));
444 for (i
= 0; i
< 3; i
++) {
445 g_object_unref(group
[i
]);
448 gtk_widget_show_all(menu
);
450 gtk_widget_set_sensitive(GTK_WIDGET(parent_item
), (targets_used
> 0));
453 /****************************************************************************
454 Change the production of one single selected city.
455 ****************************************************************************/
456 static void impr_or_unit_iterate(GtkTreeModel
*model
, GtkTreePath
*path
,
457 GtkTreeIter
*iter
, gpointer data
)
459 struct universal target
= cid_decode(GPOINTER_TO_INT(data
));
460 struct city
*pcity
= city_model_get(model
, iter
);
463 city_change_production(pcity
, &target
);
467 /****************************************************************************
468 Called by select_impr_or_unit_callback for each city that is selected in
469 the city list dialog to have a object appended to the worklist. Sends a
470 packet adding the item to the end of the worklist.
471 ****************************************************************************/
472 static void worklist_last_impr_or_unit_iterate(GtkTreeModel
*model
,
477 struct universal target
= cid_decode(GPOINTER_TO_INT(data
));
478 struct city
*pcity
= city_model_get(model
, iter
);
481 (void) city_queue_insert(pcity
, -1, &target
);
483 /* perhaps should warn the user if not successful? */
486 /****************************************************************************
487 Called by select_impr_or_unit_callback for each city that is selected in
488 the city list dialog to have a object inserted first to the worklist.
489 Sends a packet adding the current production to the first place after the
490 current production of the worklist. Then changes the production to the
492 ****************************************************************************/
493 static void worklist_first_impr_or_unit_iterate(GtkTreeModel
*model
,
498 struct universal target
= cid_decode(GPOINTER_TO_INT(data
));
499 struct city
*pcity
= city_model_get(model
, iter
);
502 (void) city_queue_insert(pcity
, 0, &target
);
504 /* perhaps should warn the user if not successful? */
507 /****************************************************************************
508 Called by select_impr_or_unit_callback for each city that is selected in
509 the city list dialog to have a object added next to the worklist. Sends a
510 packet adding the item to the first place after the current production of
512 ****************************************************************************/
513 static void worklist_next_impr_or_unit_iterate(GtkTreeModel
*model
,
518 struct universal target
= cid_decode(GPOINTER_TO_INT(data
));
519 struct city
*pcity
= city_model_get(model
, iter
);
522 (void) city_queue_insert(pcity
, 1, &target
);
524 /* perhaps should warn the user if not successful? */
527 /****************************************************************************
528 Called by select_impr_or_unit_callback for each city that is selected in
529 the city list dialog to have an object added before the last position in
531 ****************************************************************************/
532 static void worklist_next_to_last_impr_or_unit_iterate(GtkTreeModel
*model
,
537 struct universal target
= cid_decode(GPOINTER_TO_INT(data
));
538 struct city
*pcity
= city_model_get(model
, iter
);
541 city_queue_insert(pcity
, worklist_length(&pcity
->worklist
), &target
);
545 /****************************************************************************
546 Iterate the cities going to sell.
547 ****************************************************************************/
548 static void sell_impr_iterate(GtkTreeModel
*model
, GtkTreePath
*path
,
549 GtkTreeIter
*iter
, gpointer data
)
551 struct sell_data
*sd
= (struct sell_data
*) data
;
552 struct city
*pcity
= city_model_get(model
, iter
);
556 && city_has_building(pcity
, sd
->target
)) {
558 sd
->gold
+= impr_sell_gold(sd
->target
);
559 city_sell_improvement(pcity
, improvement_number(sd
->target
));
563 /****************************************************************************
564 Some build target, either improvement or unit, has been selected from
566 ****************************************************************************/
567 static void select_impr_or_unit_callback(GtkWidget
*wdg
, gpointer data
)
569 struct universal target
= cid_decode(GPOINTER_TO_INT(data
));
570 GObject
*parent
= G_OBJECT(gtk_widget_get_parent(wdg
));
571 TestCityFunc test_func
= g_object_get_data(parent
, "freeciv_test_func");
572 enum city_operation_type city_operation
=
573 GPOINTER_TO_INT(g_object_get_data(parent
, "freeciv_city_operation"));
575 /* if this is not a city operation: */
576 if (city_operation
== CO_NONE
) {
577 GtkTreeModel
*model
= GTK_TREE_MODEL(city_model
);
580 gtk_tree_selection_unselect_all(city_selection
);
581 for (itree_begin(model
, &it
); !itree_end(&it
); itree_next(&it
)) {
582 struct city
*pcity
= city_model_get(model
, TREE_ITER_PTR(it
));
584 if (NULL
!= pcity
&& test_func(pcity
, &target
)) {
585 itree_select(city_selection
, &it
);
589 GtkTreeSelectionForeachFunc foreach_func
;
590 connection_do_buffer(&client
.conn
);
591 switch (city_operation
) {
593 gtk_tree_selection_selected_foreach(city_selection
,
594 worklist_last_impr_or_unit_iterate
,
595 GINT_TO_POINTER(cid_encode(target
)));
598 gtk_tree_selection_selected_foreach(city_selection
,
599 impr_or_unit_iterate
,
600 GINT_TO_POINTER(cid_encode(target
)));
603 gtk_tree_selection_selected_foreach(city_selection
,
604 worklist_first_impr_or_unit_iterate
,
605 GINT_TO_POINTER(cid_encode(target
)));
608 gtk_tree_selection_selected_foreach(city_selection
,
609 worklist_next_impr_or_unit_iterate
,
610 GINT_TO_POINTER(cid_encode(target
)));
612 case CO_NEXT_TO_LAST
:
613 foreach_func
= worklist_next_to_last_impr_or_unit_iterate
;
614 gtk_tree_selection_selected_foreach(city_selection
, foreach_func
,
615 GINT_TO_POINTER(cid_encode(target
)));
618 fc_assert_action(target
.kind
== VUT_IMPROVEMENT
, break);
620 struct impr_type
*building
= target
.value
.building
;
621 struct sell_data sd
= { 0, 0, building
};
625 const char *imprname
= improvement_name_translation(building
);
627 /* Ask confirmation */
628 buf
= g_strdup_printf(_("Are you sure you want to sell those %s?"), imprname
);
629 w
= gtk_message_dialog_new(NULL
, GTK_DIALOG_MODAL
,
630 GTK_MESSAGE_QUESTION
,
631 GTK_BUTTONS_YES_NO
, "%s", buf
);
633 res
= gtk_dialog_run(GTK_DIALOG(w
)); /* Synchron. */
634 gtk_widget_destroy(w
);
635 if (res
== GTK_RESPONSE_NO
) {
639 gtk_tree_selection_selected_foreach(city_selection
,
640 sell_impr_iterate
, &sd
);
642 /* FIXME: plurality of sd.count is ignored! */
643 /* TRANS: "Sold 3 Harbor for 90 gold." (Pluralisation is in gold --
644 * second %d -- not in buildings.) */
645 w
= gtk_message_dialog_new(NULL
, GTK_DIALOG_MODAL
,
646 GTK_MESSAGE_INFO
, GTK_BUTTONS_OK
,
647 PL_("Sold %d %s for %d gold.",
648 "Sold %d %s for %d gold.",
650 sd
.count
, imprname
, sd
.gold
);
652 w
= gtk_message_dialog_new(NULL
, GTK_DIALOG_MODAL
,
653 GTK_MESSAGE_INFO
, GTK_BUTTONS_OK
,
654 _("No %s could be sold."),
658 g_signal_connect(w
, "response",
659 G_CALLBACK(gtk_widget_destroy
), NULL
);
660 gtk_window_present(GTK_WINDOW(w
)); /* Asynchron. */
666 connection_do_unbuffer(&client
.conn
);
670 /****************************************************************************
672 ****************************************************************************/
673 static void cma_iterate(GtkTreeModel
*model
, GtkTreePath
*path
,
674 GtkTreeIter
*iter
, gpointer data
)
676 struct city
*pcity
= city_model_get(model
, iter
);
677 int idx
= GPOINTER_TO_INT(data
);
680 if (CMA_NONE
== idx
) {
681 cma_release_city(pcity
);
683 cma_put_city_under_agent(pcity
, cmafec_preset_get_parameter(idx
));
685 refresh_city_dialog(pcity
);
689 /****************************************************************
690 Called when one clicks on an CMA item to make a selection or to
691 change a selection's preset.
692 *****************************************************************/
693 static void select_cma_callback(GtkWidget
* w
, gpointer data
)
695 int idx
= GPOINTER_TO_INT(data
);
696 GObject
*parent
= G_OBJECT(gtk_widget_get_parent(w
));
698 GPOINTER_TO_INT(g_object_get_data(parent
, "freeciv_change_cma"));
699 struct cm_parameter parameter
;
701 /* If this is not the change button but the select cities button. */
704 GtkTreeModel
*model
= GTK_TREE_MODEL(city_model
);
706 gtk_tree_selection_unselect_all(city_selection
);
707 for (itree_begin(model
, &it
); !itree_end(&it
); itree_next(&it
)) {
708 struct city
*pcity
= city_model_get(model
, TREE_ITER_PTR(it
));
715 controlled
= cma_is_city_under_agent(pcity
, ¶meter
);
718 if (idx
== CMA_NONE
) {
719 /* CMA_NONE selects not-controlled, all others require controlled */
723 } else if (controlled
) {
724 if (idx
== CMA_CUSTOM
) {
725 if (cmafec_preset_get_index_of_parameter(¶meter
) == -1) {
728 } else if (cm_are_parameter_equal(¶meter
,
729 cmafec_preset_get_parameter(idx
))) {
735 itree_select(city_selection
, &it
);
739 gtk_tree_selection_selected_foreach(city_selection
,
740 cma_iterate
, GINT_TO_POINTER(idx
));
744 /****************************************************************
745 Create the cma entries in the change menu and the select menu. The
746 indices CMA_NONE and CMA_CUSTOM are special.
747 CMA_NONE signifies a preset of "none" and CMA_CUSTOM a
749 *****************************************************************/
750 static void append_cma_to_menu_item(GtkMenuItem
*parent_item
, bool change_cma
)
754 struct cm_parameter parameter
;
757 w
= gtk_menu_item_get_submenu(parent_item
);
758 if (w
!= NULL
&& gtk_widget_get_visible(w
)) {
762 if (!can_client_issue_orders()) {
763 gtk_menu_item_set_submenu(parent_item
, NULL
);
766 menu
= gtk_menu_new();
767 gtk_menu_item_set_submenu(parent_item
, menu
);
770 w
= gtk_menu_item_new_with_label(_("none"));
771 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), w
);
772 g_signal_connect(w
, "activate", G_CALLBACK(select_cma_callback
),
773 GINT_TO_POINTER(CMA_NONE
));
774 fc_assert(GPOINTER_TO_INT(GINT_TO_POINTER(CMA_NONE
)) == CMA_NONE
);
776 for (i
= 0; i
< cmafec_preset_num(); i
++) {
777 w
= gtk_menu_item_new_with_label(cmafec_preset_get_descr(i
));
778 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), w
);
779 g_signal_connect(w
, "activate", G_CALLBACK(select_cma_callback
),
781 fc_assert(GPOINTER_TO_INT(GINT_TO_POINTER(i
)) == i
);
784 /* search for a "none" */
788 city_list_iterate(client
.conn
.playing
->cities
, pcity
) {
789 if (!cma_is_city_under_agent(pcity
, NULL
)) {
793 } city_list_iterate_end
;
796 w
= gtk_menu_item_new_with_label(_("none"));
797 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), w
);
798 g_signal_connect(w
, "activate", G_CALLBACK(select_cma_callback
),
799 GINT_TO_POINTER(CMA_NONE
));
803 * Search for a city that's under custom (not preset) agent. Might
804 * take a lonnggg time.
807 city_list_iterate(client
.conn
.playing
->cities
, pcity
) {
808 if (cma_is_city_under_agent(pcity
, ¶meter
) &&
809 cmafec_preset_get_index_of_parameter(¶meter
) == -1) {
813 } city_list_iterate_end
;
816 /* we found city that's under agent but not a preset */
817 w
= gtk_menu_item_new_with_label(_("custom"));
819 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), w
);
820 g_signal_connect(w
, "activate",
821 G_CALLBACK(select_cma_callback
), GINT_TO_POINTER(CMA_CUSTOM
));
824 /* only fill in presets that are being used. */
825 for (i
= 0; i
< cmafec_preset_num(); i
++) {
827 city_list_iterate(client
.conn
.playing
->cities
, pcity
) {
828 if (cma_is_city_under_agent(pcity
, ¶meter
) &&
829 cm_are_parameter_equal(¶meter
,
830 cmafec_preset_get_parameter(i
))) {
834 } city_list_iterate_end
;
836 w
= gtk_menu_item_new_with_label(cmafec_preset_get_descr(i
));
838 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), w
);
839 g_signal_connect(w
, "activate",
840 G_CALLBACK(select_cma_callback
), GINT_TO_POINTER(i
));
845 g_object_set_data(G_OBJECT(menu
), "freeciv_change_cma",
846 GINT_TO_POINTER(change_cma
));
847 gtk_widget_show_all(menu
);
850 /****************************************************************************
851 Helper function to append a worklist to the current work list of one city
852 in the city report. This function is called over all selected rows in the
854 ****************************************************************************/
855 static void append_worklist_foreach(GtkTreeModel
*model
, GtkTreePath
*path
,
856 GtkTreeIter
*iter
, gpointer data
)
858 const struct worklist
*pwl
= data
;
859 struct city
*pcity
= city_model_get(model
, iter
);
861 fc_assert_ret(pwl
!= NULL
);
864 city_queue_insert_worklist(pcity
, -1, pwl
);
868 /**************************************************************************
869 Menu item callback to append the global worklist associated with this
870 item to the worklists of all selected cities. The worklist pointer is
872 **************************************************************************/
873 static void append_worklist_callback(GtkMenuItem
*menuitem
, gpointer data
)
875 struct global_worklist
*pgwl
=
876 global_worklist_by_id(GPOINTER_TO_INT(data
));
878 fc_assert_ret(city_selection
!= NULL
);
881 /* Maybe removed by an other way, not an error. */
885 gtk_tree_selection_selected_foreach(city_selection
,
886 append_worklist_foreach
,
887 (gpointer
) global_worklist_get(pgwl
));
890 /****************************************************************************
891 Helper function to set a worklist for one city in the city report. This
892 function is called over all selected rows in the list view.
893 ****************************************************************************/
894 static void set_worklist_foreach(GtkTreeModel
*model
, GtkTreePath
*path
,
895 GtkTreeIter
*iter
, gpointer data
)
897 const struct worklist
*pwl
= data
;
898 struct city
*pcity
= city_model_get(model
, iter
);
900 fc_assert_ret(pwl
!= NULL
);
903 city_set_queue(pcity
, pwl
);
907 /**************************************************************************
908 Menu item callback to set a city's worklist to the global worklist
909 associated with this menu item. The worklist pointer is passed in 'data'.
910 **************************************************************************/
911 static void set_worklist_callback(GtkMenuItem
*menuitem
, gpointer data
)
913 struct global_worklist
*pgwl
=
914 global_worklist_by_id(GPOINTER_TO_INT(data
));
916 fc_assert_ret(city_selection
!= NULL
);
917 gtk_tree_selection_selected_foreach(city_selection
, set_worklist_foreach
,
918 (gpointer
) global_worklist_get(pgwl
));
921 /* Maybe removed by an other way, not an error. */
925 gtk_tree_selection_selected_foreach(city_selection
,
926 set_worklist_foreach
,
927 (gpointer
) global_worklist_get(pgwl
));
930 /**************************************************************************
931 Empty and refill the submenu of the menu item passed as 'data'. The menu
932 will be filled with menu items corresponding to the global worklists.
933 **************************************************************************/
934 static void production_menu_shown(GtkWidget
*widget
, gpointer data
)
936 GtkWidget
*menu
, *item
;
937 GtkMenuItem
*parent_item
;
942 fc_assert_ret(parent_item
!= NULL
);
943 fc_assert_ret(GTK_IS_MENU_ITEM(parent_item
));
945 callback
= g_object_get_data(G_OBJECT(parent_item
), "item_callback");
946 fc_assert_ret(callback
!= NULL
);
948 menu
= gtk_menu_item_get_submenu(parent_item
);
949 if (menu
!= NULL
&& gtk_widget_get_visible(menu
)) {
950 gtk_menu_shell_deactivate(GTK_MENU_SHELL(menu
));
954 menu
= gtk_menu_new();
955 gtk_menu_item_set_submenu(parent_item
, menu
);
958 if (!can_client_issue_orders()) {
962 gtk_container_forall(GTK_CONTAINER(menu
),
963 (GtkCallback
) gtk_widget_destroy
, NULL
);
965 global_worklists_iterate(pgwl
) {
966 item
= gtk_menu_item_new_with_label(global_worklist_name(pgwl
));
967 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
968 g_signal_connect(item
, "activate", callback
,
969 GINT_TO_POINTER(global_worklist_id(pgwl
)));
971 } global_worklists_iterate_end
;
974 item
= gtk_menu_item_new_with_label(_("(no worklists defined)"));
975 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
978 gtk_widget_show_all(menu
);
981 /****************************************************************
982 Update city report views
983 *****************************************************************/
984 static void city_report_update_views(void)
986 struct city_report_spec
*spec
;
988 GtkTreeViewColumn
*col
;
991 view
= GTK_TREE_VIEW(city_view
);
992 fc_assert_ret(view
!= NULL
);
994 columns
= gtk_tree_view_get_columns(view
);
996 for (p
= columns
; p
!= NULL
; p
= p
->next
) {
998 spec
= g_object_get_data(G_OBJECT(col
), "city_report_spec");
999 gtk_tree_view_column_set_visible(col
, spec
->show
);
1002 g_list_free(columns
);
1005 /****************************************************************
1006 User has toggled some column viewing option
1007 *****************************************************************/
1008 static void toggle_view(GtkCheckMenuItem
*item
, gpointer data
)
1010 struct city_report_spec
*spec
= data
;
1013 city_report_update_views();
1016 /****************************************************************
1017 Create view menu for city report menubar.
1018 *****************************************************************/
1019 static void update_view_menu(GtkWidget
*show_item
)
1021 GtkWidget
*menu
, *item
;
1022 struct city_report_spec
*spec
;
1025 menu
= gtk_menu_new();
1026 for(i
=0, spec
=city_report_specs
+i
; i
<NUM_CREPORT_COLS
; i
++, spec
++) {
1027 item
= gtk_check_menu_item_new_with_label(spec
->explanation
);
1028 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1029 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item
), spec
->show
);
1030 g_signal_connect(item
, "toggled", G_CALLBACK(toggle_view
), (gpointer
)spec
);
1032 gtk_menu_item_set_submenu(GTK_MENU_ITEM(show_item
), menu
);
1035 /****************************************************************
1036 Create menubar for city report
1037 *****************************************************************/
1038 static GtkWidget
*create_city_report_menubar(void)
1040 GtkWidget
*vbox
, *sep
, *menubar
, *menu
, *item
;
1042 vbox
= gtk_grid_new();
1043 gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox
),
1044 GTK_ORIENTATION_VERTICAL
);
1045 sep
= gtk_separator_new(GTK_ORIENTATION_HORIZONTAL
);
1046 gtk_container_add(GTK_CONTAINER(vbox
), sep
);
1048 menubar
= gtk_aux_menu_bar_new();
1049 gtk_container_add(GTK_CONTAINER(vbox
), menubar
);
1051 item
= gtk_menu_item_new_with_mnemonic(_("_Production"));
1052 city_production_command
= item
;
1053 gtk_menu_shell_append(GTK_MENU_SHELL(menubar
), item
);
1055 menu
= gtk_menu_new();
1056 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item
), menu
);
1058 item
= gtk_menu_item_new_with_mnemonic(_("Chan_ge"));
1059 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1060 create_change_menu(item
);
1062 item
= gtk_menu_item_new_with_mnemonic(_("Add _First"));
1063 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1064 create_first_menu(item
);
1066 item
= gtk_menu_item_new_with_mnemonic(_("Add _Next"));
1067 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1068 create_next_menu(item
);
1070 item
= gtk_menu_item_new_with_mnemonic(_("Add _2nd Last"));
1071 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1072 create_next_to_last_menu(item
);
1074 item
= gtk_menu_item_new_with_mnemonic(_("Add _Last"));
1075 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1076 create_last_menu(item
);
1078 item
= gtk_separator_menu_item_new();
1079 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1081 item
= gtk_menu_item_new_with_label(_("Set Worklist"));
1082 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1083 g_object_set_data(G_OBJECT(item
), "item_callback",
1084 set_worklist_callback
);
1085 g_signal_connect(menu
, "show", G_CALLBACK(production_menu_shown
), item
);
1087 item
= gtk_menu_item_new_with_label(_("Append Worklist"));
1088 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1089 g_object_set_data(G_OBJECT(item
), "item_callback",
1090 append_worklist_callback
);
1091 g_signal_connect(menu
, "show", G_CALLBACK(production_menu_shown
), item
);
1093 item
= gtk_menu_item_new_with_mnemonic(_("Clear _Worklist"));
1094 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1095 g_signal_connect(item
, "activate",
1096 G_CALLBACK(city_clear_worklist_callback
), NULL
);
1098 item
= gtk_menu_item_new_with_mnemonic(_("Gover_nor"));
1099 city_governor_command
= item
;
1100 gtk_menu_shell_append(GTK_MENU_SHELL(menubar
), item
);
1101 append_cma_to_menu_item(GTK_MENU_ITEM(item
), TRUE
);
1103 item
= gtk_menu_item_new_with_mnemonic(_("S_ell"));
1104 gtk_menu_shell_append(GTK_MENU_SHELL(menubar
), item
);
1105 city_sell_command
= item
;
1106 create_sell_menu(item
);
1108 item
= gtk_menu_item_new_with_mnemonic(_("_Select"));
1109 gtk_menu_shell_append(GTK_MENU_SHELL(menubar
), item
);
1110 create_select_menu(item
);
1112 item
= gtk_menu_item_new_with_mnemonic(_("_Display"));
1113 gtk_menu_shell_append(GTK_MENU_SHELL(menubar
), item
);
1114 update_view_menu(item
);
1118 /****************************************************************************
1120 ****************************************************************************/
1121 static gint
cityrep_sort_func(GtkTreeModel
*model
, GtkTreeIter
*a
,
1122 GtkTreeIter
*b
, gpointer data
)
1124 gint col
= GPOINTER_TO_INT(data
);
1125 const gchar
*str1
, *str2
;
1127 gtk_tree_model_get(model
, a
, col
, &str1
, -1);
1128 gtk_tree_model_get(model
, b
, col
, &str2
, -1);
1130 return cityrepfield_compare(str1
, str2
);
1133 /****************************************************************
1134 Create city report dialog.
1135 *****************************************************************/
1136 static void create_city_report_dialog(bool make_modal
)
1138 static char **titles
;
1139 static char (*buf
)[128];
1140 struct city_report_spec
*spec
;
1142 GtkWidget
*w
, *sw
, *menubar
;
1145 gui_dialog_new(&city_dialog_shell
, GTK_NOTEBOOK(top_notebook
), NULL
, TRUE
);
1146 gui_dialog_set_title(city_dialog_shell
, _("Cities"));
1148 gui_dialog_set_default_size(city_dialog_shell
, -1, 420);
1150 gui_dialog_response_set_callback(city_dialog_shell
,
1151 city_command_callback
);
1154 menubar
= create_city_report_menubar();
1155 gui_dialog_add_widget(city_dialog_shell
, menubar
);
1158 city_total_buy_cost_label
= gtk_label_new(NULL
);
1159 gtk_widget_set_hexpand(city_total_buy_cost_label
, TRUE
);
1160 gtk_label_set_ellipsize(GTK_LABEL(city_total_buy_cost_label
),
1161 PANGO_ELLIPSIZE_START
);
1162 gtk_container_add(GTK_CONTAINER(city_dialog_shell
->action_area
),
1163 city_total_buy_cost_label
);
1165 w
= gui_dialog_add_stockbutton(city_dialog_shell
, GTK_STOCK_EXECUTE
,
1166 _("_Buy"), CITY_BUY
);
1167 city_buy_command
= w
;
1169 w
= gui_dialog_add_stockbutton(city_dialog_shell
, GTK_STOCK_ZOOM_IN
,
1170 _("_Inspect"), CITY_POPUP
);
1171 city_popup_command
= w
;
1173 w
= gui_dialog_add_stockbutton(city_dialog_shell
, GTK_STOCK_ZOOM_FIT
,
1174 _("Cen_ter"), CITY_CENTER
);
1175 city_center_command
= w
;
1177 gui_dialog_set_default_response(city_dialog_shell
,
1178 GTK_RESPONSE_CLOSE
);
1181 buf
= fc_realloc(buf
, NUM_CREPORT_COLS
* sizeof(buf
[0]));
1182 titles
= fc_realloc(titles
, NUM_CREPORT_COLS
* sizeof(titles
[0]));
1183 for (i
= 0; i
< NUM_CREPORT_COLS
; i
++) {
1186 get_city_table_header(titles
, sizeof(buf
[0]));
1188 city_model
= city_report_dialog_store_new();
1190 city_view
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(city_model
));
1191 gtk_widget_set_hexpand(city_view
, TRUE
);
1192 gtk_widget_set_vexpand(city_view
, TRUE
);
1193 g_object_unref(city_model
);
1194 gtk_widget_set_name(city_view
, "small_font");
1195 g_signal_connect(city_view
, "row_activated",
1196 G_CALLBACK(city_activated_callback
), NULL
);
1197 city_selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(city_view
));
1198 gtk_tree_selection_set_mode(city_selection
, GTK_SELECTION_MULTIPLE
);
1199 g_signal_connect(city_selection
, "changed",
1200 G_CALLBACK(city_selection_changed_callback
), NULL
);
1202 for (i
= 0, spec
= city_report_specs
; i
< NUM_CREPORT_COLS
; i
++, spec
++) {
1204 GtkCellRenderer
*renderer
;
1205 GtkTreeViewColumn
*col
;
1207 renderer
= gtk_cell_renderer_text_new();
1208 col
= gtk_tree_view_column_new_with_attributes(NULL
, renderer
,
1210 header
= gtk_label_new(titles
[i
]);
1211 gtk_widget_set_tooltip_text(header
, spec
->explanation
);
1212 gtk_widget_show(header
);
1213 gtk_tree_view_column_set_widget(col
, header
);
1214 gtk_tree_view_column_set_visible(col
, spec
->show
);
1215 gtk_tree_view_column_set_sort_column_id(col
, i
);
1216 gtk_tree_view_column_set_reorderable(col
, TRUE
);
1217 g_object_set_data(G_OBJECT(col
), "city_report_spec", spec
);
1218 gtk_tree_view_append_column(GTK_TREE_VIEW(city_view
), col
);
1219 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(city_model
), i
,
1220 cityrep_sort_func
, GINT_TO_POINTER(i
),
1224 sw
= gtk_scrolled_window_new(NULL
, NULL
);
1225 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw
),
1226 GTK_SHADOW_ETCHED_IN
);
1227 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
),
1228 GTK_POLICY_AUTOMATIC
, GTK_POLICY_ALWAYS
);
1229 gtk_container_add(GTK_CONTAINER(sw
), city_view
);
1231 gtk_container_add(GTK_CONTAINER(city_dialog_shell
->vbox
), sw
);
1233 city_model_fill(city_model
, NULL
, NULL
);
1234 gui_dialog_show_all(city_dialog_shell
);
1236 city_selection_changed_callback(city_selection
);
1239 /****************************************************************
1240 User has chosen to select all cities
1241 *****************************************************************/
1242 static void city_select_all_callback(GtkMenuItem
*item
, gpointer data
)
1244 gtk_tree_selection_select_all(city_selection
);
1247 /****************************************************************
1248 User has chosen to unselect all cities
1249 *****************************************************************/
1250 static void city_unselect_all_callback(GtkMenuItem
*item
, gpointer data
)
1252 gtk_tree_selection_unselect_all(city_selection
);
1255 /****************************************************************
1256 User has chosen to invert selection
1257 *****************************************************************/
1258 static void city_invert_selection_callback(GtkMenuItem
*item
, gpointer data
)
1261 GtkTreeModel
*model
= GTK_TREE_MODEL(city_model
);
1263 for (itree_begin(model
, &it
); !itree_end(&it
); itree_next(&it
)) {
1264 if (itree_is_selected(city_selection
, &it
)) {
1265 itree_unselect(city_selection
, &it
);
1267 itree_select(city_selection
, &it
);
1272 /****************************************************************
1273 User has chosen to select coastal cities
1274 *****************************************************************/
1275 static void city_select_coastal_callback(GtkMenuItem
*item
, gpointer data
)
1278 GtkTreeModel
*model
= GTK_TREE_MODEL(city_model
);
1280 gtk_tree_selection_unselect_all(city_selection
);
1282 for (itree_begin(model
, &it
); !itree_end(&it
); itree_next(&it
)) {
1283 struct city
*pcity
= city_model_get(model
, TREE_ITER_PTR(it
));
1285 if (NULL
!= pcity
&& is_terrain_class_near_tile(pcity
->tile
, TC_OCEAN
)) {
1286 itree_select(city_selection
, &it
);
1291 /****************************************************************************
1292 Select all cities on the same continent.
1293 ****************************************************************************/
1294 static void same_island_iterate(GtkTreeModel
*model
, GtkTreePath
*path
,
1295 GtkTreeIter
*iter
, gpointer data
)
1297 struct city
*selected_pcity
= city_model_get(model
, iter
);
1300 if (NULL
== selected_pcity
) {
1304 for (itree_begin(model
, &it
); !itree_end(&it
); itree_next(&it
)) {
1305 struct city
*pcity
= city_model_get(model
, TREE_ITER_PTR(it
));
1308 && (tile_continent(pcity
->tile
)
1309 == tile_continent(selected_pcity
->tile
))) {
1310 itree_select(city_selection
, &it
);
1315 /****************************************************************
1316 User has chosen to select all cities on same island
1317 *****************************************************************/
1318 static void city_select_same_island_callback(GtkMenuItem
*item
, gpointer data
)
1320 gtk_tree_selection_selected_foreach(city_selection
,same_island_iterate
,NULL
);
1323 /****************************************************************
1324 User has chosen to select cities with certain target in production
1325 *****************************************************************/
1326 static void city_select_building_callback(GtkMenuItem
*item
, gpointer data
)
1328 enum production_class_type which
= GPOINTER_TO_INT(data
);
1330 GtkTreeModel
*model
= GTK_TREE_MODEL(city_model
);
1332 gtk_tree_selection_unselect_all(city_selection
);
1334 for (itree_begin(model
, &it
); !itree_end(&it
); itree_next(&it
)) {
1335 struct city
*pcity
= city_model_get(model
, TREE_ITER_PTR(it
));
1338 && ((which
== PCT_UNIT
&& VUT_UTYPE
== pcity
->production
.kind
)
1339 || (which
== PCT_NORMAL_IMPROVEMENT
1340 && VUT_IMPROVEMENT
== pcity
->production
.kind
1341 && !is_wonder(pcity
->production
.value
.building
))
1342 || (which
== PCT_WONDER
1343 && VUT_IMPROVEMENT
== pcity
->production
.kind
1344 && is_wonder(pcity
->production
.value
.building
)))) {
1345 itree_select(city_selection
, &it
);
1350 /****************************************************************************
1351 Buy the production in one single city.
1352 ****************************************************************************/
1353 static void buy_iterate(GtkTreeModel
*model
, GtkTreePath
*path
,
1354 GtkTreeIter
*iter
, gpointer data
)
1356 struct city
*pcity
= city_model_get(model
, iter
);
1358 if (NULL
!= pcity
) {
1363 /****************************************************************************
1364 Center to one single city.
1365 ****************************************************************************/
1366 static void center_iterate(GtkTreeModel
*model
, GtkTreePath
*path
,
1367 GtkTreeIter
*iter
, gpointer data
)
1369 struct city
*pcity
= city_model_get(model
, iter
);
1371 if (NULL
!= pcity
) {
1372 center_tile_mapcanvas(pcity
->tile
);
1376 /****************************************************************************
1377 Popup the dialog of a single city.
1378 ****************************************************************************/
1379 static void popup_iterate(GtkTreeModel
*model
, GtkTreePath
*path
,
1380 GtkTreeIter
*iter
, gpointer data
)
1382 struct city
*pcity
= city_model_get(model
, iter
);
1384 if (NULL
!= pcity
) {
1385 if (gui_options
.center_when_popup_city
) {
1386 center_tile_mapcanvas(pcity
->tile
);
1388 popup_city_dialog(pcity
);
1392 /****************************************************************************
1393 gui_dialog response callback.
1394 ****************************************************************************/
1395 static void city_command_callback(struct gui_dialog
*dlg
, int response
,
1400 if (1 == gtk_tree_selection_count_selected_rows(city_selection
)) {
1401 /* Center to city doesn't make sense if many city are selected. */
1402 gtk_tree_selection_selected_foreach(city_selection
, center_iterate
,
1407 gtk_tree_selection_selected_foreach(city_selection
, popup_iterate
, NULL
);
1410 gtk_tree_selection_selected_foreach(city_selection
, buy_iterate
, NULL
);
1413 gui_dialog_destroy(dlg
);
1418 /****************************************************************
1419 User has selected city row from city report.
1420 *****************************************************************/
1421 static void city_activated_callback(GtkTreeView
*view
, GtkTreePath
*path
,
1422 GtkTreeViewColumn
*col
, gpointer data
)
1424 GtkTreeModel
*model
;
1427 GdkDeviceManager
*manager
;
1428 GdkModifierType mask
;
1430 model
= gtk_tree_view_get_model(view
);
1432 if (!gtk_tree_model_get_iter(model
, &iter
, path
)) {
1436 win
= gdk_get_default_root_window();
1437 manager
= gdk_display_get_device_manager(gdk_window_get_display(win
));
1439 gdk_window_get_device_position(win
,
1440 gdk_device_manager_get_client_pointer(manager
),
1443 if (!(mask
& GDK_CONTROL_MASK
)) {
1444 popup_iterate(model
, path
, &iter
, NULL
);
1446 center_iterate(model
, path
, &iter
, NULL
);
1450 /****************************************************************************
1451 Update the city report dialog
1452 ****************************************************************************/
1453 void real_city_report_dialog_update(void)
1455 GHashTable
*selected
;
1459 if (NULL
== city_dialog_shell
) {
1463 /* Save the selection. */
1464 selected
= g_hash_table_new(NULL
, NULL
);
1465 for (itree_begin(GTK_TREE_MODEL(city_model
), &iter
);
1466 !itree_end(&iter
); itree_next(&iter
)) {
1467 if (itree_is_selected(city_selection
, &iter
)) {
1468 itree_get(&iter
, CRD_COL_CITY_ID
, &city_id
, -1);
1469 g_hash_table_insert(selected
, GINT_TO_POINTER(city_id
), NULL
);
1473 /* Update and restore the selection. */
1474 gtk_list_store_clear(city_model
);
1475 city_model_fill(city_model
, city_selection
, selected
);
1476 g_hash_table_destroy(selected
);
1478 if (gtk_widget_get_sensitive(city_governor_command
)) {
1479 append_cma_to_menu_item(GTK_MENU_ITEM(city_governor_command
), TRUE
);
1482 select_menu_cached
= FALSE
;
1485 /****************************************************************************
1486 Update the text for a single city in the city report
1487 ****************************************************************************/
1488 void real_city_report_update_city(struct city
*pcity
)
1492 if (NULL
== city_dialog_shell
) {
1496 if (!city_model_find(GTK_TREE_MODEL(city_model
), &iter
, pcity
)) {
1497 gtk_list_store_prepend(city_model
, &iter
);
1499 city_model_set(city_model
, &iter
, pcity
);
1501 update_total_buy_cost();
1504 /****************************************************************
1505 Create submenu for changing production target
1506 *****************************************************************/
1507 static void create_change_menu(GtkWidget
*item
)
1511 menu
= gtk_menu_new();
1512 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item
), menu
);
1513 g_signal_connect(menu
, "show", G_CALLBACK(popup_change_menu
), NULL
);
1515 change_units_item
= gtk_menu_item_new_with_label(_("Units"));
1516 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), change_units_item
);
1517 change_improvements_item
= gtk_menu_item_new_with_label(_("Improvements"));
1518 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), change_improvements_item
);
1519 change_wonders_item
= gtk_menu_item_new_with_label(_("Wonders"));
1520 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), change_wonders_item
);
1523 /****************************************************************
1524 Creates the last menu.
1525 *****************************************************************/
1526 static void create_last_menu(GtkWidget
*item
)
1530 menu
= gtk_menu_new();
1531 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item
), menu
);
1532 g_signal_connect(menu
, "show", G_CALLBACK(popup_last_menu
), NULL
);
1534 last_units_item
= gtk_menu_item_new_with_label(_("Units"));
1535 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), last_units_item
);
1536 last_improvements_item
= gtk_menu_item_new_with_label(_("Improvements"));
1537 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), last_improvements_item
);
1538 last_wonders_item
= gtk_menu_item_new_with_label(_("Wonders"));
1539 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), last_wonders_item
);
1542 /****************************************************************
1543 Creates the first menu.
1544 *****************************************************************/
1545 static void create_first_menu(GtkWidget
*item
)
1549 menu
= gtk_menu_new();
1550 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item
), menu
);
1551 g_signal_connect(menu
, "show", G_CALLBACK(popup_first_menu
), NULL
);
1553 first_units_item
= gtk_menu_item_new_with_label(_("Units"));
1554 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), first_units_item
);
1555 first_improvements_item
= gtk_menu_item_new_with_label(_("Improvements"));
1556 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), first_improvements_item
);
1557 first_wonders_item
= gtk_menu_item_new_with_label(_("Wonders"));
1558 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), first_wonders_item
);
1561 /****************************************************************
1562 Creates the next menu.
1563 *****************************************************************/
1564 static void create_next_menu(GtkWidget
*item
)
1568 menu
= gtk_menu_new();
1569 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item
), menu
);
1570 g_signal_connect(menu
, "show", G_CALLBACK(popup_next_menu
), NULL
);
1572 next_units_item
= gtk_menu_item_new_with_label(_("Units"));
1573 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), next_units_item
);
1574 next_improvements_item
= gtk_menu_item_new_with_label(_("Improvements"));
1575 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), next_improvements_item
);
1576 next_wonders_item
= gtk_menu_item_new_with_label(_("Wonders"));
1577 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), next_wonders_item
);
1580 /**************************************************************************
1581 Append the "next to last" submenu to the given menu item.
1582 **************************************************************************/
1583 static void create_next_to_last_menu(GtkWidget
*parent_item
)
1585 GtkWidget
*menu
, *item
;
1587 menu
= gtk_menu_new();
1588 gtk_menu_item_set_submenu(GTK_MENU_ITEM(parent_item
), menu
);
1589 g_signal_connect(menu
, "show",
1590 G_CALLBACK(popup_next_to_last_menu
), NULL
);
1592 item
= gtk_menu_item_new_with_label(_("Units"));
1593 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1594 next_to_last_units_item
= item
;
1596 item
= gtk_menu_item_new_with_label(_("Improvements"));
1597 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1598 next_to_last_improvements_item
= item
;
1600 item
= gtk_menu_item_new_with_label(_("Wonders"));
1601 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1602 next_to_last_wonders_item
= item
;
1605 /****************************************************************
1606 Create the sell menu (empty).
1607 *****************************************************************/
1608 static void create_sell_menu(GtkWidget
*item
)
1612 menu
= gtk_menu_new();
1613 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item
), menu
);
1617 /****************************************************************
1618 Pops up menu where user can select build target.
1619 *****************************************************************/
1620 static void popup_change_menu(GtkMenuShell
*menu
, gpointer data
)
1624 n
= gtk_tree_selection_count_selected_rows(city_selection
);
1626 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(change_improvements_item
),
1627 FALSE
, FALSE
, CO_CHANGE
,
1629 G_CALLBACK(select_impr_or_unit_callback
), n
);
1630 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(change_units_item
),
1631 TRUE
, FALSE
, CO_CHANGE
,
1633 G_CALLBACK(select_impr_or_unit_callback
), n
);
1634 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(change_wonders_item
),
1635 FALSE
, TRUE
, CO_CHANGE
,
1637 G_CALLBACK(select_impr_or_unit_callback
), n
);
1640 /****************************************************************
1641 Pops up the last menu.
1642 *****************************************************************/
1643 static void popup_last_menu(GtkMenuShell
*menu
, gpointer data
)
1647 n
= gtk_tree_selection_count_selected_rows(city_selection
);
1649 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(last_improvements_item
),
1650 FALSE
, FALSE
, CO_LAST
,
1652 G_CALLBACK(select_impr_or_unit_callback
), n
);
1653 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(last_units_item
),
1654 TRUE
, FALSE
, CO_LAST
,
1656 G_CALLBACK(select_impr_or_unit_callback
), n
);
1657 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(last_wonders_item
),
1658 FALSE
, TRUE
, CO_LAST
,
1660 G_CALLBACK(select_impr_or_unit_callback
), n
);
1663 /****************************************************************
1664 pops up the first menu.
1665 *****************************************************************/
1666 static void popup_first_menu(GtkMenuShell
*menu
, gpointer data
)
1670 n
= gtk_tree_selection_count_selected_rows(city_selection
);
1672 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(first_improvements_item
),
1673 FALSE
, FALSE
, CO_FIRST
,
1675 G_CALLBACK(select_impr_or_unit_callback
), n
);
1676 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(first_units_item
),
1677 TRUE
, FALSE
, CO_FIRST
,
1679 G_CALLBACK(select_impr_or_unit_callback
), n
);
1680 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(first_wonders_item
),
1681 FALSE
, TRUE
, CO_FIRST
,
1683 G_CALLBACK(select_impr_or_unit_callback
), n
);
1686 /****************************************************************
1687 Pops up the next menu.
1688 *****************************************************************/
1689 static void popup_next_menu(GtkMenuShell
*menu
, gpointer data
)
1693 n
= gtk_tree_selection_count_selected_rows(city_selection
);
1695 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(next_improvements_item
),
1696 FALSE
, FALSE
, CO_NEXT
,
1698 G_CALLBACK(select_impr_or_unit_callback
), n
);
1699 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(next_units_item
),
1700 TRUE
, FALSE
, CO_NEXT
,
1702 G_CALLBACK(select_impr_or_unit_callback
), n
);
1703 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(next_wonders_item
),
1704 FALSE
, TRUE
, CO_NEXT
,
1706 G_CALLBACK(select_impr_or_unit_callback
), n
);
1709 /**************************************************************************
1710 Re-create the submenus in the next-to-last production change menu.
1711 **************************************************************************/
1712 static void popup_next_to_last_menu(GtkMenuShell
*menu
, gpointer data
)
1718 fc_assert_ret(city_selection
!= NULL
);
1720 n
= gtk_tree_selection_count_selected_rows(city_selection
);
1721 callback
= G_CALLBACK(select_impr_or_unit_callback
);
1723 item
= next_to_last_improvements_item
;
1724 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(item
),
1725 FALSE
, FALSE
, CO_NEXT_TO_LAST
,
1728 item
= next_to_last_units_item
;
1729 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(item
),
1730 TRUE
, FALSE
, CO_NEXT_TO_LAST
,
1733 item
= next_to_last_wonders_item
;
1734 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(item
),
1735 FALSE
, TRUE
, CO_NEXT_TO_LAST
,
1740 /****************************************************************
1741 Same as can_city_sell_building(), but with universal argument.
1742 *****************************************************************/
1743 static bool can_city_sell_universal(const struct city
*pcity
,
1744 const struct universal
*target
)
1746 return target
->kind
== VUT_IMPROVEMENT
1747 && can_city_sell_building(pcity
, target
->value
.building
);
1750 /****************************************************************
1751 Update the sell menu.
1752 *****************************************************************/
1753 static void recreate_sell_menu(void)
1759 n
= gtk_tree_selection_count_selected_rows(city_selection
);
1760 menu
= gtk_menu_item_get_submenu(GTK_MENU_ITEM(city_sell_command
));
1761 gtk_menu_popdown(GTK_MENU(menu
));
1763 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(city_sell_command
),
1764 FALSE
, FALSE
, CO_SELL
,
1765 can_city_sell_universal
,
1766 G_CALLBACK(select_impr_or_unit_callback
),
1769 menu
= gtk_menu_item_get_submenu(GTK_MENU_ITEM(city_sell_command
));
1770 children
= gtk_container_get_children(GTK_CONTAINER(menu
));
1772 n
= g_list_length(children
);
1773 gtk_widget_set_sensitive(city_sell_command
, n
> 0);
1774 g_list_free(children
);
1777 /****************************************************************
1779 *****************************************************************/
1780 static void create_select_menu(GtkWidget
*item
)
1784 menu
= gtk_menu_new();
1785 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item
), menu
);
1786 g_signal_connect(menu
, "show", G_CALLBACK(popup_select_menu
), NULL
);
1788 item
= gtk_menu_item_new_with_label(_("All Cities"));
1789 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1790 g_signal_connect(item
, "activate",
1791 G_CALLBACK(city_select_all_callback
), NULL
);
1793 item
= gtk_menu_item_new_with_label(_("No Cities"));
1794 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1795 g_signal_connect(item
, "activate",
1796 G_CALLBACK(city_unselect_all_callback
), NULL
);
1798 item
= gtk_menu_item_new_with_label(_("Invert Selection"));
1799 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1800 g_signal_connect(item
, "activate",
1801 G_CALLBACK(city_invert_selection_callback
), NULL
);
1804 item
= gtk_separator_menu_item_new();
1805 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1808 item
= gtk_menu_item_new_with_label(_("Building Units"));
1809 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1810 g_signal_connect(item
, "activate",
1811 G_CALLBACK(city_select_building_callback
),
1812 GINT_TO_POINTER(PCT_UNIT
));
1814 item
= gtk_menu_item_new_with_label( _("Building Improvements"));
1815 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1816 g_signal_connect(item
, "activate",
1817 G_CALLBACK(city_select_building_callback
),
1818 GINT_TO_POINTER(PCT_NORMAL_IMPROVEMENT
));
1820 item
= gtk_menu_item_new_with_label(_("Building Wonders"));
1821 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1822 g_signal_connect(item
, "activate",
1823 G_CALLBACK(city_select_building_callback
),
1824 GINT_TO_POINTER(PCT_WONDER
));
1827 item
= gtk_separator_menu_item_new();
1828 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1832 gtk_menu_item_new_with_label(_("Building Unit"));
1833 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), select_bunit_item
);
1835 select_bimprovement_item
=
1836 gtk_menu_item_new_with_label( _("Building Improvement"));
1837 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), select_bimprovement_item
);
1839 select_bwonder_item
=
1840 gtk_menu_item_new_with_label(_("Building Wonder"));
1841 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), select_bwonder_item
);
1844 item
= gtk_separator_menu_item_new();
1845 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1848 item
= gtk_menu_item_new_with_label(_("Coastal Cities"));
1849 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1850 g_signal_connect(item
, "activate",
1851 G_CALLBACK(city_select_coastal_callback
), NULL
);
1853 select_island_item
= gtk_menu_item_new_with_label(_("Same Island"));
1854 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), select_island_item
);
1855 g_signal_connect(select_island_item
, "activate",
1856 G_CALLBACK(city_select_same_island_callback
), NULL
);
1859 item
= gtk_separator_menu_item_new();
1860 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1863 select_supported_item
= gtk_menu_item_new_with_label(_("Supported Units"));
1864 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), select_supported_item
);
1866 select_present_item
= gtk_menu_item_new_with_label(_("Units Present"));
1867 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), select_present_item
);
1869 select_built_improvements_item
=
1870 gtk_menu_item_new_with_label(_("Improvements in City"));
1871 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), select_built_improvements_item
);
1873 select_built_wonders_item
=
1874 gtk_menu_item_new_with_label(_("Wonders in City"));
1875 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), select_built_wonders_item
);
1878 item
= gtk_separator_menu_item_new();
1879 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1883 gtk_menu_item_new_with_label(_("Available Units"));
1884 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), select_units_item
);
1885 select_improvements_item
=
1886 gtk_menu_item_new_with_label(_("Available Improvements"));
1887 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), select_improvements_item
);
1888 select_wonders_item
=
1889 gtk_menu_item_new_with_label(_("Available Wonders"));
1890 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), select_wonders_item
);
1892 gtk_menu_item_new_with_label(_("Citizen Governor"));
1893 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), select_cma_item
);
1896 /****************************************************************
1897 Returns whether city is building given target
1898 *****************************************************************/
1899 static bool city_building_impr_or_unit(const struct city
*pcity
,
1900 const struct universal
*target
)
1902 return are_universals_equal(&pcity
->production
, target
);
1905 /****************************************************************
1907 *****************************************************************/
1908 static void popup_select_menu(GtkMenuShell
*menu
, gpointer data
)
1912 if (select_menu_cached
)
1915 n
= gtk_tree_selection_count_selected_rows(city_selection
);
1916 gtk_widget_set_sensitive(select_island_item
, (n
> 0));
1918 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_bunit_item
),
1919 TRUE
, FALSE
, CO_NONE
,
1920 city_building_impr_or_unit
,
1921 G_CALLBACK(select_impr_or_unit_callback
), -1);
1922 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_bimprovement_item
),
1923 FALSE
, FALSE
, CO_NONE
,
1924 city_building_impr_or_unit
,
1925 G_CALLBACK(select_impr_or_unit_callback
), -1);
1926 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_bwonder_item
),
1927 FALSE
, TRUE
, CO_NONE
,
1928 city_building_impr_or_unit
,
1929 G_CALLBACK(select_impr_or_unit_callback
), -1);
1931 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_supported_item
),
1932 TRUE
, FALSE
, CO_NONE
,
1933 city_unit_supported
,
1934 G_CALLBACK(select_impr_or_unit_callback
), -1);
1935 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_present_item
),
1936 TRUE
, FALSE
, CO_NONE
,
1938 G_CALLBACK(select_impr_or_unit_callback
), -1);
1939 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_built_improvements_item
),
1940 FALSE
, FALSE
, CO_NONE
,
1941 city_building_present
,
1942 G_CALLBACK(select_impr_or_unit_callback
), -1);
1943 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_built_wonders_item
),
1944 FALSE
, TRUE
, CO_NONE
,
1945 city_building_present
,
1946 G_CALLBACK(select_impr_or_unit_callback
), -1);
1948 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_improvements_item
),
1949 FALSE
, FALSE
, CO_NONE
,
1951 G_CALLBACK(select_impr_or_unit_callback
), -1);
1952 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_units_item
),
1953 TRUE
, FALSE
, CO_NONE
,
1955 G_CALLBACK(select_impr_or_unit_callback
), -1);
1956 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_wonders_item
),
1957 FALSE
, TRUE
, CO_NONE
,
1959 G_CALLBACK(select_impr_or_unit_callback
), -1);
1960 append_cma_to_menu_item(GTK_MENU_ITEM(select_cma_item
), FALSE
);
1962 select_menu_cached
= TRUE
;
1965 /***************************************************************************
1966 Update the value displayed by the "total buy cost" label in the city
1967 report, or make it blank if nothing can be bought.
1968 ***************************************************************************/
1969 static void update_total_buy_cost(void)
1971 GtkWidget
*label
, *view
;
1973 GtkTreeModel
*model
;
1974 GtkTreeSelection
*sel
;
1981 label
= city_total_buy_cost_label
;
1983 if (!view
|| !label
) {
1987 sel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(view
));
1988 rows
= gtk_tree_selection_get_selected_rows(sel
, &model
);
1990 for (p
= rows
; p
!= NULL
; p
= p
->next
) {
1992 if (gtk_tree_model_get_iter(model
, &iter
, path
)) {
1993 if ((pcity
= city_model_get(model
, &iter
))) {
1994 total
+= city_production_buy_gold_cost(pcity
);
1997 gtk_tree_path_free(path
);
2002 gchar
*buf
= g_strdup_printf(_("Total Buy Cost: %d"), total
);
2003 gtk_label_set_text(GTK_LABEL(label
), buf
);
2006 gtk_label_set_text(GTK_LABEL(label
), NULL
);
2010 /***************************************************************************
2011 Update city report button sensitivity and total buy cost label when the
2012 user makes a change in the selection of cities.
2013 ***************************************************************************/
2014 static void city_selection_changed_callback(GtkTreeSelection
*selection
)
2017 bool obs_may
, plr_may
;
2019 n
= gtk_tree_selection_count_selected_rows(selection
);
2021 plr_may
= obs_may
&& can_client_issue_orders();
2023 gtk_widget_set_sensitive(city_production_command
, plr_may
);
2024 gtk_widget_set_sensitive(city_governor_command
, plr_may
);
2025 gtk_widget_set_sensitive(city_center_command
, obs_may
);
2026 gtk_widget_set_sensitive(city_popup_command
, obs_may
);
2027 gtk_widget_set_sensitive(city_buy_command
, plr_may
);
2029 recreate_sell_menu();
2031 gtk_widget_set_sensitive(city_sell_command
, FALSE
);
2034 update_total_buy_cost();
2037 /**************************************************************************
2038 Clear the worklist in one selected city in the city report.
2039 **************************************************************************/
2040 static void clear_worklist_foreach_func(GtkTreeModel
*model
,
2045 struct city
*pcity
= city_model_get(model
, iter
);
2047 if (NULL
!= pcity
) {
2048 struct worklist empty
;
2050 worklist_init(&empty
);
2051 city_set_worklist(pcity
, &empty
);
2055 /**************************************************************************
2056 Called when the "clear worklist" menu item is activated.
2057 **************************************************************************/
2058 static void city_clear_worklist_callback(GtkMenuItem
*item
, gpointer data
)
2060 struct connection
*pconn
= &client
.conn
;
2062 fc_assert_ret(city_selection
!= NULL
);
2064 connection_do_buffer(pconn
);
2065 gtk_tree_selection_selected_foreach(city_selection
,
2066 clear_worklist_foreach_func
, NULL
);
2067 connection_do_unbuffer(pconn
);
2070 /****************************************************************
2071 After a selection rectangle is defined, make the cities that
2072 are hilited on the canvas exclusively hilited in the
2074 *****************************************************************/
2075 void hilite_cities_from_canvas(void)
2078 GtkTreeModel
*model
;
2080 if (!city_dialog_shell
) return;
2082 model
= GTK_TREE_MODEL(city_model
);
2084 gtk_tree_selection_unselect_all(city_selection
);
2086 for (itree_begin(model
, &it
); !itree_end(&it
); itree_next(&it
)) {
2087 struct city
*pcity
= city_model_get(model
, TREE_ITER_PTR(it
));
2089 if (NULL
!= pcity
&& is_city_hilited(pcity
)) {
2090 itree_select(city_selection
, &it
);
2095 /****************************************************************
2096 Toggle a city's hilited status.
2097 *****************************************************************/
2098 void toggle_city_hilite(struct city
*pcity
, bool on_off
)
2102 if (NULL
== city_dialog_shell
) {
2106 if (city_model_find(GTK_TREE_MODEL(city_model
), &iter
, pcity
)) {
2108 gtk_tree_selection_select_iter(city_selection
, &iter
);
2110 gtk_tree_selection_unselect_iter(city_selection
, &iter
);