Split "Establish Embassy".
[freeciv.git] / client / gui-gtk-3.0 / diplodlg.c
blob817b5030aeafeccb233b9f17a362aeb23a789f09
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.
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 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 #include <stdio.h>
19 #include <stdlib.h>
21 #include <gtk/gtk.h>
23 /* utility */
24 #include "log.h"
25 #include "mem.h"
26 #include "shared.h"
27 #include "support.h"
29 /* common */
30 #include "diptreaty.h"
31 #include "fcintl.h"
32 #include "game.h"
33 #include "government.h"
34 #include "map.h"
35 #include "packets.h"
36 #include "player.h"
37 #include "research.h"
39 /* client */
40 #include "chatline.h"
41 #include "client_main.h"
42 #include "climisc.h"
43 #include "options.h"
45 /* client/gui-gtk-3.0 */
46 #include "diplodlg.h"
47 #include "gui_main.h"
48 #include "gui_stuff.h"
49 #include "mapview.h"
50 #include "plrdlg.h"
52 #define MAX_NUM_CLAUSES 64
54 struct Diplomacy_dialog {
55 struct Treaty treaty;
56 struct gui_dialog* dialog;
58 GtkWidget *menu0;
59 GtkWidget *menu1;
61 GtkWidget *image0;
62 GtkWidget *image1;
64 GtkListStore *store;
67 struct Diplomacy_notebook {
68 struct gui_dialog* dialog;
69 GtkWidget *notebook;
72 #define SPECLIST_TAG dialog
73 #define SPECLIST_TYPE struct Diplomacy_dialog
74 #include "speclist.h"
76 #define dialog_list_iterate(dialoglist, pdialog) \
77 TYPED_LIST_ITERATE(struct Diplomacy_dialog, dialoglist, pdialog)
78 #define dialog_list_iterate_end LIST_ITERATE_END
80 static struct dialog_list *dialog_list;
81 static struct Diplomacy_notebook *dipl_main;
83 static struct Diplomacy_dialog *create_diplomacy_dialog(struct player *plr0,
84 struct player *plr1);
86 static struct Diplomacy_dialog *find_diplomacy_dialog(int other_player_id);
87 static void popup_diplomacy_dialog(int other_player_id, int initiated_from);
88 static void diplomacy_dialog_map_callback(GtkWidget *w, gpointer data);
89 static void diplomacy_dialog_seamap_callback(GtkWidget *w, gpointer data);
90 static void diplomacy_dialog_tech_callback(GtkWidget *w, gpointer data);
91 static void diplomacy_dialog_city_callback(GtkWidget *w, gpointer data);
92 static void diplomacy_dialog_ceasefire_callback(GtkWidget *w, gpointer data);
93 static void diplomacy_dialog_peace_callback(GtkWidget *w, gpointer data);
94 static void diplomacy_dialog_alliance_callback(GtkWidget *w, gpointer data);
95 static void diplomacy_dialog_vision_callback(GtkWidget *w, gpointer data);
96 static void diplomacy_dialog_embassy_callback(GtkWidget *w, gpointer data);
97 static void close_diplomacy_dialog(struct Diplomacy_dialog *pdialog);
98 static void update_diplomacy_dialog(struct Diplomacy_dialog *pdialog);
99 static void diplo_dialog_returnkey(GtkWidget *w, gpointer data);
101 static struct Diplomacy_notebook *diplomacy_main_create(void);
102 static void diplomacy_main_destroy(void);
103 static void diplomacy_main_response(struct gui_dialog *dlg, int response,
104 gpointer data);
106 #define RESPONSE_CANCEL_MEETING 100
107 #define RESPONSE_CANCEL_MEETING_ALL 101
109 /****************************************************************
110 Server tells us that either party has accepted treaty
111 *****************************************************************/
112 void handle_diplomacy_accept_treaty(int counterpart, bool I_accepted,
113 bool other_accepted)
115 struct Diplomacy_dialog *pdialog = find_diplomacy_dialog(counterpart);
117 if (!pdialog) {
118 return;
121 pdialog->treaty.accept0 = I_accepted;
122 pdialog->treaty.accept1 = other_accepted;
124 update_diplomacy_dialog(pdialog);
125 gui_dialog_alert(pdialog->dialog);
128 /****************************************************************
129 Someone is initiating meeting with us.
130 *****************************************************************/
131 void handle_diplomacy_init_meeting(int counterpart, int initiated_from)
133 popup_diplomacy_dialog(counterpart, initiated_from);
137 /****************************************************************
138 Meeting has been cancelled.
139 *****************************************************************/
140 void handle_diplomacy_cancel_meeting(int counterpart, int initiated_from)
142 struct Diplomacy_dialog *pdialog = find_diplomacy_dialog(counterpart);
144 if (!pdialog) {
145 return;
148 close_diplomacy_dialog(pdialog);
151 /****************************************************************
152 Added clause to the meeting
153 *****************************************************************/
154 void handle_diplomacy_create_clause(int counterpart, int giver,
155 enum clause_type type, int value)
157 struct Diplomacy_dialog *pdialog = find_diplomacy_dialog(counterpart);
159 if (!pdialog) {
160 return;
163 add_clause(&pdialog->treaty, player_by_number(giver), type, value);
164 update_diplomacy_dialog(pdialog);
165 gui_dialog_alert(pdialog->dialog);
168 /****************************************************************
169 Removed clause from meeting.
170 *****************************************************************/
171 void handle_diplomacy_remove_clause(int counterpart, int giver,
172 enum clause_type type, int value)
174 struct Diplomacy_dialog *pdialog = find_diplomacy_dialog(counterpart);
176 if (!pdialog) {
177 return;
180 remove_clause(&pdialog->treaty, player_by_number(giver), type, value);
181 update_diplomacy_dialog(pdialog);
182 gui_dialog_alert(pdialog->dialog);
185 /****************************************************************
186 Popup the dialog 10% inside the main-window
187 *****************************************************************/
188 static void popup_diplomacy_dialog(int other_player_id, int initiated_from)
190 struct Diplomacy_dialog *pdialog = find_diplomacy_dialog(other_player_id);
192 if (!can_client_issue_orders()) {
193 return;
196 if (!is_human(client.conn.playing)) {
197 return; /* Don't show if we are not human controlled. */
200 if (!pdialog) {
201 pdialog = create_diplomacy_dialog(client.conn.playing,
202 player_by_number(other_player_id));
205 gui_dialog_present(pdialog->dialog);
206 /* We initated the meeting - Make the tab active */
207 if (player_by_number(initiated_from) == client.conn.playing) {
208 /* we have to raise the diplomacy meeting tab as well as the selected
209 * meeting. */
210 fc_assert_ret(dipl_main != NULL);
211 gui_dialog_raise(dipl_main->dialog);
212 gui_dialog_raise(pdialog->dialog);
214 if (players_dialog_shell != NULL) {
215 gui_dialog_set_return_dialog(pdialog->dialog, players_dialog_shell);
220 /****************************************************************************
221 Utility for g_list_sort(). See below.
222 ****************************************************************************/
223 static gint sort_advance_names(gconstpointer a, gconstpointer b)
225 const struct advance *padvance1 = (const struct advance *) a;
226 const struct advance *padvance2 = (const struct advance *) b;
228 return fc_strcoll(advance_name_translation(padvance1),
229 advance_name_translation(padvance2));
232 /****************************************************************
233 Popup menu about adding clauses
234 *****************************************************************/
235 static void popup_add_menu(GtkMenuShell *parent, gpointer data)
237 struct Diplomacy_dialog *pdialog;
238 struct player *pgiver, *pother;
239 GtkWidget *item, *menu;
242 /* init. */
243 gtk_container_foreach(GTK_CONTAINER(parent),
244 (GtkCallback) gtk_widget_destroy, NULL);
246 pdialog = (struct Diplomacy_dialog *) data;
247 pgiver = (struct player *) g_object_get_data(G_OBJECT(parent), "plr");
248 pother = (pgiver == pdialog->treaty.plr0
249 ? pdialog->treaty.plr1 : pdialog->treaty.plr0);
252 /* Maps. */
253 menu = gtk_menu_new();
254 item = gtk_menu_item_new_with_mnemonic(_("World-map"));
255 gtk_menu_shell_append(GTK_MENU_SHELL(menu),item);
256 g_object_set_data(G_OBJECT(item), "plr", pgiver);
257 g_signal_connect(item, "activate",
258 G_CALLBACK(diplomacy_dialog_map_callback), pdialog);
260 item = gtk_menu_item_new_with_mnemonic(_("Sea-map"));
261 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
262 g_object_set_data(G_OBJECT(item), "plr", pgiver);
263 g_signal_connect(item, "activate",
264 G_CALLBACK(diplomacy_dialog_seamap_callback), pdialog);
266 item = gtk_menu_item_new_with_mnemonic(_("_Maps"));
267 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
268 gtk_menu_shell_append(GTK_MENU_SHELL(parent), item);
269 gtk_widget_show_all(item);
271 /* Trading: advances */
272 if (game.info.trading_tech) {
273 const struct research *gresearch = research_get(pgiver);
274 const struct research *oresearch = research_get(pother);
275 GtkWidget *advance_item;
276 GList *sorting_list = NULL;
278 advance_item = gtk_menu_item_new_with_mnemonic(_("_Advances"));
279 gtk_menu_shell_append(GTK_MENU_SHELL(parent), advance_item);
281 advance_iterate(A_FIRST, padvance) {
282 Tech_type_id i = advance_number(padvance);
284 if (research_invention_state(gresearch, i) == TECH_KNOWN
285 && research_invention_gettable(oresearch, i,
286 game.info.tech_trade_allow_holes)
287 && (research_invention_state(oresearch, i) == TECH_UNKNOWN
288 || research_invention_state(oresearch, i)
289 == TECH_PREREQS_KNOWN)) {
290 sorting_list = g_list_prepend(sorting_list, padvance);
292 } advance_iterate_end;
294 if (NULL == sorting_list) {
295 /* No advance. */
296 gtk_widget_set_sensitive(advance_item, FALSE);
297 } else {
298 GList *list_item;
299 const struct advance *padvance;
301 sorting_list = g_list_sort(sorting_list, sort_advance_names);
302 menu = gtk_menu_new();
304 /* TRANS: All technologies menu item in the diplomatic dialog. */
305 item = gtk_menu_item_new_with_label(_("All advances"));
306 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
307 g_object_set_data(G_OBJECT(item), "player_from",
308 GINT_TO_POINTER(player_number(pgiver)));
309 g_object_set_data(G_OBJECT(item), "player_to",
310 GINT_TO_POINTER(player_number(pother)));
311 g_signal_connect(item, "activate",
312 G_CALLBACK(diplomacy_dialog_tech_callback),
313 GINT_TO_POINTER(A_LAST));
314 gtk_menu_shell_append(GTK_MENU_SHELL(menu),
315 gtk_separator_menu_item_new());
317 for (list_item = sorting_list; NULL != list_item;
318 list_item = g_list_next(list_item)) {
319 padvance = (const struct advance *) list_item->data;
320 item =
321 gtk_menu_item_new_with_label(advance_name_translation(padvance));
322 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
323 g_object_set_data(G_OBJECT(item), "player_from",
324 GINT_TO_POINTER(player_number(pgiver)));
325 g_object_set_data(G_OBJECT(item), "player_to",
326 GINT_TO_POINTER(player_number(pother)));
327 g_signal_connect(item, "activate",
328 G_CALLBACK(diplomacy_dialog_tech_callback),
329 GINT_TO_POINTER(advance_number(padvance)));
332 gtk_menu_item_set_submenu(GTK_MENU_ITEM(advance_item), menu);
333 g_list_free(sorting_list);
336 gtk_widget_show_all(advance_item);
340 /* Trading: cities. */
342 /****************************************************************
343 Creates a sorted list of plr0's cities, excluding the capital and
344 any cities not visible to plr1. This means that you can only trade
345 cities visible to requesting player.
347 - Kris Bubendorfer
348 *****************************************************************/
349 if (game.info.trading_city) {
350 int i = 0, j = 0, n = city_list_size(pgiver->cities);
351 struct city **city_list_ptrs;
353 if (n > 0) {
354 city_list_ptrs = fc_malloc(sizeof(struct city *) * n);
355 } else {
356 city_list_ptrs = NULL;
359 city_list_iterate(pgiver->cities, pcity) {
360 if (!is_capital(pcity)) {
361 city_list_ptrs[i] = pcity;
362 i++;
364 } city_list_iterate_end;
366 qsort(city_list_ptrs, i, sizeof(struct city *), city_name_compare);
368 menu = gtk_menu_new();
370 for (j = 0; j < i; j++) {
371 item = gtk_menu_item_new_with_label(city_name_get(city_list_ptrs[j]));
373 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
374 g_signal_connect(item, "activate",
375 G_CALLBACK(diplomacy_dialog_city_callback),
376 GINT_TO_POINTER((player_number(pgiver) << 24) |
377 (player_number(pother) << 16) |
378 city_list_ptrs[j]->id));
380 free(city_list_ptrs);
382 item = gtk_menu_item_new_with_mnemonic(_("_Cities"));
383 gtk_widget_set_sensitive(item, (i > 0));
384 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
385 gtk_menu_shell_append(GTK_MENU_SHELL(parent), item);
386 gtk_widget_show_all(item);
390 /* Give shared vision. */
391 item = gtk_menu_item_new_with_mnemonic(_("_Give shared vision"));
392 g_object_set_data(G_OBJECT(item), "plr", pgiver);
393 g_signal_connect(item, "activate",
394 G_CALLBACK(diplomacy_dialog_vision_callback), pdialog);
396 if (gives_shared_vision(pgiver, pother)) {
397 gtk_widget_set_sensitive(item, FALSE);
399 gtk_menu_shell_append(GTK_MENU_SHELL(parent), item);
400 gtk_widget_show(item);
403 /* Give embassy. */
404 item = gtk_menu_item_new_with_mnemonic(_("Give _embassy"));
405 g_object_set_data(G_OBJECT(item), "plr", pgiver);
406 g_signal_connect(item, "activate",
407 G_CALLBACK(diplomacy_dialog_embassy_callback), pdialog);
409 /* Don't take in account the embassy effects. */
410 if (player_has_real_embassy(pother, pgiver)) {
411 gtk_widget_set_sensitive(item, FALSE);
413 gtk_menu_shell_append(GTK_MENU_SHELL(parent), item);
414 gtk_widget_show(item);
417 /* Pacts. */
418 if (pgiver == pdialog->treaty.plr0) {
419 enum diplstate_type ds;
421 ds = player_diplstate_get(pgiver, pother)->type;
423 menu = gtk_menu_new();
424 item = gtk_menu_item_new_with_mnemonic(Q_("?diplomatic_state:Cease-fire"));
425 gtk_menu_shell_append(GTK_MENU_SHELL(menu),item);
426 g_signal_connect(item, "activate",
427 G_CALLBACK(diplomacy_dialog_ceasefire_callback), pdialog);
428 gtk_widget_set_sensitive(item, ds != DS_CEASEFIRE && ds != DS_TEAM);
430 item = gtk_menu_item_new_with_mnemonic(Q_("?diplomatic_state:Peace"));
431 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
432 g_signal_connect(item, "activate",
433 G_CALLBACK(diplomacy_dialog_peace_callback), pdialog);
434 gtk_widget_set_sensitive(item, ds != DS_PEACE && ds != DS_TEAM);
436 item = gtk_menu_item_new_with_mnemonic(Q_("?diplomatic_state:Alliance"));
437 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
438 g_signal_connect(item, "activate",
439 G_CALLBACK(diplomacy_dialog_alliance_callback), pdialog);
440 gtk_widget_set_sensitive(item, ds != DS_ALLIANCE && ds != DS_TEAM);
442 item = gtk_menu_item_new_with_mnemonic(_("_Pacts"));
443 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
444 gtk_menu_shell_append(GTK_MENU_SHELL(parent), item);
445 gtk_widget_show_all(item);
449 /****************************************************************
450 Some clause activated
451 *****************************************************************/
452 static void row_callback(GtkTreeView *view, GtkTreePath *path,
453 GtkTreeViewColumn *col, gpointer data)
455 struct Diplomacy_dialog *pdialog = (struct Diplomacy_dialog *)data;
456 gint i;
457 gint *index;
459 index = gtk_tree_path_get_indices(path);
461 i = 0;
462 clause_list_iterate(pdialog->treaty.clauses, pclause) {
463 if (i == index[0]) {
464 dsend_packet_diplomacy_remove_clause_req(&client.conn,
465 player_number(pdialog->treaty.plr1),
466 player_number(pclause->from),
467 pclause->type,
468 pclause->value);
469 return;
471 i++;
472 } clause_list_iterate_end;
475 /*****************************************************************************
476 Create the main tab for diplomatic meetings.
477 *****************************************************************************/
478 static struct Diplomacy_notebook *diplomacy_main_create(void)
480 /* Collect all meetings in one main tab. */
481 if (!dipl_main) {
482 GtkWidget *dipl_box, *dipl_sw;
484 dipl_main = fc_malloc(sizeof(*dipl_main));
485 gui_dialog_new(&(dipl_main->dialog), GTK_NOTEBOOK(top_notebook),
486 dipl_main->dialog, TRUE);
487 dipl_main->notebook = gtk_notebook_new();
488 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(dipl_main->notebook),
489 GTK_POS_RIGHT);
490 gtk_notebook_set_scrollable(GTK_NOTEBOOK(dipl_main->notebook), TRUE);
492 dipl_sw = gtk_scrolled_window_new(NULL, NULL);
493 g_object_set(dipl_sw, "margin", 2, NULL);
494 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dipl_sw),
495 GTK_POLICY_AUTOMATIC,
496 GTK_POLICY_AUTOMATIC);
497 gtk_container_add(GTK_CONTAINER(dipl_sw), dipl_main->notebook);
499 /* Buttons */
500 gui_dialog_add_stockbutton(dipl_main->dialog, GTK_STOCK_CANCEL,
501 _("Cancel _all meetings"),
502 RESPONSE_CANCEL_MEETING_ALL);
504 /* Responces for _all_ meetings. */
505 gui_dialog_response_set_callback(dipl_main->dialog,
506 diplomacy_main_response);
507 gui_dialog_set_default_response(dipl_main->dialog,
508 RESPONSE_CANCEL_MEETING_ALL);
510 dipl_box = dipl_main->dialog->vbox;
511 gtk_container_add(GTK_CONTAINER(dipl_box), dipl_sw);
513 gui_dialog_show_all(dipl_main->dialog);
514 gui_dialog_present(dipl_main->dialog);
517 return dipl_main;
520 /*****************************************************************************
521 Destroy main diplomacy dialog.
522 *****************************************************************************/
523 static void diplomacy_main_destroy(void)
525 if (dipl_main->dialog) {
526 gui_dialog_destroy(dipl_main->dialog);
528 free(dipl_main);
529 dipl_main = NULL;
532 /*****************************************************************************
533 User has responded to whole diplomacy dialog (main tab).
534 *****************************************************************************/
535 static void diplomacy_main_response(struct gui_dialog *dlg, int response,
536 gpointer data)
538 if (!dipl_main) {
539 return;
542 switch (response) {
543 default:
544 log_error("unhandled response in %s: %d", __FUNCTION__, response);
545 /* No break. */
546 case GTK_RESPONSE_DELETE_EVENT: /* GTK: delete the widget. */
547 case RESPONSE_CANCEL_MEETING_ALL: /* Cancel all meetings. */
548 dialog_list_iterate(dialog_list, adialog) {
549 /* This will do a round trip to the server ans close the diolag in the
550 * client. Closing the last dialog will also close the main tab.*/
551 dsend_packet_diplomacy_cancel_meeting_req(&client.conn,
552 player_number(
553 adialog->treaty.plr1));
554 } dialog_list_iterate_end;
555 break;
559 /****************************************************************
560 Destroy diplomacy dialog
561 *****************************************************************/
562 static void diplomacy_destroy(struct Diplomacy_dialog* pdialog)
564 if (NULL != pdialog->dialog) {
565 /* pdialog->dialog may be NULL if the tab have been destroyed
566 * by an other way. */
567 gui_dialog_destroy(pdialog->dialog);
569 dialog_list_remove(dialog_list, pdialog);
570 free(pdialog);
572 if (dialog_list) {
573 /* Diplomatic meetings in one main tab. */
574 if (dialog_list_size(dialog_list) > 0) {
575 if (dipl_main && dipl_main->dialog) {
576 gchar *buf;
578 buf = g_strdup_printf(_("Diplomacy [%d]"), dialog_list_size(dialog_list));
579 gui_dialog_set_title(dipl_main->dialog, buf);
580 g_free(buf);
582 } else if (dipl_main) {
583 /* No meeting left - destroy main tab. */
584 diplomacy_main_destroy();
589 /*****************************************************************************
590 User has responded to whole diplomacy dialog (one meeting).
591 *****************************************************************************/
592 static void diplomacy_response(struct gui_dialog *dlg, int response,
593 gpointer data)
595 struct Diplomacy_dialog *pdialog = NULL;
597 fc_assert_ret(data);
598 pdialog = (struct Diplomacy_dialog *)data;
600 switch (response) {
601 case GTK_RESPONSE_ACCEPT: /* Accept treaty. */
602 dsend_packet_diplomacy_accept_treaty_req(&client.conn,
603 player_number(
604 pdialog->treaty.plr1));
605 break;
607 default:
608 log_error("unhandled response in %s: %d", __FUNCTION__, response);
609 /* No break. */
610 case GTK_RESPONSE_DELETE_EVENT: /* GTK: delete the widget. */
611 case GTK_RESPONSE_CANCEL: /* GTK: cancel button. */
612 case RESPONSE_CANCEL_MEETING: /* Cancel meetings. */
613 dsend_packet_diplomacy_cancel_meeting_req(&client.conn,
614 player_number(
615 pdialog->treaty.plr1));
616 break;
620 /*****************************************************************************
621 Setups diplomacy dialog widgets.
622 *****************************************************************************/
623 static struct Diplomacy_dialog *create_diplomacy_dialog(struct player *plr0,
624 struct player *plr1)
626 struct Diplomacy_notebook *dipl_dialog;
627 GtkWidget *vbox, *hbox, *table, *mainbox;
628 GtkWidget *label, *sw, *view, *image, *spin;
629 GtkWidget *menubar, *menuitem, *menu, *notebook;
630 struct sprite *flag_spr;
631 GtkListStore *store;
632 GtkCellRenderer *rend;
633 int i;
635 struct Diplomacy_dialog *pdialog;
636 char plr_buf[4 * MAX_LEN_NAME];
637 gchar *buf;
639 pdialog = fc_malloc(sizeof(*pdialog));
641 dialog_list_prepend(dialog_list, pdialog);
642 init_treaty(&pdialog->treaty, plr0, plr1);
644 /* Get main diplomacy tab. */
645 dipl_dialog = diplomacy_main_create();
647 buf = g_strdup_printf(_("Diplomacy [%d]"), dialog_list_size(dialog_list));
648 gui_dialog_set_title(dipl_dialog->dialog, buf);
649 g_free(buf);
651 notebook = dipl_dialog->notebook;
653 gui_dialog_new(&(pdialog->dialog), GTK_NOTEBOOK(notebook), pdialog, FALSE);
655 /* Buttons */
656 gui_dialog_add_stockbutton(pdialog->dialog, GTK_STOCK_DND,
657 _("Accept treaty"), GTK_RESPONSE_ACCEPT);
658 gui_dialog_add_stockbutton(pdialog->dialog, GTK_STOCK_CANCEL,
659 _("Cancel meeting"), RESPONSE_CANCEL_MEETING);
661 /* Responces for one meeting. */
662 gui_dialog_response_set_callback(pdialog->dialog, diplomacy_response);
663 gui_dialog_set_default_response(pdialog->dialog, RESPONSE_CANCEL_MEETING);
665 /* Label for the new meeting. */
666 buf = g_strdup_printf("%s", nation_plural_for_player(plr1));
667 gui_dialog_set_title(pdialog->dialog, buf);
669 /* Sort meeting tabs alphabetically by the tab label. */
670 for (i = 0; i < gtk_notebook_get_n_pages(GTK_NOTEBOOK(notebook)); i++) {
671 GtkWidget *prev_page
672 = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), i);
673 struct gui_dialog *prev_dialog
674 = g_object_get_data(G_OBJECT(prev_page), "gui-dialog-data");
675 const char *prev_label
676 = gtk_label_get_text(GTK_LABEL(prev_dialog->v.tab.label));
678 if (fc_strcasecmp(buf, prev_label) < 0) {
679 gtk_notebook_reorder_child(GTK_NOTEBOOK(notebook),
680 pdialog->dialog->vbox, i);
681 break;
684 g_free(buf);
686 /* Content. */
687 mainbox = pdialog->dialog->vbox;
689 /* us. */
690 vbox = gtk_grid_new();
691 gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox),
692 GTK_ORIENTATION_VERTICAL);
693 gtk_grid_set_row_spacing(GTK_GRID(vbox), 5);
694 gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
695 gtk_container_add(GTK_CONTAINER(mainbox), vbox);
697 /* Our nation. */
698 label = gtk_label_new(NULL);
699 gtk_widget_set_halign(label, GTK_ALIGN_CENTER);
700 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
701 buf = g_strdup_printf("<span size=\"large\"><u>%s</u></span>",
702 nation_plural_for_player(plr0));
703 gtk_label_set_markup(GTK_LABEL(label), buf);
704 g_free(buf);
705 gtk_container_add(GTK_CONTAINER(vbox), label);
707 hbox = gtk_grid_new();
708 gtk_grid_set_column_spacing(GTK_GRID(hbox), 5);
709 gtk_container_add(GTK_CONTAINER(vbox), hbox);
711 /* Our flag */
712 flag_spr = get_nation_flag_sprite(tileset, nation_of_player(plr0));
714 image = gtk_image_new_from_surface(flag_spr->surface);
715 gtk_container_add(GTK_CONTAINER(hbox), image);
717 /* Our name. */
718 label = gtk_label_new(NULL);
719 gtk_widget_set_hexpand(label, TRUE);
720 gtk_widget_set_halign(label, GTK_ALIGN_CENTER);
721 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
722 buf = g_strdup_printf("<span size=\"large\" weight=\"bold\">%s</span>",
723 ruler_title_for_player(plr0, plr_buf, sizeof(plr_buf)));
724 gtk_label_set_markup(GTK_LABEL(label), buf);
725 g_free(buf);
726 gtk_container_add(GTK_CONTAINER(hbox), label);
728 image = gtk_image_new();
729 pdialog->image0 = image;
730 gtk_container_add(GTK_CONTAINER(hbox), image);
732 /* Menu for clauses: we. */
733 menubar = gtk_aux_menu_bar_new();
735 menu = gtk_menu_new();
736 pdialog->menu0 = menu;
738 menuitem = gtk_image_menu_item_new_with_label(_("Add Clause..."));
739 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem),
740 gtk_image_new_from_stock(GTK_STOCK_ADD,
741 GTK_ICON_SIZE_MENU));
742 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
743 gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menuitem);
744 g_object_set_data(G_OBJECT(menu), "plr", plr0);
745 g_signal_connect(menu, "show", G_CALLBACK(popup_add_menu), pdialog);
747 /* Main table for clauses and (if activated) gold trading: we. */
748 table = gtk_grid_new();
749 gtk_widget_set_halign(table, GTK_ALIGN_CENTER);
750 gtk_widget_set_valign(table, GTK_ALIGN_CENTER);
751 gtk_grid_set_column_spacing(GTK_GRID(table), 16);
752 gtk_container_add(GTK_CONTAINER(vbox), table);
754 if (game.info.trading_gold) {
755 spin = gtk_spin_button_new_with_range(0.0, plr0->economic.gold + 0.1,
756 1.0);
757 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin), 0);
758 gtk_entry_set_width_chars(GTK_ENTRY(spin), 16);
759 gtk_grid_attach(GTK_GRID(table), spin, 1, 0, 1, 1);
760 g_object_set_data(G_OBJECT(spin), "plr", plr0);
761 g_signal_connect_after(spin, "value-changed",
762 G_CALLBACK(diplo_dialog_returnkey), pdialog);
764 label = g_object_new(GTK_TYPE_LABEL, "use-underline", TRUE,
765 "mnemonic-widget", spin, "label", _("Gold:"),
766 "xalign", 0.0, "yalign", 0.5, NULL);
767 gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1);
769 gtk_grid_attach(GTK_GRID(table), menubar, 2, 0, 1, 1);
770 } else {
771 gtk_grid_attach(GTK_GRID(table), menubar, 0, 0, 1, 1);
774 /* them. */
775 vbox = gtk_grid_new();
776 gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox),
777 GTK_ORIENTATION_VERTICAL);
778 gtk_grid_set_row_spacing(GTK_GRID(vbox), 5);
779 gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
780 gtk_container_add(GTK_CONTAINER(mainbox), vbox);
782 /* Their nation. */
783 label = gtk_label_new(NULL);
784 gtk_widget_set_halign(label, GTK_ALIGN_CENTER);
785 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
786 buf = g_strdup_printf("<span size=\"large\"><u>%s</u></span>",
787 nation_plural_for_player(plr1));
788 gtk_label_set_markup(GTK_LABEL(label), buf);
789 g_free(buf);
790 gtk_container_add(GTK_CONTAINER(vbox), label);
792 hbox = gtk_grid_new();
793 gtk_grid_set_column_spacing(GTK_GRID(hbox), 5);
794 gtk_container_add(GTK_CONTAINER(vbox), hbox);
796 /* Their flag */
797 flag_spr = get_nation_flag_sprite(tileset, nation_of_player(plr1));
799 image = gtk_image_new_from_surface(flag_spr->surface);
800 gtk_container_add(GTK_CONTAINER(hbox), image);
802 /* Their name. */
803 label = gtk_label_new(NULL);
804 gtk_widget_set_hexpand(label, TRUE);
805 gtk_widget_set_halign(label, GTK_ALIGN_CENTER);
806 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
807 buf = g_strdup_printf("<span size=\"large\" weight=\"bold\">%s</span>",
808 ruler_title_for_player(plr1, plr_buf, sizeof(plr_buf)));
809 gtk_label_set_markup(GTK_LABEL(label), buf);
810 g_free(buf);
811 gtk_container_add(GTK_CONTAINER(hbox), label);
813 image = gtk_image_new();
814 pdialog->image1 = image;
815 gtk_container_add(GTK_CONTAINER(hbox), image);
817 /* Menu for clauses: they. */
818 menubar = gtk_aux_menu_bar_new();
820 menu = gtk_menu_new();
821 pdialog->menu1 = menu;
823 menuitem = gtk_image_menu_item_new_with_label(_("Add Clause..."));
824 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem),
825 gtk_image_new_from_stock(GTK_STOCK_ADD,
826 GTK_ICON_SIZE_MENU));
827 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
828 gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menuitem);
829 g_object_set_data(G_OBJECT(menu), "plr", plr1);
830 g_signal_connect(menu, "show", G_CALLBACK(popup_add_menu), pdialog);
832 /* Main table for clauses and (if activated) gold trading: they. */
833 table = gtk_grid_new();
834 gtk_widget_set_halign(table, GTK_ALIGN_CENTER);
835 gtk_widget_set_valign(table, GTK_ALIGN_CENTER);
836 gtk_grid_set_column_spacing(GTK_GRID(table), 16);
837 gtk_container_add(GTK_CONTAINER(vbox), table);
839 if (game.info.trading_gold) {
840 spin = gtk_spin_button_new_with_range(0.0, plr1->economic.gold + 0.1,
841 1.0);
842 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin), 0);
843 gtk_entry_set_width_chars(GTK_ENTRY(spin), 16);
844 gtk_grid_attach(GTK_GRID(table), spin, 1, 0, 1, 1);
845 g_object_set_data(G_OBJECT(spin), "plr", plr1);
846 g_signal_connect_after(spin, "value-changed",
847 G_CALLBACK(diplo_dialog_returnkey), pdialog);
849 label = g_object_new(GTK_TYPE_LABEL, "use-underline", TRUE,
850 "mnemonic-widget", spin, "label", _("Gold:"),
851 "xalign", 0.0, "yalign", 0.5, NULL);
852 gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1);
854 gtk_grid_attach(GTK_GRID(table), menubar, 2, 0, 1, 1);
855 } else {
856 gtk_grid_attach(GTK_GRID(table), menubar, 0, 0, 1, 1);
859 /* Clauses. */
860 mainbox = gtk_grid_new();
861 gtk_orientable_set_orientation(GTK_ORIENTABLE(mainbox),
862 GTK_ORIENTATION_VERTICAL);
863 gtk_container_add(GTK_CONTAINER(pdialog->dialog->vbox), mainbox);
865 store = gtk_list_store_new(1, G_TYPE_STRING);
866 pdialog->store = store;
868 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
869 gtk_widget_set_hexpand(view, TRUE);
870 gtk_widget_set_vexpand(view, TRUE);
871 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
872 g_object_unref(store);
873 gtk_widget_set_size_request(view, 320, 100);
875 rend = gtk_cell_renderer_text_new();
876 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, NULL,
877 rend, "text", 0, NULL);
879 sw = gtk_scrolled_window_new(NULL, NULL);
880 g_object_set(sw, "margin", 2, NULL);
881 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
882 GTK_SHADOW_ETCHED_IN);
883 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
884 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
885 gtk_container_add(GTK_CONTAINER(sw), view);
887 label = g_object_new(GTK_TYPE_LABEL,
888 "use-underline", TRUE,
889 "mnemonic-widget", view,
890 "label", _("C_lauses:"),
891 "xalign", 0.0,
892 "yalign", 0.5,
893 NULL);
895 vbox = gtk_grid_new();
896 gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox),
897 GTK_ORIENTATION_VERTICAL);
898 gtk_container_add(GTK_CONTAINER(mainbox), vbox);
899 gtk_container_add(GTK_CONTAINER(vbox), label);
900 gtk_container_add(GTK_CONTAINER(vbox), sw);
902 gtk_widget_show_all(mainbox);
904 g_signal_connect(view, "row_activated", G_CALLBACK(row_callback), pdialog);
906 update_diplomacy_dialog(pdialog);
907 gui_dialog_show_all(pdialog->dialog);
909 return pdialog;
912 /**************************************************************************
913 Update diplomacy dialog
914 **************************************************************************/
915 static void update_diplomacy_dialog(struct Diplomacy_dialog *pdialog)
917 GtkListStore *store;
918 GtkTreeIter it;
919 bool blank = TRUE;
920 GdkPixbuf *pixbuf;
922 store = pdialog->store;
924 gtk_list_store_clear(store);
925 clause_list_iterate(pdialog->treaty.clauses, pclause) {
926 char buf[128];
928 client_diplomacy_clause_string(buf, sizeof(buf), pclause);
930 gtk_list_store_append(store, &it);
931 gtk_list_store_set(store, &it, 0, buf, -1);
932 blank = FALSE;
933 } clause_list_iterate_end;
935 if (blank) {
936 gtk_list_store_append(store, &it);
937 gtk_list_store_set(store, &it, 0,
938 _("--- This treaty is blank. "
939 "Please add some clauses. ---"), -1);
942 pixbuf = get_thumb_pixbuf(pdialog->treaty.accept0);
943 gtk_image_set_from_pixbuf(GTK_IMAGE(pdialog->image0), pixbuf);
944 g_object_unref(G_OBJECT(pixbuf));
945 pixbuf = get_thumb_pixbuf(pdialog->treaty.accept1);
946 gtk_image_set_from_pixbuf(GTK_IMAGE(pdialog->image1), pixbuf);
947 g_object_unref(G_OBJECT(pixbuf));
950 /****************************************************************************
951 Callback for the diplomatic dialog: give tech.
952 ****************************************************************************/
953 static void diplomacy_dialog_tech_callback(GtkWidget *w, gpointer data)
955 int giver, dest, other, tech;
957 giver = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "player_from"));
958 dest = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "player_to"));
959 tech = GPOINTER_TO_INT(data);
960 if (player_by_number(giver) == client_player()) {
961 other = dest;
962 } else {
963 other = giver;
966 if (A_LAST == tech) {
967 /* All techs. */
968 struct player *pgiver = player_by_number(giver);
969 struct player *pdest = player_by_number(dest);
970 const struct research *dresearch, *gresearch;
972 fc_assert_ret(NULL != pgiver);
973 fc_assert_ret(NULL != pdest);
975 dresearch = research_get(pdest);
976 gresearch = research_get(pgiver);
977 advance_iterate(A_FIRST, padvance) {
978 Tech_type_id i = advance_number(padvance);
980 if (research_invention_state(gresearch, i) == TECH_KNOWN
981 && research_invention_gettable(dresearch, i,
982 game.info.tech_trade_allow_holes)
983 && (research_invention_state(dresearch, i) == TECH_UNKNOWN
984 || research_invention_state(dresearch, i)
985 == TECH_PREREQS_KNOWN)) {
986 dsend_packet_diplomacy_create_clause_req(&client.conn, other, giver,
987 CLAUSE_ADVANCE, i);
989 } advance_iterate_end;
990 } else {
991 /* Only one tech. */
992 dsend_packet_diplomacy_create_clause_req(&client.conn, other, giver,
993 CLAUSE_ADVANCE, tech);
997 /****************************************************************
998 Callback for trading cities
999 - Kris Bubendorfer
1000 *****************************************************************/
1001 static void diplomacy_dialog_city_callback(GtkWidget * w, gpointer data)
1003 size_t choice = GPOINTER_TO_UINT(data);
1004 int giver = (choice >> 24) & 0xff, dest = (choice >> 16) & 0xff, other;
1005 int city = choice & 0xffff;
1007 if (player_by_number(giver) == client.conn.playing) {
1008 other = dest;
1009 } else {
1010 other = giver;
1013 dsend_packet_diplomacy_create_clause_req(&client.conn, other, giver,
1014 CLAUSE_CITY, city);
1017 /****************************************************************
1018 Map menu item activated
1019 *****************************************************************/
1020 static void diplomacy_dialog_map_callback(GtkWidget *w, gpointer data)
1022 struct Diplomacy_dialog *pdialog = (struct Diplomacy_dialog *)data;
1023 struct player *pgiver;
1025 pgiver = (struct player *)g_object_get_data(G_OBJECT(w), "plr");
1027 dsend_packet_diplomacy_create_clause_req(&client.conn,
1028 player_number(pdialog->treaty.plr1),
1029 player_number(pgiver), CLAUSE_MAP, 0);
1032 /****************************************************************
1033 Seamap menu item activated
1034 *****************************************************************/
1035 static void diplomacy_dialog_seamap_callback(GtkWidget *w, gpointer data)
1037 struct Diplomacy_dialog *pdialog = (struct Diplomacy_dialog *)data;
1038 struct player *pgiver;
1040 pgiver = (struct player *)g_object_get_data(G_OBJECT(w), "plr");
1042 dsend_packet_diplomacy_create_clause_req(&client.conn,
1043 player_number(pdialog->treaty.plr1),
1044 player_number(pgiver), CLAUSE_SEAMAP,
1048 /****************************************************************
1049 Adding pact clause
1050 *****************************************************************/
1051 static void diplomacy_dialog_add_pact_clause(GtkWidget *w, gpointer data,
1052 int type)
1054 struct Diplomacy_dialog *pdialog = (struct Diplomacy_dialog *)data;
1056 dsend_packet_diplomacy_create_clause_req(&client.conn,
1057 player_number(pdialog->treaty.plr1),
1058 player_number(pdialog->treaty.plr0),
1059 type, 0);
1062 /****************************************************************
1063 Ceasefire pact menu item activated
1064 *****************************************************************/
1065 static void diplomacy_dialog_ceasefire_callback(GtkWidget *w, gpointer data)
1067 diplomacy_dialog_add_pact_clause(w, data, CLAUSE_CEASEFIRE);
1070 /****************************************************************
1071 Peace pact menu item activated
1072 *****************************************************************/
1073 static void diplomacy_dialog_peace_callback(GtkWidget *w, gpointer data)
1075 diplomacy_dialog_add_pact_clause(w, data, CLAUSE_PEACE);
1078 /****************************************************************
1079 Alliance pact menu item activated
1080 *****************************************************************/
1081 static void diplomacy_dialog_alliance_callback(GtkWidget *w, gpointer data)
1083 diplomacy_dialog_add_pact_clause(w, data, CLAUSE_ALLIANCE);
1086 /****************************************************************
1087 Shared vision menu item activated
1088 *****************************************************************/
1089 static void diplomacy_dialog_vision_callback(GtkWidget *w, gpointer data)
1091 struct Diplomacy_dialog *pdialog = (struct Diplomacy_dialog *) data;
1092 struct player *pgiver =
1093 (struct player *) g_object_get_data(G_OBJECT(w), "plr");
1095 dsend_packet_diplomacy_create_clause_req(&client.conn,
1096 player_number(pdialog->treaty.plr1),
1097 player_number(pgiver), CLAUSE_VISION,
1101 /****************************************************************
1102 Embassy menu item activated
1103 *****************************************************************/
1104 static void diplomacy_dialog_embassy_callback(GtkWidget *w, gpointer data)
1106 struct Diplomacy_dialog *pdialog = (struct Diplomacy_dialog *) data;
1107 struct player *pgiver =
1108 (struct player *) g_object_get_data(G_OBJECT(w), "plr");
1110 dsend_packet_diplomacy_create_clause_req(&client.conn,
1111 player_number(pdialog->treaty.plr1),
1112 player_number(pgiver), CLAUSE_EMBASSY,
1117 /*****************************************************************
1118 Close diplomacy dialog
1119 *****************************************************************/
1120 void close_diplomacy_dialog(struct Diplomacy_dialog *pdialog)
1122 diplomacy_destroy(pdialog);
1125 /*****************************************************************
1126 Initialize diplomacy dialog
1127 *****************************************************************/
1128 void diplomacy_dialog_init()
1130 dialog_list = dialog_list_new();
1131 dipl_main = NULL;
1134 /*****************************************************************
1135 Free resources allocated for diplomacy dialog
1136 *****************************************************************/
1137 void diplomacy_dialog_done()
1139 dialog_list_destroy(dialog_list);
1142 /*****************************************************************
1143 Find diplomacy dialog between player and other player
1144 *****************************************************************/
1145 static struct Diplomacy_dialog *find_diplomacy_dialog(int other_player_id)
1147 struct player *plr0 = client.conn.playing;
1148 struct player *plr1 = player_by_number(other_player_id);
1150 dialog_list_iterate(dialog_list, pdialog) {
1151 if ((pdialog->treaty.plr0 == plr0 && pdialog->treaty.plr1 == plr1) ||
1152 (pdialog->treaty.plr0 == plr1 && pdialog->treaty.plr1 == plr0)) {
1153 return pdialog;
1155 } dialog_list_iterate_end;
1157 return NULL;
1160 /*****************************************************************
1161 User hit enter after entering gold amount
1162 *****************************************************************/
1163 static void diplo_dialog_returnkey(GtkWidget *w, gpointer data)
1165 struct Diplomacy_dialog *pdialog = (struct Diplomacy_dialog *) data;
1166 struct player *pgiver =
1167 (struct player *) g_object_get_data(G_OBJECT(w), "plr");
1168 int amount = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w));
1170 if (amount >= 0 && amount <= pgiver->economic.gold) {
1171 dsend_packet_diplomacy_create_clause_req(&client.conn,
1172 player_number(pdialog->treaty.plr1),
1173 player_number(pgiver),
1174 CLAUSE_GOLD, amount);
1175 } else {
1176 output_window_append(ftc_client, _("Invalid amount of gold specified."));
1180 /*****************************************************************
1181 Close all dialogs, for when client disconnects from game.
1182 *****************************************************************/
1183 void close_all_diplomacy_dialogs(void)
1185 while (dialog_list_size(dialog_list) > 0) {
1186 close_diplomacy_dialog(dialog_list_get(dialog_list, 0));