/* * gtkoptions.c * * by Joern Thyssen , 2003 * * This program is free software; you can redistribute it and/or modify * it under the terms of version 3 or later of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: gtkoptions.c,v 1.119 2016/01/31 12:56:01 plm Exp $ */ #include "config.h" #include "gtklocdefs.h" #include #include #include #include #include #include "backgammon.h" #include "eval.h" #include "dice.h" #include "gtkgame.h" #include "gtkfile.h" #include "sound.h" #include "drawboard.h" #include "matchequity.h" #include "format.h" #include "gtkboard.h" #include "renderprefs.h" #include "gtkwindows.h" #include "openurl.h" #if defined(USE_BOARD3D) #include "fun3d.h" #endif #include "multithread.h" #include "gtkoptions.h" #include "gtkrelational.h" typedef struct _optionswidget { GtkWidget *pwNoteBook; GtkWidget *pwAutoBearoff; GtkWidget *pwAutoCrawford; GtkWidget *pwAutoGame; GtkWidget *pwAutoMove; GtkWidget *pwAutoRoll; GtkWidget *pwTutor; GtkWidget *pwTutorCube; GtkWidget *pwTutorChequer; GtkWidget *pwTutorSkill; GtkAdjustment *padjCubeBeaver; GtkAdjustment *padjCubeAutomatic; GtkAdjustment *padjLength; GtkWidget *pwCubeUsecube; GtkWidget *pwCubeJacoby; GtkWidget *pwCubeInvert; GtkWidget *pwGameClockwise; GtkWidget *apwVariations[NUM_VARIATIONS]; GtkWidget *pwOutputMWC; GtkWidget *pwOutputGWC; GtkWidget *pwOutputMWCpst; GtkWidget *pwConfStart; GtkWidget *pwConfOverwrite; GtkWidget *apwDice[NUM_RNGS]; GtkWidget *pwRngComboBox; GtkWidget *pwBeavers; GtkWidget *pwBeaversLabel; GtkWidget *pwAutomatic; GtkWidget *pwAutomaticLabel; GtkWidget *pwMETFrame; GtkWidget *pwLoadMET; GtkWidget *pwSeed; GtkWidget *pwRecordGames; GtkWidget *pwDisplay; GtkAdjustment *padjCache; GtkAdjustment *padjDelay; GtkAdjustment *padjSeed; GtkAdjustment *padjThreads; GtkWidget *pwAutoSaveTime; GtkWidget *pwAutoSaveRollout; GtkWidget *pwAutoSaveAnalysis; GtkWidget *pwAutoSaveConfirmDelete; GtkWidget *pwIllegal; GtkWidget *pwUseDiceIcon; GtkWidget *pwShowIDs; GtkWidget *pwShowPips; GtkWidget *pwShowEPCs; GtkWidget *pwShowWastage; GtkWidget *pwAnimateNone; GtkWidget *pwAnimateBlink; GtkWidget *pwAnimateSlide; GtkWidget *pwHigherDieFirst; GtkWidget *pwGrayEdit; GtkWidget *pwSetWindowPos; GtkWidget *pwDragTargetHelp; GtkAdjustment *padjSpeed; GtkWidget *pwCheat; GtkWidget *pwCheatRollBox; GtkWidget *apwCheatRoll[2]; GtkWidget *pwGotoFirstGame; GtkWidget *pwGameListStyles; GtkWidget *pwDefaultSGFFolder; GtkWidget *pwDefaultImportFolder; GtkWidget *pwDefaultExportFolder; GtkWidget *pwWebBrowser; GtkAdjustment *padjDigits; GtkWidget *pwDigits; int fChanged; } optionswidget; typedef struct _SoundDetail { char *Path; } SoundDetail; static SoundDetail soundDetails[NUM_SOUNDS]; static GtkWidget *soundFrame; static GtkWidget *soundEnabled; static GtkWidget *soundPath; static GtkWidget *soundPathButton; static GtkWidget *soundPlayButton; static GtkWidget *soundAllDefaultButton; static GtkWidget *soundDefaultButton; static GtkWidget *soundBeepIllegal; static GtkWidget *soundsEnabled; static GtkWidget *soundList; static GtkWidget *pwSoundCommand; static gnubgsound selSound; static int SoundSkipUpdate; static int relPage, relPageActivated; static void SeedChanged(GtkWidget * UNUSED(pw), int *pf) { *pf = 1; } static void UseCubeToggled(GtkWidget * UNUSED(pw), optionswidget * pow) { gint n = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pow->pwCubeUsecube)); gtk_widget_set_sensitive(pow->pwCubeJacoby, n); gtk_widget_set_sensitive(pow->pwBeavers, n); gtk_widget_set_sensitive(pow->pwAutomatic, n); gtk_widget_set_sensitive(pow->pwBeaversLabel, n); gtk_widget_set_sensitive(pow->pwAutomaticLabel, n); gtk_widget_set_sensitive(pow->pwAutoCrawford, n); } static void DiceToggled(GtkWidget * UNUSED(pw), optionswidget * pow) { gint n = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pow->apwDice[0])); gint m = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pow->pwCheat)); gtk_widget_set_sensitive(pow->pwRngComboBox, n); gtk_widget_set_sensitive(pow->pwSeed, n); gtk_widget_set_sensitive(pow->pwCheatRollBox, m); } static void TutorToggled(GtkWidget * UNUSED(pw), optionswidget * pow) { gint n = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pow->pwTutor)); gtk_widget_set_sensitive(pow->pwTutorCube, n); gtk_widget_set_sensitive(pow->pwTutorChequer, n); gtk_widget_set_sensitive(pow->pwTutorSkill, n); } static void ToggleAnimation(GtkWidget * pw, GtkWidget * pwSpeed) { gtk_widget_set_sensitive(pwSpeed, !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pw))); } static char *aszTutor[] = { N_("Doubtful"), N_("Bad"), N_("Very bad"), NULL }; static void SoundDefaultClicked(GtkWidget * UNUSED(widget), gpointer UNUSED(userdata)) { char *defaultSound = GetDefaultSoundFile(selSound); SoundSkipUpdate = TRUE; gtk_entry_set_text(GTK_ENTRY(soundPath), defaultSound); g_free(soundDetails[selSound].Path); soundDetails[selSound].Path = defaultSound; } static void SoundAllDefaultClicked(GtkWidget * UNUSED(widget), gpointer UNUSED(userdata)) { gnubgsound i; for (i = (gnubgsound)0; i < NUM_SOUNDS; i++) { g_free(soundDetails[i].Path); soundDetails[i].Path = GetDefaultSoundFile(i); } SoundDefaultClicked(NULL, NULL); } static void SoundEnabledClicked(GtkWidget * UNUSED(widget), gpointer UNUSED(userdata)) { int enabled; if (!gtk_widget_get_realized(soundEnabled) || !gtk_widget_get_sensitive(soundEnabled)) return; enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(soundEnabled)); gtk_widget_set_sensitive(soundPath, enabled); gtk_widget_set_sensitive(soundPathButton, enabled); gtk_widget_set_sensitive(soundPlayButton, enabled); gtk_widget_set_sensitive(soundDefaultButton, enabled); if (!enabled) { g_free(soundDetails[selSound].Path); soundDetails[selSound].Path = g_strdup(""); } else if (!*soundDetails[selSound].Path) SoundDefaultClicked(0, 0); } static void SoundGrabFocus(GtkWidget * UNUSED(pw), void *UNUSED(dummy)) { gtk_widget_grab_focus(soundList); SoundEnabledClicked(0, 0); } static void SoundToggled(GtkWidget * UNUSED(pw), optionswidget * UNUSED(pow)) { int enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(soundsEnabled)); gtk_widget_set_sensitive(soundFrame, enabled); gtk_widget_set_sensitive(soundList, enabled); gtk_widget_set_sensitive(soundEnabled, enabled); gtk_widget_set_sensitive(soundPath, enabled); gtk_widget_set_sensitive(soundPathButton, enabled); gtk_widget_set_sensitive(soundPlayButton, enabled); gtk_widget_set_sensitive(soundDefaultButton, enabled); if (enabled) SoundGrabFocus(0, 0); } static void SoundSelected(GtkTreeView * treeview, gpointer UNUSED(userdata)) { GtkTreePath *path; gtk_tree_view_get_cursor(GTK_TREE_VIEW(treeview), &path, NULL); selSound = (gnubgsound) gtk_tree_path_get_indices(path)[0]; gtk_frame_set_label(GTK_FRAME(soundFrame), sound_description[selSound]); SoundSkipUpdate = TRUE; gtk_entry_set_text(GTK_ENTRY(soundPath), soundDetails[selSound].Path); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(soundEnabled), (*soundDetails[selSound].Path) ? TRUE : FALSE); } static void SoundTidy(GtkWidget * UNUSED(pw), void *UNUSED(dummy)) { unsigned int i; for (i = 0; i < NUM_SOUNDS; i++) { /* Tidy allocated memory */ g_free(soundDetails[i].Path); } } static void PathChanged(GtkWidget * widget, gpointer UNUSED(userdata)) { if (!SoundSkipUpdate) { g_free(soundDetails[selSound].Path); soundDetails[selSound].Path = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1); } else SoundSkipUpdate = FALSE; } static void SoundChangePathClicked(GtkWidget * UNUSED(widget), gpointer UNUSED(userdata)) { static char *lastSoundFolder = NULL; char *filename = GTKFileSelect(_("Select soundfile"), "*.wav", lastSoundFolder, NULL, GTK_FILE_CHOOSER_ACTION_OPEN); if (filename) { lastSoundFolder = g_path_get_dirname(filename); SoundSkipUpdate = TRUE; gtk_entry_set_text(GTK_ENTRY(soundPath), filename); g_free(soundDetails[selSound].Path); soundDetails[selSound].Path = filename; } } static void SoundPlayClicked(GtkWidget * UNUSED(widget), gpointer UNUSED(userdata)) { playSoundFile(soundDetails[selSound].Path, TRUE); } static gchar * CacheSizeString(GtkScale * UNUSED(scale), gdouble value) { return g_strdup_printf("%iMB", GetCacheMB((int)value)); } static void append_game_options(optionswidget * pow) { GtkWidget *pwp; GtkWidget *pwvbox; GtkWidget *pwf; GtkWidget *pwb; unsigned int i; static char *aszVariationsTooltips[NUM_VARIATIONS] = { N_("Use standard backgammon starting position"), N_("Use Nick \"Nack\" Ballard's Nackgammon starting position with " "standard rules."), N_("Play 1-chequer hypergammon (i.e., gammon and backgammons possible)"), N_("Play 2-chequer hypergammon (i.e., gammon and backgammons possible)"), N_("Play 3-chequer hypergammon (i.e., gammon and backgammons possible)") }; /* Game options */ pwp = gtk_alignment_new(0, 0, 0, 0); gtk_container_set_border_width(GTK_CONTAINER(pwp), 4); gtk_notebook_append_page(GTK_NOTEBOOK(pow->pwNoteBook), pwp, gtk_label_new(_("Game"))); pwvbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(pwp), pwvbox); pow->pwAutoGame = gtk_check_button_new_with_label(_("Start new games immediately")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwAutoGame, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwAutoGame, _("Whenever a game is complete, automatically " "start another one in the same match or session.")); pow->pwAutoRoll = gtk_check_button_new_with_label(_("Roll the dice automatically")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwAutoRoll, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwAutoRoll, _("On a human player's turn, if they are not " "permitted to double, then roll the dice immediately.")); pow->pwAutoMove = gtk_check_button_new_with_label(_("Play forced moves automatically")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwAutoMove, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwAutoMove, _("On a human player's turn, if there are no " "legal moves or only one legal move, then " "finish their turn for them.")); pow->pwAutoBearoff = gtk_check_button_new_with_label(_("Play bearoff moves automatically")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwAutoBearoff, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwAutoBearoff, _("On a human player's turn in a " "non-contact bearoff, if there is an " "unambiguous move which bears off as " "many chequers as possible, then " "choose that move automatically.")); pow->pwIllegal = gtk_check_button_new_with_label(_("Allow dragging to illegal points")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwIllegal), fGUIIllegal); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwIllegal, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwIllegal, _("If set, when considering your move " "you may temporarily move chequers onto " "points which cannot be reached with " "the current dice roll. If unset, you " "may move chequers only onto legal " "points. Either way, the resulting " "move must be legal when you pick up " "the dice, or it will not be accepted.")); pwf = gtk_frame_new(_("Variations")); gtk_box_pack_start(GTK_BOX(pwvbox), pwf, FALSE, FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(pwf), 4); pwb = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(pwf), pwb); for (i = 0; i < NUM_VARIATIONS; ++i) { pow->apwVariations[i] = i ? gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON (pow->apwVariations[0]), gettext(aszVariations[i])) : gtk_radio_button_new_with_label(NULL, gettext(aszVariations[i])); gtk_box_pack_start(GTK_BOX(pwb), pow->apwVariations[i], FALSE, FALSE, 0); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->apwVariations[i]), bgvDefault == (bgvariation) i); gtk_widget_set_tooltip_text(pow->apwVariations[i], gettext(aszVariationsTooltips[i])); } /* disable entries if hypergammon databases are not available */ for (i = 0; i < 3; ++i) gtk_widget_set_sensitive(GTK_WIDGET(pow->apwVariations[i + VARIATION_HYPERGAMMON_1]), apbcHyper[i] != NULL); } static void append_cube_options(optionswidget * pow) { GtkWidget *pwp; GtkWidget *pwvbox; GtkWidget *pwev; GtkWidget *pwhbox; /* Cube options */ pwp = gtk_alignment_new(0, 0, 0, 0); gtk_container_set_border_width(GTK_CONTAINER(pwp), 4); gtk_notebook_append_page(GTK_NOTEBOOK(pow->pwNoteBook), pwp, gtk_label_new(_("Cube"))); pwvbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(pwp), pwvbox); pow->pwCubeUsecube = gtk_check_button_new_with_label(_("Use doubling cube")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwCubeUsecube, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwCubeUsecube, _("When the doubling cube is used, under certain " "conditions players may offer to raise the stakes " "of the game by using the \"double\" command.")); g_signal_connect(G_OBJECT(pow->pwCubeUsecube), "toggled", G_CALLBACK(UseCubeToggled), pow); pow->pwAutoCrawford = gtk_check_button_new_with_label(_("Use Crawford rule")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwAutoCrawford, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwAutoCrawford, _("In match play, the Crawford rule specifies that " "if either player reaches match point (i.e. is " "one point away from winning the match), then " "the doubling cube may not be used for the next " "game only.")); pow->pwCubeJacoby = gtk_check_button_new_with_label(_("Use Jacoby rule")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwCubeJacoby, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwCubeJacoby, _("Under the Jacoby rule, players may not score " "double or triple for a gammon or backgammon " "unless the cube has been doubled and accepted. " "The Jacoby rule is only ever used in money " "games, not matches.")); pwev = gtk_event_box_new(); gtk_event_box_set_visible_window(GTK_EVENT_BOX(pwev), FALSE); gtk_box_pack_start(GTK_BOX(pwvbox), pwev, FALSE, FALSE, 0); pwhbox = gtk_hbox_new(FALSE, 4); gtk_container_add(GTK_CONTAINER(pwev), pwhbox); pow->pwBeaversLabel = gtk_label_new(_("Maximum number of beavers:")); gtk_box_pack_start(GTK_BOX(pwhbox), pow->pwBeaversLabel, FALSE, FALSE, 0); pow->padjCubeBeaver = GTK_ADJUSTMENT(gtk_adjustment_new(1, 0, 12, 1, 1, 0)); pow->pwBeavers = gtk_spin_button_new(GTK_ADJUSTMENT(pow->padjCubeBeaver), 1, 0); gtk_box_pack_start(GTK_BOX(pwhbox), pow->pwBeavers, TRUE, TRUE, 0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(pow->pwBeavers), TRUE); gtk_widget_set_tooltip_text(pwev, _("When doubled, a player may \"beaver\" (instantly " "redouble). This option allows you to specify " "how many consecutive redoubles are permitted. " "Beavers are only ever used in money games, not " "matches.")); pwev = gtk_event_box_new(); gtk_event_box_set_visible_window(GTK_EVENT_BOX(pwev), FALSE); gtk_box_pack_start(GTK_BOX(pwvbox), pwev, FALSE, FALSE, 0); pwhbox = gtk_hbox_new(FALSE, 4); gtk_container_add(GTK_CONTAINER(pwev), pwhbox); pow->pwAutomaticLabel = gtk_label_new(_("Maximum automatic doubles:")); gtk_box_pack_start(GTK_BOX(pwhbox), pow->pwAutomaticLabel, FALSE, FALSE, 0); pow->padjCubeAutomatic = GTK_ADJUSTMENT(gtk_adjustment_new(0, 0, 12, 1, 1, 0)); pow->pwAutomatic = gtk_spin_button_new(GTK_ADJUSTMENT(pow->padjCubeAutomatic), 1, 0); gtk_box_pack_start(GTK_BOX(pwhbox), pow->pwAutomatic, TRUE, TRUE, 0); gtk_widget_set_tooltip_text(pwev, _("If the opening roll is a double, the players " "may choose to increase the cube value and " "reroll (an \"automatic double\"). This option " "allows you to control how many automatic doubles " "may be applied. Automatic doubles are only " "ever used in money games, not matches.")); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(pow->pwAutomatic), TRUE); } static void append_tutor_options(optionswidget * pow) { GtkWidget *pwp; GtkWidget *pwvbox; GtkWidget *pwf; GtkWidget *pwev; GtkWidget *pwhbox; char **ppch; /* Tutor options */ pwp = gtk_alignment_new(0, 0, 0, 0); gtk_container_set_border_width(GTK_CONTAINER(pwp), 4); gtk_notebook_append_page(GTK_NOTEBOOK(pow->pwNoteBook), pwp, gtk_label_new(_("Tutor"))); pwf = gtk_frame_new(NULL); gtk_container_add(GTK_CONTAINER(pwp), pwf); pwvbox = gtk_vbox_new(FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(pwvbox), 6); gtk_container_add(GTK_CONTAINER(pwf), pwvbox); pow->pwTutor = gtk_check_button_new_with_label(_("Tutor mode")); gtk_frame_set_label_widget(GTK_FRAME(pwf), pow->pwTutor); gtk_widget_set_tooltip_text(pow->pwTutor, _("When using the tutor, GNU Backgammon will " "analyse your decisions during play and prompt " "you if it thinks you are making a mistake.")); g_signal_connect(G_OBJECT(pow->pwTutor), "toggled", G_CALLBACK(TutorToggled), pow); pow->pwTutorCube = gtk_check_button_new_with_label(_("Cube Decisions")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwTutorCube, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwTutorCube, _("Use the tutor for cube decisions.")); pow->pwTutorChequer = gtk_check_button_new_with_label(_("Chequer play")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwTutorChequer, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwTutorChequer, _("Use the tutor for chequer play decisions.")); pwev = gtk_event_box_new(); gtk_event_box_set_visible_window(GTK_EVENT_BOX(pwev), FALSE); gtk_box_pack_start(GTK_BOX(pwvbox), pwev, FALSE, FALSE, 4); pwhbox = gtk_hbox_new(FALSE, 4); gtk_container_add(GTK_CONTAINER(pwev), pwhbox); gtk_box_pack_start(GTK_BOX(pwhbox), gtk_label_new(_("Warning level:")), FALSE, FALSE, 0); pow->pwTutorSkill = gtk_combo_box_text_new(); gtk_box_pack_start(GTK_BOX(pwhbox), pow->pwTutorSkill, FALSE, FALSE, 0); for (ppch = aszTutor; *ppch; ppch++) { gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(pow->pwTutorSkill), gettext(*ppch)); } g_assert(nTutorSkillCurrent >= 0 && nTutorSkillCurrent <= 2); gtk_widget_set_tooltip_text(pwev, _("Specify how bad GNU Backgammon must think a " "decision is before questioning you about a " "possible mistake.")); gtk_widget_set_sensitive(pow->pwTutorSkill, fTutor); gtk_widget_set_sensitive(pow->pwTutorCube, fTutor); gtk_widget_set_sensitive(pow->pwTutorChequer, fTutor); } static void append_display_options(optionswidget * pow) { GtkWidget *pwp; GtkWidget *pwvbox; GtkWidget *pwev; GtkWidget *pwhbox; GtkWidget *pw; GtkWidget *pwAnimBox; GtkWidget *pwFrame; GtkWidget *pwBox; GtkWidget *pwSpeed; GtkWidget *pwScale; BoardData *bd = BOARD(pwBoard)->board_data; /* Display options */ pwp = gtk_alignment_new(0, 0, 0, 0); gtk_container_set_border_width(GTK_CONTAINER(pwp), 4); gtk_notebook_append_page(GTK_NOTEBOOK(pow->pwNoteBook), pwp, gtk_label_new(_("Display"))); pwvbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(pwp), pwvbox); pow->pwGameClockwise = gtk_check_button_new_with_label(_("Clockwise movement")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwGameClockwise, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwGameClockwise, _("Orient up the board so that player 1's chequers " "advance clockwise (and player 0 moves " "anticlockwise). Otherwise, player 1 moves " "anticlockwise and player 0 moves clockwise.")); pwev = gtk_event_box_new(); gtk_event_box_set_visible_window(GTK_EVENT_BOX(pwev), FALSE); gtk_box_pack_start(GTK_BOX(pwvbox), pwev, FALSE, FALSE, 0); pwhbox = gtk_hbox_new(FALSE, 4); gtk_container_add(GTK_CONTAINER(pwev), pwhbox); gtk_box_pack_start(GTK_BOX(pwhbox), gtk_label_new(_("Move delay:")), FALSE, FALSE, 0); pow->padjDelay = GTK_ADJUSTMENT(gtk_adjustment_new(nDelay, 0, 3000, 1, 10, 0)); pw = gtk_spin_button_new(GTK_ADJUSTMENT(pow->padjDelay), 1, 0); gtk_box_pack_start(GTK_BOX(pwhbox), pw, TRUE, TRUE, 0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(pw), TRUE); gtk_box_pack_start(GTK_BOX(pwhbox), gtk_label_new(_("ms")), FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pwev, _("Set a delay so that GNU Backgammon " "will pause between each move, to give you a " "chance to see it.")); pow->pwUseDiceIcon = gtk_check_button_new_with_label(_("Show dice below board when human player on roll")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwUseDiceIcon), bd->rd->fDiceArea); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwUseDiceIcon, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwUseDiceIcon, _("When it is your turn to roll, a pair of dice " "will be shown below the board, and you can " "click on them to roll. Even if you choose not " "to show the dice, you can always roll by " "clicking the area in the middle of the board " "where the dice will land.")); pow->pwShowIDs = gtk_check_button_new_with_label(_("Show Position ID in status bar")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwShowIDs), fShowIDs); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwShowIDs, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwShowIDs, _("One entry field will be shown above the board, " "which can be useful for recording, entering and " "exchanging board positions and match situations.")); pwhbox = gtk_hbox_new(FALSE, 2); pow->pwShowPips = gtk_combo_box_text_new(); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(pow->pwShowPips), _("None")); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(pow->pwShowPips), _("Pips")); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(pow->pwShowPips), _("Pips or EPC")); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(pow->pwShowPips), _("Pips and EPC")); gtk_combo_box_set_active(GTK_COMBO_BOX(pow->pwShowPips), gui_show_pips); gtk_box_pack_start(GTK_BOX(pwhbox), gtk_label_new(_("Show Pips")), FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(pwhbox), pow->pwShowPips, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(pwvbox), pwhbox, FALSE, FALSE, 0); pwAnimBox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(pwvbox), pwAnimBox, FALSE, FALSE, 0); pwFrame = gtk_frame_new(_("Animation")); gtk_box_pack_start(GTK_BOX(pwAnimBox), pwFrame, FALSE, FALSE, 4); pwBox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(pwFrame), pwBox); pow->pwAnimateNone = gtk_radio_button_new_with_label(NULL, _("None")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwAnimateNone), animGUI == ANIMATE_NONE); gtk_box_pack_start(GTK_BOX(pwBox), pow->pwAnimateNone, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwAnimateNone, _("Do not display any kind of animation for " "automatically moved chequers.")); pow->pwAnimateBlink = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(pow->pwAnimateNone), _("Blink moving chequers")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwAnimateBlink), animGUI == ANIMATE_BLINK); gtk_box_pack_start(GTK_BOX(pwBox), pow->pwAnimateBlink, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwAnimateBlink, _("When automatically moving chequers, flash " "them between the original and final points.")); pow->pwAnimateSlide = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(pow->pwAnimateNone), _("Slide moving chequers")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwAnimateSlide), animGUI == ANIMATE_SLIDE); gtk_box_pack_start(GTK_BOX(pwBox), pow->pwAnimateSlide, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwAnimateSlide, _("Show automatically moved chequers moving across " "the board between the points.")); pwev = gtk_event_box_new(); gtk_event_box_set_visible_window(GTK_EVENT_BOX(pwev), FALSE); gtk_box_pack_start(GTK_BOX(pwAnimBox), pwev, FALSE, FALSE, 0); pwSpeed = gtk_hbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(pwev), pwSpeed); pow->padjSpeed = GTK_ADJUSTMENT(gtk_adjustment_new(nGUIAnimSpeed, 0, 7, 1, 1, 0)); pwScale = gtk_hscale_new(pow->padjSpeed); gtk_widget_set_size_request(pwScale, 100, -1); gtk_scale_set_draw_value(GTK_SCALE(pwScale), FALSE); gtk_scale_set_digits(GTK_SCALE(pwScale), 0); gtk_box_pack_start(GTK_BOX(pwSpeed), gtk_label_new(_("Speed:")), FALSE, FALSE, 8); gtk_box_pack_start(GTK_BOX(pwSpeed), gtk_label_new(_("Slow")), FALSE, FALSE, 4); gtk_box_pack_start(GTK_BOX(pwSpeed), pwScale, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(pwSpeed), gtk_label_new(_("Fast")), FALSE, FALSE, 4); gtk_widget_set_tooltip_text(pwev, _("Control the rate at which blinking or sliding " "chequers are displayed.")); g_signal_connect(G_OBJECT(pow->pwAnimateNone), "toggled", G_CALLBACK(ToggleAnimation), pwSpeed); ToggleAnimation(pow->pwAnimateNone, pwSpeed); pow->pwGrayEdit = gtk_check_button_new_with_label(_("Gray board in edit mode")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwGrayEdit), fGUIGrayEdit); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwGrayEdit, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwGrayEdit, _("Gray board in edit mode to make it clearer")); pow->pwDragTargetHelp = gtk_check_button_new_with_label(_("Show target help when dragging a chequer")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwDragTargetHelp), fGUIDragTargetHelp); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwDragTargetHelp, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwDragTargetHelp, _("The possible target points for a move will be " "indicated by coloured rectangles when a chequer " "has been dragged a short distance.")); pow->pwDisplay = gtk_check_button_new_with_label(_("Display computer moves")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwDisplay, FALSE, FALSE, 0); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwDisplay), fDisplay); gtk_widget_set_tooltip_text(pow->pwDisplay, _("Show each move made by a computer player. You " "might want to turn this off when playing games " "between computer players, to speed things up.")); pow->pwSetWindowPos = gtk_check_button_new_with_label(_("Restore window positions")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwSetWindowPos, FALSE, FALSE, 0); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwSetWindowPos), fGUISetWindowPos); gtk_widget_set_tooltip_text(pow->pwSetWindowPos, _("Restore the previous size and position when " "recreating windows. This is really the job " "of the session manager and window manager, " "but since some platforms have poor or missing " "window managers, GNU Backgammon tries to " "do the best it can.")); pow->pwOutputMWC = gtk_check_button_new_with_label(_("Match equity as MWC")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwOutputMWC, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwOutputMWC, _("Show match equities as match winning chances. " "Otherwise, match equities will be shown as " "EMG (equivalent equity in a money game) " "points-per-game.")); pow->pwOutputGWC = gtk_check_button_new_with_label(_("GWC as percentage")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwOutputGWC, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwOutputGWC, _("Show game winning chances as percentages (e.g. " "58.3%). Otherwise, game winning chances will " "be shown as probabilities (e.g. 0.583).")); pow->pwOutputMWCpst = gtk_check_button_new_with_label(_("MWC as percentage")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwOutputMWCpst, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwOutputMWCpst, _("Show match winning chances as percentages (e.g. " "71.2%). Otherwise, match winning chances will " "be shown as probabilities (e.g. 0.712).")); /* number of digits in output */ pwev = gtk_event_box_new(); gtk_event_box_set_visible_window(GTK_EVENT_BOX(pwev), FALSE); gtk_box_pack_start(GTK_BOX(pwvbox), pwev, FALSE, FALSE, 0); pwhbox = gtk_hbox_new(FALSE, 4); gtk_container_add(GTK_CONTAINER(pwev), pwhbox); pw = gtk_label_new(_("Number of digits in output:")); gtk_box_pack_start(GTK_BOX(pwhbox), pw, FALSE, FALSE, 0); pow->padjDigits = GTK_ADJUSTMENT(gtk_adjustment_new(1, 0, MAX_OUTPUT_DIGITS, 1, 1, 0)); pow->pwDigits = gtk_spin_button_new(GTK_ADJUSTMENT(pow->padjDigits), 1, 0); gtk_box_pack_start(GTK_BOX(pwhbox), pow->pwDigits, TRUE, TRUE, 0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(pow->pwDigits), TRUE); gtk_widget_set_tooltip_text(pwev, _("Control the number of digits to be " "shown after the decimal point in " "probabilities and equities. " "This value is used throughout GNU Backgammon, " "i.e., in exported files, hints, analysis etc." "The default value of 3 results " "in equities output as +0.123. " "The equities and probabilities are internally " "stored with 7-8 digits, so it's possible to " "change the value " "after an analysis if you want more digits " "shown in the output. The output of match " "winning chances are derived from this value " "to produce numbers with approximately the same " "number of digits. The default value of 3 results " "in MWCs being output as 50.33%.")); } static void append_match_options(optionswidget * pow) { GtkWidget *pwp; GtkWidget *pwvbox; GtkWidget *pwev; GtkWidget *pwhbox; GtkWidget *pw; GtkWidget *pwf; GtkWidget *pwb; GtkWidget *pwhoriz; GtkWidget *pwLabelFile; /* Match options */ pwp = gtk_alignment_new(0, 0, 0, 0); gtk_container_set_border_width(GTK_CONTAINER(pwp), 4); gtk_notebook_append_page(GTK_NOTEBOOK(pow->pwNoteBook), pwp, gtk_label_new(_("Match"))); pwvbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(pwp), pwvbox); pwev = gtk_event_box_new(); gtk_event_box_set_visible_window(GTK_EVENT_BOX(pwev), FALSE); gtk_box_pack_start(GTK_BOX(pwvbox), pwev, FALSE, FALSE, 0); pwhbox = gtk_hbox_new(FALSE, 4); gtk_container_add(GTK_CONTAINER(pwev), pwhbox); gtk_box_pack_start(GTK_BOX(pwhbox), gtk_label_new(_("Default match length:")), FALSE, FALSE, 0); pow->padjLength = GTK_ADJUSTMENT(gtk_adjustment_new(nDefaultLength, 0, 99, 1, 1, 0)); pw = gtk_spin_button_new(GTK_ADJUSTMENT(pow->padjLength), 1, 0); gtk_box_pack_start(GTK_BOX(pwhbox), pw, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(pwhbox), gtk_label_new(_("length|points")), FALSE, FALSE, 0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(pw), TRUE); gtk_widget_set_tooltip_text(pwev, _("Specify the default length to use when starting " "new matches.")); pwf = gtk_frame_new(_("Match equity table")); gtk_box_pack_start(GTK_BOX(pwvbox), pwf, TRUE, TRUE, 0); gtk_container_set_border_width(GTK_CONTAINER(pwf), 4); pwb = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(pwf), pwb); pwhoriz = gtk_hbox_new(FALSE, 4); gtk_container_add(GTK_CONTAINER(pwb), pwhoriz); gtk_box_pack_start(GTK_BOX(pwhoriz), gtk_label_new(_("Current:")), FALSE, FALSE, 2); pwLabelFile = gtk_label_new((char *) miCurrent.szFileName); gtk_box_pack_end(GTK_BOX(pwhoriz), pwLabelFile, FALSE, FALSE, 2); pow->pwLoadMET = gtk_button_new_with_label(_("Load...")); gtk_box_pack_start(GTK_BOX(pwb), pow->pwLoadMET, FALSE, FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(pow->pwLoadMET), 2); gtk_widget_set_tooltip_text(pow->pwLoadMET, _("Read a file containing a match equity table.")); g_signal_connect(G_OBJECT(pow->pwLoadMET), "clicked", G_CALLBACK(SetMET), (gpointer) pwLabelFile); pow->pwCubeInvert = gtk_check_button_new_with_label(_("Invert table")); gtk_box_pack_start(GTK_BOX(pwb), pow->pwCubeInvert, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwCubeInvert, _("Use the specified match equity table " "around the other way (i.e., swap the players before " "looking up equities in the table).")); gtk_widget_set_sensitive(pow->pwLoadMET, fCubeUse); gtk_widget_set_sensitive(pow->pwCubeInvert, fCubeUse); } static void append_sound_options(optionswidget * pow) { GtkWidget *pwvboxMain; GtkWidget *pwhboxTop; GtkWidget *pwvboxTop; GtkWidget *pwScrolled; GtkWidget *pwhbox; GtkWidget *pwvboxDetails; GtkWidget *pwLabel; gnubgsound i; GtkTreeIter iter; GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); GtkListStore *store = gtk_list_store_new(1, G_TYPE_STRING); pwvboxMain = gtk_vbox_new(FALSE, 0); gtk_notebook_append_page(GTK_NOTEBOOK(pow->pwNoteBook), pwvboxMain, gtk_label_new(_("Sound"))); pwhboxTop = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(pwvboxMain), pwhboxTop, TRUE, TRUE, 0); pwvboxTop = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(pwhboxTop), pwvboxTop, TRUE, TRUE, 0); pwhbox = gtk_hbox_new(FALSE, 0); pwLabel = gtk_label_new(_("Sound command:")); gtk_box_pack_start(GTK_BOX(pwhbox), pwLabel, FALSE, FALSE, 0); pwSoundCommand = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(pwSoundCommand), sound_get_command()); gtk_box_pack_start(GTK_BOX(pwhbox), pwSoundCommand, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(pwvboxTop), pwhbox, FALSE, FALSE, 0); soundBeepIllegal = gtk_check_button_new_with_label(_("Beep on invalid input")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(soundBeepIllegal), fGUIBeep); gtk_box_pack_start(GTK_BOX(pwvboxTop), soundBeepIllegal, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(soundBeepIllegal, _("Emit a warning beep if invalid moves are attempted.")); soundsEnabled = gtk_check_button_new_with_label(_("Enable sound effects")); gtk_box_pack_start(GTK_BOX(pwvboxTop), soundsEnabled, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(soundsEnabled, _("Have GNU Backgammon make " "sound effects when various events occur.")); g_signal_connect(G_OBJECT(soundsEnabled), "toggled", G_CALLBACK(SoundToggled), NULL); #define SOUND_COL 0 for (i = (gnubgsound) 0; i < NUM_SOUNDS; i++) { /* Copy sound path data to be used in dialog */ soundDetails[i].Path = GetSoundFile(i); gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, SOUND_COL, gettext(sound_description[i]), -1); } soundList = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); g_object_unref(G_OBJECT(store)); /* The view now holds a reference. We can get rid * of our own reference */ gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(soundList)), GTK_SELECTION_BROWSE); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(soundList), -1, _("Sound Event"), renderer, "text", SOUND_COL, NULL); gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(soundList), FALSE); g_signal_connect(soundList, "cursor-changed", G_CALLBACK(SoundSelected), NULL); g_signal_connect(soundList, "map_event", G_CALLBACK(SoundGrabFocus), NULL); g_signal_connect(soundList, "destroy", G_CALLBACK(SoundTidy), NULL); pwScrolled = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pwScrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(pwScrolled), soundList); gtk_box_pack_start(GTK_BOX(pwvboxTop), pwScrolled, TRUE, TRUE, 0); soundFrame = gtk_frame_new(NULL); gtk_box_pack_start(GTK_BOX(pwvboxMain), soundFrame, FALSE, FALSE, 0); pwvboxDetails = gtk_vbox_new(FALSE, 4); gtk_container_set_border_width(GTK_CONTAINER(pwvboxDetails), 4); soundEnabled = gtk_check_button_new_with_label("Enabled"); g_signal_connect(soundEnabled, "clicked", G_CALLBACK(SoundEnabledClicked), NULL); gtk_box_pack_start(GTK_BOX(pwvboxDetails), soundEnabled, FALSE, FALSE, 0); pwhbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(pwhbox), gtk_label_new(_("Path:")), FALSE, FALSE, 0); soundPath = gtk_entry_new(); g_signal_connect(soundPath, "changed", G_CALLBACK(PathChanged), NULL); gtk_box_pack_start(GTK_BOX(pwhbox), soundPath, TRUE, TRUE, 0); soundPathButton = gtk_button_new_with_label("Browse"); g_signal_connect(soundPathButton, "clicked", G_CALLBACK(SoundChangePathClicked), NULL); gtk_box_pack_start(GTK_BOX(pwhbox), soundPathButton, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(pwvboxDetails), pwhbox, FALSE, FALSE, 0); pwhbox = gtk_hbox_new(FALSE, 4); soundPlayButton = gtk_button_new_with_label("Play Sound"); g_signal_connect(soundPlayButton, "clicked", G_CALLBACK(SoundPlayClicked), NULL); gtk_box_pack_start(GTK_BOX(pwhbox), soundPlayButton, FALSE, FALSE, 0); /* sound default button */ soundDefaultButton = gtk_button_new_with_label("Reset Default"); g_signal_connect(soundDefaultButton, "clicked", G_CALLBACK(SoundDefaultClicked), NULL); gtk_box_pack_start(GTK_BOX(pwhbox), soundDefaultButton, FALSE, FALSE, 0); /* sound all defaults button */ soundAllDefaultButton = gtk_button_new_with_label("Reset All to Defaults"); g_signal_connect(soundAllDefaultButton, "clicked", G_CALLBACK(SoundAllDefaultClicked), NULL); gtk_box_pack_start(GTK_BOX(pwhbox), soundAllDefaultButton, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(pwvboxDetails), pwhbox, FALSE, FALSE, 0); gtk_container_add(GTK_CONTAINER(soundFrame), pwvboxDetails); /* Set true so event fired */ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(soundsEnabled), TRUE); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(soundsEnabled), fSound); } static void append_dice_options(optionswidget * pow) { GtkWidget *pwp, *pwvbox, *pwhbox, *pwvbox2, *pwvbox3, *pw, *frame; unsigned int i; unsigned long nRandom; #if defined(HAVE_LIBGMP) int blumblum = TRUE; #else int blumblum = FALSE; #endif int rngsAdded = 0, rngSelected = -1; InitRNG(&nRandom, NULL, FALSE, rngCurrent); pwp = gtk_alignment_new(0, 0, 0, 0); gtk_container_set_border_width(GTK_CONTAINER(pwp), 4); gtk_notebook_append_page(GTK_NOTEBOOK(pow->pwNoteBook), pwp, gtk_label_new(_("Dice"))); pwvbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(pwp), pwvbox); frame = gtk_frame_new(_("Dice generation")); gtk_box_pack_start(GTK_BOX(pwvbox), frame, TRUE, TRUE, 0); pwvbox2 = gtk_vbox_new(FALSE, 1); gtk_container_set_border_width(GTK_CONTAINER(pwvbox2), 4); gtk_container_add(GTK_CONTAINER(frame), pwvbox2); pow->pwRngComboBox = NULL; for (i = 0; i < NUM_RNGS; i++) { if (i >= NUM_RNGS - 3) { pow->apwDice[i] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(pow->apwDice[0]), gettext(aszRNG[i])); gtk_box_pack_start(GTK_BOX(pwvbox2), pow->apwDice[i], FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->apwDice[i], gettext(aszRNGTip[i])); g_signal_connect(G_OBJECT(pow->apwDice[i]), "toggled", G_CALLBACK(DiceToggled), pow); } if (i < NUM_RNGS - 3) { if (i == 0) { pow->apwDice[0] = gtk_radio_button_new_with_label(NULL, _("Random number generator")); gtk_box_pack_start(GTK_BOX(pwvbox2), pow->apwDice[0], FALSE, FALSE, 0); g_signal_connect(G_OBJECT(pow->apwDice[0]), "toggled", G_CALLBACK(DiceToggled), pow); pwvbox3 = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(pwvbox2), pwvbox3, FALSE, FALSE, 0); pwhbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(pwvbox3), pwhbox, FALSE, FALSE, 0); /* Rng types */ pow->pwRngComboBox = gtk_combo_box_text_new(); gtk_box_pack_start(GTK_BOX(pwhbox), pow->pwRngComboBox, FALSE, FALSE, 26); /* NB. Doesn't look like gtk currently supports tooltips for individual combobox entries */ gtk_widget_set_tooltip_text(pow->pwRngComboBox, _("Select a random number generator to use")); /* Seed */ pwhbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(pwvbox3), pwhbox, FALSE, FALSE, 0); pow->pwSeed = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(pwhbox), pow->pwSeed, TRUE, TRUE, 26); gtk_box_pack_start(GTK_BOX(pow->pwSeed), gtk_label_new(_("Seed: ")), FALSE, FALSE, 0); pow->padjSeed = GTK_ADJUSTMENT(gtk_adjustment_new(nRandom, 0, UINT_MAX, 1, 1, 0)); pw = gtk_spin_button_new(GTK_ADJUSTMENT(pow->padjSeed), 1, 0); gtk_box_pack_start(GTK_BOX(pow->pwSeed), pw, FALSE, FALSE, 0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(pw), TRUE); gtk_widget_set_tooltip_text(pow->pwSeed, _("Specify the \"seed\" (generator state), which " "can be useful in some circumstances to provide " "duplicate dice sequences.")); pow->fChanged = 0; g_signal_connect(G_OBJECT(pw), "changed", G_CALLBACK(SeedChanged), &pow->fChanged); } if (!(i == RNG_BBS && !blumblum)) { gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(pow->pwRngComboBox), aszRNG[i]); if (i == rngCurrent) rngSelected = rngsAdded; rngsAdded++; } } } if (rngSelected == -1) rngSelected = rngsAdded - 1; gtk_combo_box_set_active(GTK_COMBO_BOX(pow->pwRngComboBox), rngSelected); /* dice manipulation */ /* Enable dice manipulation-widget */ pow->pwCheat = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON (pow->apwDice[NUM_RNGS - 1]), _("Dice manipulation")); gtk_box_pack_start(GTK_BOX(pwvbox2), pow->pwCheat, FALSE, FALSE, 0); /* select rolls for player */ pow->pwCheatRollBox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(pwvbox2), pow->pwCheatRollBox, FALSE, FALSE, 0); for (i = 0; i < 2; ++i) { static const char *aszCheatRoll[] = { N_("best"), N_("second best"), N_("third best"), N_("4th best"), N_("5th best"), N_("6th best"), N_("7th best"), N_("8th best"), N_("9th best"), N_("10th best"), N_("median"), N_("10th worst"), N_("9th worst"), N_("8th worst"), N_("7th worst"), N_("6th worst"), N_("5th worst"), N_("4th worst"), N_("third worst"), N_("second worst"), N_("worst"), NULL }; char *sz; const char **ppch; pwhbox = gtk_hbox_new(FALSE, 4); gtk_box_pack_start(GTK_BOX(pow->pwCheatRollBox), pwhbox, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(pwhbox), gtk_label_new(_("Always roll the ")), FALSE, FALSE, 0); pow->apwCheatRoll[i] = gtk_combo_box_text_new(); gtk_box_pack_start(GTK_BOX(pwhbox), pow->apwCheatRoll[i], FALSE, FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(pow->apwCheatRoll[i]), 1); for (ppch = aszCheatRoll; *ppch; ++ppch) gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(pow->apwCheatRoll[i]), gettext(*ppch)); sz = g_strdup_printf(_("roll for player %s."), ap[i].szName); gtk_box_pack_start(GTK_BOX(pwhbox), gtk_label_new(sz), FALSE, FALSE, 0); g_free(sz); } gtk_widget_set_tooltip_text(pow->pwCheat, _("Now it's proven! GNU Backgammon is able to " "manipulate the dice. This is meant as a " "learning tool. Examples of use: (a) learn " "how to double aggressively after a good opening " "sequence, (b) learn to control your temper " "while things are going bad, (c) learn to play " "very good or very bad rolls, or (d) just have fun. ")); pow->pwHigherDieFirst = gtk_check_button_new_with_label(_("Show higher die on left")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwHigherDieFirst), fGUIHighDieFirst); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwHigherDieFirst, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwHigherDieFirst, _("Force the higher of the two dice to be shown " "on the left.")); /* get the sensitivity of the widgets right */ DiceToggled(NULL, pow); } static void append_other_options(optionswidget * pow) { GtkWidget *pwp; GtkWidget *pwvbox; GtkWidget *pwev; GtkWidget *pwhbox; GtkWidget *table; GtkWidget *label; GtkWidget *pw; GtkWidget *pwScale; /* Other options */ pwp = gtk_alignment_new(0, 0, 0, 0); gtk_container_set_border_width(GTK_CONTAINER(pwp), 4); gtk_notebook_append_page(GTK_NOTEBOOK(pow->pwNoteBook), pwp, gtk_label_new(_("Other"))); pwvbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(pwp), pwvbox); pow->pwConfStart = gtk_check_button_new_with_label(_("Confirm when aborting game")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwConfStart, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwConfStart, _("Ask for confirmation when ending a game or " "starting a new game would erase the record " "of the game in progress.")); pow->pwConfOverwrite = gtk_check_button_new_with_label(_("Confirm when overwriting existing files")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwConfOverwrite, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwConfOverwrite, _("Confirm when overwriting existing files")); pow->pwRecordGames = gtk_check_button_new_with_label(_("Record all games")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwRecordGames, FALSE, FALSE, 0); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwRecordGames), fRecord); gtk_widget_set_tooltip_text(pow->pwRecordGames, _("Keep the game records for all previous games in " "the current match or session. You might want " "to disable this when playing extremely long " "matches or sessions, to save memory.")); pwev = gtk_event_box_new(); gtk_event_box_set_visible_window(GTK_EVENT_BOX(pwev), FALSE); gtk_box_pack_start(GTK_BOX(pwvbox), pwev, FALSE, FALSE, 0); pwhbox = gtk_hbox_new(FALSE, 4); gtk_container_add(GTK_CONTAINER(pwev), pwhbox); /* goto first game upon loading option */ pow->pwGotoFirstGame = gtk_check_button_new_with_label(_("Goto first game when loading matches or sessions")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwGotoFirstGame, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwGotoFirstGame, _("This option controls whether GNU Backgammon " "shows the board after the last move in the " "match, game, or session or whether it should " "show the first move in the first game")); /* display styles in game list */ pow->pwGameListStyles = gtk_check_button_new_with_label(_("Display colours for marked moves in game list")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwGameListStyles, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwGameListStyles, _("This option controls whether moves in the " "game list window are shown in different " "colours depending on their analysis")); table = gtk_table_new(2, 3, FALSE); label = gtk_label_new(_("Default SGF folder:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); pow->pwDefaultSGFFolder = gtk_file_chooser_button_new(NULL, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); if (default_sgf_folder) gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(pow->pwDefaultSGFFolder), default_sgf_folder); gtk_table_attach_defaults(GTK_TABLE(table), pow->pwDefaultSGFFolder, 1, 2, 0, 1); label = gtk_label_new(_("Default Import folder:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); pow->pwDefaultImportFolder = gtk_file_chooser_button_new(NULL, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); if (default_import_folder) gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(pow->pwDefaultImportFolder), default_import_folder); gtk_table_attach_defaults(GTK_TABLE(table), pow->pwDefaultImportFolder, 1, 2, 1, 2); label = gtk_label_new(_("Default Export folder:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3); pow->pwDefaultExportFolder = gtk_file_chooser_button_new(NULL, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); if (default_export_folder) gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(pow->pwDefaultExportFolder), default_export_folder); gtk_table_attach_defaults(GTK_TABLE(table), pow->pwDefaultExportFolder, 1, 2, 2, 3); gtk_box_pack_start(GTK_BOX(pwvbox), table, FALSE, FALSE, 3); pwhbox = gtk_hbox_new(FALSE, 4); label = gtk_label_new(_("Web browser:")); gtk_box_pack_start(GTK_BOX(pwhbox), label, FALSE, FALSE, 0); pow->pwWebBrowser = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(pow->pwWebBrowser), get_web_browser()); gtk_box_pack_start(GTK_BOX(pwhbox), pow->pwWebBrowser, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(pwvbox), pwhbox, FALSE, FALSE, 3); pwev = gtk_event_box_new(); gtk_event_box_set_visible_window(GTK_EVENT_BOX(pwev), FALSE); gtk_box_pack_start(GTK_BOX(pwvbox), pwev, FALSE, FALSE, 0); pw = gtk_hbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(pwev), pw); pow->padjCache = GTK_ADJUSTMENT(gtk_adjustment_new(GetEvalCacheSize(), 0, CACHE_SIZE_GUIMAX - 16, 1, 1, 0)); pwScale = gtk_hscale_new(pow->padjCache); gtk_widget_set_size_request(pwScale, 100, -1); gtk_scale_set_draw_value(GTK_SCALE(pwScale), TRUE); g_signal_connect(G_OBJECT(pwScale), "format-value", G_CALLBACK(CacheSizeString), NULL); gtk_scale_set_digits(GTK_SCALE(pwScale), 0); gtk_box_pack_start(GTK_BOX(pw), gtk_label_new(_("Cache:")), FALSE, FALSE, 8); gtk_box_pack_start(GTK_BOX(pw), gtk_label_new(_("Small")), FALSE, FALSE, 4); gtk_box_pack_start(GTK_BOX(pw), pwScale, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(pw), gtk_label_new(_("Large")), FALSE, FALSE, 4); gtk_widget_set_tooltip_text(pwev, _("GNU Backgammon uses a cache of previous " "evaluations to speed up processing. " "Increasing the size may help evaluations " "complete more quickly, but decreasing " "the size will use less memory.")); #if defined(USE_MULTITHREAD) pwev = gtk_event_box_new(); gtk_event_box_set_visible_window(GTK_EVENT_BOX(pwev), FALSE); gtk_box_pack_start(GTK_BOX(pwvbox), pwev, FALSE, FALSE, 0); pwhbox = gtk_hbox_new(FALSE, 4); gtk_container_add(GTK_CONTAINER(pwev), pwhbox); gtk_box_pack_start(GTK_BOX(pwhbox), gtk_label_new(_("Eval Threads:")), FALSE, FALSE, 0); pow->padjThreads = GTK_ADJUSTMENT(gtk_adjustment_new(MT_GetNumThreads(), 1, MAX_NUMTHREADS, 1, 1, 0)); pw = gtk_spin_button_new(GTK_ADJUSTMENT(pow->padjThreads), 1, 0); gtk_widget_set_size_request(GTK_WIDGET(pw), 50, -1); gtk_box_pack_start(GTK_BOX(pwhbox), pw, FALSE, FALSE, 0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(pw), TRUE); gtk_box_pack_start(GTK_BOX(pwhbox), gtk_label_new(_("threads")), FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pwev, _("The number of threads to use in multi-threaded operations," " this should be set to the number of logical processing units available")); #endif pwhbox = gtk_hbox_new(FALSE, 4); gtk_box_pack_start(GTK_BOX(pwvbox), pwhbox, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(pwhbox), gtk_label_new(_("Auto save frequency")), FALSE, FALSE, 0); pow->pwAutoSaveTime = gtk_spin_button_new_with_range(1, 240, 1); gtk_box_pack_start(GTK_BOX(pwhbox), pow->pwAutoSaveTime, FALSE, FALSE, 0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(pow->pwAutoSaveTime), TRUE); gtk_spin_button_set_value(GTK_SPIN_BUTTON(pow->pwAutoSaveTime), nAutoSaveTime); gtk_widget_set_tooltip_text(pow->pwAutoSaveTime, _ ("Set the auto save frequency. You must also enable backup during analysis and/or during rollout")); gtk_box_pack_start(GTK_BOX(pwhbox), gtk_label_new(_("minute(s)")), FALSE, FALSE, 0); pow->pwAutoSaveRollout = gtk_check_button_new_with_label(_("Auto save rollouts")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwAutoSaveRollout, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwAutoSaveRollout, _("Auto save during and after rollouts")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwAutoSaveRollout), fAutoSaveRollout); pow->pwAutoSaveAnalysis = gtk_check_button_new_with_label(_("Auto save analysis")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwAutoSaveAnalysis, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwAutoSaveAnalysis, _("Auto save during and after analysis of games and matches")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwAutoSaveAnalysis), fAutoSaveAnalysis); pow->pwAutoSaveConfirmDelete = gtk_check_button_new_with_label(_("Confirm deletion of auto saves")); gtk_box_pack_start(GTK_BOX(pwvbox), pow->pwAutoSaveConfirmDelete, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(pow->pwAutoSaveConfirmDelete, _("Ask before auto saves are deleted")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwAutoSaveConfirmDelete), fAutoSaveConfirmDelete); } static GtkWidget * OptionsPages(optionswidget * pow) { GtkWidget *pwp; pow->pwNoteBook = gtk_notebook_new(); gtk_container_set_border_width(GTK_CONTAINER(pow->pwNoteBook), 8); append_game_options(pow); append_cube_options(pow); append_tutor_options(pow); append_display_options(pow); append_match_options(pow); append_sound_options(pow); append_dice_options(pow); /* Database options */ pwp = gtk_alignment_new(0, 0, 0, 0); gtk_container_set_border_width(GTK_CONTAINER(pwp), 4); relPage = gtk_notebook_append_page(GTK_NOTEBOOK(pow->pwNoteBook), pwp, gtk_label_new(_("Database"))); relPageActivated = FALSE; gtk_container_add(GTK_CONTAINER(pwp), RelationalOptions()); append_other_options(pow); return pow->pwNoteBook; } static char checkupdate_sz[128]; static int checkupdate_n; #define CHECKUPDATE(button,flag,string) \ checkupdate_n = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( (button) ) ); \ if ( checkupdate_n != (flag)){ \ sprintf(checkupdate_sz, (string), checkupdate_n ? "on" : "off"); \ UserCommand(checkupdate_sz); \ } static void SetSoundSettings(void) { gnubgsound i; outputoff(); fGUIBeep = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(soundBeepIllegal)); CHECKUPDATE(soundBeepIllegal, fGUIBeep, "set gui beep %s"); CHECKUPDATE(soundsEnabled, fSound, "set sound enable %s"); for (i = (gnubgsound)0; i < NUM_SOUNDS; i++) { if (*soundDetails[i].Path) SetSoundFile(i, soundDetails[i].Path); else SetSoundFile(i, ""); } sound_set_command(gtk_entry_get_text(GTK_ENTRY(pwSoundCommand))); outputon(); } static void OptionsOK(GtkWidget * pw, optionswidget * pow) { char sz[128]; int n; unsigned int u, i; gchar *filename, *command, *tmp, *newfolder; const gchar *new_browser; static const char *set_rng_cmds[NUM_RNGS] = { "set rng bbs", "set rng isaac", "set rng md5", "set rng mersenne", "set rng manual", "set rng random.org", NULL, }; BoardData *bd = BOARD(pwBoard)->board_data; gtk_widget_hide(gtk_widget_get_toplevel(pw)); CHECKUPDATE(pow->pwAutoBearoff, fAutoBearoff, "set automatic bearoff %s") CHECKUPDATE(pow->pwAutoCrawford, fAutoCrawford, "set automatic crawford %s") CHECKUPDATE(pow->pwAutoGame, fAutoGame, "set automatic game %s") CHECKUPDATE(pow->pwAutoRoll, fAutoRoll, "set automatic roll %s") CHECKUPDATE(pow->pwAutoMove, fAutoMove, "set automatic move %s") CHECKUPDATE(pow->pwTutor, fTutor, "set tutor mode %s") CHECKUPDATE(pow->pwTutorCube, fTutorCube, "set tutor cube %s") CHECKUPDATE(pow->pwTutorChequer, fTutorChequer, "set tutor chequer %s") { GtkTreeModel *model; GtkTreeIter iter; model = gtk_combo_box_get_model(GTK_COMBO_BOX(pow->pwTutorSkill)); if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(pow->pwTutorSkill), &iter)) { gchar *selection; gtk_tree_model_get(model, &iter, 0, &selection, -1); if (!strcmp(selection, gettext(aszTutor[0]))) { /* N_("Doubtful") */ if (TutorSkill != SKILL_DOUBTFUL) UserCommand("set tutor skill doubtful"); } else if (!strcmp(selection, gettext(aszTutor[1]))) { /* N_("Bad") */ if (TutorSkill != SKILL_BAD) UserCommand("set tutor skill bad"); } else if (!strcmp(selection, gettext(aszTutor[2]))) { /* N_("Very Bad") */ if (TutorSkill != SKILL_VERYBAD) UserCommand("set tutor skill very bad"); } else { /* g_assert(FALSE); Unknown Selection, defaulting */ if (TutorSkill != SKILL_DOUBTFUL) UserCommand("set tutor skill doubtful"); } g_free(selection); } } CHECKUPDATE(pow->pwCubeUsecube, fCubeUse, "set cube use %s") CHECKUPDATE(pow->pwCubeJacoby, fJacoby, "set jacoby %s") CHECKUPDATE(pow->pwCubeInvert, fInvertMET, "set invert met %s") CHECKUPDATE(pow->pwGameClockwise, fClockwise, "set clockwise %s") for (i = 0; i < NUM_VARIATIONS; ++i) if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pow->apwVariations[i])) && bgvDefault != (bgvariation) i) { sprintf(sz, "set variation %s", aszVariationCommands[i]); UserCommand(sz); break; } CHECKUPDATE(pow->pwOutputMWC, fOutputMWC, "set output mwc %s") CHECKUPDATE(pow->pwOutputGWC, fOutputWinPC, "set output winpc %s") CHECKUPDATE(pow->pwOutputMWCpst, fOutputMatchPC, "set output matchpc %s") if ((n = (int) gtk_adjustment_get_value(pow->padjDigits)) != fOutputDigits) { sprintf(sz, "set output digits %d", n); UserCommand(sz); } /* ... */ CHECKUPDATE(pow->pwConfStart, fConfirmNew, "set confirm new %s") CHECKUPDATE(pow->pwConfOverwrite, fConfirmSave, "set confirm save %s") if ((u = (unsigned int) gtk_adjustment_get_value(pow->padjCubeAutomatic)) != cAutoDoubles) { sprintf(sz, "set automatic doubles %u", u); UserCommand(sz); } if ((u = (unsigned int) gtk_adjustment_get_value(pow->padjCubeBeaver)) != nBeavers) { sprintf(sz, "set beavers %u", u); UserCommand(sz); } if ((u = (unsigned int) gtk_adjustment_get_value(pow->padjLength)) != nDefaultLength) { sprintf(sz, "set matchlength %u", u); UserCommand(sz); } if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pow->apwDice[0]))) { /* rng selected */ char *selRNG = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(pow->pwRngComboBox)); for (i = 0; i < NUM_RNGS - 3; i++) { if (!strcmp(selRNG, aszRNG[i])) break; } g_free(selRNG); } else { for (i = NUM_RNGS - 3; i < NUM_RNGS; i++) { if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pow->apwDice[i]))) break; } } if (i < RNG_FILE && i != (unsigned int) rngCurrent) { UserCommand(set_rng_cmds[i]); } else if (i == RNG_FILE && i != (unsigned int) rngCurrent) { filename = GTKFileSelect(_("Select file with dice"), NULL, NULL, NULL, GTK_FILE_CHOOSER_ACTION_OPEN); if (filename) { command = g_strconcat("set rng file \"", filename, "\"", NULL); UserCommand(command); g_free(command); g_free(filename); } } CHECKUPDATE(pow->pwRecordGames, fRecord, "set record %s") CHECKUPDATE(pow->pwDisplay, fDisplay, "set display %s") if ((u = (unsigned int) gtk_adjustment_get_value(pow->padjCache)) != GetEvalCacheSize()) { SetEvalCacheSize(u); } #if defined(USE_MULTITHREAD) if ((u = (unsigned int) gtk_adjustment_get_value(pow->padjThreads)) != MT_GetNumThreads()) { sprintf(sz, "set threads %u", u); UserCommand(sz); } #endif if (gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pow->pwAutoSaveTime)) != nAutoSaveTime) { sprintf(sz, "set autosave time %d", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pow->pwAutoSaveTime))); UserCommand(sz); } CHECKUPDATE(pow->pwAutoSaveAnalysis, fAutoSaveAnalysis, "set autosave analysis %s"); CHECKUPDATE(pow->pwAutoSaveRollout, fAutoSaveRollout, "set autosave rollout %s"); CHECKUPDATE(pow->pwAutoSaveConfirmDelete, fAutoSaveConfirmDelete, "set autosave confirm %s"); if ((u = (unsigned int) gtk_adjustment_get_value(pow->padjDelay)) != nDelay) { sprintf(sz, "set delay %u", u); UserCommand(sz); } if (pow->fChanged == 1) { u = (unsigned int) gtk_adjustment_get_value(pow->padjSeed); sprintf(sz, "set seed %u", u); UserCommand(sz); } SetSoundSettings(); CHECKUPDATE(pow->pwIllegal, fGUIIllegal, "set gui illegal %s") CHECKUPDATE(pow->pwUseDiceIcon, bd->rd->fDiceArea, "set gui dicearea %s") CHECKUPDATE(pow->pwShowIDs, fShowIDs, "set gui showids %s") CHECKUPDATE(pow->pwHigherDieFirst, fGUIHighDieFirst, "set gui highdiefirst %s") CHECKUPDATE(pow->pwSetWindowPos, fGUISetWindowPos, "set gui windowpositions %s") CHECKUPDATE(pow->pwGrayEdit, fGUIGrayEdit, "set gui grayedit %s") CHECKUPDATE(pow->pwDragTargetHelp, fGUIDragTargetHelp, "set gui dragtargethelp %s") { #if defined(USE_BOARD3D) if (display_is_3d(bd->rd)) updateDiceOccPos(bd, bd->bd3d); else #endif if (gtk_widget_get_realized(pwBoard)) { board_create_pixmaps(pwBoard, bd); gtk_widget_queue_draw(bd->drawing_area); } } switch (gtk_combo_box_get_active(GTK_COMBO_BOX(pow->pwShowPips))) { case GUI_SHOW_PIPS_NONE: if (gui_show_pips != GUI_SHOW_PIPS_NONE) UserCommand("set gui showpip none"); break; case GUI_SHOW_PIPS_PIPS: if (gui_show_pips != GUI_SHOW_PIPS_PIPS) UserCommand("set gui showpip pips"); break; case GUI_SHOW_PIPS_EPC: if (gui_show_pips != GUI_SHOW_PIPS_EPC) UserCommand("set gui showpip epc"); break; case GUI_SHOW_PIPS_WASTAGE: if (gui_show_pips != GUI_SHOW_PIPS_WASTAGE) UserCommand("set gui showpip wastage"); break; default: g_assert_not_reached(); } if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pow->pwAnimateNone)) && animGUI != ANIMATE_NONE) UserCommand("set gui animation none"); else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pow->pwAnimateBlink)) && animGUI != ANIMATE_BLINK) UserCommand("set gui animation blink"); else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pow->pwAnimateSlide)) && animGUI != ANIMATE_SLIDE) UserCommand("set gui animation slide"); if ((u = (unsigned int) gtk_adjustment_get_value(pow->padjSpeed)) != nGUIAnimSpeed) { sprintf(sz, "set gui animation speed %u", u); UserCommand(sz); } /* dice manipulation */ n = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pow->pwCheat)); if (n != fCheat) { sprintf(sz, "set cheat enable %s", n ? "on" : "off"); UserCommand(sz); } for (i = 0; i < 2; ++i) { u = gtk_combo_box_get_active(GTK_COMBO_BOX(pow->apwCheatRoll[i])); if (u != afCheatRoll[i]) { sprintf(sz, "set cheat player %u roll %u", i, u + 1); UserCommand(sz); } } CHECKUPDATE(pow->pwGotoFirstGame, fGotoFirstGame, "set gotofirstgame %s") CHECKUPDATE(pow->pwGameListStyles, fStyledGamelist, "set styledgamelist %s") newfolder = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pow->pwDefaultSGFFolder)); if (newfolder && (!default_sgf_folder || strcmp(newfolder, default_sgf_folder))) { tmp = g_strdup_printf("set sgf folder \"%s\"", newfolder); UserCommand(tmp); g_free(tmp); } g_free(newfolder); newfolder = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pow->pwDefaultImportFolder)); if (newfolder && (!default_import_folder || strcmp(newfolder, default_import_folder))) { tmp = g_strdup_printf("set import folder \"%s\"", newfolder); UserCommand(tmp); g_free(tmp); } g_free(newfolder); newfolder = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pow->pwDefaultExportFolder)); if (newfolder && (!default_export_folder || strcmp(newfolder, default_export_folder))) { tmp = g_strdup_printf("set export folder \"%s\"", newfolder); UserCommand(tmp); g_free(tmp); } g_free(newfolder); new_browser = gtk_entry_get_text(GTK_ENTRY(pow->pwWebBrowser)); if (new_browser && (!get_web_browser() || strcmp(new_browser, get_web_browser()))) { tmp = g_strdup_printf("set browser \"%s\"", new_browser); UserCommand(tmp); g_free(tmp); } if (relPageActivated) RelationalSaveOptions(); UserCommand("save settings"); /* Destroy widget on exit */ gtk_widget_destroy(gtk_widget_get_toplevel(pw)); } static void OptionsSet(optionswidget * pow) { unsigned int i; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwAutoBearoff), fAutoBearoff); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwAutoCrawford), fAutoCrawford); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwAutoGame), fAutoGame); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwAutoMove), fAutoMove); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwAutoRoll), fAutoRoll); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwTutor), fTutor); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwTutorCube), fTutorCube); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwTutorChequer), fTutorChequer); gtk_combo_box_set_active(GTK_COMBO_BOX(pow->pwTutorSkill), nTutorSkillCurrent); gtk_adjustment_set_value(pow->padjCubeBeaver, nBeavers); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwCubeUsecube), fCubeUse); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwCubeJacoby), fJacoby); gtk_adjustment_set_value(pow->padjCubeAutomatic, cAutoDoubles); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwCubeInvert), fInvertMET); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwGameClockwise), fClockwise); for (i = 0; i < NUM_VARIATIONS; ++i) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->apwVariations[i]), bgvDefault == (bgvariation) i); if (rngCurrent >= NUM_RNGS - 3) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->apwDice[rngCurrent]), TRUE); /* dice manipulation */ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwCheat), fCheat); for (i = 0; i < 2; ++i) gtk_combo_box_set_active(GTK_COMBO_BOX(pow->apwCheatRoll[i]), afCheatRoll[i]); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwOutputMWC), fOutputMWC); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwOutputGWC), fOutputWinPC); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwOutputMWCpst), fOutputMatchPC); gtk_adjustment_set_value(pow->padjDigits, fOutputDigits); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwConfStart), fConfirmNew); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwConfOverwrite), fConfirmSave); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwGotoFirstGame), fGotoFirstGame); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pow->pwGameListStyles), fStyledGamelist); } static void OptionsPageChange(GtkNotebook * UNUSED(notebook), gpointer * UNUSED(page), gint tabNumber, gpointer UNUSED(data)) { if (tabNumber == relPage && !relPageActivated) { RelationalOptionsShown(); relPageActivated = TRUE; } } extern void GTKSetOptions(void) { GtkWidget *pwDialog, *pwOptions; optionswidget ow; pwDialog = GTKCreateDialog(_("GNU Backgammon - General options"), DT_QUESTION, NULL, DIALOG_FLAG_MODAL, G_CALLBACK(OptionsOK), &ow); gtk_container_add(GTK_CONTAINER(DialogArea(pwDialog, DA_MAIN)), pwOptions = OptionsPages(&ow)); g_signal_connect(G_OBJECT(pwOptions), "switch-page", G_CALLBACK(OptionsPageChange), NULL); OptionsSet(&ow); GTKRunDialog(pwDialog); }