1
/* This file is a part of gtkboard, a board games system.
2
Copyright (C) 2003, Arvind Narayanan <arvindn@users.sourceforge.net>
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation; either version 2 of the License, or
7
(at your option) any later version.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software
16
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
27
#include "ui_common.h"
34
#include "libgnome/libgnome.h"
35
#include "libgnomeui/libgnomeui.h"
36
#include "../pixmaps/logo48.xpm"
39
GtkWidget *sb_message_label, *sb_game_label, *sb_score_label,
40
*sb_who_label, *sb_player_label, *sb_time_label, *sb_turn_image,
41
*menu_main, *menu_info_bar, *menu_info_separator, *menu_warning_bar;
42
GtkWidget *sb_game_separator, *sb_who_separator, *sb_score_separator,
43
*sb_player_separator, *sb_time_separator, *sb_turn_separator,
44
*sb_warning_separator;
45
#define SB_MESSAGE_STRLEN 64
46
gchar sb_message_str[SB_MESSAGE_STRLEN] = "";
47
#define SB_SCORE_STRLEN 32
48
gchar sb_score_str[SB_SCORE_STRLEN] = "";
49
GtkItemFactory *menu_factory = NULL;
51
void sb_messagebar_message (gchar *);
52
void menu_cleanup_var_menus ();
54
static char * menu_paths_sens_machine_thinking[] =
66
static char * menu_paths_sens_no_game[] =
72
"/Game/Zap Highscores",
76
"/Settings/Flip Board",
80
static char * menu_paths_sens_no_back_forw[] =
86
static char *menu_paths_sens_single_player[] =
89
"/Settings/Flip Board",
90
// "/Settings/Eval function",
93
static char *menu_paths_sens_two_players[] =
96
"/Game/Zap Highscores",
99
static char *menu_paths_sens_ui_stopped[] =
104
static char *menu_paths_sens_machine_not_thinking[] =
109
static char *menu_paths_sens_eval_function[] =
111
// "/Settings/Eval function",
114
void sb_set_score (gchar *score)
116
strncpy (sb_score_str, score, SB_SCORE_STRLEN-1);
120
void menu_sensitize (int which, gboolean sens)
122
int i, num_paths = -1;
123
char **menu_des_paths = NULL;
124
if (!state_gui_active) return;
127
case MENU_SENS_MACHINE_THINKING:
128
menu_des_paths = menu_paths_sens_machine_thinking;
129
num_paths = sizeof (menu_paths_sens_machine_thinking) /
130
sizeof (menu_paths_sens_machine_thinking[0]);
132
case MENU_SENS_MACHINE_NOT_THINKING:
133
menu_des_paths = menu_paths_sens_machine_not_thinking;
134
num_paths = sizeof (menu_paths_sens_machine_not_thinking) /
135
sizeof (menu_paths_sens_machine_not_thinking[0]);
137
case MENU_SENS_NO_GAME:
138
menu_des_paths = menu_paths_sens_no_game;
139
num_paths = sizeof (menu_paths_sens_no_game) /
140
sizeof (menu_paths_sens_no_game[0]);
142
case MENU_SENS_NO_BACK_FORW:
143
menu_des_paths = menu_paths_sens_no_back_forw;
144
num_paths = sizeof (menu_paths_sens_no_back_forw) /
145
sizeof (menu_paths_sens_no_back_forw[0]);
147
case MENU_SENS_SINGLE_PLAYER:
148
menu_des_paths = menu_paths_sens_single_player;
149
num_paths = sizeof (menu_paths_sens_single_player) /
150
sizeof (menu_paths_sens_single_player[0]);
152
case MENU_SENS_TWO_PLAYERS:
153
menu_des_paths = menu_paths_sens_two_players;
154
num_paths = sizeof (menu_paths_sens_two_players) /
155
sizeof (menu_paths_sens_two_players[0]);
157
case MENU_SENS_UI_STOPPED:
158
menu_des_paths = menu_paths_sens_ui_stopped;
159
num_paths = sizeof (menu_paths_sens_ui_stopped) /
160
sizeof (menu_paths_sens_ui_stopped[0]);
162
case MENU_SENS_EVAL_FUNCTION:
163
menu_des_paths = menu_paths_sens_eval_function;
164
num_paths = sizeof (menu_paths_sens_eval_function) /
165
sizeof (menu_paths_sens_eval_function[0]);
168
g_assert_not_reached ();
170
for (i=0; i<num_paths; i++)
171
gtk_widget_set_sensitive (gtk_item_factory_get_widget (menu_factory,
172
menu_des_paths[i]), sens);
175
void sb_set_turn_image ()
177
#if GTK_MAJOR_VERSION == 2
178
// FIXME: can't get existing bgcolor
180
static char pixbufs [7][size*(size+1)];
182
static GdkPixmap *pixmaps[7];
183
int colors[7] = {0x007700, 0x77ff77, 0x770000, 0xff7777, 0x000077, 0x7777ff,
186
static int first = 1;
187
static int previndex = -1;
194
pixmap_data = pixmap_ball_gen (size, pixbufs[i], colors[i],
196
pixmaps[i] = gdk_pixmap_create_from_xpm_d
197
((GdkWindow *)main_window->window, NULL, NULL, pixmap_data);
199
gtk_image_set_from_pixmap (GTK_IMAGE (sb_turn_image),
200
pixmaps[previndex = 6], NULL);
203
if (opt_infile || !opt_game)
207
if (!game_single_player && ui_white == HUMAN && ui_black == HUMAN
208
&& cur_pos.player == BLACK) index = 4;
209
else index = (player_to_play == HUMAN ? 0 : 2);
210
if (ui_stopped) index++;
212
g_assert (index >= 0 && index <= 6);
213
if (index == previndex) return;
214
gtk_image_set_from_pixmap (GTK_IMAGE (sb_turn_image),
215
pixmaps[previndex = index], NULL);
219
static void sb_set_cursor ()
221
static GdkCursor *cursor_normal = NULL, *cursor_busy = NULL,
222
*cursor_inactive = NULL;
223
// FIXME: is it ok to hard code the shape of the normal cursor?
224
if (!cursor_normal) cursor_normal = gdk_cursor_new (GDK_LEFT_PTR);
225
if (!cursor_busy) cursor_busy = gdk_cursor_new (GDK_WATCH);
226
if (!cursor_inactive) cursor_inactive = gdk_cursor_new (GDK_XTERM);
227
if (player_to_play == MACHINE && !ui_stopped)
228
gdk_window_set_cursor (board_area->window, cursor_busy);
229
else if (player_to_play == MACHINE && ui_stopped)
230
gdk_window_set_cursor (board_area->window, cursor_inactive);
232
gdk_window_set_cursor (board_area->window, cursor_normal);
235
void menu_board_flip_cb ()
237
if (game_single_player)
239
sb_error ("Can't flip board in single player game", TRUE);
242
if (!game_allow_flip)
244
sb_error ("This game doesn't allow the board to be flipped", TRUE);
247
state_board_flipped = state_board_flipped ? FALSE : TRUE;
248
board_redraw (NULL, NULL);
252
static void menu_show_dialog_real (gchar *title, gchar *message, gboolean wrap)
253
// A modal dialog with a label. Don't use it for showing large amounts of text
255
GtkWidget *dialog, *okay_button, *label;
257
#if GTK_MAJOR_VERSION == 1
258
label = gtk_label_new (message);
259
dialog = gtk_dialog_new();
260
gtk_window_set_title (GTK_WINDOW (dialog), title);
261
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (main_window));
262
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
263
okay_button = gtk_button_new_with_label("OK");
265
gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked",
266
GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);
267
gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
270
label = gtk_label_new (NULL);
271
gtk_label_set_markup (GTK_LABEL (label), message);
272
dialog = gtk_dialog_new_with_buttons (title, GTK_WINDOW (main_window),
273
GTK_DIALOG_MODAL, NULL);
274
gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 100);
275
okay_button = gtk_dialog_add_button (GTK_DIALOG (dialog),
276
GTK_STOCK_OK, GTK_RESPONSE_NONE);
277
g_signal_connect_swapped (GTK_OBJECT (dialog),
278
"response", G_CALLBACK (gtk_widget_destroy), GTK_OBJECT (dialog));
279
gtk_label_set_selectable (GTK_LABEL (label), TRUE);
281
gtk_label_set_line_wrap (GTK_LABEL (label), wrap);
282
gtk_widget_grab_focus (okay_button);
284
gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
285
gtk_widget_show_all (dialog);
288
void menu_show_dialog (gchar *title, gchar *message)
290
menu_show_dialog_real (title, message, FALSE);
293
void menu_show_dialog_wrap (gchar *title, gchar *message)
295
menu_show_dialog_real (title, message, TRUE);
299
void menu_pause_cb (GtkWidget *dialog)
301
gtk_widget_destroy (GTK_WIDGET (dialog));
302
menu_start_stop_game (NULL, MENU_START_GAME);
305
void menu_show_pause_dialog ()
308
GtkWidget *dialog, *okay_button, *label;
309
gchar *title = "Game paused - gtkboard";
310
gchar *msg = "Game paused. Click OK to continue";
314
label = gtk_label_new (msg);
315
#if GTK_MAJOR_VERSION == 1
316
dialog = gtk_dialog_new();
317
gtk_window_set_title (GTK_WINDOW (dialog), title);
318
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (main_window));
319
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
320
okay_button = gtk_button_new_with_label("OK");
322
gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked",
323
GTK_SIGNAL_FUNC (menu_pause_cb), (gpointer) dialog);
324
gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
326
gtk_widget_grab_focus (okay_button);
328
gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
329
gtk_widget_show_all (dialog);
331
dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
336
/* dialog = gtk_dialog_new_with_buttons (title, GTK_WINDOW (main_window),
337
GTK_DIALOG_MODAL, NULL);
338
gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 100);
339
okay_button = gtk_dialog_add_button (GTK_DIALOG (dialog),
340
GTK_STOCK_OK, GTK_RESPONSE_NONE);
341
gtk_label_set_selectable (GTK_LABEL (label), TRUE);
345
#if GTK_MAJOR_VERSION > 1
346
gtk_dialog_run (GTK_DIALOG (dialog));
347
menu_pause_cb (dialog);
351
void menu_show_about_dialog (gpointer data)
355
GdkPixmap *logo_pixmap;
356
GdkPixbuf *logo_pixbuf;
357
const gchar *authors[] = {"Arvind Narayanan <arvindn@users.sourceforge.net>", "Ron Hale-Evans <rwhe@ludism.org>", NULL};
358
gchar *logo_filename;
359
logo_filename = g_strdup_printf ("%s/pixmaps/gtkboard.png", DATADIR);
360
logo_pixbuf = gdk_pixbuf_new_from_file (logo_filename, NULL);
363
fprintf (stderr, "Warning: couldn't load icon from file %s\n", logo_filename);
364
logo_pixmap = gdk_pixmap_create_from_xpm_d (main_window->window, NULL, NULL, logo48_xpm);
365
logo_pixbuf = gdk_pixbuf_get_from_drawable (NULL, logo_pixmap,
366
gdk_colormap_get_system (), 0, 0, 0, 0, -1, -1);
367
gdk_pixmap_unref (logo_pixmap);
369
g_free (logo_filename);
370
about = gnome_about_new (PACKAGE, VERSION,
371
"Copyright (C) 2003 Arvind Narayanan",
372
NULL, authors, NULL, NULL, logo_pixbuf);
373
gtk_widget_show (about);
375
menu_show_dialog ("About gtkboard",
376
"gtkboard " VERSION "\n"
377
"http://gtkboard.sourceforge.net/\n"
378
"Maintainer: Arvind Narayanan <arvindn@users.sourceforge.net>\n"
379
"Released under the GNU General Public License\n"
380
"See the file COPYING for details\n"
382
"The documentation is available in the doc/ directory\n"
383
"of the source distribution or in the directory\n"
384
"/usr/local/doc/gtkboard-" VERSION "/ if you installed from binary rpm.\n"
385
"The latest documentation will always be available at\n"
386
"http://gtkboard.sourceforge.net/doc/"
391
void menu_show_begging_dialog (gpointer data)
393
menu_show_dialog_wrap ("Begging bowl",
394
"Thanks for using gtkboard. I hope you liked it.\n\n"
395
"The download counter on sourceforge is broken. "
396
"They call it an \"inaccuracy\", but the fact of the matter is that it's firmly stuck at zero, which means that I have no idea how many people are downloading/using the software. So you see, I'm as lonely as a lark (or whatever it is that's supposed to be very lonely.) So if you have any comments or suggestions, or even just some kind words, it would be nice if you can mail them me. My email is arvindn@users.sourceforge.net. Thanks."
400
void menu_help_home_page (gpointer data)
403
if (!gnome_url_show ("http://gtkboard.sourceforge.net/", NULL))
404
sb_error ("Couldn't launch home page", TRUE);
406
fprintf (stderr, "warning: menu_show_home_page() called even though gnome integration not compiled in\n");
412
void menu_put_player ();
414
void menu_start_stop_game (gpointer data, guint what)
418
case MENU_START_GAME:
419
if (!opt_game) break;
425
sb_error ("Game over", FALSE);
430
sb_error ("Not yet implemented", TRUE);
434
ui_send_make_move ();
438
if (!opt_game) break;
439
if (ui_stopped) break;
443
if (game_single_player && ui_white == HUMAN)
444
menu_show_pause_dialog ();
446
case MENU_RESET_GAME:
448
int saved_white = ui_white;
449
int saved_black = ui_black;
450
if (!opt_game) break;
451
ui_terminate_game ();
453
ui_white = saved_white;
454
ui_black = saved_black;
455
menu_put_player(FALSE);
456
sb_reset_human_time ();
458
ui_send_make_move ();
463
printf ("menu_start_stop_game: %d\n", what);
469
// set the menu corresponding to ui_white and ui_black
470
// if first is TRUE use opt_white and opt_black
471
void menu_put_player (gboolean first)
473
gchar *path, *paths[4] = {
474
"/Settings/Player/Human-Human", "/Settings/Player/Human-Machine",
475
"/Settings/Player/Machine-Human", "/Settings/Player/Machine-Machine"};
476
if (!state_gui_active) return;
477
if (first) {ui_white = opt_white; ui_black = opt_black;}
480
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM
481
(gtk_item_factory_get_widget (menu_factory, "/Settings/Player/File")),
486
else if (ui_white == HUMAN && ui_black == HUMAN)
488
else if (ui_white == HUMAN && ui_black == MACHINE)
490
else if (ui_white == MACHINE && ui_black == HUMAN)
492
else if (ui_white == MACHINE && ui_black == MACHINE)
496
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM
497
(gtk_item_factory_get_widget (menu_factory, path)), TRUE);
500
void menu_put_game ()
502
gchar path[128] = "/Game/Select Game/";
505
// FIXME: don't use strcat
506
strncat (path, opt_game->group, 128);
507
strncat (path, "/", 128);
509
strncat (path, opt_game->name, 128);
510
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM
511
(gtk_item_factory_get_widget (menu_factory, path)), TRUE);
514
GtkWidget *menu_selector;
516
void menu_load_file (GtkFileSelection *selector, gpointer user_data)
518
gchar const *filename;
520
filename = gtk_file_selection_get_filename
521
(GTK_FILE_SELECTION(menu_selector));
522
if (!(in = fopen (filename, "r")))
524
gchar *tempstr = g_strdup_printf
525
("Could not open file \"%s\" for reading", filename);
526
sb_error (tempstr, TRUE);
533
// FIXME: shouldn't this be MACHINE ?
534
ui_white = ui_black = NONE;
535
menu_put_player (FALSE);
536
cur_pos.player = WHITE;
537
game_set_init_pos (&cur_pos);
539
sb_message ("Opened file", FALSE);
542
void menu_set_player (gpointer *data, guint what, GtkWidget *widget)
544
/* the callback for a radio button appears to
545
be called TWICE, once when selected and once when something else
548
if (!GTK_CHECK_MENU_ITEM(widget)->active)
551
if (what >= 1 && what <= 4)
588
void menu_save_file_dialog ()
590
sb_error ("Not yet implemented", TRUE);
593
void menu_load_file_dialog ()
595
if (game_single_player)
597
sb_error ("Can't load from file for single player game.", FALSE);
600
menu_selector = gtk_file_selection_new ("");
601
g_assert (menu_selector);
602
/*gtk_file_selection_complete (
603
GTK_FILE_SELECTION (menu_selector), "*.cbgf");*/
605
gtk_signal_connect (GTK_OBJECT
606
(GTK_FILE_SELECTION(menu_selector)->ok_button),
607
"clicked", GTK_SIGNAL_FUNC (menu_load_file), NULL);
609
gtk_signal_connect_object (GTK_OBJECT
610
(GTK_FILE_SELECTION(menu_selector)->ok_button),
611
"clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
612
(gpointer) menu_selector);
614
gtk_signal_connect_object (
615
GTK_OBJECT (GTK_FILE_SELECTION(menu_selector)->cancel_button),
616
"clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
617
(gpointer) menu_selector);
619
gtk_widget_show (menu_selector);
622
void menu_show_game_doc (gpointer data, guint which)
624
GtkWidget *dialog, *msgarea, *okay_button, *vbar, *hbox, *scrwin;
626
char *msgstr = "Nothing available"; // default
631
switch (game_doc_about_status)
633
case STATUS_NONE: impl = ""; break;
634
case STATUS_UNPLAYABLE: impl = "Partially implemented (unplayable)"; break;
635
case STATUS_PARTIAL: impl = "Partially implemented (playable)"; break;
636
case STATUS_COMPLETE: impl = "Fully implemented"; break;
639
snprintf (titlestr, 64, "About %s - gtkboard", menu_get_game_name());
640
#if GTK_MAJOR_VERSION > 1
641
msgstr = g_strdup_printf ("<big><b>%s</b></big> <i>%s</i>\n<b>Status:</b> %s\n<b>URL:</b> <tt>http://gtkboard.sourceforge.net/games/%s</tt>",
643
msgstr = g_strdup_printf ("%s -- %s\nStatus: %s\nURL: http://gtkboard.sourceforge.net/games/%s",
646
game_single_player ? "Single player game" : "Two player game",
650
menu_show_dialog (titlestr, msgstr);
654
snprintf (titlestr, 64, "%s rules - gtkboard", menu_get_game_name());
655
if (game_doc_rules) msgstr = game_doc_rules;
657
case MENU_DOC_STRATEGY:
658
snprintf (titlestr, 64, "%s strategy - gtkboard", menu_get_game_name());
659
if (game_doc_strategy) msgstr = game_doc_strategy;
661
case MENU_DOC_HISTORY:
662
snprintf (titlestr, 64, "%s history - gtkboard", menu_get_game_name());
663
if (game_doc_history) msgstr = game_doc_history;
669
vbar = gtk_vscrollbar_new(NULL);
670
#if GTK_MAJOR_VERSION == 1
671
dialog = gtk_dialog_new();
672
gtk_window_set_title (GTK_WINDOW (dialog), titlestr);
673
hbox = gtk_hbox_new (FALSE, 0);
674
msgarea = gtk_text_new (NULL,
675
gtk_range_get_adjustment (GTK_RANGE (vbar)));
676
gtk_text_set_word_wrap (GTK_TEXT (msgarea), TRUE);
677
gtk_text_insert (GTK_TEXT (msgarea), NULL, NULL, NULL, msgstr, -1);
678
gtk_box_pack_start (GTK_BOX (hbox), msgarea, TRUE, TRUE, 10);
679
gtk_box_pack_start (GTK_BOX (hbox), vbar, FALSE, FALSE, 0);
680
okay_button = gtk_button_new_with_label(" OK ");
681
gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked",
682
GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);
683
gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area),
684
okay_button, FALSE, FALSE, 0);
685
gtk_widget_grab_focus (okay_button); // contributed by Paddu
686
gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), hbox);
689
dialog = gtk_dialog_new_with_buttons (titlestr, GTK_WINDOW (main_window),
690
0, GTK_STOCK_OK, GTK_RESPONSE_NONE, NULL);
691
gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 300);
692
g_signal_connect_swapped (GTK_OBJECT (dialog),
693
"response", G_CALLBACK (gtk_widget_destroy),
694
GTK_OBJECT (dialog));
695
msgarea = gtk_text_view_new ();
696
gtk_text_view_set_editable (GTK_TEXT_VIEW (msgarea), FALSE);
697
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (msgarea), GTK_WRAP_WORD);
698
gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (msgarea), FALSE);
699
gtk_text_buffer_set_text (gtk_text_view_get_buffer
700
(GTK_TEXT_VIEW (msgarea)), msgstr, -1);
701
scrwin = gtk_scrolled_window_new (NULL,
702
gtk_range_get_adjustment (GTK_RANGE(vbar)));
703
gtk_container_add (GTK_CONTAINER (scrwin), msgarea);
704
gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), scrwin);
706
gtk_widget_show_all (dialog);
709
void menu_put_level (char *level_name)
711
gchar path[128] = "/Game/Levels/";
712
strcat (path, level_name);
713
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM
714
(gtk_item_factory_get_widget (menu_factory, path)), TRUE);
717
gchar *menu_get_game_name ()
719
if (game_levels) return game_levels[0].game->name;
720
else return opt_game->name;
723
gchar *menu_get_game_name_with_level ()
725
static gchar name[128];
729
GameLevel *level = game_levels;
730
while (level->game != opt_game) { assert (level->name); level++; }
731
tempstr = g_strdup_printf ("%s (%s)",
732
game_levels[0].game->name, level->name);
733
strncpy (name, tempstr, 127);
736
else return opt_game->name;
739
void menu_set_level (gpointer data, guint which, GtkWidget *widget)
742
if (!GTK_CHECK_MENU_ITEM(widget)->active)
744
if (!state_gui_active)
746
assert (game_levels);
747
old_game = game_levels[which].game;
748
ui_terminate_game ();
750
gtk_label_set_text (GTK_LABEL (sb_game_label),
751
menu_get_game_name_with_level ());
755
GtkWidget *menu_recent_widgets[NUM_RECENT_GAMES] = {NULL};
758
static void menu_recent_game_cb (GtkWidget *widget, gpointer gamename)
761
gchar *name = gamename;
762
Game *old_game = opt_game;
763
for (i=0; i<num_games; i++)
765
if (!strcasecmp (games[i]->name, name))
767
menu_cleanup_var_menus ();
769
ui_terminate_game ();
771
if (old_game == opt_game) menu_start_game ();
772
else menu_put_game ();
777
void menu_insert_game_item (gchar *gamename, int position)
781
int offset = 1; // number of menu entries before start of recent items
782
game_menu = (GtkMenu *) gtk_item_factory_get_widget (menu_factory, "/Game");
784
child = gtk_menu_item_new_with_label (gamename);
785
gtk_menu_shell_insert (GTK_MENU_SHELL (game_menu), child, position - 1 + offset);
786
gtk_widget_show(GTK_WIDGET (child));
787
menu_recent_widgets [position-1] = child;
788
gtk_signal_connect (GTK_OBJECT (child), "activate", GTK_SIGNAL_FUNC (menu_recent_game_cb), (gpointer) gamename);
791
void menu_insert_recent_game (gchar *gamename)
796
for (i=0; i<NUM_RECENT_GAMES; i++)
798
tmpname = prefs_get_config_val (tmp = g_strdup_printf ("recent_game_%d", i+1));
801
if (!strcasecmp (gamename, tmpname))
808
gtk_widget_destroy (menu_recent_widgets[i == NUM_RECENT_GAMES ? i - 1 : i]);
809
menu_recent_widgets[i] = NULL;
810
gtk_item_factory_delete_item (menu_factory, tmp = g_strdup_printf ("/Game/%s", tmpname));
816
if (j == NUM_RECENT_GAMES) continue;
817
tmpname = prefs_get_config_val (tmp = g_strdup_printf ("recent_game_%d", j));
819
prefs_set_config_val (tmp = g_strdup_printf ("recent_game_%d", j+1), tmpname);
820
menu_recent_widgets [j] = menu_recent_widgets[j-1];
822
prefs_set_config_val ("recent_game_1", gamename);
824
menu_insert_game_item (gamename, 1);
827
void menu_start_game ()
833
GtkItemFactoryEntry help_items [3];
834
help_items[0].path = g_strdup_printf ("/Help/%s", opt_game->name);
835
help_items[0].accelerator = NULL;
836
help_items[0].callback = NULL;
837
help_items[0].item_type = "<Branch>";
838
gtk_item_factory_create_item (menu_factory, help_items, NULL, 1);
840
help_items[0].path = g_strdup_printf ("/Help/%s/_About", opt_game->name);
841
help_items[0].callback_action = MENU_DOC_ABOUT;
842
help_items[1].path = g_strdup_printf ("/Help/%s/_Rules", opt_game->name);
843
help_items[1].callback_action = MENU_DOC_RULES;
844
help_items[2].path = g_strdup_printf ("/Help/%s/_Strategy", opt_game->name);
845
help_items[2].callback_action = MENU_DOC_STRATEGY;
846
help_items[3].path = g_strdup_printf ("/Help/%s/_History", opt_game->name);
847
help_items[3].callback_action = MENU_DOC_HISTORY;
850
help_items[i].accelerator = NULL;
851
help_items[i].callback = menu_show_game_doc;
852
help_items[i].item_type = "";
854
gtk_item_factory_create_items (menu_factory,
855
4, help_items, NULL);
858
gtk_label_set_text (GTK_LABEL (sb_game_label),
859
menu_get_game_name_with_level());
864
GtkItemFactoryEntry *level_items, level_item;
865
for (cnt = 0; game_levels[cnt].name; cnt++)
867
level_items = g_new0 (GtkItemFactoryEntry, cnt);
869
/* level_item.path = "/Game/Levels";
870
level_item.accelerator = NULL;
871
level_item.callback = NULL;
872
level_item.item_type = "<Branch>";
873
gtk_item_factory_create_item (menu_factory, &level_item, NULL, 1);
875
gtk_widget_show (gtk_item_factory_get_item (menu_factory,
878
for (i=0; i<cnt; i++)
880
level_items[i].path = g_strdup_printf ("/Game/Levels/%s",
881
game_levels[i].name);
882
level_items[i].callback_action = i;
883
level_items[i].accelerator = NULL;
884
level_items[i].callback = menu_set_level;
885
level_items[i].item_type = i == 0 ? "<RadioItem>":
886
g_strdup_printf ("/Game/Levels/%s", game_levels[0].name);
887
// FIXME: possible memory leak here
889
gtk_item_factory_create_items (menu_factory,
890
cnt, level_items, NULL);
893
menu_insert_recent_game (menu_get_game_name ());
896
void menu_cleanup_var_menus ()
902
gchar *name = menu_get_game_name();
903
// FIXME: do we need to delete recursively?
904
gtk_item_factory_delete_item (menu_factory,
905
tempstr = g_strdup_printf ("/Help/%s", name));
913
for (i = 0; game_levels[i].name; i++)
915
gtk_item_factory_delete_item (menu_factory,
916
tmp = g_strdup_printf ("/Game/Levels/%s", game_levels[i].name));
919
gtk_widget_hide (gtk_item_factory_get_widget (menu_factory, "/Game/Levels"));
923
void menu_set_game (gpointer data, guint which, GtkWidget *widget)
925
if (!GTK_CHECK_MENU_ITEM(widget)->active)
927
if (!state_gui_active)
929
g_assert (which >= 0 && which < num_games);
931
menu_cleanup_var_menus ();
933
ui_terminate_game ();
934
opt_game = games[which];
940
void menu_set_delay_cb (gpointer data, guint delay, GtkWidget *widget)
942
if (!GTK_CHECK_MENU_ITEM(widget)->active)
946
fprintf (move_fout, "MSEC_PER_MOVE %d\n", opt_delay = delay);
952
void menu_back_forw (gpointer data, guint what)
958
if (!game_allow_back_forw) break;
959
if (!opt_game) break;
960
if (!game_allow_undo)
964
fprintf (move_fout, "BACK_MOVE \n");
967
move = move_fread_ack (move_fin);
970
sb_error ("Initial position. Can't go back.", FALSE);
973
board_apply_refresh (move, NULL);
974
if (!game_single_player)
975
cur_pos.player = (cur_pos.player == WHITE ? BLACK : WHITE);
976
cur_pos.num_moves --;
977
if (game_single_player && !game_allow_undo)
979
if (!ui_cheated && game_scorecmp)
980
sb_message ("You cheated! No highscore for this game.", FALSE);
983
// FIXME: there should be only one round of communication
984
// in which client gets both the move and who_won
986
if (game_reset_uistate) game_reset_uistate();
990
if (!game_allow_back_forw) break;
991
if (!opt_game) break;
994
fprintf (move_fout, "FORW_MOVE \n");
997
move = move_fread_ack (move_fin);
1000
sb_error ("Final position. Can't go forward.", FALSE);
1003
board_apply_refresh (move, NULL);
1004
if (!game_single_player)
1005
cur_pos.player = (cur_pos.player == WHITE ? BLACK : WHITE);
1006
cur_pos.num_moves ++;
1007
ui_check_who_won ();
1008
if (game_reset_uistate) game_reset_uistate();
1016
//! This function is no longer used. Eval function should be set only from the command line.
1017
void menu_set_eval_function ()
1020
GtkWidget *menu, *menuitem;
1021
GtkItemFactoryEntry heur_item;
1022
static HeurTab *oldtab = NULL;
1023
char *colors[2], **color, pathbuf[64];
1025
colors[0] = game_white_string;
1026
colors[1] = game_black_string;
1027
for (color = colors; color <= colors+1; color++)
1030
for (i=0; oldtab[i].name; i++)
1032
char *path = g_strdup_printf ("/Settings/Eval function/%s/%s",
1033
*color, oldtab[i].name);
1034
gtk_item_factory_delete_item (menu_factory, path);
1038
for (i=0; game_htab[i].name; i++)
1040
heur_item.path = g_strdup_printf ("/Settings/Eval function/%s/%s",
1041
*color, game_htab[i].name);
1042
if (i == 0) strncpy (pathbuf, heur_item.path, 63);
1043
heur_item.accelerator = NULL;
1044
heur_item.callback = NULL;
1045
heur_item.callback_action = 0;
1046
heur_item.item_type = (i == 0 ? "<RadioItem>" : pathbuf);
1047
gtk_item_factory_create_item (menu_factory, &heur_item, NULL, 1);
1048
g_free (heur_item.path);
1054
void menu_enable_sound_cb (gpointer data, guint what)
1056
sound_set_enabled (what == 0 ? FALSE : TRUE);
1060
void sb_message_dialog_show (char *msg, gboolean error)
1063
#if GTK_MAJOR_VERSION > 1
1064
dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
1066
error ? GTK_MESSAGE_ERROR : GTK_MESSAGE_INFO,
1069
gtk_dialog_run (GTK_DIALOG (dialog));
1070
gtk_widget_destroy (dialog);
1072
menu_show_dialog ("Error - gtkboard", msg);
1075
void sb_error (char *msg, gboolean serious)
1077
if (!state_gui_active)
1079
fprintf (stderr, "Fatal error: %s\n", msg);
1083
//menu_show_dialog ("Error - gtkboard", msg);
1084
sb_message_dialog_show (msg, TRUE);
1086
sb_messagebar_message (msg);
1089
void sb_message (char *msg, gboolean serious)
1091
if (!state_gui_active)
1092
fprintf (stderr, "%s\n", msg);
1096
//sb_error (msg, serious);
1097
sb_message_dialog_show (msg, FALSE);
1099
sb_messagebar_message (msg);
1103
gchar *sb_ftime(int temps)
1105
static gchar ftime[10] = " : : ";
1106
ftime[6] = temps % 10 + '0';
1108
ftime[4] = temps % 10 + '0';
1110
ftime[3] = temps % 6 + '0';
1112
ftime[1] = temps % 10 + '0';
1114
ftime[0] = temps % 6 + '0';
1119
static int sb_human_time = 0;
1121
void sb_reset_human_time ()
1125
if (!state_gui_active)
1127
gtk_label_set_text (GTK_LABEL(sb_time_label), tempstr
1128
= g_strdup_printf ("Time:%s", sb_ftime(sb_human_time)));
1132
int sb_get_human_time ()
1134
return sb_human_time;
1137
static int sb_last_msg_time = -1;
1139
void sb_messagebar_message (gchar *msg)
1141
sb_last_msg_time = 0;
1142
strncpy (sb_message_str, msg, SB_MESSAGE_STRLEN-1);
1147
// first call all the sens and then all the desens
1149
// FIXME: isn't there a more elegant way to do this?
1150
gboolean machine_thinking, machine_not_thinking,
1151
no_game, single_player, two_players,
1152
no_back_forw, eval_fn;
1153
machine_thinking = (!ui_stopped && player_to_play == MACHINE);
1154
machine_not_thinking = !machine_thinking;
1155
no_game = opt_game ? FALSE : TRUE;
1156
single_player = game_single_player;
1157
two_players = !single_player;
1158
no_back_forw = !game_allow_back_forw;
1159
eval_fn = game_htab ? FALSE : TRUE;
1161
if (!machine_thinking) menu_sensitize (MENU_SENS_MACHINE_THINKING, TRUE);
1162
if (!machine_not_thinking) menu_sensitize (MENU_SENS_MACHINE_NOT_THINKING, TRUE);
1163
if (!no_game) menu_sensitize (MENU_SENS_NO_GAME, TRUE);
1164
if (!single_player) menu_sensitize (MENU_SENS_SINGLE_PLAYER, TRUE);
1165
if (!two_players) menu_sensitize (MENU_SENS_TWO_PLAYERS, TRUE);
1166
if (!no_back_forw) menu_sensitize (MENU_SENS_NO_BACK_FORW, TRUE);
1167
if (!ui_stopped) menu_sensitize (MENU_SENS_UI_STOPPED, TRUE);
1168
if (!eval_fn) menu_sensitize (MENU_SENS_EVAL_FUNCTION, TRUE);
1170
if (machine_thinking) menu_sensitize (MENU_SENS_MACHINE_THINKING, FALSE);
1171
if (machine_not_thinking) menu_sensitize (MENU_SENS_MACHINE_NOT_THINKING, FALSE);
1172
if (no_game) menu_sensitize (MENU_SENS_NO_GAME, FALSE);
1173
if (single_player) menu_sensitize (MENU_SENS_SINGLE_PLAYER, FALSE);
1174
if (two_players) menu_sensitize (MENU_SENS_TWO_PLAYERS, FALSE);
1175
if (no_back_forw) menu_sensitize (MENU_SENS_NO_BACK_FORW, FALSE);
1176
if (ui_stopped) menu_sensitize (MENU_SENS_UI_STOPPED, FALSE);
1177
if (eval_fn) menu_sensitize (MENU_SENS_EVAL_FUNCTION, FALSE);
1179
// TODO: express this in data rather than code
1182
gtk_widget_show (gtk_item_factory_get_widget (menu_factory,
1184
gtk_widget_hide (gtk_item_factory_get_widget (menu_factory,
1189
gtk_widget_hide (gtk_item_factory_get_widget (menu_factory,
1191
gtk_widget_show (gtk_item_factory_get_widget (menu_factory,
1195
if (sound_get_enabled ())
1197
gtk_widget_show (gtk_item_factory_get_widget (menu_factory,
1198
"/Settings/Disable Sound"));
1199
gtk_widget_hide (gtk_item_factory_get_widget (menu_factory,
1200
"/Settings/Enable Sound"));
1204
gtk_widget_hide (gtk_item_factory_get_widget (menu_factory,
1205
"/Settings/Disable Sound"));
1206
gtk_widget_show (gtk_item_factory_get_widget (menu_factory,
1207
"/Settings/Enable Sound"));
1212
gtk_widget_hide (menu_info_bar);
1213
gtk_widget_hide (menu_info_separator);
1217
gtk_widget_show (menu_info_bar);
1218
gtk_widget_show (menu_info_separator);
1221
gtk_widget_show (gtk_item_factory_get_item (menu_factory, "/Game/Levels"));
1223
gtk_widget_hide (gtk_item_factory_get_item (menu_factory, "/Game/Levels"));
1224
if (game_doc_about_status == STATUS_COMPLETE || game_doc_about_status == STATUS_NONE)
1226
gtk_widget_hide (menu_warning_bar);
1227
gtk_widget_hide (sb_warning_separator);
1231
gtk_widget_show (menu_warning_bar);
1232
gtk_widget_show (sb_warning_separator);
1237
//! NOTE: sb_update() is idempotent. When in doubt, call sb_update().
1240
char player[5] = "?/?";
1241
if (!state_gui_active) return;
1243
if (game_single_player)
1245
gtk_widget_hide (sb_player_label);
1246
gtk_widget_hide (sb_who_label);
1247
gtk_widget_hide (sb_player_separator);
1248
gtk_widget_hide (sb_who_separator);
1249
gtk_widget_show (sb_time_separator);
1250
gtk_widget_show (sb_time_label);
1254
gtk_widget_show (sb_player_label);
1255
gtk_widget_show (sb_who_label);
1256
gtk_widget_show (sb_player_separator);
1257
gtk_widget_show (sb_who_separator);
1258
gtk_widget_hide (sb_time_separator);
1259
gtk_widget_hide (sb_time_label);
1260
if (ui_white == HUMAN) player[0] = 'H';
1261
if (ui_white == MACHINE) player[0] = 'M';
1262
if (ui_black == HUMAN) player[2] = 'H';
1263
if (ui_black == MACHINE) player[2] = 'M';
1264
gtk_label_set_text (GTK_LABEL(sb_player_label),
1265
ui_white != NONE ? player : "File");
1266
gtk_label_set_text (GTK_LABEL(sb_who_label), cur_pos.player == WHITE ?
1267
game_white_string : game_black_string);
1269
gtk_label_set_text (GTK_LABEL(sb_score_label), sb_score_str);
1270
sb_set_turn_image();
1274
gboolean sb_update_periodic ()
1276
static gboolean first = TRUE;
1277
if (!state_gui_active) return TRUE;
1278
if (sb_message_str[0] != '\0' && sb_last_msg_time < 0)
1279
sb_last_msg_time = 0;
1280
if (sb_message_str[0] == '\0') sb_last_msg_time = -1;
1281
if (sb_last_msg_time >= 0) sb_last_msg_time++;
1282
if (sb_last_msg_time >= 30)
1283
sb_message_str[0] = '\0';
1284
gtk_label_set_text (GTK_LABEL(sb_message_label), sb_message_str);
1286
gchar *tempstr = NULL;
1287
if (!ui_stopped && (player_to_play == HUMAN || game_single_player))
1288
gtk_label_set_text (GTK_LABEL(sb_time_label),
1289
tempstr = g_strdup_printf ("Time:%s", sb_ftime(sb_human_time++)));
1291
gtk_label_set_text (GTK_LABEL(sb_time_label),
1292
tempstr = g_strdup_printf ("Time:%s", sb_ftime(sb_human_time)));
1293
if (tempstr) g_free (tempstr);