/* * gtkgame.c * * by Joern Thyssen , 2002 * * 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: gtktheory.c,v 1.66 2017/08/19 22:14:27 plm Exp $ */ #include "config.h" #include "gtklocdefs.h" #include #include #include #include #include "backgammon.h" #include "eval.h" #include "gtktheory.h" #include "matchequity.h" #include "gtkwindows.h" #define MAXPLY 4 typedef struct _theorywidget { cubeinfo ci; /* radio buttons */ GtkWidget *apwRadio[2]; /* frames ("match score" and "money game") */ GtkWidget *apwFrame[2]; /* gammon/backgammon rates widgets */ GtkAdjustment *aapwRates[2][2]; /* score */ GtkAdjustment *apwScoreAway[2]; /* cube */ GtkWidget *apwCube[7]; GtkWidget *pwCubeFrame; /* crawford, jacoby and more */ GtkWidget *pwCrawford, *pwJacoby, *pwBeavers; /* reset */ GtkWidget *pwReset; /* market window */ GtkWidget *apwMW[2]; /* window graphs */ GtkWidget *apwGraph[2]; /* gammon prices */ GtkWidget *pwGammonPrice; /* dead double, live cash, and dead too good points; for graph drawing */ float aar[2][3]; /* radio buttons for plies */ GtkWidget *apwPly[MAXPLY+1]; } theorywidget; static void ResetTheory(GtkWidget * UNUSED(pw), theorywidget * ptw) { float aarRates[2][2]; evalcontext ec = { FALSE, 0, FALSE, TRUE, 0.0 }; float arOutput[NUM_OUTPUTS]; int i, j; /* get current gammon rates */ GetMatchStateCubeInfo(&ptw->ci, &ms); getCurrentGammonRates(aarRates, arOutput, msBoard(), &ptw->ci, &ec); /* cube */ j = 1; for (i = 0; i < 7; i++) { if (j == ptw->ci.nCube) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ptw->apwCube[i]), TRUE); break; } j *= 2; } /* set match play/money play radio button */ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ptw->apwRadio[ptw->ci.nMatchTo == 0]), TRUE); /* crawford, jacoby, beavers */ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ptw->pwCrawford), ptw->ci.fCrawford); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ptw->pwJacoby), ptw->ci.fJacoby); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ptw->pwBeavers), ptw->ci.fBeavers); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ptw->apwPly[ec.nPlies]), TRUE); for (i = 0; i < 2; i++) { /* set score for player i */ gtk_adjustment_set_value(GTK_ADJUSTMENT(ptw->apwScoreAway[i]), (ptw->ci.nMatchTo) ? (ptw->ci.nMatchTo - ptw->ci.anScore[i]) : 1); for (j = 0; j < 2; j++) /* gammon/backgammon rates */ gtk_adjustment_set_value(GTK_ADJUSTMENT(ptw->aapwRates[i][j]), aarRates[i][j] * 100.0f); } } static void TheoryGetValues(theorywidget * ptw, cubeinfo * pci, float aarRates[2][2]) { int i, j; /* get rates */ for (i = 0; i < 2; i++) for (j = 0; j < 2; j++) aarRates[i][j] = 0.01f * (float) gtk_adjustment_get_value(ptw->aapwRates[i][j]); /* money game or match play */ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ptw->apwRadio[0]))) { /* match play */ int n0 = (int) gtk_adjustment_get_value(ptw->apwScoreAway[0]); int n1 = (int) gtk_adjustment_get_value(ptw->apwScoreAway[1]); pci->nMatchTo = (n1 > n0) ? n1 : n0; pci->anScore[0] = pci->nMatchTo - n0; pci->anScore[1] = pci->nMatchTo - n1; pci->fCrawford = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ptw->pwCrawford)); j = 1; for (i = 0; i < 7; i++) { if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ptw->apwCube[i]))) { pci->nCube = j; break; } j *= 2; } } else { /* money play */ pci->nMatchTo = 0; pci->anScore[0] = pci->anScore[1] = 0; pci->fJacoby = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ptw->pwJacoby)); pci->fBeavers = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ptw->pwBeavers)); } } static void do_mw_views(theorywidget * ptw) { int i; GtkListStore *store; GtkCellRenderer *renderer; for (i = 0; i < 2; i++) { store = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); ptw->apwMW[i] = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); g_object_unref(store); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(ptw->apwMW[i]), -1, "", renderer, "text", 0, NULL); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(ptw->apwMW[i]), -1, _("Dead cube"), renderer, "text", 1, NULL); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(ptw->apwMW[i]), -1, _("Fully live"), renderer, "text", 2, NULL); } } static void remove_mw_rows(theorywidget * ptw) { int i; GtkTreeModel *model; GtkTreeIter iter; for (i = 0; i < 2; ++i) { model = gtk_tree_view_get_model(GTK_TREE_VIEW(ptw->apwMW[i])); if (gtk_tree_model_iter_nth_child(model, &iter, NULL, 0)) while (gtk_list_store_remove(GTK_LIST_STORE(model), &iter)) { }; } } static void add_mw_money_rows(theorywidget * ptw, const cubeinfo * pci, float aarRates[2][2]) { int i, j, k; gchar *asz[3]; float aaarPoints[2][7][2]; GtkListStore *store; GtkTreeIter iter; const char *aszMoneyPointLabel[] = { N_("Take Point (TP)"), N_("Beaver Point (BP)"), N_("Raccoon Point (RP)"), N_("Initial Double Point (IDP)"), N_("Redouble Point (RDP)"), N_("Cash Point (CP)"), N_("Too Good point (TG)") }; /* money play */ getMoneyPoints(aaarPoints, pci->fJacoby, pci->fBeavers, aarRates); for (i = 0; i < 2; ++i) { store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ptw->apwMW[i]))); for (j = 0; j < 7; j++) { asz[0] = g_strdup(gettext(aszMoneyPointLabel[j])); for (k = 0; k < 2; k++) asz[k + 1] = g_strdup_printf("%7.3f%%", 100.0f * aaarPoints[i][j][k]); gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, asz[0], 1, asz[1], 2, asz[2], -1); for (k = 0; k < 3; ++k) g_free(asz[k]); } ptw->aar[i][0] = aaarPoints[i][3][0]; ptw->aar[i][1] = aaarPoints[i][5][1]; ptw->aar[i][2] = aaarPoints[i][6][0]; } } static void add_mw_match_rows(theorywidget * ptw, const cubeinfo * pci, float aarRates[2][2]) { int i, j, k; gchar *asz[3]; float aaarPointsMatch[2][4][2]; int afAutoRedouble[2]; int afDead[2]; GtkListStore *store; GtkTreeIter iter; const char *aszMatchPlayLabel[] = { N_("Take Point (TP)"), N_("Double point (DP)"), N_("Cash Point (CP)"), N_("Too Good point (TG)") }; for (i = 0; i < 2; i++) { store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ptw->apwMW[i]))); getMatchPoints(aaarPointsMatch, afAutoRedouble, afDead, pci, aarRates); for (j = 0; j < 4; j++) { asz[0] = g_strdup(gettext(aszMatchPlayLabel[j])); for (k = 0; k < 2; k++) { int f = ((!k) || (!afDead[i])) && !(k && afAutoRedouble[i] && !j) && !(k && afAutoRedouble[i] && j == 3); f = f || (k && afAutoRedouble[!i] && !j); f = f && (!pci->nMatchTo || (pci->anScore[i] + pci->nCube < pci->nMatchTo)); if (f) asz[1 + k] = g_strdup_printf("%7.3f%%", 100.0f * aaarPointsMatch[i][j][k]); else asz[1 + k] = g_strdup(""); } gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, asz[0], 1, asz[1], 2, asz[2], -1); for (k = 0; k < 3; ++k) g_free(asz[k]); } ptw->aar[i][0] = aaarPointsMatch[i][1][0]; ptw->aar[i][1] = aaarPointsMatch[i][2][1]; ptw->aar[i][2] = aaarPointsMatch[i][3][0]; } } static void TheoryUpdated(GtkWidget * UNUSED(pw), theorywidget * ptw) { cubeinfo ci; float aarRates[2][2]; int i, j; gchar *pch; GtkTextBuffer *buffer; GtkTextIter iter; /* get values */ TheoryGetValues(ptw, &ci, aarRates); /* set max on the gammon spinners */ for (i = 0; i < 2; ++i) gtk_adjustment_set_upper(ptw->aapwRates[i][1], 100.0 - gtk_adjustment_get_value(ptw->aapwRates[i][0])); SetCubeInfo(&ci, ci.nCube, 0, 0, ci.nMatchTo, ci.anScore, ci.fCrawford, ci.fJacoby, ci.fBeavers, ci.bgv); /* hide show widgets */ gtk_widget_show(ptw->apwFrame[0]); gtk_widget_show(ptw->apwFrame[1]); gtk_widget_hide(ptw->apwFrame[ci.nMatchTo != 0]); /* update match play widget */ gtk_widget_set_sensitive(ptw->pwCrawford, ((ci.anScore[0] == ci.nMatchTo - 1) ^ (ci.anScore[1] == ci.nMatchTo - 1))); if (ci.nMatchTo) { gtk_widget_set_sensitive(ptw->pwCubeFrame, ci.nMatchTo != 1); j = 1; for (i = 0; i < 7; i++) { gtk_widget_set_sensitive(ptw->apwCube[i], j < 2 * ci.nMatchTo); j *= 2; } } /* update money play widget */ /* * update market window widgets */ remove_mw_rows(ptw); if (ci.nMatchTo) add_mw_match_rows(ptw, &ci, aarRates); else add_mw_money_rows(ptw, &ci, aarRates); for (i = 0; i < 2; i++) gtk_widget_queue_draw(ptw->apwGraph[i]); /* * Update gammon price widgets */ buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ptw->pwGammonPrice)); gtk_text_buffer_set_text(buffer, "", -1); gtk_text_buffer_get_end_iter(buffer, &iter); if (ci.nMatchTo) { pch = g_strdup_printf(_("Gammon values at %d-away, %d-away (%d cube)\n\n"), ci.nMatchTo - ci.anScore[0], ci.nMatchTo - ci.anScore[1], ci.nCube); gtk_text_buffer_insert(buffer, &iter, pch, -1); g_free(pch); gtk_text_buffer_insert(buffer, &iter, _("Player Gammon BG\n"), -1); for (j = 0; j < 2; ++j) { pch = g_strdup_printf("%-31.31s %6.4f %6.4f\n", ap[j].szName, 0.5f * ci.arGammonPrice[j], 0.5f * (ci.arGammonPrice[2 + j] + ci.arGammonPrice[j])); gtk_text_buffer_insert(buffer, &iter, pch, -1); g_free(pch); } } else { gtk_text_buffer_insert(buffer, &iter, _("Gammon values for money game:\n\n"), -1); for (i = 0; i < 2; ++i) { pch = g_strdup_printf(_("%s:\n\n" "Player " "Gammon BG\n"), i ? _("Doubled cube") : _("Centered cube")); gtk_text_buffer_insert(buffer, &iter, pch, -1); g_free(pch); SetCubeInfo(&ci, 1, i ? 1 : -1, 0, ci.nMatchTo, ci.anScore, ci.fCrawford, ci.fJacoby, ci.fBeavers, ci.bgv); for (j = 0; j < 2; ++j) { pch = g_strdup_printf("%-31.31s %6.4f %6.4f\n", ap[j].szName, 0.5f * ci.arGammonPrice[j], 0.5f * (ci.arGammonPrice[2 + j] + ci.arGammonPrice[j])); gtk_text_buffer_insert(buffer, &iter, pch, -1); g_free(pch); } gtk_text_buffer_insert(buffer, &iter, "\n", -1); } } } static gboolean GraphDraw(GtkWidget * pwGraph, cairo_t * cr, theorywidget * ptw) { GtkAllocation allocation; int i, x, y, cx, cy, iPlayer, ax[3]; char sz[4]; PangoLayout *layout; gtk_widget_get_allocation(pwGraph, &allocation); x = 8; y = 12; cx = allocation.width - 16 - 1; cy = allocation.height - 12; layout = gtk_widget_create_pango_layout(pwGraph, NULL); pango_layout_set_font_description(layout, pango_font_description_from_string("sans 7")); /* FIXME: The co-ordinates used in this function should be determined * from the text size, not hard-coded. But GDK's text handling will * undergo an overhaul with Pango once GTK+ 2.0 comes out, so let's * cheat for now and then get it right once 2.0 is here. */ iPlayer = pwGraph == ptw->apwGraph[1]; for (i = 0; i <= 20; i++) { gtk_locdef_paint_vline(gtk_widget_get_style(pwGraph), gtk_widget_get_window(pwGraph), cr, GTK_STATE_NORMAL, NULL, pwGraph, "tick", y - 1, (i & 3) ? y - 3 : y - 5, x + cx * i / 20); if (!(i & 3)) { int width; int height; sprintf(sz, "%d", i * 5); pango_layout_set_text(layout, sz, -1); pango_layout_get_pixel_size(layout, &width, &height); gtk_locdef_paint_layout(gtk_widget_get_style(pwGraph), gtk_widget_get_window(pwGraph), cr, GTK_STATE_NORMAL, TRUE, NULL, pwGraph, "label", x + cx * i / 20 - width / 2 /* FIXME */ , y - height - 1, layout); } } g_object_unref(layout); for (i = 0; i < 3; i++) ax[i] = (int) (x + cx * ptw->aar[iPlayer][i]); gtk_locdef_paint_box(gtk_widget_get_style(pwGraph), gtk_widget_get_window(pwGraph), cr, GTK_STATE_NORMAL, GTK_SHADOW_IN, NULL, pwGraph, "doubling-window", x, 12, cx, cy); /* FIXME it's horrible to abuse the "state" parameters like this */ if (ptw->aar[iPlayer][1] > ptw->aar[iPlayer][0]) gtk_locdef_paint_box(gtk_widget_get_style(pwGraph), gtk_widget_get_window(pwGraph), cr, GTK_STATE_ACTIVE, GTK_SHADOW_OUT, NULL, pwGraph, "take", ax[0], 13, ax[1] - ax[0], cy - 2); if (ptw->aar[iPlayer][2] > ptw->aar[iPlayer][1]) gtk_locdef_paint_box(gtk_widget_get_style(pwGraph), gtk_widget_get_window(pwGraph), cr, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT, NULL, pwGraph, "drop", ax[1], 13, ax[2] - ax[1], cy - 2); if (ptw->aar[iPlayer][2] < 1.0f) gtk_locdef_paint_box(gtk_widget_get_style(pwGraph), gtk_widget_get_window(pwGraph), cr, GTK_STATE_SELECTED, GTK_SHADOW_OUT, NULL, pwGraph, "too-good", ax[2], 13, x + cx - ax[2], cy - 2); return TRUE; } #if ! GTK_CHECK_VERSION(3,0,0) static void GraphExpose(GtkWidget * pwGraph, GdkEventExpose * UNUSED(pev), theorywidget * ptw) { cairo_t *cr; cr = gdk_cairo_create(gtk_widget_get_window(pwGraph)); GraphDraw(pwGraph, cr, ptw); cairo_destroy(cr); } #endif static void PlyClicked(GtkWidget * pw, theorywidget * ptw) { int *pi = (int *) g_object_get_data(G_OBJECT(pw), "ply"); int f = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pw)); cubeinfo ci; decisionData dd; evalcontext ec = { FALSE, 0, FALSE, TRUE, 0.0 }; int i, j; if (!f) return; GetMatchStateCubeInfo(&ci, &ms); TheoryGetValues(ptw, &ci, dd.aarRates); ec.nPlies = *pi; dd.pboard = msBoard(); dd.pci = &ci; dd.pec = &ec; if (RunAsyncProcess((AsyncFun) asyncGammonRates, &dd, _("Evaluating gammon percentages")) != 0) { fInterrupt = FALSE; return; } for (i = 0; i < 2; ++i) for (j = 0; j < 2; ++j) gtk_adjustment_set_value(GTK_ADJUSTMENT(ptw->aapwRates[i][j]), dd.aarRates[i][j] * 100.0f); TheoryUpdated(NULL, ptw); } /* * Display widget with misc. theory: * - market windows * - gammon price * * Input: * fActivePage: with notebook page should receive focus. * */ extern void GTKShowTheory(const int fActivePage) { GtkWidget *pwDialog, *pwNotebook; GtkWidget *pwOuterHBox, *pwVBox, *pwHBox; GtkWidget *pwFrame, *pwTable, *pwAlign; GtkWidget *pw, *pwx, *pwz; int i, j; char sz[256]; int *pi; PangoFontDescription *font_desc; theorywidget *ptw; /* create dialog */ pwDialog = GTKCreateDialog(_("GNU Backgammon - Theory"), DT_INFO, NULL, DIALOG_FLAG_MODAL | DIALOG_FLAG_NOTIDY, NULL, NULL); gtk_window_set_default_size(GTK_WINDOW(pwDialog), 660, 300); ptw = malloc(sizeof(theorywidget)); g_object_set_data_full(G_OBJECT(pwDialog), "theorywidget", ptw, free); #if GTK_CHECK_VERSION(3,0,0) pwOuterHBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); #else pwOuterHBox = gtk_hbox_new(FALSE, 8); #endif gtk_container_set_border_width(GTK_CONTAINER(pwOuterHBox), 8); gtk_container_add(GTK_CONTAINER(DialogArea(pwDialog, DA_MAIN)), pwOuterHBox); #if GTK_CHECK_VERSION(3,0,0) pwVBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); #else pwVBox = gtk_vbox_new(FALSE, 0); #endif gtk_box_pack_start(GTK_BOX(pwOuterHBox), pwVBox, FALSE, FALSE, 0); /* match/money play */ #if GTK_CHECK_VERSION(3,0,0) pwHBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); #else pwHBox = gtk_hbox_new(FALSE, 0); #endif gtk_box_pack_start(GTK_BOX(pwVBox), pwHBox, FALSE, FALSE, 0); gtk_container_add(GTK_CONTAINER(pwHBox), ptw->apwRadio[0] = gtk_radio_button_new_with_label(NULL, _("Match play"))); gtk_container_add(GTK_CONTAINER(pwHBox), ptw->apwRadio[1] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(ptw->apwRadio[0]), _("Money game"))); g_signal_connect(G_OBJECT(ptw->apwRadio[0]), "toggled", G_CALLBACK(TheoryUpdated), ptw); g_signal_connect(G_OBJECT(ptw->apwRadio[1]), "toggled", G_CALLBACK(TheoryUpdated), ptw); gtk_container_add(GTK_CONTAINER(pwHBox), ptw->pwReset = gtk_button_new_with_label(_("Reset"))); g_signal_connect(G_OBJECT(ptw->pwReset), "clicked", G_CALLBACK(ResetTheory), ptw); /* match score widget */ ptw->apwFrame[0] = gtk_frame_new(_("Match score")); gtk_box_pack_start(GTK_BOX(pwVBox), ptw->apwFrame[0], FALSE, FALSE, 0); #if GTK_CHECK_VERSION(3,0,0) pw = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); #else pw = gtk_vbox_new(FALSE, 0); #endif gtk_container_add(GTK_CONTAINER(ptw->apwFrame[0]), pw); pwTable = gtk_table_new(2, 3, FALSE); gtk_container_add(GTK_CONTAINER(pw), pwTable); for (i = 0; i < 2; i++) { gtk_table_attach(GTK_TABLE(pwTable), pwx = gtk_label_new(ap[i].szName), 0, 1, 0 + i, 1 + i, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 4, 0); gtk_misc_set_alignment(GTK_MISC(pwx), 0, 0.5); ptw->apwScoreAway[i] = GTK_ADJUSTMENT(gtk_adjustment_new(1, 1, 64, 1, 5, 0)); gtk_table_attach(GTK_TABLE(pwTable), gtk_spin_button_new(ptw->apwScoreAway[i], 1, 0), 1, 2, 0 + i, 1 + i, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 4, 0); gtk_table_attach(GTK_TABLE(pwTable), pwx = gtk_label_new(_("-away")), 2, 3, 0 + i, 1 + i, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 4, 0); gtk_misc_set_alignment(GTK_MISC(pwx), 0, 0.5); g_signal_connect(G_OBJECT(ptw->apwScoreAway[i]), "value-changed", G_CALLBACK(TheoryUpdated), ptw); } #if GTK_CHECK_VERSION(3,0,0) pwHBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); #else pwHBox = gtk_hbox_new(FALSE, 0); #endif gtk_container_add(GTK_CONTAINER(pw), pwHBox); gtk_container_add(GTK_CONTAINER(pwHBox), ptw->pwCrawford = gtk_check_button_new_with_label(_("Crawford game"))); g_signal_connect(G_OBJECT(ptw->pwCrawford), "toggled", G_CALLBACK(TheoryUpdated), ptw); ptw->pwCubeFrame = gtk_frame_new(_("Cube")); gtk_container_add(GTK_CONTAINER(pw), ptw->pwCubeFrame); #if GTK_CHECK_VERSION(3,0,0) pwHBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); #else pwHBox = gtk_hbox_new(FALSE, 0); #endif gtk_container_add(GTK_CONTAINER(ptw->pwCubeFrame), pwHBox); j = 1; for (i = 0; i < 7; i++) { sprintf(sz, "%d", j); if (!i) gtk_container_add(GTK_CONTAINER(pwHBox), ptw->apwCube[i] = gtk_radio_button_new_with_label(NULL, sz)); else gtk_container_add(GTK_CONTAINER(pwHBox), ptw->apwCube[i] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(ptw->apwCube[0]), sz)); g_signal_connect(G_OBJECT(ptw->apwCube[i]), "toggled", G_CALLBACK(TheoryUpdated), ptw); j *= 2; } /* match equity table */ pwFrame = gtk_frame_new(_("Match equity table")); gtk_container_add(GTK_CONTAINER(pw), pwFrame); #if GTK_CHECK_VERSION(3,0,0) pwx = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); #else pwx = gtk_vbox_new(FALSE, 4); #endif gtk_container_add(GTK_CONTAINER(pwFrame), pwx); gtk_box_pack_start(GTK_BOX(pwx), pwz = gtk_label_new((char *) miCurrent.szName), FALSE, FALSE, 0); gtk_misc_set_alignment(GTK_MISC(pwz), 0, 0.5); gtk_box_pack_start(GTK_BOX(pwx), pwz = gtk_label_new((char *) miCurrent.szFileName), FALSE, FALSE, 0); gtk_misc_set_alignment(GTK_MISC(pwz), 0, 0.5); gtk_box_pack_start(GTK_BOX(pwx), pwz = gtk_label_new((char *) miCurrent.szDescription), FALSE, FALSE, 0); gtk_misc_set_alignment(GTK_MISC(pwz), 0, 0.5); /* money play widget */ ptw->apwFrame[1] = gtk_frame_new(_("Money play")); gtk_box_pack_start(GTK_BOX(pwVBox), ptw->apwFrame[1], FALSE, FALSE, 0); #if GTK_CHECK_VERSION(3,0,0) pwHBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); #else pwHBox = gtk_hbox_new(FALSE, 0); #endif gtk_container_add(GTK_CONTAINER(ptw->apwFrame[1]), pwHBox); gtk_container_add(GTK_CONTAINER(pwHBox), ptw->pwJacoby = gtk_check_button_new_with_label(_("Jacoby rule"))); g_signal_connect(G_OBJECT(ptw->pwJacoby), "toggled", G_CALLBACK(TheoryUpdated), ptw); gtk_container_add(GTK_CONTAINER(pwHBox), ptw->pwBeavers = gtk_check_button_new_with_label(_("Beavers allowed"))); g_signal_connect(G_OBJECT(ptw->pwBeavers), "toggled", G_CALLBACK(TheoryUpdated), ptw); /* gammon and backgammon percentages */ pwFrame = gtk_frame_new(_("Gammon and backgammon percentages")); gtk_box_pack_start(GTK_BOX(pwVBox), pwFrame, FALSE, FALSE, 0); #if GTK_CHECK_VERSION(3,0,0) pwx = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); #else pwx = gtk_vbox_new(FALSE, 0); #endif gtk_container_add(GTK_CONTAINER(pwFrame), pwx); pwTable = gtk_table_new(3, 3, TRUE); gtk_box_pack_start(GTK_BOX(pwx), pwTable, FALSE, FALSE, 4); for (i = 0; i < 2; i++) { /* player name */ gtk_table_attach(GTK_TABLE(pwTable), pw = gtk_label_new(ap[i].szName), 0, 1, 1 + i, 2 + i, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 4, 0); gtk_misc_set_alignment(GTK_MISC(pw), 0, 0.5); /* column title */ gtk_table_attach(GTK_TABLE(pwTable), pw = gtk_label_new(i ? _("bg rate(%)") : _("gammon rate(%)")), 1 + i, 2 + i, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 4, 0); gtk_misc_set_alignment(GTK_MISC(pw), 0, 0.5); for (j = 0; j < 2; j++) { ptw->aapwRates[i][j] = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 100.0, 0.01, 1.0, 0)); gtk_table_attach(GTK_TABLE(pwTable), gtk_spin_button_new(ptw->aapwRates[i][j], 0.01, 2), j + 1, j + 2, i + 1, i + 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 4, 0); g_signal_connect(G_OBJECT(ptw->aapwRates[i][j]), "value-changed", G_CALLBACK(TheoryUpdated), ptw); } } /* radio buttons with plies */ #if GTK_CHECK_VERSION(3,0,0) pwz = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); #else pwz = gtk_hbox_new(FALSE, 4); #endif gtk_box_pack_start(GTK_BOX(pwx), pwz, FALSE, FALSE, 4); for (i = 0; i <= MAXPLY; ++i) { gchar *sz = g_strdup_printf(_("%d ply"), i); if (!i) ptw->apwPly[i] = gtk_radio_button_new_with_label(NULL, sz); else ptw->apwPly[i] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(ptw->apwPly[0]), sz); g_free(sz); pi = (int *) g_malloc(sizeof(int)); *pi = i; g_object_set_data_full(G_OBJECT(ptw->apwPly[i]), "ply", pi, g_free); gtk_box_pack_start(GTK_BOX(pwz), ptw->apwPly[i], FALSE, FALSE, 4); g_signal_connect(G_OBJECT(ptw->apwPly[i]), "toggled", G_CALLBACK(PlyClicked), ptw); } /* add notebook pages */ pwNotebook = gtk_notebook_new(); gtk_container_set_border_width(GTK_CONTAINER(pwNotebook), 0); gtk_box_pack_start(GTK_BOX(pwOuterHBox), pwNotebook, TRUE, TRUE, 0); /* market window */ #if GTK_CHECK_VERSION(3,0,0) pwVBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); #else pwVBox = gtk_vbox_new(FALSE, 10); #endif gtk_notebook_append_page(GTK_NOTEBOOK(pwNotebook), pwVBox, gtk_label_new(_("Market window"))); do_mw_views(ptw); for (i = 0; i < 2; ++i) { sprintf(sz, _("Market window for player %s"), ap[i].szName); pwFrame = gtk_frame_new(sz); gtk_box_pack_start(GTK_BOX(pwVBox), pwFrame, FALSE, FALSE, 0); gtk_container_add(GTK_CONTAINER(pwFrame), ptw->apwMW[i]); } /* window graph */ #if GTK_CHECK_VERSION(3,0,0) pwVBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); #else pwVBox = gtk_vbox_new(FALSE, 0); #endif gtk_notebook_append_page(GTK_NOTEBOOK(pwNotebook), pwVBox, gtk_label_new(_("Window graph"))); for (i = 0; i < 2; i++) { sprintf(sz, _("Window graph for player %s"), ap[i].szName); pwFrame = gtk_frame_new(sz); gtk_box_pack_start(GTK_BOX(pwVBox), pwFrame, FALSE, FALSE, 4); gtk_container_add(GTK_CONTAINER(pwFrame), pwAlign = gtk_alignment_new(0.5, 0.5, 1, 0)); gtk_container_add(GTK_CONTAINER(pwAlign), ptw->apwGraph[i] = gtk_drawing_area_new()); gtk_widget_set_name(ptw->apwGraph[i], "gnubg-doubling-window-graph"); gtk_container_set_border_width(GTK_CONTAINER(pwAlign), 4); gtk_widget_set_size_request(ptw->apwGraph[i], -1, 48); #if GTK_CHECK_VERSION(3,0,0) g_signal_connect(G_OBJECT(ptw->apwGraph[i]), "draw", G_CALLBACK(GraphDraw), ptw); #else g_signal_connect(G_OBJECT(ptw->apwGraph[i]), "expose_event", G_CALLBACK(GraphExpose), ptw); #endif } /* gammon prices */ #if GTK_CHECK_VERSION(3,0,0) pwVBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); #else pwVBox = gtk_vbox_new(FALSE, 0); #endif ptw->pwGammonPrice = gtk_text_view_new(); gtk_text_view_set_editable(GTK_TEXT_VIEW(ptw->pwGammonPrice), FALSE); font_desc = pango_font_description_from_string("Monospace"); gtk_widget_modify_font(ptw->pwGammonPrice, font_desc); pango_font_description_free(font_desc); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(ptw->pwGammonPrice), GTK_WRAP_NONE); gtk_container_add(GTK_CONTAINER(pwVBox), ptw->pwGammonPrice); gtk_notebook_append_page(GTK_NOTEBOOK(pwNotebook), pwVBox, gtk_label_new(_("Gammon values"))); /* show dialog */ ResetTheory(NULL, ptw); gtk_widget_show_all(pwDialog); TheoryUpdated(NULL, ptw); gtk_notebook_set_current_page(GTK_NOTEBOOK(pwNotebook), fActivePage ? 2 /* prices */ : 0 /* market */ ); }