This is the doxygen documentation for gtkboard.

.
Main Page   Data Structures   File List   Data Fields   Globals  

menu.c

Go to the documentation of this file.
00001 /*  This file is a part of gtkboard, a board games system.
00002     Copyright (C) 2003, Arvind Narayanan <arvindn@users.sourceforge.net>
00003 
00004     This program is free software; you can redistribute it and/or modify
00005     it under the terms of the GNU General Public License as published by
00006     the Free Software Foundation; either version 2 of the License, or
00007     (at your option) any later version.
00008 
00009     This program is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012     GNU General Public License for more details.
00013 
00014     You should have received a copy of the GNU General Public License
00015     along with this program; if not, write to the Free Software
00016     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
00017 
00018 */
00019 #include <string.h>
00020 #include <assert.h>
00021 #include <stdlib.h>
00022 
00023 #include "config.h"
00024 #include "ui.h"
00025 #include "menu.h"
00026 #include "move.h"
00027 #include "ui_common.h"
00028 #include "aaball.h"
00029 #include "board.h"
00030 
00031 GtkWidget *sb_message_label, *sb_game_label, *sb_score_label,
00032         *sb_who_label, *sb_player_label, *sb_time_label, *sb_turn_image,
00033         *menu_main;
00034 GtkWidget *sb_game_separator, *sb_who_separator, *sb_score_separator,
00035         *sb_player_separator, *sb_time_separator, *sb_turn_separator;
00036 #define SB_MESSAGE_STRLEN 64
00037 gchar sb_message_str[SB_MESSAGE_STRLEN] = "";
00038 #define SB_SCORE_STRLEN 32
00039 gchar sb_score_str[SB_SCORE_STRLEN] = "";
00040 GtkItemFactory *menu_factory = NULL;
00041 
00042 void sb_messagebar_message (gchar *);
00043 
00044 static char * menu_paths_sens_machine_thinking[] = 
00045 {
00046         "/File/Load game",
00047         "/File/Save game",
00048         "/Game/Start",
00049         "/Game/New",
00050         "/Game/Select Game",
00051         "/Settings",
00052         "/Move/Back",
00053         "/Move/Forward",
00054 };
00055 
00056 static char * menu_paths_sens_no_game[] = 
00057 {
00058         "/Game/Start",
00059         "/Game/Pause",
00060         "/Game/New",
00061         "/Game/Highscores",
00062         "/Game/Zap Highscores",
00063         "/File/Save game",
00064         "/Move/Back",
00065         "/Move/Forward",
00066         "/Settings/Flip Board",
00067         "/Settings/Player",
00068 };
00069 
00070 static char * menu_paths_sens_no_back_forw[] = 
00071 {
00072         "/Move/Back",
00073         "/Move/Forward",
00074 };
00075 
00076 static char *menu_paths_sens_single_player[] =
00077 {
00078         "/Settings/Player",
00079         "/Settings/Flip Board",
00080 //      "/Settings/Eval function",
00081 };
00082 
00083 static char *menu_paths_sens_two_players[] =
00084 {
00085         "/Game/Highscores",
00086         "/Game/Zap Highscores",
00087 };
00088 
00089 static char *menu_paths_sens_ui_stopped[] = 
00090 {
00091         "/Game/Pause",
00092 };
00093 
00094 static char *menu_paths_sens_machine_not_thinking[] = 
00095 {
00096         "/Move/Move Now",
00097 };
00098 
00099 static char *menu_paths_sens_eval_function[] = 
00100 {
00101 //      "/Settings/Eval function",
00102 };
00103 
00104 void sb_set_score (gchar *score)
00105 {
00106         strncpy (sb_score_str, score, SB_SCORE_STRLEN-1);
00107         sb_update ();
00108 }
00109 
00110 void menu_sensitize (int which, gboolean sens)
00111 {
00112         int i, num_paths = -1;
00113         char **menu_des_paths = NULL;
00114         if (!state_gui_active) return;
00115         switch (which)
00116         {
00117                 case MENU_SENS_MACHINE_THINKING: 
00118                         menu_des_paths = menu_paths_sens_machine_thinking;
00119                         num_paths = sizeof (menu_paths_sens_machine_thinking) / 
00120                                 sizeof (menu_paths_sens_machine_thinking[0]);
00121                         break;
00122                 case MENU_SENS_MACHINE_NOT_THINKING: 
00123                         menu_des_paths = menu_paths_sens_machine_not_thinking;
00124                         num_paths = sizeof (menu_paths_sens_machine_not_thinking) / 
00125                                 sizeof (menu_paths_sens_machine_not_thinking[0]);
00126                         break;
00127                 case MENU_SENS_NO_GAME: 
00128                         menu_des_paths = menu_paths_sens_no_game;
00129                         num_paths = sizeof (menu_paths_sens_no_game) / 
00130                                 sizeof (menu_paths_sens_no_game[0]);
00131                         break;
00132                 case MENU_SENS_NO_BACK_FORW: 
00133                         menu_des_paths = menu_paths_sens_no_back_forw;
00134                         num_paths = sizeof (menu_paths_sens_no_back_forw) / 
00135                                 sizeof (menu_paths_sens_no_back_forw[0]);
00136                         break;
00137                 case MENU_SENS_SINGLE_PLAYER: 
00138                         menu_des_paths = menu_paths_sens_single_player;
00139                         num_paths = sizeof (menu_paths_sens_single_player) / 
00140                                 sizeof (menu_paths_sens_single_player[0]);
00141                         break;
00142                 case MENU_SENS_TWO_PlayerS: 
00143                         menu_des_paths = menu_paths_sens_two_players;
00144                         num_paths = sizeof (menu_paths_sens_two_players) / 
00145                                 sizeof (menu_paths_sens_two_players[0]);
00146                         break;
00147                 case MENU_SENS_UI_STOPPED: 
00148                         menu_des_paths = menu_paths_sens_ui_stopped;
00149                         num_paths = sizeof (menu_paths_sens_ui_stopped) / 
00150                                 sizeof (menu_paths_sens_ui_stopped[0]);
00151                         break;
00152                 case MENU_SENS_EVAL_FUNCTION:
00153                         menu_des_paths = menu_paths_sens_eval_function;
00154                         num_paths = sizeof (menu_paths_sens_eval_function) / 
00155                                 sizeof (menu_paths_sens_eval_function[0]);
00156                         break;
00157                 default:
00158                         g_assert_not_reached ();
00159         }
00160         for (i=0; i<num_paths; i++)
00161                 gtk_widget_set_sensitive (gtk_item_factory_get_widget (menu_factory, 
00162                                         menu_des_paths[i]), sens);
00163 }
00164 
00165 void sb_set_turn_image ()
00166 {
00167 #if GTK_MAJOR_VERSION == 2
00168         // FIXME: can't get existing bgcolor
00169         const int size = 20;
00170         static char pixbufs [7][size*(size+1)];
00171         char **pixmap_data;
00172         static GdkPixmap *pixmaps[7];
00173         int colors[7] = {0x007700, 0x77ff77, 0x770000, 0xff7777, 0x000077, 0x7777ff,
00174                                         0x777777};
00175         int i, j;
00176         static int first = 1;
00177         static int previndex = -1;
00178         int index = -1;
00179         if (first)
00180         {
00181                 int i;
00182                 for (i=0; i<7; i++)
00183                 {
00184                         pixmap_data = pixmap_ball_gen (size, pixbufs[i], colors[i], 
00185                                         0xffffff, 6.5, 24);
00186                         pixmaps[i] = gdk_pixmap_create_from_xpm_d 
00187                                 ((GdkWindow *)main_window->window, NULL, NULL, pixmap_data);
00188                 }
00189                 gtk_image_set_from_pixmap (GTK_IMAGE (sb_turn_image), 
00190                                 pixmaps[previndex = 6], NULL);
00191                 first = 0;
00192         }
00193         if (opt_infile || !opt_game)
00194                 index = 6;
00195         else 
00196         {
00197                 if (!game_single_player && ui_white == HUMAN && ui_black == HUMAN
00198                                 && cur_pos.player == BLACK) index = 4;
00199                 else index =  (player_to_play == HUMAN ? 0 : 2);
00200                 if (ui_stopped) index++;
00201         }
00202         g_assert (index >= 0 && index <= 6);
00203         if (index == previndex) return;
00204         gtk_image_set_from_pixmap (GTK_IMAGE (sb_turn_image), 
00205                         pixmaps[previndex = index], NULL);
00206 #endif
00207 }
00208 
00209 static void sb_set_cursor ()
00210 {
00211         static GdkCursor *cursor_normal = NULL, *cursor_busy = NULL, 
00212                 *cursor_inactive = NULL;
00213         // FIXME: is it ok to hard code the shape of the normal cursor?
00214         if (!cursor_normal) cursor_normal = gdk_cursor_new (GDK_LEFT_PTR);
00215         if (!cursor_busy) cursor_busy = gdk_cursor_new (GDK_WATCH);
00216         if (!cursor_inactive) cursor_inactive = gdk_cursor_new (GDK_XTERM);
00217         if (player_to_play == MACHINE && !ui_stopped)
00218                 gdk_window_set_cursor (board_area->window, cursor_busy);
00219         else if (player_to_play == MACHINE && ui_stopped)
00220                 gdk_window_set_cursor (board_area->window, cursor_inactive);
00221         else
00222                 gdk_window_set_cursor (board_area->window, cursor_normal);
00223 }
00224 
00225 void menu_board_flip_cb ()
00226 {
00227         if (game_single_player)
00228         {
00229                 sb_error ("Can't flip board in single player game", TRUE);
00230                 return;
00231         }
00232         if (!game_allow_flip)
00233         {
00234                 sb_error ("This game doesn't allow the board to be flipped", TRUE);
00235                 return;
00236         }
00237         state_board_flipped = state_board_flipped ? FALSE : TRUE;
00238         board_redraw (NULL, NULL);
00239 }
00240 
00241 
00242 static void menu_show_dialog_real (gchar *title, gchar *message, gboolean wrap)
00243         // A modal dialog with a label. Don't use it for showing large amounts of text
00244 {
00245         GtkWidget *dialog, *okay_button, *label;
00246 
00247         label = gtk_label_new (message);
00248 #if GTK_MAJOR_VERSION == 1
00249         dialog = gtk_dialog_new();
00250         gtk_window_set_title (GTK_WINDOW (dialog), title);
00251         gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (main_window));
00252         gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
00253         okay_button = gtk_button_new_with_label("OK");
00254 
00255         gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked",
00256                         GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);
00257         gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
00258                         okay_button);
00259 #else
00260         dialog = gtk_dialog_new_with_buttons (title, GTK_WINDOW (main_window),
00261                         GTK_DIALOG_MODAL, NULL);
00262         gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 100);
00263         okay_button = gtk_dialog_add_button (GTK_DIALOG (dialog), 
00264                         GTK_STOCK_OK, GTK_RESPONSE_NONE);
00265         g_signal_connect_swapped (GTK_OBJECT (dialog), 
00266                         "response", G_CALLBACK (gtk_widget_destroy), GTK_OBJECT (dialog));
00267         gtk_label_set_selectable (GTK_LABEL (label), TRUE);
00268 #endif
00269         gtk_label_set_line_wrap (GTK_LABEL (label), wrap);
00270         gtk_widget_grab_focus (okay_button);
00271 
00272         gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
00273         gtk_widget_show_all (dialog);
00274 }
00275 
00276 void menu_show_dialog (gchar *title, gchar *message)
00277 {
00278         menu_show_dialog_real (title, message, FALSE);
00279 }
00280 
00281 void menu_show_dialog_wrap (gchar *title, gchar *message)
00282 {
00283         menu_show_dialog_real (title, message, TRUE);
00284 }
00285         
00286 
00287 void menu_pause_cb (GtkWidget *dialog)
00288 {
00289         gtk_widget_destroy (GTK_WIDGET (dialog));
00290         menu_start_stop_game (NULL, MENU_START_GAME);
00291 }
00292 
00293 void menu_show_pause_dialog ()
00294         // Game paused
00295 {
00296         GtkWidget *dialog, *okay_button, *label;
00297         gchar *title = "Game paused - gtkboard";
00298 
00299         board_hide();
00300 
00301         label = gtk_label_new ("Game paused. Click OK to continue");
00302 #if GTK_MAJOR_VERSION == 1
00303         dialog = gtk_dialog_new();
00304         gtk_window_set_title (GTK_WINDOW (dialog), title);
00305         gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (main_window));
00306         gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
00307         okay_button = gtk_button_new_with_label("OK");
00308 
00309         gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked",
00310                         GTK_SIGNAL_FUNC (menu_pause_cb), (gpointer) dialog);
00311         gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
00312                         okay_button);
00313 #else
00314         dialog = gtk_dialog_new_with_buttons (title, GTK_WINDOW (main_window),
00315                         GTK_DIALOG_MODAL, NULL);
00316         gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 100);
00317         okay_button = gtk_dialog_add_button (GTK_DIALOG (dialog), 
00318                         GTK_STOCK_OK, GTK_RESPONSE_NONE);
00319         gtk_label_set_selectable (GTK_LABEL (label), TRUE);
00320 #endif
00321         gtk_widget_grab_focus (okay_button);
00322 
00323         gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
00324         gtk_widget_show_all (dialog);
00325 
00326 #if GTK_MAJOR_VERSION > 1
00327         gtk_dialog_run (GTK_DIALOG (dialog));
00328         menu_pause_cb (dialog);
00329 #endif
00330 }
00331 
00332 void menu_show_about_dialog (gpointer data)
00333 {
00334         menu_show_dialog ("About gtkboard", 
00335                         "gtkboard " VERSION "\n"
00336                         "http://gtkboard.sourceforge.net/\n"
00337                         "Maintainer: Arvind Narayanan <arvindn@users.sourceforge.net>\n"
00338                         "Released under the GNU General Public License\n"
00339                         "See the file COPYING for details\n"
00340                         "\n"
00341                         "The documentation is available in the doc/ directory\n"
00342                         "of the source distribution or in the directory\n" 
00343                         "/usr/local/doc/gtkboard-" VERSION "/ if you installed from binary rpm.\n"
00344                         "The latest documentation will always be available at\n"
00345                         "http://gtkboard.sourceforge.net/doc/"
00346                         );
00347 }
00348 
00349 void menu_show_begging_dialog (gpointer data)
00350 {
00351         menu_show_dialog_wrap ("Begging bowl",
00352                         "Thanks for using gtkboard. I hope you liked it.\n\n"
00353                         "The download counter on sourceforge is broken. "
00354                         "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."
00355                         );
00356 }
00357 
00358         
00359 void menu_put_player ();
00360 
00361 void menu_start_stop_game (gpointer data, guint what)
00362 {
00363         switch (what)
00364         {
00365                 case MENU_START_GAME:
00366                         if (!opt_game) break;
00367                         if (!ui_stopped)
00368                                 break;
00369                         board_show();
00370                         if (ui_gameover)
00371                         {
00372                                 sb_error ("Game over", FALSE);
00373                                 break;
00374                         }
00375                         if (!impl_check()) 
00376                         {       
00377                                 sb_error ("Not yet implemented", TRUE);
00378                                 break;
00379                         }
00380                         ui_stopped = FALSE;
00381                         ui_send_make_move ();
00382                         sb_update();
00383                         break;
00384                 case MENU_STOP_GAME:
00385                         if (!opt_game) break;
00386                         if (ui_stopped) break;
00387                         ui_stopped = TRUE;
00388                         ui_cancel_move ();
00389                         sb_update();
00390                         if (game_single_player && ui_white == HUMAN)
00391                                 menu_show_pause_dialog ();
00392                         break;
00393                 case MENU_RESET_GAME:
00394                         {
00395                         int saved_white = ui_white;
00396                         int saved_black = ui_black;
00397                         if (!opt_game) break;
00398                         ui_terminate_game ();
00399                         ui_start_game ();
00400                         ui_white = saved_white;
00401                         ui_black = saved_black;
00402                         menu_put_player(FALSE);
00403                         sb_reset_human_time ();
00404                         sb_update();
00405                         break;
00406                         }
00407                 default:
00408                         printf ("menu_start_stop_game: %d\n", what);
00409                         assert (0);
00410         }
00411 }
00412 
00413 
00414 // set the menu corresponding to ui_white and ui_black
00415 // if first is TRUE use opt_white and opt_black
00416 void menu_put_player (gboolean first)
00417 {
00418         gchar *path, *paths[4] = { 
00419                 "/Settings/Player/Human-Human", "/Settings/Player/Human-Machine",
00420                 "/Settings/Player/Machine-Human", "/Settings/Player/Machine-Machine"};
00421         if (!state_gui_active) return;
00422         if (first) {ui_white = opt_white; ui_black = opt_black;}
00423         if (opt_infile)
00424         {
00425                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM 
00426                 (gtk_item_factory_get_widget (menu_factory, "/Settings/Player/File")), 
00427                               TRUE);
00428                         
00429                 return;
00430         }       
00431         else if (ui_white == HUMAN && ui_black == HUMAN)
00432                 path = paths[0];
00433         else if (ui_white == HUMAN && ui_black == MACHINE)
00434                 path = paths[1];
00435         else if (ui_white == MACHINE && ui_black == HUMAN)
00436                 path = paths[2];
00437         else if (ui_white == MACHINE && ui_black == MACHINE)
00438                 path = paths[3];
00439         else
00440                 return;
00441         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM 
00442                         (gtk_item_factory_get_widget (menu_factory, path)), TRUE);
00443 }
00444 
00445 void menu_put_game ()
00446 {
00447         gchar path[32] = "/Game/Select Game/";
00448         strcat (path, opt_game->name);
00449         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM 
00450                         (gtk_item_factory_get_widget (menu_factory, path)), TRUE);
00451 }
00452 
00453 GtkWidget *menu_selector;
00454         
00455 void menu_load_file (GtkFileSelection *selector, gpointer user_data) 
00456 {
00457         gchar const *filename;
00458         static FILE *in;
00459         filename = gtk_file_selection_get_filename 
00460                 (GTK_FILE_SELECTION(menu_selector));
00461         if (!(in = fopen (filename, "r")))
00462         {
00463                 gchar *tempstr = g_strdup_printf 
00464                         ("Could not open file \"%s\" for reading", filename);
00465                 sb_error (tempstr, TRUE);
00466                 g_free (tempstr);
00467                 return;
00468         }
00469         if (opt_infile)
00470                 fclose (opt_infile);
00471         opt_infile = in;
00472         // FIXME: shouldn't this be MACHINE ?
00473         ui_white = ui_black = NONE;
00474         menu_put_player (FALSE);
00475         cur_pos.player = WHITE;
00476         game_set_init_pos (&cur_pos);
00477         board_redraw_all ();
00478         sb_message ("Opened file", FALSE);
00479 }
00480 
00481 void menu_set_player (gpointer *data, guint what, GtkWidget *widget)
00482 {
00483         /* the callback for a radio button appears to
00484            be called TWICE, once when selected and once when something else
00485            is selected. */
00486         
00487         if (!GTK_CHECK_MENU_ITEM(widget)->active)
00488                 return;
00489 
00490         if (what >= 1 && what <= 4)
00491                 if (opt_infile)
00492                 {
00493                         fclose (opt_infile);
00494                         opt_infile = NULL;
00495                 }
00496 
00497         ui_stopped = TRUE;
00498 
00499         switch (what)
00500         {
00501                 case 1:
00502                         ui_white = HUMAN;
00503                         ui_black = HUMAN;
00504                         break;
00505                 case 2:
00506                         ui_white = HUMAN;
00507                         ui_black = MACHINE;
00508                         break;
00509                 case 3:
00510                         ui_white = MACHINE;
00511                         ui_black = HUMAN;
00512                         break;
00513                 case 4:
00514                         ui_white = MACHINE;
00515                         ui_black = MACHINE;
00516                         break;
00517 
00518                 default:
00519                         ui_white = NONE;
00520                         ui_black = NONE;
00521                         break;
00522         }
00523 
00524         sb_update ();
00525 }
00526 
00527 void menu_save_file_dialog ()
00528 {
00529         sb_error ("Not yet implemented", TRUE);
00530 }
00531 
00532 void menu_load_file_dialog ()
00533 {
00534         if (game_single_player)
00535         {
00536                 sb_error ("Can't load from file for single player game.", FALSE);
00537                 return;
00538         }
00539         menu_selector = gtk_file_selection_new ("");
00540         g_assert (menu_selector);
00541         /*gtk_file_selection_complete (
00542                         GTK_FILE_SELECTION (menu_selector), "*.cbgf");*/
00543         
00544         gtk_signal_connect (GTK_OBJECT 
00545                 (GTK_FILE_SELECTION(menu_selector)->ok_button),
00546                 "clicked", GTK_SIGNAL_FUNC (menu_load_file), NULL);
00547                            
00548         gtk_signal_connect_object (GTK_OBJECT 
00549                 (GTK_FILE_SELECTION(menu_selector)->ok_button),
00550                 "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
00551                 (gpointer) menu_selector);
00552 
00553         gtk_signal_connect_object (
00554                 GTK_OBJECT (GTK_FILE_SELECTION(menu_selector)->cancel_button),
00555                 "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
00556                 (gpointer) menu_selector);
00557    
00558    gtk_widget_show (menu_selector);
00559 }
00560 
00561 void menu_show_game_doc (gpointer data, guint which)
00562 {
00563         GtkWidget *dialog, *msgarea, *okay_button, *vbar, *hbox, *scrwin;
00564         char *msgstr = "Nothing available"; // default
00565         char titlestr[64];
00566         switch (which)
00567         {
00568                 case MENU_DOC_ABOUT:
00569                         snprintf (titlestr, 64, "About %s - gtkboard", opt_game->name);
00570                         if (game_doc_about) msgstr = game_doc_about;
00571                         menu_show_dialog (titlestr, msgstr);
00572                         return;
00573                 case MENU_DOC_RULES:
00574                         snprintf (titlestr, 64, "%s rules - gtkboard", opt_game->name);
00575                         if (game_doc_rules) msgstr = game_doc_rules;
00576                         break;
00577                 case MENU_DOC_STRATEGY:
00578                         snprintf (titlestr, 64, "%s strategy - gtkboard", opt_game->name);
00579                         if (game_doc_strategy) msgstr = game_doc_strategy;
00580                         break;
00581                 default:
00582                         assert (0);
00583         }
00584 
00585         vbar = gtk_vscrollbar_new(NULL);
00586 #if GTK_MAJOR_VERSION == 1
00587         dialog = gtk_dialog_new();
00588         gtk_window_set_title (GTK_WINDOW (dialog), titlestr);
00589         hbox = gtk_hbox_new (FALSE, 0);
00590         msgarea = gtk_text_new (NULL, 
00591                         gtk_range_get_adjustment (GTK_RANGE (vbar)));
00592         gtk_text_set_word_wrap (GTK_TEXT (msgarea), TRUE);
00593         gtk_text_insert (GTK_TEXT (msgarea), NULL, NULL, NULL, msgstr, -1);
00594         gtk_box_pack_start (GTK_BOX (hbox), msgarea, TRUE, TRUE, 10);
00595         gtk_box_pack_start (GTK_BOX (hbox), vbar, FALSE, FALSE, 0);
00596         okay_button = gtk_button_new_with_label("  OK  ");
00597         gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked",
00598                         GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);
00599         gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area), 
00600                         okay_button, FALSE, FALSE, 0);
00601         gtk_widget_grab_focus (okay_button);    // contributed by Paddu
00602         gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), hbox);
00603 
00604 #else
00605         dialog = gtk_dialog_new_with_buttons (titlestr, GTK_WINDOW (main_window),
00606                         0, GTK_STOCK_OK, GTK_RESPONSE_NONE, NULL);
00607         gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 300);
00608         g_signal_connect_swapped (GTK_OBJECT (dialog),
00609                         "response", G_CALLBACK (gtk_widget_destroy),
00610                         GTK_OBJECT (dialog));
00611         msgarea = gtk_text_view_new ();
00612         gtk_text_view_set_editable (GTK_TEXT_VIEW (msgarea), FALSE);
00613         gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (msgarea), GTK_WRAP_WORD);
00614         gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (msgarea), FALSE);
00615         gtk_text_buffer_set_text (gtk_text_view_get_buffer 
00616                         (GTK_TEXT_VIEW (msgarea)), msgstr, -1);
00617         scrwin = gtk_scrolled_window_new (NULL,
00618                 gtk_range_get_adjustment (GTK_RANGE(vbar)));
00619         gtk_container_add (GTK_CONTAINER (scrwin), msgarea);
00620         gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), scrwin);
00621 #endif
00622         gtk_widget_show_all (dialog);
00623 }
00624 
00625 void menu_start_game ()
00626 {
00627         ui_start_game ();
00628         
00629         {
00630         int i;
00631         GtkItemFactoryEntry help_items [3];
00632         help_items[0].path = g_strdup_printf ("/Help/%s", opt_game->name);
00633         help_items[0].accelerator = NULL;
00634         help_items[0].callback = NULL;
00635         help_items[0].item_type = "<Branch>";
00636         gtk_item_factory_create_item (menu_factory, help_items, NULL, 1);
00637         
00638         help_items[0].path = g_strdup_printf ("/Help/%s/_About", opt_game->name); 
00639         help_items[0].callback_action = MENU_DOC_ABOUT;
00640         help_items[1].path = g_strdup_printf ("/Help/%s/_Rules", opt_game->name); 
00641         help_items[1].callback_action = MENU_DOC_RULES;
00642         help_items[2].path = g_strdup_printf ("/Help/%s/_Strategy", opt_game->name); 
00643         help_items[2].callback_action = MENU_DOC_STRATEGY;
00644         for (i=0; i<3; i++)
00645         {
00646                 help_items[i].accelerator = NULL;
00647                 help_items[i].callback = menu_show_game_doc;
00648                 help_items[i].item_type = "";
00649         }
00650         gtk_item_factory_create_items (menu_factory, 
00651                         3, help_items, NULL);
00652         }
00653         gtk_label_set_text (GTK_LABEL (sb_game_label), opt_game->name);
00654 }
00655 
00656 void menu_set_game (gpointer data, guint which, GtkWidget *widget)
00657 {
00658         gchar *tempstr;
00659         if (!GTK_CHECK_MENU_ITEM(widget)->active)
00660                 return;
00661         if (!state_gui_active)
00662                 return;
00663         g_assert (which >= 0 && which < num_games);
00664         
00665         if (opt_game)
00666         {
00667                 // FIXME: do we need to delete recursively?
00668                 gtk_item_factory_delete_item (menu_factory, 
00669                                 tempstr = g_strdup_printf ("/Help/%s", opt_game->name));
00670                 g_free (tempstr);
00671         }
00672 
00673         if (opt_game)
00674                 ui_terminate_game ();
00675         opt_game = games[which];
00676         menu_start_game ();
00677         sb_update ();
00678 }
00679 
00680 
00681 void menu_set_delay_cb (gpointer data, guint delay, GtkWidget *widget)
00682 {
00683         if (!GTK_CHECK_MENU_ITEM(widget)->active)
00684                 return;
00685         if (move_fout)
00686         {
00687                 fprintf (move_fout, "MSEC_PER_MOVE %d\n", opt_delay = delay);
00688                 fflush (move_fout);
00689         }
00690 }
00691 
00692 
00693 void menu_back_forw (gpointer data, guint what)
00694 {
00695         byte *move;
00696         switch (what)
00697         {
00698                 case MENU_BACK:
00699                         if (!game_allow_back_forw) break;
00700                         if (!opt_game) break;
00701                         if (!game_allow_undo)
00702                                 ui_stopped = TRUE;
00703                         if (move_fout)
00704                         {
00705                                 fprintf (move_fout, "BACK_MOVE \n");
00706                                 fflush (move_fout);
00707                         }
00708                         move = move_fread_ack (move_fin);
00709                         if (!move)
00710                         {
00711                                 sb_error ("Initial position. Can't go back.", FALSE);
00712                                 break;
00713                         }
00714                         board_apply_refresh (move, NULL);
00715                         if (!game_single_player)
00716                                 cur_pos.player = (cur_pos.player == WHITE ? BLACK : WHITE);
00717                         cur_pos.num_moves --;
00718                         if (game_single_player && !game_allow_undo)
00719                         {
00720                                 if (!ui_cheated && game_scorecmp)
00721                                         sb_message ("You cheated! No highscore for this game.", FALSE);
00722                                 ui_cheated = TRUE;
00723                         }
00724                         // FIXME: there should be only one round of communication 
00725                         // in which client gets both the move and who_won
00726                         ui_check_who_won ();
00727                         if (game_reset_uistate) game_reset_uistate();
00728                         sb_update ();
00729                         break;
00730                 case MENU_FORW:
00731                         if (!game_allow_back_forw) break;
00732                         if (!opt_game) break;
00733                         if (move_fout)
00734                         {
00735                                 fprintf (move_fout, "FORW_MOVE \n");
00736                                 fflush (move_fout);
00737                         }
00738                         move = move_fread_ack (move_fin);
00739                         if (!move)
00740                         {
00741                                 sb_error ("Final position. Can't go forward.", FALSE);
00742                                 break;
00743                         }
00744                         board_apply_refresh (move, NULL);
00745                         if (!game_single_player)
00746                                 cur_pos.player = (cur_pos.player == WHITE ? BLACK : WHITE);
00747                         cur_pos.num_moves ++;
00748                         ui_check_who_won ();
00749                         if (game_reset_uistate) game_reset_uistate();
00750                         sb_update ();
00751                         break;
00752                 default:
00753                         assert (0);
00754         }
00755 }
00756 
00758 void menu_set_eval_function ()
00759 {
00760         int i;
00761         GtkWidget *menu, *menuitem;
00762         GtkItemFactoryEntry heur_item;
00763         static HeurTab *oldtab = NULL;
00764         char *colors[2], **color, pathbuf[64];
00765         return;
00766         colors[0] = game_white_string;
00767         colors[1] = game_black_string;
00768         for (color = colors; color <= colors+1; color++)
00769         {
00770                 if (oldtab)
00771                 for (i=0; oldtab[i].name; i++)
00772                 {
00773                         char *path = g_strdup_printf ("/Settings/Eval function/%s/%s",
00774                                 *color, oldtab[i].name);
00775                         gtk_item_factory_delete_item (menu_factory, path);
00776                         g_free (path);
00777                 }
00778                 if (game_htab)
00779                 for (i=0; game_htab[i].name; i++)
00780                 {
00781                         heur_item.path = g_strdup_printf ("/Settings/Eval function/%s/%s", 
00782                                         *color, game_htab[i].name);
00783                         if (i == 0) strncpy (pathbuf, heur_item.path, 63);
00784                         heur_item.accelerator = NULL;
00785                         heur_item.callback = NULL;
00786                         heur_item.callback_action = 0;
00787                         heur_item.item_type = (i == 0 ? "<RadioItem>" : pathbuf);
00788                         gtk_item_factory_create_item (menu_factory, &heur_item, NULL, 1);
00789                         g_free (heur_item.path);
00790                 }
00791         }
00792         oldtab = game_htab;
00793 }
00794         
00795 void sb_error (char *msg, gboolean serious)
00796 {
00797         if (!state_gui_active)
00798         {
00799                 fprintf (stderr, "Fatal error: %s\n", msg);
00800                 exit (2);
00801         }
00802         if (serious)
00803                 menu_show_dialog ("Error - gtkboard", msg);
00804         else
00805                 sb_messagebar_message (msg);
00806 }
00807 
00808 void sb_message (char *msg, gboolean serious)
00809 {
00810         if (!state_gui_active)
00811                 fprintf (stderr, "%s\n", msg);
00812         else
00813                 sb_error (msg, serious);
00814 }
00815 
00816 gchar *sb_ftime(int temps)
00817 {
00818         static gchar ftime[10] = "  :  : ";
00819         ftime[6] = temps % 10 + '0';
00820         temps /= 10;
00821         ftime[4] = temps % 10 + '0';
00822         temps /= 10;
00823         ftime[3] = temps % 6 + '0';
00824         temps /= 6;
00825         ftime[1] = temps % 10 + '0';
00826         temps /= 10;
00827         ftime[0] = temps % 6 + '0';
00828         temps /= 6;
00829         return ftime;
00830 }
00831 
00832 static int sb_human_time = 0;
00833 
00834 void sb_reset_human_time ()
00835 {
00836         gchar *tempstr;
00837         sb_human_time = 0;
00838         if (!state_gui_active)
00839                 return;
00840         gtk_label_set_text (GTK_LABEL(sb_time_label), tempstr
00841                          = g_strdup_printf ("Time:%s", sb_ftime(sb_human_time)));
00842         g_free (tempstr);
00843 }
00844 
00845 int sb_get_human_time ()
00846 {
00847         return sb_human_time;
00848 }
00849 
00850 static int sb_last_msg_time = -1;
00851 
00852 void sb_messagebar_message (gchar *msg)
00853 {
00854         sb_last_msg_time = 0;
00855         strncpy (sb_message_str, msg, SB_MESSAGE_STRLEN-1);
00856         sb_update ();
00857 }
00858 
00859 void menu_update ()
00860         // first call all the sens and then all the desens
00861 {
00862         // FIXME: isn't there a more elegant way to do this?
00863         gboolean machine_thinking, machine_not_thinking,
00864                 no_game, single_player, two_players,
00865                 no_back_forw, eval_fn;
00866         machine_thinking = (!ui_stopped && player_to_play == MACHINE);
00867         machine_not_thinking = !machine_thinking;
00868         no_game = opt_game ? FALSE : TRUE;
00869         single_player = game_single_player;
00870         two_players = !single_player;
00871         no_back_forw = !game_allow_back_forw;
00872         eval_fn = game_htab ? FALSE : TRUE;
00873 
00874         if (!machine_thinking) menu_sensitize (MENU_SENS_MACHINE_THINKING, TRUE);
00875         if (!machine_not_thinking) menu_sensitize (MENU_SENS_MACHINE_NOT_THINKING, TRUE);
00876         if (!no_game) menu_sensitize (MENU_SENS_NO_GAME, TRUE);
00877         if (!single_player) menu_sensitize (MENU_SENS_SINGLE_PLAYER, TRUE);
00878         if (!two_players) menu_sensitize (MENU_SENS_TWO_PlayerS, TRUE);
00879         if (!no_back_forw) menu_sensitize (MENU_SENS_NO_BACK_FORW, TRUE);
00880         if (!ui_stopped) menu_sensitize (MENU_SENS_UI_STOPPED, TRUE);
00881         if (!eval_fn) menu_sensitize (MENU_SENS_EVAL_FUNCTION, TRUE);
00882 
00883         if (machine_thinking) menu_sensitize (MENU_SENS_MACHINE_THINKING, FALSE);
00884         if (machine_not_thinking) menu_sensitize (MENU_SENS_MACHINE_NOT_THINKING, FALSE);
00885         if (no_game) menu_sensitize (MENU_SENS_NO_GAME, FALSE);
00886         if (single_player) menu_sensitize (MENU_SENS_SINGLE_PLAYER, FALSE);
00887         if (two_players) menu_sensitize (MENU_SENS_TWO_PlayerS, FALSE);
00888         if (no_back_forw) menu_sensitize (MENU_SENS_NO_BACK_FORW, FALSE);
00889         if (ui_stopped) menu_sensitize (MENU_SENS_UI_STOPPED, FALSE);
00890         if (eval_fn) menu_sensitize (MENU_SENS_EVAL_FUNCTION, FALSE);
00891                 
00892 }
00893         
00894 void sb_update ()
00895 {
00896         char player[5] = "?/?";
00897         if (!state_gui_active) return;
00898         menu_update ();
00899         if (game_single_player)
00900         {
00901                 gtk_widget_hide (sb_player_label);
00902                 gtk_widget_hide (sb_who_label);
00903                 gtk_widget_hide (sb_player_separator);
00904                 gtk_widget_hide (sb_who_separator);
00905                 gtk_widget_show (sb_time_separator);
00906                 gtk_widget_show (sb_time_label);
00907         }
00908         else
00909         {
00910                 gtk_widget_show (sb_player_label);
00911                 gtk_widget_show (sb_who_label);
00912                 gtk_widget_show (sb_player_separator);
00913                 gtk_widget_show (sb_who_separator);
00914                 gtk_widget_hide (sb_time_separator);
00915                 gtk_widget_hide (sb_time_label);
00916                 if (ui_white == HUMAN) player[0] = 'H';
00917                 if (ui_white == MACHINE) player[0] = 'M';
00918                 if (ui_black == HUMAN) player[2] = 'H';
00919                 if (ui_black == MACHINE) player[2] = 'M';
00920                 gtk_label_set_text (GTK_LABEL(sb_player_label), 
00921                                 ui_white != NONE ? player : "File");
00922                 gtk_label_set_text (GTK_LABEL(sb_who_label), cur_pos.player == WHITE ? 
00923                                 game_white_string : game_black_string);
00924         }
00925         gtk_label_set_text (GTK_LABEL(sb_score_label), sb_score_str);
00926         sb_set_turn_image();
00927         sb_set_cursor ();
00928 }
00929 
00930 gboolean sb_update_periodic ()
00931 {
00932         static gboolean first = TRUE;
00933         if (!state_gui_active) return TRUE;
00934         if (sb_message_str[0] != '\0' && sb_last_msg_time < 0)
00935                 sb_last_msg_time = 0;
00936         if (sb_message_str[0] == '\0') sb_last_msg_time = -1;
00937         if (sb_last_msg_time >= 0) sb_last_msg_time++;
00938         if (sb_last_msg_time >= 30)
00939                 sb_message_str[0] = '\0';
00940         gtk_label_set_text (GTK_LABEL(sb_message_label), sb_message_str);
00941         {
00942         gchar *tempstr = NULL;
00943         if (!ui_stopped && (player_to_play == HUMAN))
00944                 gtk_label_set_text (GTK_LABEL(sb_time_label),
00945                          tempstr = g_strdup_printf ("Time:%s", sb_ftime(sb_human_time++)));
00946         if (first)
00947                 gtk_label_set_text (GTK_LABEL(sb_time_label),
00948                          tempstr = g_strdup_printf ("Time:%s", sb_ftime(sb_human_time)));
00949         if (tempstr) g_free (tempstr);
00950         }
00951         first = FALSE;
00952         return TRUE;
00953 }