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>
30 #include "diptreaty.h"
33 #include "government.h"
41 #include "client_main.h"
45 /* client/gui-gtk-3.0 */
48 #include "gui_stuff.h"
52 #define MAX_NUM_CLAUSES 64
54 struct Diplomacy_dialog
{
56 struct gui_dialog
* dialog
;
67 struct Diplomacy_notebook
{
68 struct gui_dialog
* dialog
;
72 #define SPECLIST_TAG dialog
73 #define SPECLIST_TYPE struct Diplomacy_dialog
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
,
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
,
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
,
115 struct Diplomacy_dialog
*pdialog
= find_diplomacy_dialog(counterpart
);
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
);
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
);
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
);
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()) {
196 if (!is_human(client
.conn
.playing
)) {
197 return; /* Don't show if we are not human controlled. */
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
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
;
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
);
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
) {
296 gtk_widget_set_sensitive(advance_item
, FALSE
);
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
;
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.
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
;
354 city_list_ptrs
= fc_malloc(sizeof(struct city
*) * n
);
356 city_list_ptrs
= NULL
;
359 city_list_iterate(pgiver
->cities
, pcity
) {
360 if (!is_capital(pcity
)) {
361 city_list_ptrs
[i
] = pcity
;
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
);
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
);
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
;
459 index
= gtk_tree_path_get_indices(path
);
462 clause_list_iterate(pdialog
->treaty
.clauses
, pclause
) {
464 dsend_packet_diplomacy_remove_clause_req(&client
.conn
,
465 player_number(pdialog
->treaty
.plr1
),
466 player_number(pclause
->from
),
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. */
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
),
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
);
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
);
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
);
532 /*****************************************************************************
533 User has responded to whole diplomacy dialog (main tab).
534 *****************************************************************************/
535 static void diplomacy_main_response(struct gui_dialog
*dlg
, int response
,
544 log_error("unhandled response in %s: %d", __FUNCTION__
, response
);
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
,
553 adialog
->treaty
.plr1
));
554 } dialog_list_iterate_end
;
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
);
573 /* Diplomatic meetings in one main tab. */
574 if (dialog_list_size(dialog_list
) > 0) {
575 if (dipl_main
&& dipl_main
->dialog
) {
578 buf
= g_strdup_printf(_("Diplomacy [%d]"), dialog_list_size(dialog_list
));
579 gui_dialog_set_title(dipl_main
->dialog
, 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
,
595 struct Diplomacy_dialog
*pdialog
= NULL
;
598 pdialog
= (struct Diplomacy_dialog
*)data
;
601 case GTK_RESPONSE_ACCEPT
: /* Accept treaty. */
602 dsend_packet_diplomacy_accept_treaty_req(&client
.conn
,
604 pdialog
->treaty
.plr1
));
608 log_error("unhandled response in %s: %d", __FUNCTION__
, response
);
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
,
615 pdialog
->treaty
.plr1
));
620 /*****************************************************************************
621 Setups diplomacy dialog widgets.
622 *****************************************************************************/
623 static struct Diplomacy_dialog
*create_diplomacy_dialog(struct player
*plr0
,
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
;
632 GtkCellRenderer
*rend
;
635 struct Diplomacy_dialog
*pdialog
;
636 char plr_buf
[4 * MAX_LEN_NAME
];
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
);
651 notebook
= dipl_dialog
->notebook
;
653 gui_dialog_new(&(pdialog
->dialog
), GTK_NOTEBOOK(notebook
), pdialog
, FALSE
);
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
++) {
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
);
687 mainbox
= pdialog
->dialog
->vbox
;
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
);
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
);
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
);
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
);
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
);
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,
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);
771 gtk_grid_attach(GTK_GRID(table
), menubar
, 0, 0, 1, 1);
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
);
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
);
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
);
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
);
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
);
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,
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);
856 gtk_grid_attach(GTK_GRID(table
), menubar
, 0, 0, 1, 1);
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:"),
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
);
912 /**************************************************************************
913 Update diplomacy dialog
914 **************************************************************************/
915 static void update_diplomacy_dialog(struct Diplomacy_dialog
*pdialog
)
922 store
= pdialog
->store
;
924 gtk_list_store_clear(store
);
925 clause_list_iterate(pdialog
->treaty
.clauses
, pclause
) {
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);
933 } clause_list_iterate_end
;
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()) {
966 if (A_LAST
== tech
) {
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
,
989 } advance_iterate_end
;
992 dsend_packet_diplomacy_create_clause_req(&client
.conn
, other
, giver
,
993 CLAUSE_ADVANCE
, tech
);
997 /****************************************************************
998 Callback for trading cities
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
) {
1013 dsend_packet_diplomacy_create_clause_req(&client
.conn
, other
, giver
,
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 /****************************************************************
1050 *****************************************************************/
1051 static void diplomacy_dialog_add_pact_clause(GtkWidget
*w
, gpointer data
,
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
),
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();
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
)) {
1155 } dialog_list_iterate_end
;
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
);
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));