1 /* Pioneers - Implementation of the excellent Settlers of Catan board game.
2  *   Go buy a copy.
3  *
4  * Copyright (C) 1999 Dave Cole
5  * Copyright (C) 2003 Bas Wijnen <shevek@fmf.nl>
6  * Copyright (C) 2004-2005 Roland Clobus <rclobus@bigfoot.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22 
23 #include "config.h"
24 #include <math.h>
25 #include <ctype.h>
26 #include <assert.h>
27 
28 #include "aboutbox.h"
29 #include "frontend.h"
30 #include "cards.h"
31 #include "cost.h"
32 #include "log.h"
33 #include "common_gtk.h"
34 #include "histogram.h"
35 #include "theme.h"
36 #include "config-gnome.h"
37 #include "audio.h"
38 #include "notification.h"
39 
40 static GtkWidget *preferences_dlg;
41 GtkWidget *app_window;		/* main application window */
42 
43 #define MAP_WIDTH 350		/* default map width */
44 #define MAP_HEIGHT 200		/* default map height */
45 
46 #define PIONEERS_ICON_FILE	"pioneers.png"
47 
48 /* Callback functions from the resource file */
49 G_MODULE_EXPORT void game_quit_cb(GObject * gobject, gpointer user_data);
50 G_MODULE_EXPORT void game_legend_cb(GObject * gobject, gpointer user_data);
51 G_MODULE_EXPORT void game_histogram_cb(GObject * gobject,
52 				       gpointer user_data);
53 G_MODULE_EXPORT void game_settings_cb(GObject * gobject,
54 				      gpointer user_data);
55 G_MODULE_EXPORT void show_admin_interface_cb(GObject * gobject,
56 					     gpointer user_data);
57 G_MODULE_EXPORT void zoom_normal_cb(GObject * gobject, gpointer user_data);
58 G_MODULE_EXPORT void zoom_center_map_cb(GObject * gobject,
59 					gpointer user_data);
60 G_MODULE_EXPORT void toggle_full_screen_cb(GObject * gobject,
61 					   gpointer user_data);
62 G_MODULE_EXPORT void showhide_toolbar_cb(GObject * gobject,
63 					 gpointer user_data);
64 G_MODULE_EXPORT void preferences_cb(GObject * gobject, gpointer user_data);
65 G_MODULE_EXPORT void help_about_cb(GObject * gobject, gpointer user_data);
66 #ifdef HAVE_HELP
67 G_MODULE_EXPORT void help_manual_cb(GObject * gobject, gpointer user_data);
68 #endif
69 
70 static GuiMap *gmap;		/* handle to map drawing code */
71 
72 enum {
73 	MAP_PAGE,		/* the map */
74 	TRADE_PAGE,		/* trading interface */
75 	QUOTE_PAGE,		/* submit quotes page */
76 	LEGEND_PAGE,		/* legend */
77 	SPLASH_PAGE		/* splash screen */
78 };
79 
80 static GtkWidget *map_notebook;	/* map area panel */
81 static GtkWidget *trade_page;	/* trade page in map area */
82 static GtkWidget *quote_page;	/* quote page in map area */
83 static GtkWidget *legend_page;	/* legend page in map area */
84 static GtkWidget *splash_page;	/* splash page in map area */
85 
86 static GtkWidget *develop_notebook;	/* development card area panel */
87 
88 static GtkWidget *messages_txt;	/* messages text widget */
89 static GtkWidget *prompt_lbl;	/* big prompt messages */
90 
91 static GtkWidget *app_bar;
92 static GtkWidget *net_status;
93 static GtkWidget *vp_target_status;
94 
95 static GtkWidget *main_paned;	/* Horizontal for 16:9, Vertical for 4:3 mode */
96 static GtkWidget *chat_panel = NULL;	/* Panel for chat, placed below or to the right */
97 
98 static GtkBuilder *builder = NULL;	/* The manager of the GUI */
99 static GActionGroup *action_group = NULL;	/* Global action group */
100 
101 static gboolean toolbar_show_accelerators = TRUE;
102 static gboolean color_messages_enabled = TRUE;
103 static gboolean legend_page_enabled = TRUE;
104 static gboolean charity_enabled = FALSE;
105 static TAutomaticRoll automatic_roll = ROLL_MANUALLY;
106 
107 static GList *rules_callback_list = NULL;
108 
109 static void gui_set_toolbar_visible(gboolean visible);
110 static void gui_toolbar_show_accelerators(gboolean show_accelerators);
111 
redirect_gui_event_cb(G_GNUC_UNUSED GSimpleAction * action,G_GNUC_UNUSED GVariant * parameter,gpointer user_data)112 static void redirect_gui_event_cb(G_GNUC_UNUSED GSimpleAction * action,
113 				  G_GNUC_UNUSED GVariant * parameter,
114 				  gpointer user_data)
115 {
116 	route_gui_event(g_variant_get_int32(user_data));
117 }
118 
game_leave_cb(G_GNUC_UNUSED GSimpleAction * action,G_GNUC_UNUSED GVariant * parameter,G_GNUC_UNUSED gpointer user_data)119 static void game_leave_cb(G_GNUC_UNUSED GSimpleAction * action,
120 			  G_GNUC_UNUSED GVariant * parameter,
121 			  G_GNUC_UNUSED gpointer user_data)
122 {
123 	frontend_quote_end();
124 	route_gui_event(GUI_DISCONNECT);
125 }
126 
game_quit_cb(G_GNUC_UNUSED GObject * gobject,G_GNUC_UNUSED gpointer user_data)127 void game_quit_cb(G_GNUC_UNUSED GObject * gobject,
128 		  G_GNUC_UNUSED gpointer user_data)
129 {
130 	guimap_delete(gmap);
131 	route_gui_event(GUI_QUIT);
132 }
133 
show_admin_interface_cb(G_GNUC_UNUSED GObject * gobject,G_GNUC_UNUSED gpointer user_data)134 void show_admin_interface_cb(G_GNUC_UNUSED GObject * gobject,
135 			     G_GNUC_UNUSED gpointer user_data)
136 {
137 #ifdef ADMIN_GTK
138 	show_admin_interface();
139 #endif
140 }
141 
toggle_full_screen_cb(GObject * gobject,gpointer user_data)142 void toggle_full_screen_cb(GObject * gobject, gpointer user_data)
143 {
144 	if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(gobject))) {
145 		gtk_window_fullscreen(GTK_WINDOW(user_data));
146 	} else {
147 		gtk_window_unfullscreen(GTK_WINDOW(user_data));
148 	}
149 }
150 
zoom_normal_cb(G_GNUC_UNUSED GObject * gobject,G_GNUC_UNUSED gpointer user_data)151 void zoom_normal_cb(G_GNUC_UNUSED GObject * gobject,
152 		    G_GNUC_UNUSED gpointer user_data)
153 {
154 	guimap_zoom_normal(gmap);
155 }
156 
zoom_center_map_cb(G_GNUC_UNUSED GObject * gobject,G_GNUC_UNUSED gpointer user_data)157 void zoom_center_map_cb(G_GNUC_UNUSED GObject * gobject,
158 			G_GNUC_UNUSED gpointer user_data)
159 {
160 	guimap_zoom_center_map(gmap);
161 }
162 
gui_get_dialog_button(GtkDialog * dlg,gint button)163 GtkWidget *gui_get_dialog_button(GtkDialog * dlg, gint button)
164 {
165 	GList *list;
166 
167 	g_return_val_if_fail(dlg != NULL, NULL);
168 	g_assert(gtk_dialog_get_action_area(dlg) != NULL);
169 
170 	list =
171 	    gtk_container_get_children(GTK_CONTAINER
172 				       (gtk_dialog_get_action_area(dlg)));
173 	list = g_list_nth(list, button);
174 	if (list != NULL) {
175 		g_assert(list->data != NULL);
176 		return GTK_WIDGET(list->data);
177 	}
178 	return NULL;
179 }
180 
gui_reset(void)181 void gui_reset(void)
182 {
183 	guimap_reset(gmap);
184 }
185 
gui_set_instructions(const gchar * text)186 void gui_set_instructions(const gchar * text)
187 {
188 	gtk_statusbar_push(GTK_STATUSBAR(app_bar), 0, text);
189 }
190 
gui_set_vp_target_value(gint vp)191 void gui_set_vp_target_value(gint vp)
192 {
193 	gchar *vp_text;
194 
195 	/* Victory points target in statusbar */
196 	vp_text = g_strdup_printf(_("Points needed to win: %i"), vp);
197 
198 	gtk_label_set_text(GTK_LABEL(vp_target_status), vp_text);
199 	g_free(vp_text);
200 }
201 
gui_set_net_status(const gchar * text)202 void gui_set_net_status(const gchar * text)
203 {
204 	gtk_label_set_text(GTK_LABEL(net_status), text);
205 }
206 
gui_cursor_none(void)207 void gui_cursor_none(void)
208 {
209 	MapElement dummyElement;
210 	dummyElement.pointer = NULL;
211 	guimap_cursor_set(gmap, NO_CURSOR, -1, NULL, NULL, NULL,
212 			  &dummyElement, FALSE);
213 }
214 
gui_cursor_set(CursorType type,CheckFunc check_func,SelectFunc select_func,CancelFunc cancel_func,const MapElement * user_data)215 void gui_cursor_set(CursorType type,
216 		    CheckFunc check_func, SelectFunc select_func,
217 		    CancelFunc cancel_func, const MapElement * user_data)
218 {
219 	guimap_cursor_set(gmap, type, my_player_num(),
220 			  check_func, select_func, cancel_func, user_data,
221 			  FALSE);
222 }
223 
gui_draw_hex(const Hex * hex)224 void gui_draw_hex(const Hex * hex)
225 {
226 	if (gmap->surface != NULL)
227 		guimap_draw_hex(gmap, hex);
228 }
229 
gui_draw_edge(const Edge * edge)230 void gui_draw_edge(const Edge * edge)
231 {
232 	if (gmap->surface != NULL)
233 		guimap_draw_edge(gmap, edge);
234 }
235 
gui_draw_node(const Node * node)236 void gui_draw_node(const Node * node)
237 {
238 	if (gmap->surface != NULL)
239 		guimap_draw_node(gmap, node);
240 }
241 
gui_highlight_chits(gint roll)242 void gui_highlight_chits(gint roll)
243 {
244 	guimap_highlight_chits(gmap, roll);
245 }
246 
button_press_map_cb(GtkWidget * area,GdkEventButton * event,G_GNUC_UNUSED gpointer user_data)247 static gint button_press_map_cb(GtkWidget * area, GdkEventButton * event,
248 				G_GNUC_UNUSED gpointer user_data)
249 {
250 	if (gtk_widget_get_window(area) == NULL || gmap->map == NULL)
251 		return FALSE;
252 
253 	if (event->button == 1 && event->type == GDK_BUTTON_PRESS) {
254 		guimap_cursor_select(gmap);
255 		return TRUE;
256 	}
257 	return FALSE;
258 }
259 
build_map_area(void)260 static GtkWidget *build_map_area(void)
261 {
262 	GtkWidget *map_area = guimap_build_drawingarea(gmap, MAP_WIDTH,
263 						       MAP_HEIGHT);
264 	gtk_widget_add_events(map_area, GDK_BUTTON_PRESS_MASK);
265 	g_signal_connect(G_OBJECT(map_area), "button_press_event",
266 			 G_CALLBACK(button_press_map_cb), NULL);
267 
268 	return map_area;
269 }
270 
build_messages_panel(void)271 static GtkWidget *build_messages_panel(void)
272 {
273 	GtkWidget *vbox;
274 	GtkWidget *label;
275 	GtkWidget *scroll_win;
276 
277 	vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
278 	gtk_widget_show(vbox);
279 
280 	/* Label for messages log */
281 	label = gtk_label_new(NULL);
282 	gtk_label_set_markup(GTK_LABEL(label), _("<b>Messages</b>"));
283 	gtk_label_set_xalign(GTK_LABEL(label), 0.0);
284 	gtk_widget_show(label);
285 	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
286 
287 	scroll_win = gtk_scrolled_window_new(NULL, NULL);
288 	gtk_widget_set_size_request(scroll_win, -1, 80);
289 	gtk_widget_show(scroll_win);
290 	gtk_box_pack_start(GTK_BOX(vbox), scroll_win, TRUE, TRUE, 0);
291 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_win),
292 				       GTK_POLICY_AUTOMATIC,
293 				       GTK_POLICY_AUTOMATIC);
294 
295 	messages_txt = gtk_text_view_new();
296 	gtk_widget_show(messages_txt);
297 	gtk_container_add(GTK_CONTAINER(scroll_win), messages_txt);
298 	gtk_text_view_set_editable(GTK_TEXT_VIEW(messages_txt), FALSE);
299 	gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(messages_txt),
300 				    GTK_WRAP_WORD);
301 
302 	message_window_set_text(messages_txt, chat_panel);
303 
304 	return vbox;
305 }
306 
gui_show_trade_page(gboolean show)307 void gui_show_trade_page(gboolean show)
308 {
309 	/* Normal keyboard focus when visible */
310 	chat_set_grab_focus_on_update(!show);
311 	if (show) {
312 		gtk_widget_show(trade_page);
313 		gtk_notebook_set_current_page(GTK_NOTEBOOK(map_notebook),
314 					      TRADE_PAGE);
315 	} else {
316 		gtk_notebook_prev_page(GTK_NOTEBOOK(map_notebook));
317 		gtk_widget_hide(trade_page);
318 	}
319 }
320 
gui_show_quote_page(gboolean show)321 void gui_show_quote_page(gboolean show)
322 {
323 	/* Normal keyboard focus when visible */
324 	chat_set_grab_focus_on_update(!show);
325 	if (show) {
326 		gtk_widget_show(quote_page);
327 		gtk_notebook_set_current_page(GTK_NOTEBOOK(map_notebook),
328 					      QUOTE_PAGE);
329 	} else {
330 		gtk_notebook_prev_page(GTK_NOTEBOOK(map_notebook));
331 		gtk_widget_hide(quote_page);
332 	}
333 }
334 
gui_theme_changed(void)335 static void gui_theme_changed(void)
336 {
337 	g_assert(legend_page != NULL);
338 	gtk_widget_queue_draw(legend_page);
339 	gtk_widget_queue_draw(gmap->area);
340 }
341 
gui_show_legend_page(gboolean show)342 void gui_show_legend_page(gboolean show)
343 {
344 	if (show) {
345 		gtk_widget_show(legend_page);
346 		gtk_notebook_set_current_page(GTK_NOTEBOOK(map_notebook),
347 					      LEGEND_PAGE);
348 	} else
349 		gtk_widget_hide(legend_page);
350 }
351 
gui_show_splash_page(gboolean show,GtkWidget * chat_widget)352 void gui_show_splash_page(gboolean show, GtkWidget * chat_widget)
353 {
354 	static GtkWidget *widget = NULL;
355 	if (chat_widget != NULL)
356 		widget = chat_widget;
357 	g_assert(widget != NULL);
358 
359 	chat_set_grab_focus_on_update(TRUE);
360 	if (show) {
361 		gtk_widget_show(splash_page);
362 		gtk_notebook_set_current_page(GTK_NOTEBOOK(map_notebook),
363 					      SPLASH_PAGE);
364 		gtk_widget_hide(widget);
365 	} else {
366 		gtk_widget_hide(splash_page);
367 		gtk_notebook_set_current_page(GTK_NOTEBOOK(map_notebook),
368 					      MAP_PAGE);
369 		gtk_widget_show(widget);
370 	}
371 }
372 
splash_build_page(void)373 static GtkWidget *splash_build_page(void)
374 {
375 	GtkWidget *image;
376 	gchar *filename;
377 
378 	filename = g_build_filename(DATADIR, "pixmaps", "pioneers",
379 				    "splash.png", NULL);
380 	image = gtk_image_new_from_file(filename);
381 	gtk_widget_show(image);
382 	g_free(filename);
383 
384 	return image;
385 }
386 
build_map_panel(void)387 static GtkWidget *build_map_panel(void)
388 {
389 	GtkWidget *lbl;
390 	GtkWidget *hbox;
391 	GtkWidget *close_button;
392 
393 	map_notebook = gtk_notebook_new();
394 	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(map_notebook), GTK_POS_TOP);
395 	gtk_widget_show(map_notebook);
396 
397 	/* Tab page name */
398 	lbl = gtk_label_new(_("Map"));
399 	gtk_widget_show(lbl);
400 	gtk_notebook_insert_page(GTK_NOTEBOOK(map_notebook),
401 				 build_map_area(), lbl, MAP_PAGE);
402 
403 	hbox = create_label_with_close_button(
404 						     /* Tab page name */
405 						     _("Trade"),
406 						     /* Tooltip */
407 						     _("Finish trading"),
408 						     &close_button);
409 	frontend_gui_register(close_button, GUI_TRADE_FINISH, "clicked");
410 	trade_page = trade_build_page();
411 	gtk_notebook_insert_page(GTK_NOTEBOOK(map_notebook),
412 				 trade_page, hbox, TRADE_PAGE);
413 	gtk_widget_hide(trade_page);
414 
415 	hbox = create_label_with_close_button(
416 						     /* Tab page name */
417 						     _("Quote"),
418 						     /* Tooltip */
419 						     _(""
420 						       "Reject domestic trade"),
421 						     &close_button);
422 	frontend_gui_register(close_button, GUI_QUOTE_REJECT, "clicked");
423 	quote_page = quote_build_page();
424 	gtk_notebook_insert_page(GTK_NOTEBOOK(map_notebook),
425 				 quote_page, hbox, QUOTE_PAGE);
426 	gtk_widget_hide(quote_page);
427 
428 	/* Tab page name */
429 	lbl = gtk_label_new(_("Legend"));
430 	gtk_widget_show(lbl);
431 	legend_page = legend_create_content();
432 	gtk_notebook_insert_page(GTK_NOTEBOOK(map_notebook),
433 				 legend_page, lbl, LEGEND_PAGE);
434 	if (!legend_page_enabled)
435 		gui_show_legend_page(FALSE);
436 	theme_register_callback(G_CALLBACK(gui_theme_changed));
437 
438 	/* Tab page name, shown for the splash screen */
439 	lbl = gtk_label_new(_("Welcome to Pioneers"));
440 	gtk_widget_show(lbl);
441 	splash_page = splash_build_page();
442 	gtk_notebook_insert_page(GTK_NOTEBOOK(map_notebook),
443 				 splash_page, lbl, SPLASH_PAGE);
444 
445 	return map_notebook;
446 }
447 
gui_discard_show(void)448 void gui_discard_show(void)
449 {
450 	gtk_notebook_set_current_page(GTK_NOTEBOOK(develop_notebook), 1);
451 }
452 
gui_discard_hide(void)453 void gui_discard_hide(void)
454 {
455 	gtk_notebook_set_current_page(GTK_NOTEBOOK(develop_notebook), 0);
456 }
457 
gui_gold_show(void)458 void gui_gold_show(void)
459 {
460 	gtk_notebook_set_current_page(GTK_NOTEBOOK(develop_notebook), 2);
461 }
462 
gui_gold_hide(void)463 void gui_gold_hide(void)
464 {
465 	gtk_notebook_set_current_page(GTK_NOTEBOOK(develop_notebook), 0);
466 }
467 
gui_prompt_show(const gchar * message)468 void gui_prompt_show(const gchar * message)
469 {
470 	gtk_label_set_text(GTK_LABEL(prompt_lbl), message);
471 	/* Force resize of the notebook, this is needed because
472 	 * GTK does not redraw when the text in a label changes.
473 	 */
474 	gtk_container_check_resize(GTK_CONTAINER(develop_notebook));
475 	gtk_notebook_set_current_page(GTK_NOTEBOOK(develop_notebook), 3);
476 }
477 
gui_prompt_hide(void)478 void gui_prompt_hide(void)
479 {
480 	gtk_notebook_set_current_page(GTK_NOTEBOOK(develop_notebook), 0);
481 }
482 
prompt_build_page(void)483 static GtkWidget *prompt_build_page(void)
484 {
485 	prompt_lbl = gtk_label_new("");
486 	gtk_widget_show(prompt_lbl);
487 	return prompt_lbl;
488 }
489 
build_develop_panel(void)490 static GtkWidget *build_develop_panel(void)
491 {
492 	develop_notebook = gtk_notebook_new();
493 	gtk_notebook_set_show_tabs(GTK_NOTEBOOK(develop_notebook), FALSE);
494 	gtk_notebook_set_show_border(GTK_NOTEBOOK(develop_notebook),
495 				     FALSE);
496 	gtk_widget_show(develop_notebook);
497 
498 	gtk_notebook_insert_page(GTK_NOTEBOOK(develop_notebook),
499 				 develop_build_page(), NULL, 0);
500 	gtk_notebook_insert_page(GTK_NOTEBOOK(develop_notebook),
501 				 discard_build_page(), NULL, 1);
502 	gtk_notebook_insert_page(GTK_NOTEBOOK(develop_notebook),
503 				 gold_build_page(), NULL, 2);
504 	gtk_notebook_insert_page(GTK_NOTEBOOK(develop_notebook),
505 				 prompt_build_page(), NULL, 3);
506 
507 	return develop_notebook;
508 }
509 
get_16_9_layout(void)510 static gboolean get_16_9_layout(void)
511 {
512 	GtkWidget *paned;
513 
514 	g_return_val_if_fail(main_paned != NULL, FALSE);
515 	g_return_val_if_fail(chat_panel != NULL, FALSE);
516 
517 	paned = gtk_paned_get_child1(GTK_PANED(main_paned));
518 	if (gtk_widget_get_parent(chat_panel) == paned)
519 		return FALSE;
520 	return TRUE;
521 }
522 
set_16_9_layout(gboolean layout_16_9)523 static void set_16_9_layout(gboolean layout_16_9)
524 {
525 	GtkWidget *paned;
526 	gboolean can_remove;
527 
528 	g_return_if_fail(main_paned != NULL);
529 	g_return_if_fail(chat_panel != NULL);
530 
531 	paned = gtk_paned_get_child1(GTK_PANED(main_paned));
532 
533 	/* Increase reference count, otherwise it will be destroyed */
534 	g_object_ref(chat_panel);
535 
536 	/* Initially the widget has no parent, and cannot be removed */
537 	can_remove = gtk_widget_get_parent(chat_panel) != NULL;
538 
539 	if (layout_16_9) {
540 		if (can_remove)
541 			gtk_container_remove(GTK_CONTAINER(paned),
542 					     chat_panel);
543 		gtk_container_add(GTK_CONTAINER(main_paned), chat_panel);
544 	} else {
545 		if (can_remove)
546 			gtk_container_remove(GTK_CONTAINER(main_paned),
547 					     chat_panel);
548 		gtk_container_add(GTK_CONTAINER(paned), chat_panel);
549 	}
550 	g_object_unref(chat_panel);
551 }
552 
build_main_interface(void)553 static GtkWidget *build_main_interface(void)
554 {
555 	GtkWidget *vbox;
556 	GtkWidget *hpaned;
557 	GtkWidget *vpaned;
558 	GtkWidget *panel;
559 
560 	hpaned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
561 	gtk_widget_show(hpaned);
562 
563 	vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 3);
564 	gtk_widget_show(vbox);
565 	gtk_paned_pack1(GTK_PANED(hpaned), vbox, FALSE, TRUE);
566 
567 	gtk_box_pack_start(GTK_BOX(vbox),
568 			   identity_build_panel(), FALSE, TRUE, 0);
569 	gtk_box_pack_start(GTK_BOX(vbox),
570 			   resource_build_panel(), FALSE, TRUE, 0);
571 	gtk_box_pack_start(GTK_BOX(vbox),
572 			   build_develop_panel(), FALSE, TRUE, 0);
573 	gtk_box_pack_start(GTK_BOX(vbox),
574 			   player_build_summary(), TRUE, TRUE, 0);
575 
576 	main_paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
577 	gtk_widget_show(main_paned);
578 
579 	vpaned = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
580 	gtk_widget_show(vpaned);
581 
582 	gtk_paned_pack1(GTK_PANED(main_paned), vpaned, TRUE, TRUE);
583 
584 	gtk_paned_pack1(GTK_PANED(vpaned), build_map_panel(), TRUE, TRUE);
585 
586 	chat_panel = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
587 	gui_show_splash_page(TRUE, chat_panel);
588 
589 	panel = chat_build_panel();
590 	frontend_gui_register(panel, GUI_DISCONNECT, NULL);
591 	gtk_box_pack_start(GTK_BOX(chat_panel), panel, FALSE, TRUE, 0);
592 	gtk_box_pack_start(GTK_BOX(chat_panel),
593 			   build_messages_panel(), TRUE, TRUE, 0);
594 
595 	set_16_9_layout(config_get_int_with_default
596 			("settings/layout_16_9", TRUE));
597 
598 	gtk_paned_pack2(GTK_PANED(hpaned), main_paned, TRUE, TRUE);
599 	return hpaned;
600 }
601 
theme_change_cb(GObject * gobject,G_GNUC_UNUSED gpointer user_data)602 static void theme_change_cb(GObject * gobject,
603 			    G_GNUC_UNUSED gpointer user_data)
604 {
605 	gint idx = gtk_combo_box_get_active(GTK_COMBO_BOX(gobject));
606 	MapTheme *theme = g_list_nth_data(theme_get_list(), idx);
607 	if (theme != theme_get_current()) {
608 		config_set_string("settings/theme", theme->name);
609 		theme_set_current(theme);
610 		if (gmap->surface != NULL) {
611 			cairo_surface_destroy(gmap->surface);
612 			gmap->surface = NULL;
613 		}
614 		theme_rescale(2 * gmap->x_point);
615 	}
616 
617 }
618 
show_legend_cb(GtkToggleButton * widget,G_GNUC_UNUSED gpointer user_data)619 static void show_legend_cb(GtkToggleButton * widget,
620 			   G_GNUC_UNUSED gpointer user_data)
621 {
622 	legend_page_enabled = gtk_toggle_button_get_active(widget);
623 	gui_show_legend_page(legend_page_enabled);
624 	config_set_int("settings/legend_page", legend_page_enabled);
625 }
626 
message_color_cb(GtkToggleButton * widget,G_GNUC_UNUSED gpointer user_data)627 static void message_color_cb(GtkToggleButton * widget,
628 			     G_GNUC_UNUSED gpointer user_data)
629 {
630 	color_messages_enabled = gtk_toggle_button_get_active(widget);
631 	config_set_int("settings/color_messages", color_messages_enabled);
632 	log_set_func_message_color_enable(color_messages_enabled);
633 }
634 
chat_color_cb(GtkToggleButton * widget,G_GNUC_UNUSED gpointer user_data)635 static void chat_color_cb(GtkToggleButton * widget,
636 			  G_GNUC_UNUSED gpointer user_data)
637 {
638 	color_chat_enabled = gtk_toggle_button_get_active(widget);
639 	config_set_int("settings/color_chat", color_chat_enabled);
640 }
641 
summary_color_cb(GtkToggleButton * widget,G_GNUC_UNUSED gpointer user_data)642 static void summary_color_cb(GtkToggleButton * widget,
643 			     G_GNUC_UNUSED gpointer user_data)
644 {
645 	gboolean color_summary = gtk_toggle_button_get_active(widget);
646 	config_set_int("settings/color_summary", color_summary);
647 	set_color_summary(color_summary);
648 }
649 
silent_mode_cb(GtkToggleButton * widget,G_GNUC_UNUSED gpointer user_data)650 static void silent_mode_cb(GtkToggleButton * widget,
651 			   G_GNUC_UNUSED gpointer user_data)
652 {
653 	GtkToggleButton *announce_button = user_data;
654 
655 	gboolean silent_mode = gtk_toggle_button_get_active(widget);
656 	config_set_int("settings/silent_mode", silent_mode);
657 	set_silent_mode(silent_mode);
658 	gtk_toggle_button_set_inconsistent(announce_button, silent_mode);
659 	gtk_widget_set_sensitive(GTK_WIDGET(announce_button),
660 				 !silent_mode);
661 }
662 
announce_player_cb(GtkToggleButton * widget,G_GNUC_UNUSED gpointer user_data)663 static void announce_player_cb(GtkToggleButton * widget,
664 			       G_GNUC_UNUSED gpointer user_data)
665 {
666 	gboolean announce_player = gtk_toggle_button_get_active(widget);
667 	config_set_int("settings/announce_player", announce_player);
668 	set_announce_player(announce_player);
669 }
670 
toggle_16_9_cb(GtkToggleButton * widget,G_GNUC_UNUSED gpointer user_data)671 static void toggle_16_9_cb(GtkToggleButton * widget,
672 			   G_GNUC_UNUSED gpointer user_data)
673 {
674 	gboolean layout_16_9 = gtk_toggle_button_get_active(widget);
675 	config_set_int("settings/layout_16_9", layout_16_9);
676 	set_16_9_layout(layout_16_9);
677 }
678 
toggle_notifications_cb(GtkToggleButton * widget,G_GNUC_UNUSED gpointer user_data)679 static void toggle_notifications_cb(GtkToggleButton * widget,
680 				    G_GNUC_UNUSED gpointer user_data)
681 {
682 	gboolean show_notifications = gtk_toggle_button_get_active(widget);
683 	config_set_int("settings/show_notifications", show_notifications);
684 	set_show_notifications(show_notifications);
685 }
686 
showhide_toolbar_cb(GObject * gobject,G_GNUC_UNUSED gpointer user_data)687 void showhide_toolbar_cb(GObject * gobject,
688 			 G_GNUC_UNUSED gpointer user_data)
689 {
690 	gui_set_toolbar_visible(gtk_check_menu_item_get_active
691 				(GTK_CHECK_MENU_ITEM(gobject)));
692 }
693 
toolbar_shortcuts_cb(void)694 static void toolbar_shortcuts_cb(void)
695 {
696 	gui_toolbar_show_accelerators(!toolbar_show_accelerators);
697 }
698 
get_charity_enabled(void)699 gboolean get_charity_enabled(void)
700 {
701 	return charity_enabled;
702 }
703 
set_charity_enabled(gboolean new_charity_enabled)704 void set_charity_enabled(gboolean new_charity_enabled)
705 {
706 	if (new_charity_enabled != charity_enabled) {
707 		charity_enabled = new_charity_enabled;
708 		config_set_int("settings/charity_enabled",
709 			       charity_enabled);
710 	}
711 }
712 
get_automatic_roll(void)713 TAutomaticRoll get_automatic_roll(void)
714 {
715 	return automatic_roll;
716 }
717 
set_automatic_roll(TAutomaticRoll new_automatic_roll)718 void set_automatic_roll(TAutomaticRoll new_automatic_roll)
719 {
720 	if (new_automatic_roll != automatic_roll) {
721 		automatic_roll = new_automatic_roll;
722 		config_set_int("settings/automatic_roll", automatic_roll);
723 	}
724 }
725 
automatic_roll_changed_cb(GtkComboBox * widget,G_GNUC_UNUSED gpointer user_data)726 static void automatic_roll_changed_cb(GtkComboBox * widget,
727 				      G_GNUC_UNUSED gpointer user_data)
728 {
729 	GtkTreeIter iter;
730 
731 	if (gtk_combo_box_get_active_iter(widget, &iter)) {
732 		gint value;
733 		gtk_tree_model_get(gtk_combo_box_get_model(widget), &iter,
734 				   1, &value, -1);
735 		set_automatic_roll(value);
736 	}
737 }
738 
preferences_cb(G_GNUC_UNUSED GObject * gobject,gpointer user_data)739 void preferences_cb(G_GNUC_UNUSED GObject * gobject, gpointer user_data)
740 {
741 	GtkWidget *silent_mode_widget;
742 	GtkWidget *widget;
743 	GtkWidget *dlg_vbox;
744 	GtkWidget *theme_label;
745 	GtkWidget *theme_list;
746 	GtkWidget *layout;
747 	GtkListStore *auto_roll_list;
748 	GtkCellRenderer *cell;
749 	GtkTreeIter iter;
750 	GtkTreeIter active_iter;
751 
752 	guint row;
753 	gint color_summary;
754 	GList *theme_elt;
755 	int i;
756 
757 	if (preferences_dlg != NULL) {
758 		gtk_window_present(GTK_WINDOW(preferences_dlg));
759 		return;
760 	};
761 
762 	/* Caption of preferences dialog */
763 	preferences_dlg = gtk_dialog_new_with_buttons(_(""
764 							"Pioneers Preferences"),
765 						      GTK_WINDOW
766 						      (user_data),
767 						      GTK_DIALOG_DESTROY_WITH_PARENT,
768 						      /* Button text */
769 						      _("_Close"),
770 						      GTK_RESPONSE_CLOSE,
771 						      NULL);
772 	gtk_dialog_set_default_response(GTK_DIALOG(preferences_dlg),
773 					GTK_RESPONSE_CLOSE);
774 	g_signal_connect(G_OBJECT(preferences_dlg), "destroy",
775 			 G_CALLBACK(gtk_widget_destroyed),
776 			 &preferences_dlg);
777 	g_signal_connect(G_OBJECT(preferences_dlg), "response",
778 			 G_CALLBACK(gtk_widget_destroy), NULL);
779 	gtk_widget_show(preferences_dlg);
780 
781 	dlg_vbox =
782 	    gtk_dialog_get_content_area(GTK_DIALOG(preferences_dlg));
783 	gtk_widget_show(dlg_vbox);
784 
785 	layout = gtk_grid_new();
786 	gtk_grid_set_row_spacing(GTK_GRID(layout), 3);
787 	gtk_grid_set_column_spacing(GTK_GRID(layout), 5);
788 	gtk_widget_show(layout);
789 	gtk_box_pack_start(GTK_BOX(dlg_vbox), layout, FALSE, TRUE, 0);
790 	gtk_container_set_border_width(GTK_CONTAINER(layout), 5);
791 
792 	row = 0;
793 
794 	theme_list = gtk_combo_box_text_new();
795 	gtk_widget_set_hexpand(theme_list, TRUE);
796 	/* Label for changing the theme, in the preferences dialog */
797 	theme_label = gtk_label_new(_("Theme:"));
798 	gtk_label_set_xalign(GTK_LABEL(theme_label), 0.0);
799 	gtk_widget_show(theme_list);
800 	gtk_widget_show(theme_label);
801 
802 	for (i = 0, theme_elt = theme_get_list();
803 	     theme_elt != NULL; ++i, theme_elt = g_list_next(theme_elt)) {
804 		MapTheme *theme = theme_elt->data;
805 		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT
806 					       (theme_list), theme->name);
807 		if (theme == theme_get_current())
808 			gtk_combo_box_set_active(GTK_COMBO_BOX(theme_list),
809 						 i);
810 	}
811 	g_signal_connect(G_OBJECT(theme_list), "changed",
812 			 G_CALLBACK(theme_change_cb), NULL);
813 
814 	gtk_grid_attach(GTK_GRID(layout), theme_label, 0, row, 1, 1);
815 	gtk_grid_attach(GTK_GRID(layout), theme_list, 1, row, 1, 1);
816 	gtk_widget_set_tooltip_text(theme_list,
817 				    /* Tooltip for changing the theme in the preferences dialog */
818 				    _("Choose one of the themes"));
819 	row++;
820 
821 	/* Label for the option to show the legend */
822 	widget = gtk_check_button_new_with_label(_("Show legend"));
823 	gtk_widget_show(widget);
824 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
825 				     legend_page_enabled);
826 	g_signal_connect(G_OBJECT(widget), "toggled",
827 			 G_CALLBACK(show_legend_cb), NULL);
828 	gtk_grid_attach(GTK_GRID(layout), widget, 0, row, 2, 1);
829 	gtk_widget_set_tooltip_text(widget,
830 				    /* Tooltip for the option to show the legend */
831 				    _(""
832 				      "Show the legend as a page beside the map"));
833 	row++;
834 
835 	/* Label for the option to display log messages in color */
836 	widget = gtk_check_button_new_with_label(_("Messages with color"));
837 	gtk_widget_show(widget);
838 	gtk_grid_attach(GTK_GRID(layout), widget, 0, row, 2, 1);
839 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
840 				     color_messages_enabled);
841 	g_signal_connect(G_OBJECT(widget), "toggled",
842 			 G_CALLBACK(message_color_cb), NULL);
843 	gtk_widget_set_tooltip_text(widget,
844 				    /* Tooltip for the option to display log messages in color */
845 				    _("Show new messages with color"));
846 	row++;
847 
848 	widget = gtk_check_button_new_with_label(
849 							/* Label for the option to display chat in color of player */
850 							_(""
851 							  "Chat in color of player"));
852 	gtk_widget_show(widget);
853 	gtk_grid_attach(GTK_GRID(layout), widget, 0, row, 2, 1);
854 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
855 				     color_chat_enabled);
856 	g_signal_connect(G_OBJECT(widget), "toggled",
857 			 G_CALLBACK(chat_color_cb), NULL);
858 	gtk_widget_set_tooltip_text(widget,
859 				    /* Tooltip for the option to display chat in color of player */
860 				    _(""
861 				      "Show new chat messages in the color of the player"));
862 	row++;
863 
864 	/* Label for the option to display the summary with colors */
865 	widget = gtk_check_button_new_with_label(_("Summary with color"));
866 	gtk_widget_show(widget);
867 	gtk_grid_attach(GTK_GRID(layout), widget, 0, row, 2, 1);
868 	color_summary =
869 	    config_get_int_with_default("settings/color_summary", TRUE);
870 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), color_summary);	/* @todo RC use correct variable */
871 	g_signal_connect(G_OBJECT(widget), "toggled",
872 			 G_CALLBACK(summary_color_cb), NULL);
873 	gtk_widget_set_tooltip_text(widget,
874 				    /* Tooltip for the option to display the summary with colors */
875 				    _("Use colors in the player summary"));
876 	row++;
877 
878 	widget =
879 	    /* Label for the option to display keyboard accelerators in the toolbar */
880 	    gtk_check_button_new_with_label(_("Toolbar with shortcuts"));
881 	gtk_widget_show(widget);
882 	gtk_grid_attach(GTK_GRID(layout), widget, 0, row, 2, 1);
883 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
884 				     toolbar_show_accelerators);
885 	g_signal_connect(G_OBJECT(widget), "toggled",
886 			 G_CALLBACK(toolbar_shortcuts_cb), NULL);
887 	gtk_widget_set_tooltip_text(widget,
888 				    /* Tooltip for the option to display keyboard accelerators in the toolbar */
889 				    _(""
890 				      "Show keyboard shortcuts in the toolbar"));
891 	row++;
892 
893 	silent_mode_widget =
894 	    /* Label for the option to disable all sounds */
895 	    gtk_check_button_new_with_label(_("Silent mode"));
896 	gtk_widget_show(silent_mode_widget);
897 	gtk_grid_attach(GTK_GRID(layout), silent_mode_widget, 0, row, 2,
898 			1);
899 	gtk_widget_set_tooltip_text(silent_mode_widget,
900 				    /* Tooltip for the option to disable all sounds */
901 				    _(""
902 				      "In silent mode no sounds are made"));
903 	row++;
904 
905 	widget =
906 	    /* Label for the option to announce when players/spectators enter */
907 	    gtk_check_button_new_with_label(_("Announce new players"));
908 	gtk_widget_show(widget);
909 	gtk_grid_attach(GTK_GRID(layout), widget, 0, row, 2, 1);
910 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
911 				     get_announce_player());
912 	g_signal_connect(G_OBJECT(widget), "toggled",
913 			 G_CALLBACK(announce_player_cb), NULL);
914 	gtk_widget_set_tooltip_text(widget,
915 				    /* Tooltip for the option to use sound when players/spectators enter */
916 				    _(""
917 				      "Make a sound when a new player or spectator enters the game"));
918 	row++;
919 
920 	/* Silent mode widget is connected an initialized after the announce button */
921 	g_signal_connect(G_OBJECT(silent_mode_widget), "toggled",
922 			 G_CALLBACK(silent_mode_cb), widget);
923 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(silent_mode_widget),
924 				     get_silent_mode());
925 
926 #ifdef HAVE_NOTIFY
927 	/* Label for the option to use the notifications. */
928 	widget = gtk_check_button_new_with_label(_("Show notifications"));
929 	gtk_widget_show(widget);
930 	gtk_grid_attach(GTK_GRID(layout), widget, 0, row, 2, 1);
931 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
932 				     get_show_notifications());
933 	g_signal_connect(G_OBJECT(widget), "toggled",
934 			 G_CALLBACK(toggle_notifications_cb), NULL);
935 	gtk_widget_set_tooltip_text(widget,
936 				    /* Tooltip for notifications option. */
937 				    _("Show notifications when it's your "
938 				      "turn or when new trade is available"));
939 	row++;
940 #endif
941 
942 	/* Label for the option to use the 16:9 layout. */
943 	widget = gtk_check_button_new_with_label(_("Use 16:9 layout"));
944 	gtk_widget_show(widget);
945 	gtk_grid_attach(GTK_GRID(layout), widget, 0, row, 2, 1);
946 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
947 				     get_16_9_layout());
948 	g_signal_connect(G_OBJECT(widget), "toggled",
949 			 G_CALLBACK(toggle_16_9_cb), NULL);
950 	gtk_widget_set_tooltip_text(widget,
951 				    /* Tooltip for 16:9 option. */
952 				    _(""
953 				      "Use a 16:9 friendly layout for the window"));
954 	row++;
955 
956 	auto_roll_list = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
957 	gtk_list_store_append(auto_roll_list, &iter);
958 	gtk_list_store_set(auto_roll_list, &iter,
959 			   0, _("Roll the dice manually each turn"),
960 			   1, ROLL_MANUALLY, -1);
961 	if (get_automatic_roll() == ROLL_MANUALLY) {
962 		active_iter = iter;
963 	}
964 	gtk_list_store_append(auto_roll_list, &iter);
965 	gtk_list_store_set(auto_roll_list, &iter,
966 			   0,
967 			   _(""
968 			     "Roll the dice automatically, except when you have a soldier card"),
969 			   1, ROLL_AUTOMATICALLY_EXCEPT_WITH_SOLDIER_CARD,
970 			   -1);
971 	if (get_automatic_roll() ==
972 	    ROLL_AUTOMATICALLY_EXCEPT_WITH_SOLDIER_CARD) {
973 		active_iter = iter;
974 	}
975 	gtk_list_store_append(auto_roll_list, &iter);
976 	gtk_list_store_set(auto_roll_list, &iter,
977 			   0,
978 			   _(""
979 			     "Roll the dice automatically, except when you have a development card"),
980 			   1, ROLL_AUTOMATICALLY_EXCEPT_WITH_RESOURCE_CARD,
981 			   -1);
982 	if (get_automatic_roll() ==
983 	    ROLL_AUTOMATICALLY_EXCEPT_WITH_RESOURCE_CARD) {
984 		active_iter = iter;
985 	}
986 	gtk_list_store_append(auto_roll_list, &iter);
987 	gtk_list_store_set(auto_roll_list, &iter,
988 			   0, _("Roll the dice automatically"),
989 			   1, ROLL_AUTOMATICALLY, -1);
990 	if (get_automatic_roll() == ROLL_AUTOMATICALLY) {
991 		active_iter = iter;
992 	}
993 	widget =
994 	    gtk_combo_box_new_with_model(GTK_TREE_MODEL(auto_roll_list));
995 	gtk_combo_box_set_active_iter(GTK_COMBO_BOX(widget), &active_iter);
996 
997 	cell = gtk_cell_renderer_text_new();
998 	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(widget), cell, TRUE);
999 	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(widget),
1000 				       cell, "text", 0, NULL);
1001 
1002 	gtk_widget_show(widget);
1003 	gtk_grid_attach(GTK_GRID(layout), widget, 0, row, 2, 1);
1004 	g_signal_connect(G_OBJECT(widget), "changed",
1005 			 G_CALLBACK(automatic_roll_changed_cb), NULL);
1006 	gtk_widget_set_tooltip_text(widget,
1007 				    /* Tooltip for automatic roll option. */
1008 				    _(""
1009 				      "Automate the rolling of the dice"));
1010 	row++;
1011 
1012 }
1013 
help_about_cb(G_GNUC_UNUSED GObject * gobject,gpointer user_data)1014 void help_about_cb(G_GNUC_UNUSED GObject * gobject, gpointer user_data)
1015 {
1016 	aboutbox_display(GTK_WINDOW(user_data),
1017 			 /* Caption of about box */
1018 			 _("About Pioneers"));
1019 }
1020 
game_legend_cb(G_GNUC_UNUSED GObject * gobject,gpointer user_data)1021 void game_legend_cb(G_GNUC_UNUSED GObject * gobject, gpointer user_data)
1022 {
1023 	legend_create_dlg(GTK_WINDOW(user_data));
1024 }
1025 
game_histogram_cb(G_GNUC_UNUSED GObject * gobject,gpointer user_data)1026 void game_histogram_cb(G_GNUC_UNUSED GObject * gobject, gpointer user_data)
1027 {
1028 	histogram_create_dlg(GTK_WINDOW(user_data));
1029 }
1030 
game_settings_cb(G_GNUC_UNUSED GObject * gobject,gpointer user_data)1031 void game_settings_cb(G_GNUC_UNUSED GObject * gobject, gpointer user_data)
1032 {
1033 	settings_create_dlg(GTK_WINDOW(user_data));
1034 }
1035 
1036 #ifdef HAVE_HELP
help_manual_cb(G_GNUC_UNUSED GObject * gobject,gpointer user_data)1037 void help_manual_cb(G_GNUC_UNUSED GObject * gobject, gpointer user_data)
1038 {
1039 	GError *error = NULL;
1040 	gtk_show_uri_on_window(GTK_WINDOW(user_data), "help:pioneers",
1041 			       GDK_CURRENT_TIME, &error);
1042 	if (error) {
1043 		log_message(MSG_ERROR, "%s: %s\n", _("Show the manual"),
1044 			    error->message);
1045 		g_error_free(error);
1046 	}
1047 }
1048 #endif
1049 
getAction(GuiEvent id)1050 static GAction *getAction(GuiEvent id)
1051 {
1052 	const gchar *path = NULL;
1053 #ifdef ADMIN_GTK
1054 	frontend_gui_register_action(gtk_ui_manager_get_action
1055 				     (manager,
1056 				      "ui/MainMenu/GameMenu/GameAdmin"),
1057 				     GUI_CONNECT);
1058 #endif
1059 
1060 	switch (id) {
1061 	case GUI_CONNECT:
1062 		path = "action_game_new";
1063 		break;
1064 	case GUI_DISCONNECT:
1065 		path = "action_game_leave";
1066 		break;
1067 	case GUI_CHANGE_NAME:
1068 		path = "action_player_name";
1069 		break;
1070 	case GUI_ROLL:
1071 		path = "action_roll_dice";
1072 		break;
1073 	case GUI_TRADE:
1074 		path = "action_trade";
1075 		break;
1076 	case GUI_UNDO:
1077 		path = "action_undo";
1078 		break;
1079 	case GUI_FINISH:
1080 		path = "action_finish";
1081 		break;
1082 	case GUI_ROAD:
1083 		path = "action_build_road";
1084 		break;
1085 	case GUI_SHIP:
1086 		path = "action_build_ship";
1087 		break;
1088 	case GUI_MOVE_SHIP:
1089 		path = "action_move_ship";
1090 		break;
1091 	case GUI_BRIDGE:
1092 		path = "action_build_bridge";
1093 		break;
1094 	case GUI_SETTLEMENT:
1095 		path = "action_build_settlement";
1096 		break;
1097 	case GUI_CITY:
1098 		path = "action_build_city";
1099 		break;
1100 	case GUI_BUY_DEVELOP:
1101 		path = "action_buy_development";
1102 		break;
1103 	case GUI_CITY_WALL:
1104 		path = "action_build_city_wall";
1105 		break;
1106 	default:
1107 		break;
1108 	};
1109 
1110 	if (!path)
1111 		return NULL;
1112 
1113 	return g_action_map_lookup_action(G_ACTION_MAP(action_group),
1114 					  path);
1115 }
1116 
1117 /** Set the visibility of the toolbar */
gui_set_toolbar_visible(gboolean visible)1118 static void gui_set_toolbar_visible(gboolean visible)
1119 {
1120 	GtkWidget *toolbar =
1121 	    GTK_WIDGET(gtk_builder_get_object(builder, "toolbar"));
1122 
1123 	if (visible)
1124 		gtk_widget_show(GTK_WIDGET(toolbar));
1125 	else
1126 		gtk_widget_hide(GTK_WIDGET(toolbar));
1127 	config_set_int("settings/show_toolbar", visible);
1128 }
1129 
1130 /* Note:
1131  * 1. the accelerators are not translated
1132  * 2. the accelerators are duplicated here from the .ui file
1133  * 3. the UI file has Roll Dice\nF1 to ensure the proper initial size
1134  */
1135 /* *INDENT-OFF* */
1136 static struct {
1137 	const gchar *text;
1138 	const gchar *accelerator;
1139 } toolbar_accelerators[] = {
1140 	{ N_("Roll Dice"), "F1" },
1141 	{ N_("Trade"), "F2" },
1142 	{ N_("Undo"), "F3" },
1143 	{ N_("Finish") , "F4" },
1144 	{ N_("Road"), "F5" },
1145 	{ N_("Ship"), "F6" },
1146 	{ N_("Move Ship"), "F7" },
1147 	{ N_("Bridge"), "F8" },
1148 	{ N_("Settlement"), "F9" },
1149 	{ N_("City"), "F10" },
1150 	{ N_("Develop"), "F11" },
1151 	{ N_("City Wall"), NULL },
1152 };
1153 /* *INDENT-ON* */
1154 
1155 /** Show the accelerators in the toolbar */
gui_toolbar_show_accelerators(gboolean show_accelerators)1156 static void gui_toolbar_show_accelerators(gboolean show_accelerators)
1157 {
1158 	GtkToolbar *tb;
1159 	gint n, i;
1160 
1161 	toolbar_show_accelerators = show_accelerators;
1162 
1163 	tb = GTK_TOOLBAR(gtk_builder_get_object(builder, "toolbar"));
1164 	g_return_if_fail(tb != NULL);
1165 
1166 	n = gtk_toolbar_get_n_items(tb);
1167 	for (i = 0; i < n; i++) {
1168 		GtkToolItem *ti;
1169 		GtkToolButton *tbtn;
1170 		gchar *text;
1171 		guint j;
1172 
1173 		ti = gtk_toolbar_get_nth_item(tb, i);
1174 		tbtn = GTK_TOOL_BUTTON(ti);
1175 		g_assert(tbtn != NULL);
1176 
1177 		text = g_strdup(gtk_tool_button_get_label(tbtn));
1178 		if (strchr(text, '\n'))
1179 			*strchr(text, '\n') = '\0';
1180 		/* Find the matching entry */
1181 		for (j = 0; j < G_N_ELEMENTS(toolbar_accelerators); j++) {
1182 			if (strcmp(text, _(toolbar_accelerators[j].text))
1183 			    == 0) {
1184 				if (show_accelerators) {
1185 					gchar *label;
1186 
1187 					if (toolbar_accelerators
1188 					    [j].accelerator == NULL)
1189 						label =
1190 						    g_strdup_printf
1191 						    ("%s\n", text);
1192 					else {
1193 						label =
1194 						    g_strdup_printf
1195 						    ("%s\n(%s)",
1196 						     text,
1197 						     toolbar_accelerators
1198 						     [j].accelerator);
1199 					}
1200 					gtk_tool_button_set_label
1201 					    (tbtn, label);
1202 					g_free(label);
1203 				} else {
1204 					gtk_tool_button_set_label
1205 					    (tbtn, text);
1206 				}
1207 				break;
1208 			}
1209 		}
1210 		g_free(text);
1211 	}
1212 	config_set_int("settings/toolbar_show_accelerators",
1213 		       toolbar_show_accelerators);
1214 }
1215 
1216 /** Show or hide a button in the toolbar */
gui_toolbar_show_button(const gchar * id,gboolean visible)1217 static void gui_toolbar_show_button(const gchar * id, gboolean visible)
1218 {
1219 	GtkToolItem *item =
1220 	    GTK_TOOL_ITEM(gtk_builder_get_object(builder, id));
1221 
1222 	g_return_if_fail(item != NULL);
1223 	gtk_tool_item_set_visible_horizontal(item, visible);
1224 }
1225 
gui_rules_register_callback(GCallback callback)1226 void gui_rules_register_callback(GCallback callback)
1227 {
1228 	rules_callback_list = g_list_append(rules_callback_list, callback);
1229 }
1230 
gui_set_game_params(const GameParams * params)1231 void gui_set_game_params(const GameParams * params)
1232 {
1233 	GList *list;
1234 	GtkWidget *label;
1235 
1236 	gmap->map = params->map;
1237 	gmap->player_num = my_player_num();
1238 	gtk_widget_queue_resize(gmap->area);
1239 
1240 	gui_toolbar_show_button("BuildRoad",
1241 				params->num_build_type[BUILD_ROAD] > 0);
1242 	gui_toolbar_show_button("BuildShip",
1243 				params->num_build_type[BUILD_SHIP] > 0);
1244 	gui_toolbar_show_button("MoveShip",
1245 				params->num_build_type[BUILD_SHIP] > 0);
1246 	gui_toolbar_show_button("BuildBridge",
1247 				params->num_build_type[BUILD_BRIDGE] > 0);
1248 	/* In theory, it is possible to play a game without cities */
1249 	gui_toolbar_show_button("BuildCity",
1250 				params->num_build_type[BUILD_CITY] > 0);
1251 	gui_toolbar_show_button("BuildCityWall",
1252 				params->num_build_type[BUILD_CITY_WALL] >
1253 				0);
1254 
1255 	identity_draw();
1256 
1257 	gui_set_vp_target_value(params->victory_points);
1258 
1259 	list = rules_callback_list;
1260 	while (list) {
1261 		G_CALLBACK(list->data) ();
1262 		list = g_list_next(list);
1263 	}
1264 
1265 	label =
1266 	    gtk_notebook_get_tab_label(GTK_NOTEBOOK(map_notebook),
1267 				       legend_page);
1268 	g_object_ref(label);
1269 
1270 	gtk_widget_destroy(legend_page);
1271 	legend_page = legend_create_content();
1272 	gtk_notebook_insert_page(GTK_NOTEBOOK(map_notebook),
1273 				 legend_page, label, LEGEND_PAGE);
1274 	if (!legend_page_enabled)
1275 		gui_show_legend_page(FALSE);
1276 	g_object_unref(label);
1277 }
1278 
build_status_bar(void)1279 static GtkWidget *build_status_bar(void)
1280 {
1281 	GtkWidget *vsep;
1282 
1283 	app_bar = gtk_statusbar_new();
1284 	gtk_widget_show(app_bar);
1285 
1286 	vp_target_status = gtk_label_new("");
1287 	gtk_widget_show(vp_target_status);
1288 	gtk_box_pack_start(GTK_BOX(app_bar), vp_target_status, FALSE, TRUE,
1289 			   0);
1290 
1291 	vsep = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
1292 	gtk_widget_show(vsep);
1293 	gtk_box_pack_start(GTK_BOX(app_bar), vsep, FALSE, TRUE, 0);
1294 
1295 	/* Network status: offline */
1296 	net_status = gtk_label_new(_("Offline"));
1297 	gtk_widget_show(net_status);
1298 	gtk_box_pack_start(GTK_BOX(app_bar), net_status, FALSE, TRUE, 0);
1299 
1300 	vsep = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
1301 	gtk_widget_show(vsep);
1302 	gtk_box_pack_start(GTK_BOX(app_bar), vsep, FALSE, TRUE, 0);
1303 
1304 	gtk_box_pack_start(GTK_BOX(app_bar),
1305 			   player_build_turn_area(), FALSE, TRUE, 0);
1306 
1307 	/* Initial text in status bar */
1308 	gui_set_instructions(_("Welcome to Pioneers!"));
1309 
1310 	return app_bar;
1311 }
1312 
register_pixmaps(void)1313 static void register_pixmaps(void)
1314 {
1315 	GtkIconTheme *iconTheme = gtk_icon_theme_get_default();
1316 	gchar *path;
1317 
1318 	path = g_build_filename(DATADIR, "pixmaps", "pioneers", NULL);
1319 	gtk_icon_theme_append_search_path(iconTheme, path);
1320 	g_free(path);
1321 }
1322 
add_guievent_action(GActionGroup * action_group,const gchar * name,GuiEvent event)1323 static void add_guievent_action(GActionGroup * action_group,
1324 				const gchar * name, GuiEvent event)
1325 {
1326 	GSimpleAction *action = g_simple_action_new(name, NULL);
1327 	g_signal_connect(action, "activate",
1328 			 G_CALLBACK(redirect_gui_event_cb),
1329 			 g_variant_new_int32(event));
1330 	g_action_map_add_action(G_ACTION_MAP(action_group),
1331 				G_ACTION(action));
1332 }
1333 
gui_build_interface(void)1334 GtkWidget *gui_build_interface(void)
1335 {
1336 	GtkWidget *vbox;
1337 	gchar *icon_file;
1338 	GSimpleAction *action;
1339 
1340 	player_init();
1341 
1342 	gmap = guimap_new();
1343 
1344 	register_pixmaps();
1345 
1346 	builder =
1347 	    gtk_builder_new_from_resource
1348 	    ("/net/sourceforge/pio/client/gtk/client.ui");
1349 	app_window =
1350 	    GTK_WIDGET(gtk_builder_get_object(builder, "toplevel"));
1351 	/* The name of the application */
1352 	gtk_window_set_title(GTK_WINDOW(app_window), _("Pioneers"));
1353 	gtk_builder_connect_signals(builder, app_window);
1354 
1355 	vbox = GTK_WIDGET(gtk_builder_get_object(builder, "vbox"));
1356 
1357 	icon_file =
1358 	    g_build_filename(DATADIR, "pixmaps", PIONEERS_ICON_FILE, NULL);
1359 	if (g_file_test(icon_file, G_FILE_TEST_EXISTS)) {
1360 		gtk_window_set_default_icon_from_file(icon_file, NULL);
1361 	} else {
1362 		/* Missing pixmap, main icon file */
1363 		g_warning("Pixmap not found: %s", icon_file);
1364 	}
1365 	g_free(icon_file);
1366 
1367 	color_chat_enabled =
1368 	    config_get_int_with_default("settings/color_chat", TRUE);
1369 
1370 	color_messages_enabled =
1371 	    config_get_int_with_default("settings/color_messages", TRUE);
1372 	log_set_func_message_color_enable(color_messages_enabled);
1373 
1374 	set_color_summary(config_get_int_with_default
1375 			  ("settings/color_summary", TRUE));
1376 
1377 	set_silent_mode(config_get_int_with_default
1378 			("settings/silent_mode", FALSE));
1379 	set_announce_player(config_get_int_with_default
1380 			    ("settings/announce_player", TRUE));
1381 	set_show_notifications(config_get_int_with_default
1382 			       ("settings/show_notifications", TRUE));
1383 	set_charity_enabled(config_get_int_with_default
1384 			    ("settings/charity_enabled", FALSE));
1385 	set_automatic_roll(config_get_int_with_default
1386 			   ("settings/automatic_roll",
1387 			    get_automatic_roll()));
1388 
1389 	legend_page_enabled =
1390 	    config_get_int_with_default("settings/legend_page", FALSE);
1391 
1392 	gtk_box_pack_start(GTK_BOX(vbox), build_main_interface(), TRUE,
1393 			   TRUE, 0);
1394 	gtk_box_pack_start(GTK_BOX(vbox), build_status_bar(), FALSE, FALSE,
1395 			   0);
1396 
1397 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM
1398 				       (gtk_builder_get_object
1399 					(builder,
1400 					 "toolbar_visible")),
1401 				       config_get_int_with_default
1402 				       ("settings/show_toolbar", TRUE));
1403 
1404 	g_signal_connect(G_OBJECT(app_window), "key_press_event",
1405 			 G_CALLBACK(hotkeys_handler), NULL);
1406 
1407 	gtk_widget_show(app_window);
1408 
1409 	action_group = G_ACTION_GROUP(g_simple_action_group_new());
1410 	add_guievent_action(action_group, "action_game_new", GUI_CONNECT);
1411 	action = g_simple_action_new("action_game_leave", NULL);
1412 	g_signal_connect(action, "activate",
1413 			 G_CALLBACK(game_leave_cb), NULL);
1414 	g_action_map_add_action(G_ACTION_MAP(action_group),
1415 				G_ACTION(action));
1416 	add_guievent_action(action_group, "action_player_name",
1417 			    GUI_CHANGE_NAME);
1418 	add_guievent_action(action_group, "action_roll_dice", GUI_ROLL);
1419 	add_guievent_action(action_group, "action_trade", GUI_TRADE);
1420 	add_guievent_action(action_group, "action_undo", GUI_UNDO);
1421 	add_guievent_action(action_group, "action_finish", GUI_FINISH);
1422 	add_guievent_action(action_group, "action_build_road", GUI_ROAD);
1423 	add_guievent_action(action_group, "action_build_ship", GUI_SHIP);
1424 	add_guievent_action(action_group, "action_move_ship",
1425 			    GUI_MOVE_SHIP);
1426 	add_guievent_action(action_group, "action_build_bridge",
1427 			    GUI_BRIDGE);
1428 	add_guievent_action(action_group,
1429 			    "action_build_settlement", GUI_SETTLEMENT);
1430 	add_guievent_action(action_group, "action_build_city", GUI_CITY);
1431 	add_guievent_action(action_group, "action_buy_development",
1432 			    GUI_BUY_DEVELOP);
1433 	add_guievent_action(action_group, "action_build_city_wall",
1434 			    GUI_CITY_WALL);
1435 	gtk_widget_insert_action_group(app_window, "win", action_group);
1436 
1437 	frontend_gui_register_action(getAction(GUI_CONNECT), GUI_CONNECT);
1438 	frontend_gui_register_action(getAction(GUI_DISCONNECT),
1439 				     GUI_DISCONNECT);
1440 #ifdef ADMIN_GTK
1441 	/** @todo RC 2005-05-26 Admin interface: Not tested */
1442 	frontend_gui_register_action(gtk_ui_manager_get_action
1443 				     (manager,
1444 				      "ui/MainMenu/GameMenu/GameAdmin"),
1445 				     GUI_ADMIN);
1446 	gtk_menu_item_set_visible(GTK_MENU_ITEM
1447 				  (gtk_builder_get_object
1448 				   (builder, "admin")), TRUE);
1449 #endif
1450 	frontend_gui_register_action(getAction(GUI_CHANGE_NAME),
1451 				     GUI_CHANGE_NAME);
1452 	frontend_gui_register_action(getAction(GUI_ROLL), GUI_ROLL);
1453 	frontend_gui_register_action(getAction(GUI_TRADE), GUI_TRADE);
1454 	frontend_gui_register_action(getAction(GUI_UNDO), GUI_UNDO);
1455 	frontend_gui_register_action(getAction(GUI_FINISH), GUI_FINISH);
1456 	frontend_gui_register_action(getAction(GUI_ROAD), GUI_ROAD);
1457 	frontend_gui_register_action(getAction(GUI_SHIP), GUI_SHIP);
1458 	frontend_gui_register_action(getAction(GUI_MOVE_SHIP),
1459 				     GUI_MOVE_SHIP);
1460 	frontend_gui_register_action(getAction(GUI_BRIDGE), GUI_BRIDGE);
1461 	frontend_gui_register_action(getAction(GUI_SETTLEMENT),
1462 				     GUI_SETTLEMENT);
1463 	frontend_gui_register_action(getAction(GUI_CITY), GUI_CITY);
1464 	frontend_gui_register_action(getAction(GUI_BUY_DEVELOP),
1465 				     GUI_BUY_DEVELOP);
1466 	frontend_gui_register_action(getAction(GUI_CITY_WALL),
1467 				     GUI_CITY_WALL);
1468 #if 0
1469 	frontend_gui_register_destroy(gtk_ui_manager_get_action
1470 				      (manager, "GameQuit"), GUI_QUIT);
1471 #endif
1472 #ifdef HAVE_HELP
1473 	gtk_widget_set_visible(GTK_WIDGET
1474 			       (gtk_builder_get_object
1475 				(builder, "help_manual")), TRUE);
1476 #endif
1477 
1478 
1479 	gui_toolbar_show_button("BuildShip", FALSE);
1480 	gui_toolbar_show_button("MoveShip", FALSE);
1481 	gui_toolbar_show_button("BuildBridge", FALSE);
1482 	gui_toolbar_show_button("BuildCityWall", FALSE);
1483 
1484 	gui_toolbar_show_accelerators(config_get_int_with_default
1485 				      ("settings/toolbar_show_accelerators",
1486 				       TRUE));
1487 
1488 	gtk_widget_show(app_window);
1489 	g_signal_connect(G_OBJECT(app_window), "delete_event",
1490 			 G_CALLBACK(game_quit_cb), NULL);
1491 
1492 	return app_window;
1493 }
1494 
gui_set_show_no_setup_nodes(gboolean show)1495 void gui_set_show_no_setup_nodes(gboolean show)
1496 {
1497 	guimap_set_show_no_setup_nodes(gmap, show);
1498 }
1499 
frontend_get_map(void)1500 Map *frontend_get_map(void)
1501 {
1502 	g_return_val_if_fail(gmap != NULL, NULL);
1503 	return gmap->map;
1504 }
1505 
frontend_set_map(Map * map)1506 void frontend_set_map(Map * map)
1507 {
1508 	g_assert(gmap != NULL);
1509 	gmap->map = map;
1510 }
1511