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 "astring.h"
27 #include "fcintl.h"
28 #include "support.h"
29 
30 /* common */
31 #include "diptreaty.h"
32 #include "packets.h"
33 #include "nation.h"
34 #include "player.h"
35 
36 /* client */
37 #include "chatline.h"
38 #include "client_main.h"
39 #include "climisc.h"
40 #include "connectdlg_common.h"
41 #include "dialogs.h"
42 #include "gui_main.h"
43 #include "gui_stuff.h"
44 #include "inteldlg.h"
45 #include "spaceshipdlg.h"
46 #include "tilespec.h"
47 #include "colors.h"
48 #include "graphics.h"
49 #include "options.h"
50 #include "text.h"
51 
52 #include "plrdlg.h"
53 
54 struct gui_dialog *players_dialog_shell;
55 static GtkWidget *players_list;
56 static GtkTreeSelection *players_selection;
57 static GtkWidget *players_int_command;
58 static GtkWidget *players_meet_command;
59 static GtkWidget *players_war_command;
60 static GtkWidget *players_vision_command;
61 static GtkWidget *players_sship_command;
62 
63 static GtkListStore *players_dialog_store;
64 #define PLR_DLG_COL_STYLE       (0 + num_player_dlg_columns)
65 #define PLR_DLG_COL_WEIGHT      (1 + num_player_dlg_columns)
66 #define PLR_DLG_COL_ID          (2 + num_player_dlg_columns)
67 
68 static void create_players_dialog(void);
69 static void players_meet_callback(GtkMenuItem *item, gpointer data);
70 static void players_war_callback(GtkMenuItem *item, gpointer data);
71 static void players_vision_callback(GtkMenuItem *item, gpointer data);
72 static void players_intel_callback(GtkMenuItem *item, gpointer data);
73 static void players_sship_callback(GtkMenuItem *item, gpointer data);
74 static void players_ai_toggle_callback(GtkMenuItem *item, gpointer data);
75 static void players_ai_skill_callback(GtkMenuItem *item, gpointer data);
76 
77 
78 static void update_views(void);
79 
80 /**************************************************************************
81 popup the dialog 10% inside the main-window, and optionally raise it.
82 **************************************************************************/
popup_players_dialog(bool raise)83 void popup_players_dialog(bool raise)
84 {
85   if (!players_dialog_shell){
86     create_players_dialog();
87   }
88   gui_dialog_present(players_dialog_shell);
89   if (raise) {
90     gui_dialog_raise(players_dialog_shell);
91   }
92 }
93 
94 /****************************************************************
95  Closes the players dialog.
96 *****************************************************************/
popdown_players_dialog(void)97 void popdown_players_dialog(void)
98 {
99   if (players_dialog_shell) {
100     gui_dialog_destroy(players_dialog_shell);
101   }
102 }
103 
104 /***************************************************************************
105   Create a small colored square representing the player color, for use
106   in player lists.
107   May return NULL if the player has no color yet.
108 ***************************************************************************/
create_player_icon(const struct player * plr)109 GdkPixbuf *create_player_icon(const struct player *plr)
110 {
111   int width, height;
112   GdkPixbuf *tmp;
113   GdkPixmap *pixmap;
114 
115   if (!player_has_color(tileset, plr)) {
116     return NULL;
117   }
118 
119   gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
120 
121   pixmap = gdk_pixmap_new(root_window, width, height, -1);
122 
123   gdk_gc_set_foreground(civ_gc,
124                         &get_color(tileset,
125 				   COLOR_PLAYER_COLOR_BACKGROUND)->color);
126   gdk_draw_rectangle(pixmap, civ_gc, TRUE, 0, 0, width, height);
127 
128   gdk_gc_set_foreground(civ_gc, &get_player_color(tileset, plr)->color);
129   gdk_draw_rectangle(pixmap, civ_gc, TRUE, 1, 1, width - 2, height - 2);
130 
131   tmp = gdk_pixbuf_get_from_drawable(NULL, pixmap, NULL,
132       0, 0, 0, 0, -1, -1);
133 
134   g_object_unref(pixmap);
135   return tmp;
136 }
137 
138 /**************************************************************************
139   Refresh player menu
140 **************************************************************************/
update_players_menu(void)141 static void update_players_menu(void)
142 {
143   GtkTreeModel *model;
144   GtkTreeIter it;
145 
146   if (gtk_tree_selection_get_selected(players_selection, &model, &it)) {
147     struct player *plr;
148     gint plrno;
149 
150     gtk_tree_model_get(model, &it, PLR_DLG_COL_ID, &plrno, -1);
151     plr = player_by_number(plrno);
152 
153     if (plr->spaceship.state != SSHIP_NONE) {
154       gtk_widget_set_sensitive(players_sship_command, TRUE);
155     } else {
156       gtk_widget_set_sensitive(players_sship_command, FALSE);
157     }
158 
159     if (NULL != client.conn.playing) {
160       /* We keep button sensitive in case of DIPL_SENATE_BLOCKING, so that player
161        * can request server side to check requirements of those effects with omniscience */
162       gtk_widget_set_sensitive(players_war_command,
163                                can_client_issue_orders()
164                                && pplayer_can_cancel_treaty(client_player(),
165                                                             player_by_number(plrno))
166                                != DIPL_ERROR);
167     } else {
168       gtk_widget_set_sensitive(players_war_command, FALSE);
169     }
170 
171     gtk_widget_set_sensitive(players_vision_command,
172 			     can_client_issue_orders()
173 			     && gives_shared_vision(client.conn.playing, plr)
174                              && !players_on_same_team(client.conn.playing, plr));
175 
176     gtk_widget_set_sensitive(players_meet_command, can_meet_with_player(plr));
177     gtk_widget_set_sensitive(players_int_command, can_intel_with_player(plr));
178     return;
179   }
180 
181   gtk_widget_set_sensitive(players_meet_command, FALSE);
182   gtk_widget_set_sensitive(players_int_command, FALSE);
183 }
184 
185 /**************************************************************************
186   Something selected from player menu
187 **************************************************************************/
selection_callback(GtkTreeSelection * selection,gpointer data)188 static void selection_callback(GtkTreeSelection *selection, gpointer data)
189 {
190   update_players_menu();
191 }
192 
193 /**************************************************************************
194   Button pressed on player list
195 **************************************************************************/
button_press_callback(GtkTreeView * view,GdkEventButton * ev)196 static gboolean button_press_callback(GtkTreeView *view, GdkEventButton *ev)
197 {
198   if (ev->type == GDK_2BUTTON_PRESS) {
199     GtkTreePath *path;
200 
201     gtk_tree_view_get_cursor(view, &path, NULL);
202     if (path) {
203       GtkTreeModel *model = gtk_tree_view_get_model(view);
204       GtkTreeIter it;
205       gint id;
206       struct player *plr;
207 
208       gtk_tree_model_get_iter(model, &it, path);
209       gtk_tree_path_free(path);
210 
211       gtk_tree_model_get(model, &it, PLR_DLG_COL_ID, &id, -1);
212       plr = player_by_number(id);
213 
214       if (ev->button == 1) {
215         if (can_intel_with_player(plr)) {
216           popup_intel_dialog(plr);
217         }
218       } else if (can_meet_with_player(plr)) {
219         dsend_packet_diplomacy_init_meeting_req(&client.conn, id);
220       }
221     }
222   }
223   return FALSE;
224 }
225 
226 /**************************************************************************
227   Sorting function for plr dlg.
228 **************************************************************************/
plrdlg_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer data)229 static gint plrdlg_sort_func(GtkTreeModel *model,
230 			      GtkTreeIter *a, GtkTreeIter *b, gpointer data)
231 {
232   GValue value = { 0, };
233   struct player *player1;
234   struct player *player2;
235   gint n;
236 
237   n = GPOINTER_TO_INT(data);
238 
239   gtk_tree_model_get_value(model, a, PLR_DLG_COL_ID, &value);
240   player1 = player_by_number(g_value_get_int(&value));
241   g_value_unset(&value);
242 
243   gtk_tree_model_get_value(model, b, PLR_DLG_COL_ID, &value);
244   player2 = player_by_number(g_value_get_int(&value));
245   g_value_unset(&value);
246 
247   return player_dlg_columns[n].sort_func(player1, player2);
248 }
249 
250 /****************************************************************************
251   Create a player dialog store.
252 ****************************************************************************/
players_dialog_store_new(void)253 static GtkListStore *players_dialog_store_new(void)
254 {
255   GtkListStore *store;
256   GType model_types[num_player_dlg_columns + 3];
257   int i;
258 
259   for (i = 0; i < num_player_dlg_columns; i++) {
260     switch (player_dlg_columns[i].type) {
261     case COL_FLAG:
262       model_types[i] = GDK_TYPE_PIXBUF;
263       break;
264     case COL_COLOR:
265       model_types[i] = GDK_TYPE_PIXBUF;
266       break;
267     case COL_BOOLEAN:
268       model_types[i] = G_TYPE_BOOLEAN;
269       break;
270     case COL_TEXT:
271     case COL_RIGHT_TEXT:
272       model_types[i] = G_TYPE_STRING;
273       break;
274     }
275   }
276   /* special (invisible rows) - Text style, weight and player id */
277   model_types[i++] = G_TYPE_INT;        /* PLR_DLG_COL_STYLE. */
278   model_types[i++] = G_TYPE_INT;        /* PLR_DLG_COL_WEIGHT. */
279   model_types[i++] = G_TYPE_INT;        /* PLR_DLG_COL_ID. */
280 
281   store = gtk_list_store_newv(i, model_types);
282 
283   /* Set sort order */
284   for (i = 0; i < num_player_dlg_columns; i++) {
285     if (player_dlg_columns[i].sort_func != NULL) {
286         gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), i,
287                                         plrdlg_sort_func, GINT_TO_POINTER(i),
288                                         NULL);
289     }
290   }
291 
292   return store;
293 }
294 
295 /**************************************************************************
296   Toggled column visibility
297 **************************************************************************/
toggle_view(GtkCheckMenuItem * item,gpointer data)298 static void toggle_view(GtkCheckMenuItem* item, gpointer data)
299 {
300   struct player_dlg_column* pcol = data;
301 
302   pcol->show = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item));
303   update_views();
304 }
305 
306 /*************************************************************************
307   Called whenever player toggles the 'Show/Dead Players' menu item
308 *************************************************************************/
toggle_dead_players(GtkCheckMenuItem * item,gpointer data)309 static void toggle_dead_players(GtkCheckMenuItem* item, gpointer data)
310 {
311   gui_options.player_dlg_show_dead_players =
312     gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item));
313   real_players_dialog_update(NULL);
314 }
315 
316 /**************************************************************************
317   Create and return the "diplomacy" menu for the player report. This menu
318   contains diplomacy actions the current player can use on other nations.
319 **************************************************************************/
create_diplomacy_menu(void)320 static GtkWidget *create_diplomacy_menu(void)
321 {
322   GtkWidget *menu, *item;
323 
324   menu = gtk_menu_new();
325 
326   item = gtk_menu_item_new_with_mnemonic(_("_Meet"));
327   g_signal_connect(item, "activate",
328                    G_CALLBACK(players_meet_callback), NULL);
329   gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
330   players_meet_command = item;
331 
332   item = gtk_menu_item_new_with_mnemonic(_("Cancel _Treaty"));
333   g_signal_connect(item, "activate",
334                    G_CALLBACK(players_war_callback), NULL);
335   gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
336   players_war_command = item;
337 
338   item = gtk_menu_item_new_with_mnemonic(_("_Withdraw Vision"));
339   g_signal_connect(item, "activate",
340                    G_CALLBACK(players_vision_callback), NULL);
341   gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
342   players_vision_command = item;
343 
344   return menu;
345 }
346 
347 /**************************************************************************
348   Create and return the "intelligence" menu. The items in this menu are
349   used by the player to see more detailed information about other nations.
350 **************************************************************************/
create_intelligence_menu(void)351 static GtkWidget *create_intelligence_menu(void)
352 {
353   GtkWidget *menu, *item;
354 
355   menu = gtk_menu_new();
356 
357   item = gtk_menu_item_new_with_mnemonic(_("_Report"));
358   g_signal_connect(item, "activate",
359                    G_CALLBACK(players_intel_callback), NULL);
360   gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
361   players_int_command = item;
362 
363   item = gtk_menu_item_new_with_mnemonic(_("_Spaceship"));
364   g_signal_connect(item, "activate",
365                    G_CALLBACK(players_sship_callback), NULL);
366   gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
367   players_sship_command = item;
368 
369   return menu;
370 }
371 
372 /**************************************************************************
373   Create 'show' menu for player dialog
374 **************************************************************************/
create_show_menu(void)375 static GtkWidget* create_show_menu(void)
376 {
377   int i;
378   GtkWidget *menu = gtk_menu_new();
379   GtkWidget *item;
380 
381   /* index starting at one (1) here to force playername to always be shown */
382   for (i = 1; i < num_player_dlg_columns; i++) {
383     struct player_dlg_column *pcol;
384 
385     pcol = &player_dlg_columns[i];
386     item = gtk_check_menu_item_new_with_label(pcol->title);
387     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), pcol->show);
388     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
389     g_signal_connect(item, "toggled", G_CALLBACK(toggle_view), pcol);
390   }
391 
392   item = gtk_separator_menu_item_new();
393   gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
394 
395   item = gtk_check_menu_item_new_with_label(Q_("?show:Dead Players"));
396   gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item),
397                                  gui_options.player_dlg_show_dead_players);
398   gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
399   g_signal_connect(item, "toggled", G_CALLBACK(toggle_dead_players), NULL);
400 
401   return menu;
402 }
403 
404 /**************************************************************************
405   Create all of player dialog
406 **************************************************************************/
create_players_dialog(void)407 void create_players_dialog(void)
408 {
409   int i;
410   GtkWidget *sep, *sw;
411   GtkWidget *menubar, *menu, *item, *vbox;
412   enum ai_level level;
413 
414   gui_dialog_new(&players_dialog_shell, GTK_NOTEBOOK(top_notebook), NULL,
415                  TRUE);
416   /* TRANS: Nations report title */
417   gui_dialog_set_title(players_dialog_shell, _("Nations"));
418 
419   gui_dialog_add_button(players_dialog_shell,
420       GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
421 
422   gui_dialog_set_default_size(players_dialog_shell, -1, 270);
423 
424   players_dialog_store = players_dialog_store_new();
425 
426   players_list = gtk_tree_view_new_with_model(GTK_TREE_MODEL
427                                               (players_dialog_store));
428   g_object_unref(players_dialog_store);
429   gtk_widget_set_name(players_list, "small_font");
430 
431   players_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(players_list));
432   g_signal_connect(players_selection, "changed",
433       G_CALLBACK(selection_callback), NULL);
434   g_signal_connect(players_list, "button_press_event",
435       G_CALLBACK(button_press_callback), NULL);
436 
437   for (i = 0; i < num_player_dlg_columns; i++) {
438     struct player_dlg_column *pcol;
439     GtkCellRenderer *renderer;
440     GtkTreeViewColumn *col;
441 
442     pcol = &player_dlg_columns[i];
443     col = NULL;
444 
445     switch (pcol->type) {
446     case COL_FLAG:
447       renderer = gtk_cell_renderer_pixbuf_new();
448 
449       col = gtk_tree_view_column_new_with_attributes(pcol->title,
450          renderer, "pixbuf", i, NULL);
451       break;
452     case COL_BOOLEAN:
453       renderer = gtk_cell_renderer_toggle_new();
454 
455       col = gtk_tree_view_column_new_with_attributes(pcol->title, renderer,
456         "active", i, NULL);
457       break;
458     case COL_COLOR:
459       renderer = gtk_cell_renderer_pixbuf_new();
460 
461       col = gtk_tree_view_column_new_with_attributes(pcol->title, renderer,
462              "pixbuf", i, NULL);
463       break;
464     case COL_TEXT:
465       renderer = gtk_cell_renderer_text_new();
466       g_object_set(renderer, "style-set", TRUE, "weight-set", TRUE, NULL);
467 
468       col = gtk_tree_view_column_new_with_attributes(pcol->title, renderer,
469 	  "text", i,
470 	  "style", PLR_DLG_COL_STYLE,
471 	  "weight", PLR_DLG_COL_WEIGHT,
472 	  NULL);
473       gtk_tree_view_column_set_sort_column_id(col, i);
474       break;
475     case COL_RIGHT_TEXT:
476       renderer = gtk_cell_renderer_text_new();
477       g_object_set(renderer, "style-set", TRUE, "weight-set", TRUE, NULL);
478 
479       col = gtk_tree_view_column_new_with_attributes(pcol->title, renderer,
480 	  "text", i,
481 	  "style", PLR_DLG_COL_STYLE,
482 	  "weight", PLR_DLG_COL_WEIGHT,
483 	  NULL);
484       gtk_tree_view_column_set_sort_column_id(col, i);
485       g_object_set(renderer, "xalign", 1.0, NULL);
486       gtk_tree_view_column_set_alignment(col, 1.0);
487       break;
488     }
489 
490     if (col) {
491       gtk_tree_view_append_column(GTK_TREE_VIEW(players_list), col);
492     }
493   }
494 
495   gtk_tree_view_set_search_column(GTK_TREE_VIEW(players_list),
496                                   player_dlg_default_sort_column());
497 
498   sw = gtk_scrolled_window_new(NULL, NULL);
499   gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
500 				      GTK_SHADOW_ETCHED_IN);
501   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
502 		                 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
503   gtk_container_add(GTK_CONTAINER(sw), players_list);
504 
505   gtk_box_pack_start(GTK_BOX(players_dialog_shell->vbox), sw,
506 		     TRUE, TRUE, 0);
507 
508   vbox = gtk_vbox_new(FALSE, 0);
509 
510   sep = gtk_hseparator_new();
511   gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0);
512 
513   menubar = gtk_aux_menu_bar_new();
514   gtk_box_pack_start(GTK_BOX(vbox), menubar, TRUE, TRUE, 0);
515 
516 
517   gui_dialog_add_widget(players_dialog_shell, vbox);
518   gtk_box_set_child_packing(GTK_BOX(players_dialog_shell->action_area),
519                             vbox, FALSE, FALSE, 0, GTK_PACK_START);
520 
521   item = gtk_menu_item_new_with_mnemonic(_("Di_plomacy"));
522   menu = create_diplomacy_menu();
523   gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
524   gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
525 
526   item = gtk_menu_item_new_with_mnemonic(_("_Intelligence"));
527   menu = create_intelligence_menu();
528   gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
529   gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
530 
531   item = gtk_menu_item_new_with_mnemonic(_("_Display"));
532   menu = create_show_menu();
533   gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
534   gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
535 
536   item = gtk_menu_item_new_with_mnemonic(_("_AI"));
537   gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
538 
539   menu = gtk_menu_new();
540   gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
541 
542   item = gtk_menu_item_new_with_mnemonic(_("_Toggle AI Mode"));
543   g_signal_connect(item, "activate",
544       G_CALLBACK(players_ai_toggle_callback), NULL);
545   gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
546 
547   sep = gtk_separator_menu_item_new();
548   gtk_menu_shell_append(GTK_MENU_SHELL(menu), sep);
549 
550   for (level = 0; level < AI_LEVEL_COUNT; level++) {
551     if (is_settable_ai_level(level)) {
552       const char *level_name = ai_level_translated_name(level);
553 
554       item = gtk_menu_item_new_with_label(level_name);
555       g_signal_connect(item, "activate",
556                        G_CALLBACK(players_ai_skill_callback),
557                        GUINT_TO_POINTER(level));
558       gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
559     }
560   }
561   gtk_widget_show_all(menu);
562 
563   gui_dialog_show_all(players_dialog_shell);
564 
565   real_players_dialog_update(NULL);
566 
567   gui_dialog_set_default_response(players_dialog_shell,
568     GTK_RESPONSE_CLOSE);
569 
570   gtk_tree_view_focus(GTK_TREE_VIEW(players_list));
571 }
572 
573 
574 /**************************************************************************
575 ...
576 **************************************************************************/
577 #define MIN_DIMENSION 5
578 
579 /**************************************************************************
580  Builds the flag pixmap. May return NULL if there is not enough memory.
581  You must call g_object_unref on the returned pixbuf when it is no
582  longer needed.
583 **************************************************************************/
get_flag(const struct nation_type * nation)584 GdkPixbuf *get_flag(const struct nation_type *nation)
585 {
586   int x0, y0, x1, y1, w, h;
587   GdkPixbuf *im;
588   struct sprite *flag;
589 
590   flag = get_nation_flag_sprite(tileset, nation);
591 
592   /* calculate the bounding box ... */
593   sprite_get_bounding_box(flag, &x0, &y0, &x1, &y1);
594 
595   fc_assert_ret_val(x0 != -1, NULL);
596   fc_assert_ret_val(y0 != -1, NULL);
597   fc_assert_ret_val(x1 != -1, NULL);
598   fc_assert_ret_val(y1 != -1, NULL);
599 
600   w = (x1 - x0) + 1;
601   h = (y1 - y0) + 1;
602 
603   /* if the flag is smaller then 5 x 5, something is wrong */
604   fc_assert_ret_val(w >= MIN_DIMENSION && h >= MIN_DIMENSION, NULL);
605 
606   /* croping */
607   im = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, w, h);
608   if (im != NULL) {
609     gdk_pixbuf_copy_area(sprite_get_pixbuf(flag), x0, y0, w, h,
610                          im, 0, 0);
611   }
612 
613   /* and finaly store the scaled flag pixbuf in the static flags array */
614   return im;
615 }
616 
617 
618 /**************************************************************************
619   Fills the player list with the information for 'pplayer' at the row
620   given by 'it'.
621 **************************************************************************/
fill_row(GtkListStore * store,GtkTreeIter * it,const struct player * pplayer)622 static void fill_row(GtkListStore *store, GtkTreeIter *it,
623                      const struct player *pplayer)
624 {
625   struct player_dlg_column* pcol;
626   GdkPixbuf *pixbuf;
627   int style = PANGO_STYLE_NORMAL, weight = PANGO_WEIGHT_NORMAL;
628   int k;
629 
630   for (k = 0; k < num_player_dlg_columns; k++) {
631     pcol = &player_dlg_columns[k];
632     switch (pcol->type) {
633     case COL_TEXT:
634     case COL_RIGHT_TEXT:
635       gtk_list_store_set(store, it, k, pcol->func(pplayer), -1);
636       break;
637     case COL_FLAG:
638       pixbuf = get_flag(nation_of_player(pplayer));
639       if (pixbuf != NULL) {
640         gtk_list_store_set(store, it, k, pixbuf, -1);
641         g_object_unref(pixbuf);
642       }
643       break;
644     case COL_COLOR:
645       pixbuf = create_player_icon(pplayer);
646       if (pixbuf != NULL) {
647         gtk_list_store_set(store, it, k, pixbuf, -1);
648         g_object_unref(pixbuf);
649       }
650       break;
651     case COL_BOOLEAN:
652       gtk_list_store_set(store, it, k, pcol->bool_func(pplayer), -1);
653       break;
654     }
655   }
656 
657    /* now add some eye candy ... */
658   if (client_has_player()) {
659     switch (player_diplstate_get(client_player(), pplayer)->type) {
660     case DS_WAR:
661       weight = PANGO_WEIGHT_NORMAL;
662       style = PANGO_STYLE_ITALIC;
663       break;
664     case DS_ALLIANCE:
665     case DS_TEAM:
666       weight = PANGO_WEIGHT_BOLD;
667       style = PANGO_STYLE_NORMAL;
668       break;
669     case DS_ARMISTICE:
670     case DS_CEASEFIRE:
671     case DS_PEACE:
672     case DS_NO_CONTACT:
673       weight = PANGO_WEIGHT_NORMAL;
674       style = PANGO_STYLE_NORMAL;
675       break;
676     case DS_LAST:
677       break;
678     }
679   }
680 
681   gtk_list_store_set(store, it,
682                      PLR_DLG_COL_STYLE, style,
683                      PLR_DLG_COL_WEIGHT, weight,
684                      PLR_DLG_COL_ID, player_number(pplayer),
685                      -1);
686 }
687 
688 /**************************************************************************
689   Return TRUE if the player should be shown in the player list.
690 **************************************************************************/
player_should_be_shown(const struct player * pplayer)691 static bool player_should_be_shown(const struct player *pplayer)
692 {
693   return NULL != pplayer && (gui_options.player_dlg_show_dead_players
694                              || pplayer->is_alive)
695          && (!is_barbarian(pplayer));
696 }
697 
698 /**************************************************************************
699   Clear and refill the entire player list.
700 **************************************************************************/
real_players_dialog_update(void * unused)701 void real_players_dialog_update(void *unused)
702 {
703   GtkTreeModel *model;
704   GtkTreeIter iter;
705   int selected;
706 
707   if (NULL == players_dialog_shell) {
708     return;
709   }
710 
711   /* Save the selection. */
712   if (gtk_tree_selection_get_selected(players_selection, &model, &iter)) {
713     gtk_tree_model_get(model, &iter, PLR_DLG_COL_ID, &selected, -1);
714   } else {
715     selected = -1;
716   }
717 
718   gtk_list_store_clear(players_dialog_store);
719   players_iterate(pplayer) {
720     if (!player_should_be_shown(pplayer)) {
721       continue;
722     }
723     gtk_list_store_append(players_dialog_store, &iter);
724     fill_row(players_dialog_store, &iter, pplayer);
725     if (player_number(pplayer) == selected) {
726       /* Restore the selection. */
727       gtk_tree_selection_select_iter(players_selection, &iter);
728     }
729   } players_iterate_end;
730 
731   update_views();
732 }
733 
734 /**************************************************************************
735   Callback for diplomatic meetings button. This button is enabled iff
736   we can meet with the other player.
737 **************************************************************************/
players_meet_callback(GtkMenuItem * item,gpointer data)738 void players_meet_callback(GtkMenuItem *item, gpointer data)
739 {
740   GtkTreeModel *model;
741   GtkTreeIter it;
742 
743   if (gtk_tree_selection_get_selected(players_selection, &model, &it)) {
744     gint plrno;
745 
746     gtk_tree_model_get(model, &it, PLR_DLG_COL_ID, &plrno, -1);
747 
748     dsend_packet_diplomacy_init_meeting_req(&client.conn, plrno);
749   }
750 }
751 
752 /**************************************************************************
753   Confirm pact/treaty cancellation.
754   Frees strings passed in.
755 **************************************************************************/
confirm_cancel_pact(enum clause_type clause,int plrno,char * title,char * question)756 static void confirm_cancel_pact(enum clause_type clause, int plrno,
757                                 char *title, char *question)
758 {
759   GtkWidget *shell;
760 
761   shell = gtk_message_dialog_new(NULL, 0,
762                                  GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
763                                  "%s", question);
764   gtk_window_set_title(GTK_WINDOW(shell), title);
765   setup_dialog(shell, toplevel);
766   gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_NO);
767 
768   if (gtk_dialog_run(GTK_DIALOG(shell)) == GTK_RESPONSE_YES) {
769     dsend_packet_diplomacy_cancel_pact(&client.conn, plrno, clause);
770   }
771   gtk_widget_destroy(shell);
772   FC_FREE(title);
773   FC_FREE(question);
774 }
775 
776 /**************************************************************************
777   Pact cancellation requested
778 **************************************************************************/
players_war_callback(GtkMenuItem * item,gpointer data)779 void players_war_callback(GtkMenuItem *item, gpointer data)
780 {
781   GtkTreeModel *model;
782   GtkTreeIter it;
783 
784   if (gtk_tree_selection_get_selected(players_selection, &model, &it)) {
785     struct astring title = ASTRING_INIT, question = ASTRING_INIT;
786     gint plrno;
787     struct player *aplayer;
788     enum diplstate_type oldstate, newstate;
789 
790     gtk_tree_model_get(model, &it, PLR_DLG_COL_ID, &plrno, -1);
791     aplayer = player_by_number(plrno);
792     fc_assert_ret(aplayer != NULL);
793 
794     oldstate = player_diplstate_get(client_player(), aplayer)->type;
795     newstate = cancel_pact_result(oldstate);
796 
797     /* TRANS: %s is a diplomatic state: "Cancel Cease-fire" */
798     astr_set(&title, _("Cancel %s"), diplstate_type_translated_name(oldstate));
799 
800     if (newstate == DS_WAR) {
801       astr_set(&question, _("Really declare war on the %s?"),
802                nation_plural_for_player(aplayer));
803     } else {
804       /* TRANS: "Cancel Belgian Alliance? ... will be Armistice." */
805       astr_set(&question, _("Cancel %s %s? New diplomatic state will be %s."),
806                nation_adjective_for_player(aplayer),
807                diplstate_type_translated_name(oldstate),
808                diplstate_type_translated_name(newstate));
809     }
810 
811     /* can be any pact clause */
812     confirm_cancel_pact(CLAUSE_CEASEFIRE, plrno,
813                         astr_to_str(&title), astr_to_str(&question));
814   }
815 }
816 
817 /**************************************************************************
818   Withdrawing shared vision
819 **************************************************************************/
players_vision_callback(GtkMenuItem * item,gpointer data)820 void players_vision_callback(GtkMenuItem *item, gpointer data)
821 {
822   GtkTreeModel *model;
823   GtkTreeIter it;
824 
825   if (gtk_tree_selection_get_selected(players_selection, &model, &it)) {
826     struct astring question = ASTRING_INIT;
827     gint plrno;
828     struct player *aplayer;
829 
830     gtk_tree_model_get(model, &it, PLR_DLG_COL_ID, &plrno, -1);
831     aplayer = player_by_number(plrno);
832     fc_assert_ret(aplayer != NULL);
833 
834     /* TRANS: "...from the Belgians?" */
835     astr_set(&question, _("Withdraw shared vision from the %s?"),
836              nation_plural_for_player(aplayer));
837 
838     confirm_cancel_pact(CLAUSE_VISION, plrno,
839                         fc_strdup(_("Withdraw Shared Vision")),
840                         astr_to_str(&question));
841   }
842 }
843 
844 /**************************************************************************
845   Intelligence report query
846 **************************************************************************/
players_intel_callback(GtkMenuItem * item,gpointer data)847 void players_intel_callback(GtkMenuItem *item, gpointer data)
848 {
849   GtkTreeModel *model;
850   GtkTreeIter it;
851 
852   if (gtk_tree_selection_get_selected(players_selection, &model, &it)) {
853     gint plrno;
854 
855     gtk_tree_model_get(model, &it, PLR_DLG_COL_ID, &plrno, -1);
856 
857     if (can_intel_with_player(player_by_number(plrno))) {
858       popup_intel_dialog(player_by_number(plrno));
859     }
860   }
861 }
862 
863 /**************************************************************************
864   Spaceship query callback
865 **************************************************************************/
players_sship_callback(GtkMenuItem * item,gpointer data)866 void players_sship_callback(GtkMenuItem *item, gpointer data)
867 {
868   GtkTreeModel *model;
869   GtkTreeIter it;
870 
871   if (gtk_tree_selection_get_selected(players_selection, &model, &it)) {
872     gint plrno;
873 
874     gtk_tree_model_get(model, &it, PLR_DLG_COL_ID, &plrno, -1);
875     popup_spaceship_dialog(player_by_number(plrno));
876   }
877 }
878 
879 /**************************************************************************
880   AI toggle callback.
881 **************************************************************************/
players_ai_toggle_callback(GtkMenuItem * item,gpointer data)882 static void players_ai_toggle_callback(GtkMenuItem *item, gpointer data)
883 {
884   GtkTreeModel *model;
885   GtkTreeIter it;
886 
887   if (gtk_tree_selection_get_selected(players_selection, &model, &it)) {
888     gint plrno;
889 
890     gtk_tree_model_get(model, &it, PLR_DLG_COL_ID, &plrno, -1);
891 
892     send_chat_printf("/aitoggle \"%s\"", player_name(player_by_number(plrno)));
893   }
894 }
895 
896 /**************************************************************************
897   AI skill level setting callback.
898 **************************************************************************/
players_ai_skill_callback(GtkMenuItem * item,gpointer data)899 static void players_ai_skill_callback(GtkMenuItem *item, gpointer data)
900 {
901   GtkTreeModel *model;
902   GtkTreeIter it;
903 
904   if (gtk_tree_selection_get_selected(players_selection, &model, &it)) {
905     gint plrno;
906 
907     gtk_tree_model_get(model, &it, PLR_DLG_COL_ID, &plrno, -1);
908 
909     send_chat_printf("/%s %s",
910                      ai_level_cmd(GPOINTER_TO_UINT(data)),
911                      player_name(player_by_number(plrno)));
912   }
913 }
914 
915 /**************************************************************************
916   Refresh players dialog views.
917 **************************************************************************/
update_views(void)918 static void update_views(void)
919 {
920   int i;
921 
922   for (i = 0; i < num_player_dlg_columns; i++) {
923     GtkTreeViewColumn *col;
924 
925     col = gtk_tree_view_get_column(GTK_TREE_VIEW(players_list), i);
926     gtk_tree_view_column_set_visible(col, player_dlg_columns[i].show);
927   }
928 }
929