URI: 
       toptdialog.c - vaccinewars - be a doctor and try to vaccinate the world
  HTML git clone git://src.adamsgaard.dk/vaccinewars
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       toptdialog.c (35785B)
       ---
            1 /************************************************************************
            2  * optdialog.c    Configuration file editing dialog                     *
            3  * Copyright (C)  2002-2004  Ben Webb                                   *
            4  *                Email: benwebb@users.sf.net                           *
            5  *                WWW: https://dopewars.sourceforge.io/                 *
            6  *                                                                      *
            7  * This program is free software; you can redistribute it and/or        *
            8  * modify it under the terms of the GNU General Public License          *
            9  * as published by the Free Software Foundation; either version 2       *
           10  * of the License, or (at your option) any later version.               *
           11  *                                                                      *
           12  * This program is distributed in the hope that it will be useful,      *
           13  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
           14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
           15  * GNU General Public License for more details.                         *
           16  *                                                                      *
           17  * You should have received a copy of the GNU General Public License    *
           18  * along with this program; if not, write to the Free Software          *
           19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,               *
           20  *                   MA  02111-1307, USA.                               *
           21  ************************************************************************/
           22 
           23 #ifdef HAVE_CONFIG_H
           24 #include <config.h>
           25 #endif
           26 
           27 #include <string.h>             /* For strcmp */
           28 #include <stdlib.h>             /* For atoi */
           29 
           30 #include "configfile.h"         /* For UpdateConfigFile etc. */
           31 #include "dopewars.h"           /* For struct GLOBALS etc. */
           32 #include "gtk_client.h"         /* For mainwindow etc. */
           33 #include "nls.h"                /* For _ function */
           34 #include "sound.h"              /* For SoundPlay */
           35 #include "gtkport/gtkport.h"    /* For gtk_ functions */
           36 
           37 struct ConfigWidget {
           38   GtkWidget *widget;
           39   gint globind;
           40   int maxindex;
           41   gchar **data;
           42 };
           43 
           44 static GSList *configlist = NULL, *clists = NULL;
           45 
           46 struct ConfigMembers {
           47   gchar *label, *name;
           48 };
           49 
           50 static void FreeConfigWidgets(void)
           51 {
           52   while (configlist) {
           53     int i;
           54     struct ConfigWidget *cwid = (struct ConfigWidget *)configlist->data;
           55 
           56     for (i = 0; i < cwid->maxindex; i++) {
           57       g_free(cwid->data[i]);
           58     }
           59     g_free(cwid->data);
           60     configlist = g_slist_remove(configlist, cwid);
           61   }
           62 }
           63 
           64 static void UpdateAllLists(void)
           65 {
           66   GSList *listpt;
           67 
           68   for (listpt = clists; listpt; listpt = g_slist_next(listpt)) {
           69     GtkTreeView *tv = GTK_TREE_VIEW(listpt->data);
           70     GtkTreeSelection *treesel = gtk_tree_view_get_selection(tv);
           71     /* Force unselection, which should trigger *_sel_changed function to
           72        copy widget data into configuration */
           73     gtk_tree_selection_unselect_all(treesel);
           74   }
           75 }
           76 
           77 static void SaveConfigWidget(struct GLOBALS *gvar, struct ConfigWidget *cwid,
           78                              int structind)
           79 {
           80   gboolean changed = FALSE;
           81 
           82   if (gvar->BoolVal) {
           83     gboolean *boolpt, newset;
           84 
           85     boolpt = GetGlobalBoolean(cwid->globind, structind);
           86     if (cwid->maxindex) {
           87       newset = (cwid->data[structind - 1] != NULL);
           88     } else {
           89       newset = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cwid->widget));
           90     }
           91     changed = (*boolpt != newset);
           92     *boolpt = newset;
           93   } else {
           94     gchar *text;
           95 
           96     if (cwid->maxindex) {
           97       text = cwid->data[structind - 1];
           98     } else {
           99       text = gtk_editable_get_chars(GTK_EDITABLE(cwid->widget), 0, -1);
          100     }
          101     if (gvar->IntVal) {
          102       int *intpt, newset;
          103 
          104       intpt = GetGlobalInt(cwid->globind, structind);
          105       newset = atoi(text);
          106       if (newset < gvar->MinVal) {
          107         newset = gvar->MinVal;
          108       }
          109       if (gvar->MaxVal > gvar->MinVal && newset > gvar->MaxVal) {
          110         newset = gvar->MaxVal;
          111       }
          112       changed = (*intpt != newset);
          113       *intpt = newset;
          114     } else if (gvar->PriceVal) {
          115       price_t *pricept, newset;
          116 
          117       pricept = GetGlobalPrice(cwid->globind, structind);
          118       newset = strtoprice(text);
          119       changed = (*pricept != newset);
          120       *pricept = newset;
          121     } else if (gvar->StringVal) {
          122       gchar **strpt;
          123 
          124       strpt = GetGlobalString(cwid->globind, structind);
          125       changed = (strcmp(*strpt, text) != 0);
          126       AssignName(strpt, text);
          127     }
          128     if (!cwid->maxindex) {
          129       g_free(text);
          130     }
          131   }
          132   gvar->Modified |= changed;
          133 }
          134 
          135 static void ResizeList(struct GLOBALS *gvar, int newmax)
          136 {
          137   int i;
          138 
          139   for (i = 0; i < NUMGLOB; i++) {
          140     if (Globals[i].StructListPt == gvar->StructListPt
          141         && Globals[i].ResizeFunc) {
          142       Globals[i].Modified = TRUE;
          143       (Globals[i].ResizeFunc) (newmax);
          144       return;
          145     }
          146   }
          147   g_assert(0);
          148 }
          149 
          150 static void SaveConfigWidgets(void)
          151 {
          152   GSList *listpt;
          153 
          154   UpdateAllLists();
          155 
          156   for (listpt = configlist; listpt; listpt = g_slist_next(listpt)) {
          157     struct ConfigWidget *cwid = (struct ConfigWidget *)listpt->data;
          158     struct GLOBALS *gvar;
          159 
          160     gvar = &Globals[cwid->globind];
          161     if (gvar->NameStruct && gvar->NameStruct[0]) {
          162       int i;
          163 
          164       if (cwid->maxindex != *gvar->MaxIndex) {
          165         ResizeList(gvar, cwid->maxindex);
          166       }
          167 
          168       for (i = 1; i <= *gvar->MaxIndex; i++) {
          169         SaveConfigWidget(gvar, cwid, i);
          170       }
          171     } else {
          172       SaveConfigWidget(gvar, cwid, 0);
          173     }
          174   }
          175 }
          176 
          177 static void AddConfigWidget(GtkWidget *widget, int ind)
          178 {
          179   struct ConfigWidget *cwid = g_new(struct ConfigWidget, 1);
          180   struct GLOBALS *gvar;
          181   
          182   cwid->widget = widget;
          183   cwid->globind = ind;
          184   cwid->data = NULL;
          185   cwid->maxindex = 0;
          186 
          187   gvar = &Globals[ind];
          188   if (gvar->MaxIndex) {
          189     int i;
          190 
          191     cwid->maxindex = *gvar->MaxIndex;
          192     cwid->data = g_new(gchar *, *gvar->MaxIndex);
          193     for (i = 1; i <= *gvar->MaxIndex; i++) {
          194       if (gvar->StringVal) {
          195         cwid->data[i - 1] = g_strdup(*GetGlobalString(ind, i));
          196       } else if (gvar->IntVal) {
          197         cwid->data[i - 1] =
          198             g_strdup_printf("%d", *GetGlobalInt(ind, i));
          199       } else if (gvar->PriceVal) {
          200         cwid->data[i - 1] = pricetostr(*GetGlobalPrice(ind, i));
          201       } else if (gvar->BoolVal) {
          202         if (*GetGlobalBoolean(ind, i)) {
          203           cwid->data[i - 1] = g_strdup("1");
          204         } else {
          205           cwid->data[i - 1] = NULL;
          206         }
          207       }
          208     }
          209   }
          210   configlist = g_slist_append(configlist, cwid);
          211 }
          212 
          213 static GtkWidget *NewConfigCheck(gchar *name, gchar *label)
          214 {
          215   GtkWidget *check;
          216   int ind;
          217   struct GLOBALS *gvar;
          218 
          219   ind = GetGlobalIndex(name, NULL);
          220   g_assert(ind >= 0);
          221   gvar = &Globals[ind];
          222   g_assert(gvar->BoolVal);
          223 
          224   check = gtk_check_button_new_with_label(label);
          225   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), *gvar->BoolVal);
          226 
          227   AddConfigWidget(check, ind);
          228 
          229   return check;
          230 }
          231 
          232 static GtkWidget *NewConfigEntry(gchar *name)
          233 {
          234   GtkWidget *entry;
          235   gchar *tmpstr;
          236   int ind;
          237   struct GLOBALS *gvar;
          238 
          239   ind = GetGlobalIndex(name, NULL);
          240   g_assert(ind >= 0);
          241 
          242   entry = gtk_entry_new();
          243   gvar = &Globals[ind];
          244 
          245   if (gvar->StringVal) {
          246     gtk_entry_set_text(GTK_ENTRY(entry), *gvar->StringVal);
          247   } else if (gvar->IntVal) {
          248     if (gvar->MaxVal > gvar->MinVal) {
          249       GtkAdjustment *spin_adj;
          250 
          251       gtk_widget_destroy(entry);
          252       spin_adj = (GtkAdjustment *)gtk_adjustment_new(*gvar->IntVal,
          253                                                      gvar->MinVal,
          254                                                      gvar->MaxVal,
          255                                                      1.0, 10.0, 0.0);
          256       entry = gtk_spin_button_new(spin_adj, 1.0, 0);
          257     } else {
          258       tmpstr = g_strdup_printf("%d", *gvar->IntVal);
          259       gtk_entry_set_text(GTK_ENTRY(entry), tmpstr);
          260       g_free(tmpstr);
          261     }
          262   } else if (gvar->PriceVal) {
          263     tmpstr = pricetostr(*gvar->PriceVal);
          264     gtk_entry_set_text(GTK_ENTRY(entry), tmpstr);
          265     g_free(tmpstr);
          266   }
          267 
          268   AddConfigWidget(entry, ind);
          269 
          270   return entry;
          271 }
          272 
          273 static void AddStructConfig(GtkWidget *grid, int row, gchar *structname,
          274                             struct ConfigMembers *member)
          275 {
          276   int ind;
          277   struct GLOBALS *gvar;
          278 
          279   ind = GetGlobalIndex(structname, member->name);
          280   g_assert(ind >= 0);
          281 
          282   gvar = &Globals[ind];
          283   if (gvar->BoolVal) {
          284     GtkWidget *check;
          285 
          286     check = gtk_check_button_new_with_label(_(member->label));
          287     dp_gtk_grid_attach(GTK_GRID(grid), check, 0, row, 2, 1, TRUE);
          288     AddConfigWidget(check, ind);
          289   } else {
          290     GtkWidget *label, *entry;
          291 
          292     label = gtk_label_new(_(member->label));
          293     dp_gtk_grid_attach(GTK_GRID(grid), label, 0, row, 1, 1, FALSE);
          294     if (gvar->IntVal && gvar->MaxVal > gvar->MinVal) {
          295       GtkAdjustment *spin_adj = (GtkAdjustment *)
          296           gtk_adjustment_new(gvar->MinVal, gvar->MinVal, gvar->MaxVal,
          297                              1.0, 10.0, 0.0);
          298       entry = gtk_spin_button_new(spin_adj, 1.0, 0);
          299     } else {
          300       entry = gtk_entry_new();
          301     }
          302     dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, row, 1, 1, TRUE);
          303     AddConfigWidget(entry, ind);
          304   }
          305 }
          306 
          307 static void swap_rows(GtkTreeView *tv, gint selrow, gint swaprow,
          308                       gchar *structname)
          309 {
          310   GSList *listpt;
          311   GtkTreeIter seliter, swapiter;
          312   GtkTreeModel *model = gtk_tree_view_get_model(tv);
          313   GtkTreeSelection *treesel = gtk_tree_view_get_selection(tv);
          314 
          315   g_assert(gtk_tree_model_iter_nth_child(model, &seliter, NULL, selrow));
          316   g_assert(gtk_tree_model_iter_nth_child(model, &swapiter, NULL, swaprow));
          317 
          318   gtk_tree_selection_unselect_iter(treesel, &seliter);
          319   gtk_list_store_swap(GTK_LIST_STORE(model), &seliter, &swapiter);
          320 
          321   for (listpt = configlist; listpt; listpt = g_slist_next(listpt)) {
          322     struct ConfigWidget *cwid = (struct ConfigWidget *)listpt->data;
          323     struct GLOBALS *gvar;
          324 
          325     gvar = &Globals[cwid->globind];
          326 
          327     if (gvar->NameStruct && strcmp(structname, gvar->NameStruct) == 0) {
          328       gchar *tmp = cwid->data[selrow];
          329 
          330       cwid->data[selrow] = cwid->data[swaprow];
          331       cwid->data[swaprow] = tmp;
          332     }
          333   }
          334 
          335   gtk_tree_selection_select_iter(treesel, &seliter);
          336 }
          337 
          338 /* Return the index of the currently selected row, or -1 if none is selected.
          339    This works only for lists (not trees) with GTK_SELECTION_SINGLE mode */
          340 static int get_tree_selection_row_index(GtkTreeSelection *treesel,
          341                                         GtkTreeModel **model)
          342 {
          343   int row = -1;
          344   GList *selrows = gtk_tree_selection_get_selected_rows(treesel, model);
          345   if (selrows) {
          346     GtkTreePath *path = selrows->data;
          347     gint depth;
          348     gint *inds = gtk_tree_path_get_indices_with_depth(path, &depth);
          349     g_assert(selrows->next == NULL);
          350     g_assert(depth == 1);
          351     row = inds[0];
          352   }
          353   g_list_free_full(selrows, (GDestroyNotify)gtk_tree_path_free);
          354   return row;
          355 }
          356 
          357 static void list_delete(GtkWidget *widget, gchar *structname)
          358 {
          359   GtkTreeView *tv;
          360   GtkTreeSelection *treesel;
          361   GtkTreeModel *model;
          362   int minlistlength, nrows, row;
          363 
          364   tv = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(widget), "treeview"));
          365   g_assert(tv);
          366   treesel = gtk_tree_view_get_selection(tv);
          367   row = get_tree_selection_row_index(treesel, &model);
          368 
          369   minlistlength = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(model),
          370                                                     "minlistlength"));
          371   nrows = gtk_tree_model_iter_n_children(model, NULL);
          372 
          373   if (nrows > minlistlength && row >= 0) {
          374     GtkTreeIter iter;
          375     GSList *listpt;
          376     gboolean valid;
          377     /* Prevent selection changed from reading deleted entry */
          378     g_object_set_data(G_OBJECT(model), "oldsel", GINT_TO_POINTER(-1));
          379     g_assert(gtk_tree_model_iter_nth_child(model, &iter, NULL, row));
          380     gtk_tree_selection_unselect_iter(treesel, &iter);
          381     valid = gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
          382 
          383     for (listpt = configlist; listpt; listpt = g_slist_next(listpt)) {
          384       struct ConfigWidget *cwid = (struct ConfigWidget *)listpt->data;
          385       struct GLOBALS *gvar;
          386 
          387       gvar = &Globals[cwid->globind];
          388       if (gvar->NameStruct && strcmp(structname, gvar->NameStruct) == 0) {
          389         int i;
          390 
          391         cwid->maxindex--;
          392         g_free(cwid->data[row]);
          393         for (i = row; i < cwid->maxindex; i++) {
          394           cwid->data[i] = cwid->data[i + 1];
          395         }
          396         cwid->data = g_realloc(cwid->data, sizeof(gchar *) * cwid->maxindex);
          397       }
          398     }
          399     if (valid) {
          400       gtk_tree_selection_select_iter(treesel, &iter);
          401     }
          402   }
          403 }
          404 
          405 static void list_new(GtkWidget *widget, gchar *structname)
          406 {
          407   GtkTreeView *tv;
          408   GtkListStore *store;
          409   GtkTreeSelection *treesel;
          410   GtkTreeIter iter;
          411   int row;
          412   GSList *listpt;
          413   gchar *newname;
          414 
          415   tv = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(widget), "treeview"));
          416   g_assert(tv);
          417   treesel = gtk_tree_view_get_selection(tv);
          418   store = GTK_LIST_STORE(gtk_tree_view_get_model(tv));
          419 
          420   newname = g_strdup_printf(_("New %s"), structname);
          421   gtk_list_store_append(store, &iter);
          422   gtk_list_store_set(store, &iter, 0, newname, -1);
          423   row = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL) - 1;
          424 
          425   for (listpt = configlist; listpt; listpt = g_slist_next(listpt)) {
          426     struct ConfigWidget *cwid = (struct ConfigWidget *)listpt->data;
          427     struct GLOBALS *gvar;
          428 
          429     gvar = &Globals[cwid->globind];
          430     if (gvar->NameStruct && strcmp(structname, gvar->NameStruct) == 0) {
          431       cwid->maxindex++;
          432       g_assert(cwid->maxindex == row + 1);
          433       cwid->data = g_realloc(cwid->data, sizeof(gchar *) * cwid->maxindex);
          434       if (strcmp(gvar->Name, "Name") == 0) {
          435         cwid->data[row] = g_strdup(newname);
          436       } else {
          437         cwid->data[row] = g_strdup("");
          438       }
          439     }
          440   }
          441   g_free(newname);
          442 
          443   gtk_tree_selection_select_iter(treesel, &iter);
          444 }
          445 
          446 static void list_up(GtkWidget *widget, gchar *structname)
          447 {
          448   GtkTreeView *tv;
          449   GtkTreeSelection *treesel;
          450   int row;
          451 
          452   tv = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(widget), "treeview"));
          453   g_assert(tv);
          454   treesel = gtk_tree_view_get_selection(tv);
          455   row = get_tree_selection_row_index(treesel, NULL);
          456 
          457   if (row > 0) {
          458     swap_rows(tv, row, row - 1, structname);
          459   }
          460 }
          461 
          462 static void list_down(GtkWidget *widget, gchar *structname)
          463 {
          464   GtkTreeView *tv;
          465   GtkTreeSelection *treesel;
          466   GtkTreeModel *model;
          467   int row, nrows;
          468 
          469   tv = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(widget), "treeview"));
          470   g_assert(tv);
          471   treesel = gtk_tree_view_get_selection(tv);
          472   row = get_tree_selection_row_index(treesel, &model);
          473   nrows = gtk_tree_model_iter_n_children(model, NULL);
          474 
          475   if (row < nrows - 1 && row >= 0) {
          476     swap_rows(tv, row, row + 1, structname);
          477   }
          478 }
          479 
          480 static void list_sel_changed(GtkTreeSelection *treesel, gpointer data)
          481 {
          482   GtkTreeModel *model;
          483   GtkWidget *delbut, *upbut, *downbut;
          484   int minlistlength, nrows, row, oldsel;
          485   GSList *listpt;
          486   gchar *structname = data;
          487 
          488   row = get_tree_selection_row_index(treesel, &model);
          489   nrows = gtk_tree_model_iter_n_children(model, NULL);
          490 
          491   delbut  = GTK_WIDGET(g_object_get_data(G_OBJECT(model), "delete"));
          492   upbut   = GTK_WIDGET(g_object_get_data(G_OBJECT(model), "up"));
          493   downbut = GTK_WIDGET(g_object_get_data(G_OBJECT(model), "down"));
          494   oldsel = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(model), "oldsel"));
          495   g_assert(delbut && upbut && downbut);
          496   minlistlength = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(model),
          497                                                     "minlistlength"));
          498 
          499   gtk_widget_set_sensitive(delbut, nrows > minlistlength);
          500   gtk_widget_set_sensitive(upbut, row > 0);
          501   gtk_widget_set_sensitive(downbut, row < nrows - 1);
          502 
          503   /* Store any edited data from old-selected row */
          504   if (oldsel >= 0) {
          505     for (listpt = configlist; listpt; listpt = g_slist_next(listpt)) {
          506       struct ConfigWidget *conf = (struct ConfigWidget *)listpt->data;
          507       struct GLOBALS *gvar;
          508 
          509       gvar = &Globals[conf->globind];
          510 
          511       if (gvar->NameStruct && strcmp(structname, gvar->NameStruct) == 0) {
          512         g_free(conf->data[oldsel]);
          513         conf->data[oldsel] = NULL;
          514 
          515         if (gvar->BoolVal) {
          516           if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(conf->widget))) {
          517             conf->data[oldsel] = g_strdup("1");
          518           }
          519         } else {
          520           conf->data[oldsel] = gtk_editable_get_chars(
          521                                          GTK_EDITABLE(conf->widget), 0, -1);
          522           gtk_entry_set_text(GTK_ENTRY(conf->widget), "");
          523         }
          524         if (strcmp(gvar->Name, "Name") == 0) {
          525           GtkTreeIter ositer;
          526           g_assert(gtk_tree_model_iter_nth_child(model, &ositer, NULL, oldsel));
          527           gtk_list_store_set(GTK_LIST_STORE(model), &ositer, 0,
          528                              conf->data[oldsel], -1);
          529         }
          530       }
          531     }
          532   }
          533   g_object_set_data(G_OBJECT(model), "oldsel", GINT_TO_POINTER(row));
          534 
          535   /* Update widgets with selected row */
          536   if (row >= 0) {
          537     for (listpt = configlist; listpt; listpt = g_slist_next(listpt)) {
          538       struct ConfigWidget *conf = (struct ConfigWidget *)listpt->data;
          539       struct GLOBALS *gvar;
          540 
          541       gvar = &Globals[conf->globind];
          542 
          543       if (gvar->NameStruct && strcmp(structname, gvar->NameStruct) == 0) {
          544         if (gvar->BoolVal) {
          545           gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(conf->widget),
          546                                        conf->data[row] != NULL);
          547         } else {
          548           gtk_entry_set_text(GTK_ENTRY(conf->widget), conf->data[row]);
          549         }
          550       }
          551     }
          552   }
          553 }
          554 
          555 static void sound_sel_changed(GtkTreeSelection *treesel, gpointer data)
          556 {
          557   GtkTreeModel *model;
          558   GtkTreeIter iter;
          559   GtkWidget *entry;
          560   int row, oldsel, globind;
          561 
          562   row = get_tree_selection_row_index(treesel, &model);
          563   oldsel = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(model), "oldsel"));
          564   entry = GTK_WIDGET(g_object_get_data(G_OBJECT(model), "entry"));
          565 
          566   /* Store any edited data from old-selected row */
          567   if (oldsel >= 0) {
          568     gchar *text, **oldtext;
          569     g_assert(gtk_tree_model_iter_nth_child(model, &iter, NULL, oldsel));
          570     gtk_tree_model_get(model, &iter, 2, &globind, -1);
          571     g_assert(globind >=0 && globind < NUMGLOB);
          572 
          573     text = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
          574     oldtext = GetGlobalString(globind, 0);
          575     g_assert(text && oldtext);
          576     if (strcmp(text, *oldtext) != 0) {
          577       AssignName(GetGlobalString(globind, 0), text);
          578       Globals[globind].Modified = TRUE;
          579     }
          580     gtk_entry_set_text(GTK_ENTRY(entry), "");
          581     g_free(text);
          582   }
          583 
          584   g_object_set_data(G_OBJECT(model), "oldsel", GINT_TO_POINTER(row));
          585   /* Update new selection */
          586   if (row >= 0) {
          587     gchar **text;
          588     g_assert(gtk_tree_model_iter_nth_child(model, &iter, NULL, row));
          589     gtk_tree_model_get(model, &iter, 2, &globind, -1);
          590     g_assert(globind >=0 && globind < NUMGLOB);
          591     text = GetGlobalString(globind, 0);
          592     gtk_entry_set_text(GTK_ENTRY(entry), *text);
          593   }
          594 }
          595 
          596 static void BrowseSound(GtkWidget *entry)
          597 {
          598   gchar *oldtext, *newtext;
          599   GtkWidget *dialog = gtk_widget_get_ancestor(entry, GTK_TYPE_WINDOW);
          600 
          601   oldtext = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
          602 
          603   newtext = GtkGetFile(dialog, oldtext, _("Select sound file"));
          604   g_free(oldtext);
          605   if (newtext) {
          606     gtk_entry_set_text(GTK_ENTRY(entry), newtext);
          607     g_free(newtext);
          608   }
          609 }
          610 
          611 static void TestPlaySound(GtkWidget *entry)
          612 {
          613   gchar *text;
          614   gboolean sound_enabled;
          615 
          616   text = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
          617   sound_enabled = IsSoundEnabled();
          618   SoundEnable(TRUE);
          619   SoundPlay(text);
          620   SoundEnable(sound_enabled);
          621   g_free(text);
          622 }
          623 
          624 static void OKCallback(GtkWidget *widget, GtkWidget *dialog)
          625 {
          626   GtkToggleButton *unicode_check;
          627 
          628   SaveConfigWidgets();
          629   unicode_check = GTK_TOGGLE_BUTTON(g_object_get_data(G_OBJECT(dialog),
          630                                                       "unicode_check"));
          631   UpdateConfigFile(NULL, gtk_toggle_button_get_active(unicode_check));
          632   gtk_widget_destroy(dialog);
          633 }
          634 
          635 static gchar *GetHelpPage(const gchar *pagename)
          636 {
          637   gchar *root, *file;
          638 
          639   root = GetDocRoot();
          640   file = g_strdup_printf("%shelp/%s.html", root, pagename);
          641   g_free(root);
          642   return file;
          643 }
          644 
          645 static void HelpCallback(GtkWidget *widget, GtkWidget *notebook)
          646 {
          647   const static gchar *pagehelp[] = {
          648     "general", "locations", "drugs", "guns", "cops", "server", "sounds"
          649   };
          650   gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
          651   gchar *help;
          652 
          653   help = GetHelpPage(pagehelp[page]);
          654   DisplayHTML(widget, OurWebBrowser, help);
          655   g_free(help);
          656 }
          657 
          658 static void FinishOptDialog(GtkWidget *widget, gpointer data)
          659 {
          660   FreeConfigWidgets();
          661 
          662   g_slist_free(clists);
          663   clists = NULL;
          664 }
          665 
          666 static GtkWidget *CreateList(gchar *structname, struct ConfigMembers *members)
          667 {
          668   GtkWidget *hbox, *vbox, *hbbox, *tv, *scrollwin, *button, *grid;
          669   GtkTreeSelection *treesel;
          670   GtkListStore *store;
          671   GtkCellRenderer *renderer;
          672   GtkTreeIter iter;
          673 
          674   int ind, minlistlength = 0;
          675   gint i, nummembers;
          676   struct GLOBALS *gvar;
          677   struct ConfigMembers namemember = { N_("Name"), "Name" };
          678 
          679   ind = GetGlobalIndex(structname, "Name");
          680   g_assert(ind >= 0);
          681   gvar = &Globals[ind];
          682   g_assert(gvar->StringVal && gvar->MaxIndex);
          683 
          684   for (i = 0; i < NUMGLOB; i++) {
          685     if (Globals[i].StructListPt == gvar->StructListPt
          686         && Globals[i].ResizeFunc) {
          687       minlistlength = Globals[i].MinVal;
          688     }
          689   }
          690 
          691   nummembers = 0;
          692   while (members && members[nummembers].label) {
          693     nummembers++;
          694   }
          695 
          696   hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10);
          697 
          698   vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
          699 
          700   tv = gtk_scrolled_tree_view_new(&scrollwin);
          701   store = gtk_list_store_new(1, G_TYPE_STRING);
          702   gtk_tree_view_set_model(GTK_TREE_VIEW(tv), GTK_TREE_MODEL(store));
          703   renderer = gtk_cell_renderer_text_new();
          704   gtk_tree_view_insert_column_with_attributes(
          705                GTK_TREE_VIEW(tv), -1, structname, renderer, "text", 0, NULL);
          706   g_object_unref(store);
          707   gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(tv), FALSE);
          708 
          709   treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv));
          710   g_signal_connect(G_OBJECT(treesel), "changed", G_CALLBACK(list_sel_changed),
          711                    structname);
          712   gtk_tree_selection_set_mode(treesel, GTK_SELECTION_SINGLE);
          713   gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store),
          714           GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
          715 
          716   clists = g_slist_append(clists, tv);
          717 
          718   for (i = 1; i <= *gvar->MaxIndex; i++) {
          719     gtk_list_store_append(store, &iter);
          720     gtk_list_store_set(store, &iter, 0, *GetGlobalString(ind, i), -1);
          721   }
          722   gtk_box_pack_start(GTK_BOX(vbox), scrollwin, TRUE, TRUE, 0);
          723 
          724   hbbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
          725   gtk_box_set_homogeneous(GTK_BOX(hbbox), TRUE);
          726   g_object_set_data(G_OBJECT(store), "oldsel", GINT_TO_POINTER(-1));
          727 
          728   button = gtk_button_new_with_label(_("New"));
          729   g_object_set_data(G_OBJECT(button), "treeview", tv);
          730   g_signal_connect(G_OBJECT(button), "clicked",
          731                    G_CALLBACK(list_new), structname);
          732   gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0);
          733 
          734   button = gtk_button_new_with_label(_("Delete"));
          735   gtk_widget_set_sensitive(button, FALSE);
          736   g_object_set_data(G_OBJECT(button), "treeview", tv);
          737   g_object_set_data(G_OBJECT(store), "delete", button);
          738   g_object_set_data(G_OBJECT(store), "minlistlength",
          739                     GINT_TO_POINTER(minlistlength));
          740   g_signal_connect(G_OBJECT(button), "clicked",
          741                    G_CALLBACK(list_delete), structname);
          742   gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0);
          743 
          744   button = gtk_button_new_with_label(_("Up"));
          745   gtk_widget_set_sensitive(button, FALSE);
          746   g_object_set_data(G_OBJECT(button), "treeview", tv);
          747   g_object_set_data(G_OBJECT(store), "up", button);
          748   g_signal_connect(G_OBJECT(button), "clicked",
          749                    G_CALLBACK(list_up), structname);
          750   gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0);
          751 
          752   button = gtk_button_new_with_label(_("Down"));
          753   gtk_widget_set_sensitive(button, FALSE);
          754   g_object_set_data(G_OBJECT(button), "treeview", tv);
          755   g_object_set_data(G_OBJECT(store), "down", button);
          756   g_signal_connect(G_OBJECT(button), "clicked",
          757                    G_CALLBACK(list_down), structname);
          758   gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0);
          759 
          760   gtk_box_pack_start(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
          761   gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
          762 
          763   grid = dp_gtk_grid_new(nummembers + 1, 2, FALSE);
          764   gtk_grid_set_row_spacing(GTK_GRID(grid), 5);
          765   gtk_grid_set_column_spacing(GTK_GRID(grid), 5);
          766 
          767   AddStructConfig(grid, 0, structname, &namemember);
          768   for (i = 0; i < nummembers; i++) {
          769     AddStructConfig(grid, i + 1, structname, &members[i]);
          770   }
          771 
          772   gtk_box_pack_start(GTK_BOX(hbox), grid, TRUE, TRUE, 0);
          773 
          774   return hbox;
          775 }
          776 
          777 static void FillSoundsList(GtkTreeView *tv)
          778 {
          779   GtkListStore *store;
          780   GtkTreeIter iter;
          781   gint i;
          782 
          783   /* Don't update the widget until we're done */
          784   store = GTK_LIST_STORE(gtk_tree_view_get_model(tv));
          785   g_object_ref(store);
          786   gtk_tree_view_set_model(tv, NULL);
          787 
          788   gtk_list_store_clear(store);
          789   for (i = 0; i < NUMGLOB; i++) {
          790     if (strlen(Globals[i].Name) > 7
          791         && strncmp(Globals[i].Name, "Sounds.", 7) == 0) {
          792       gtk_list_store_append(store, &iter);
          793       gtk_list_store_set(store, &iter, 0, &Globals[i].Name[7],
          794                          1, _(Globals[i].Help), 2, i, -1);
          795     }
          796   }
          797 
          798   gtk_tree_view_set_model(tv, GTK_TREE_MODEL(store));
          799 }
          800 
          801 void OptDialog(GtkWidget *widget, gpointer data)
          802 {
          803   GtkWidget *dialog, *notebook, *label, *check, *entry, *grid;
          804   GtkWidget *hbox, *vbox, *vbox2, *hsep, *button, *hbbox, *tv;
          805   GtkWidget *scrollwin;
          806   GtkAccelGroup *accel_group;
          807   gchar *sound_titles[2];
          808   GtkCellRenderer *renderer;
          809   GtkListStore *store;
          810   GtkTreeSelection *treesel;
          811 
          812   struct ConfigMembers locmembers[] = {
          813     { N_("Police presence"), "PolicePresence" },
          814     { N_("Minimum no. of drugs"), "MinDrug" },
          815     { N_("Maximum no. of drugs"), "MaxDrug" },
          816     { NULL, NULL }
          817   };
          818   struct ConfigMembers drugmembers[] = {
          819     { N_("Minimum normal price"), "MinPrice" },
          820     { N_("Maximum normal price"), "MaxPrice" },
          821     { N_("Can be specially cheap"), "Cheap" },
          822     { N_("Cheap string"), "CheapStr" },
          823     { N_("Can be specially expensive"), "Expensive" },
          824     { NULL, NULL }
          825   };
          826   struct ConfigMembers gunmembers[] = {
          827     { N_("Price"), "Price" },
          828     { N_("Inventory space"), "Space" },
          829     { N_("Damage"), "Damage" },
          830     { NULL, NULL }
          831   };
          832   struct ConfigMembers copmembers[] = {
          833     { N_("Name of one deputy"), "DeputyName" },
          834     { N_("Name of several deputies"), "DeputiesName" },
          835     { N_("Minimum no. of deputies"), "MinDeputies" },
          836     { N_("Maximum no. of deputies"), "MaxDeputies" },
          837     { N_("Cop armor"), "Armor" },
          838     { N_("Deputy armor"), "DeputyArmor" },
          839     { NULL, NULL }
          840   };
          841 
          842   dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
          843   accel_group = gtk_accel_group_new();
          844   gtk_window_add_accel_group(GTK_WINDOW(dialog), accel_group);
          845 
          846   gtk_window_set_title(GTK_WINDOW(dialog), _("Options"));
          847   my_set_dialog_position(GTK_WINDOW(dialog));
          848   gtk_container_set_border_width(GTK_CONTAINER(dialog), 7);
          849   gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
          850 
          851   gtk_window_set_transient_for(GTK_WINDOW(dialog),
          852                                GTK_WINDOW(MainWindow));
          853 
          854   vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 7);
          855 
          856   notebook = gtk_notebook_new();
          857 
          858   grid = dp_gtk_grid_new(8, 3, FALSE);
          859   gtk_grid_set_row_spacing(GTK_GRID(grid), 5);
          860   gtk_grid_set_column_spacing(GTK_GRID(grid), 5);
          861 
          862   check = NewConfigCheck("Sanitized", _("Remove drug references"));
          863   dp_gtk_grid_attach(GTK_GRID(grid), check, 0, 0, 1, 1, FALSE);
          864 
          865   check = gtk_check_button_new_with_label(_("Unicode config file"));
          866   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), IsConfigFileUTF8());
          867   dp_gtk_grid_attach(GTK_GRID(grid), check, 1, 0, 2, 1, TRUE);
          868   g_object_set_data(G_OBJECT(dialog), "unicode_check", check);
          869 
          870   label = gtk_label_new(_("Game length (turns)"));
          871   dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1, FALSE);
          872   entry = NewConfigEntry("NumTurns");
          873   dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 1, 2, 1, TRUE);
          874 
          875   label = gtk_label_new(_("Starting cash"));
          876   dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 2, 1, 1, FALSE);
          877   entry = NewConfigEntry("StartCash");
          878   dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 2, 2, 1, TRUE);
          879 
          880   label = gtk_label_new(_("Starting debt"));
          881   dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 3, 1, 1, FALSE);
          882   entry = NewConfigEntry("StartDebt");
          883   dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 3, 2, 1, TRUE);
          884 
          885   label = gtk_label_new(_("Currency symbol"));
          886   dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 4, 1, 1, FALSE);
          887   entry = NewConfigEntry("Currency.Symbol");
          888   dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 4, 1, 1, TRUE);
          889   check = NewConfigCheck("Currency.Prefix", _("Symbol prefixes prices"));
          890   dp_gtk_grid_attach(GTK_GRID(grid), check, 2, 4, 1, 1, TRUE);
          891 
          892   label = gtk_label_new(_("Name of one bitch"));
          893   dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 5, 1, 1, FALSE);
          894   entry = NewConfigEntry("Names.Bitch");
          895   dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 5, 2, 1, TRUE);
          896 
          897   label = gtk_label_new(_("Name of several bitches"));
          898   dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 6, 1, 1, FALSE);
          899   entry = NewConfigEntry("Names.Bitches");
          900   dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 6, 2, 1, TRUE);
          901 
          902 #ifndef CYGWIN
          903   label = gtk_label_new(_("Web browser"));
          904   dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 7, 1, 1, FALSE);
          905   entry = NewConfigEntry("WebBrowser");
          906   dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 7, 2, 1, TRUE);
          907 #endif
          908 
          909   gtk_container_set_border_width(GTK_CONTAINER(grid), 7);
          910   label = gtk_label_new(_("General"));
          911   gtk_notebook_append_page(GTK_NOTEBOOK(notebook), grid, label);
          912 
          913   hbox = CreateList("Location", locmembers);
          914   gtk_container_set_border_width(GTK_CONTAINER(hbox), 7);
          915 
          916   label = gtk_label_new(_("Locations"));
          917   gtk_notebook_append_page(GTK_NOTEBOOK(notebook), hbox, label);
          918 
          919   vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
          920   gtk_container_set_border_width(GTK_CONTAINER(vbox2), 7);
          921 
          922   hbox = CreateList("Drug", drugmembers);
          923   gtk_box_pack_start(GTK_BOX(vbox2), hbox, TRUE, TRUE, 0);
          924 
          925   hsep = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
          926   gtk_box_pack_start(GTK_BOX(vbox2), hsep, FALSE, FALSE, 0);
          927 
          928   grid = dp_gtk_grid_new(2, 2, FALSE);
          929   gtk_grid_set_row_spacing(GTK_GRID(grid), 5);
          930   gtk_grid_set_column_spacing(GTK_GRID(grid), 5);
          931   label = gtk_label_new(_("Expensive string 1"));
          932   dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1, FALSE);
          933   entry = NewConfigEntry("Drugs.ExpensiveStr1");
          934   dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 0, 1, 1, TRUE);
          935 
          936   label = gtk_label_new(_("Expensive string 2"));
          937   dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1, FALSE);
          938   entry = NewConfigEntry("Drugs.ExpensiveStr2");
          939   dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 1, 1, 1, TRUE);
          940   gtk_box_pack_start(GTK_BOX(vbox2), grid, FALSE, FALSE, 0);
          941 
          942   label = gtk_label_new(_("Drugs"));
          943   gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, label);
          944 
          945   hbox = CreateList("Gun", gunmembers);
          946   gtk_container_set_border_width(GTK_CONTAINER(hbox), 7);
          947   label = gtk_label_new(_("Guns"));
          948   gtk_notebook_append_page(GTK_NOTEBOOK(notebook), hbox, label);
          949 
          950   hbox = CreateList("Cop", copmembers);
          951   gtk_container_set_border_width(GTK_CONTAINER(hbox), 7);
          952   label = gtk_label_new(_("Cops"));
          953   gtk_notebook_append_page(GTK_NOTEBOOK(notebook), hbox, label);
          954 
          955 #ifdef NETWORKING
          956   grid = dp_gtk_grid_new(6, 4, FALSE);
          957   gtk_grid_set_row_spacing(GTK_GRID(grid), 5);
          958   gtk_grid_set_column_spacing(GTK_GRID(grid), 5);
          959 
          960   check = NewConfigCheck("MetaServer.Active",
          961                          _("Server reports to metaserver"));
          962   dp_gtk_grid_attach(GTK_GRID(grid), check, 0, 0, 2, 1, TRUE);
          963 
          964 #ifdef CYGWIN
          965   check = NewConfigCheck("MinToSysTray", _("Minimize to System Tray"));
          966   dp_gtk_grid_attach(GTK_GRID(grid), check, 2, 0, 2, 1, TRUE);
          967 #endif
          968 
          969   label = gtk_label_new(_("Metaserver URL"));
          970   dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1, FALSE);
          971   entry = NewConfigEntry("MetaServer.URL");
          972   dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 1, 3, 1, TRUE);
          973 
          974   label = gtk_label_new(_("Comment"));
          975   dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 4, 1, 1, FALSE);
          976   entry = NewConfigEntry("MetaServer.Comment");
          977   dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 4, 3, 1, TRUE);
          978 
          979   label = gtk_label_new(_("MOTD (welcome message)"));
          980   dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 5, 1, 1, FALSE);
          981   entry = NewConfigEntry("ServerMOTD");
          982   dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 5, 3, 1, TRUE);
          983 
          984   gtk_container_set_border_width(GTK_CONTAINER(grid), 7);
          985   label = gtk_label_new(_("Server"));
          986   gtk_notebook_append_page(GTK_NOTEBOOK(notebook), grid, label);
          987 #endif
          988 
          989   vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
          990   gtk_container_set_border_width(GTK_CONTAINER(vbox2), 7);
          991 
          992   sound_titles[0] = _("Sound name");
          993   sound_titles[1] = _("Description");
          994   tv = gtk_scrolled_tree_view_new(&scrollwin);
          995   store = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
          996   g_object_set_data(G_OBJECT(store), "oldsel", GINT_TO_POINTER(-1));
          997   gtk_tree_view_set_model(GTK_TREE_VIEW(tv), GTK_TREE_MODEL(store));
          998   renderer = gtk_cell_renderer_text_new();
          999   gtk_tree_view_insert_column_with_attributes(
         1000                GTK_TREE_VIEW(tv), -1, sound_titles[0], renderer,
         1001                "text", 0, NULL);
         1002   gtk_tree_view_insert_column_with_attributes(
         1003                GTK_TREE_VIEW(tv), -1, sound_titles[1], renderer,
         1004                "text", 1, NULL);
         1005   g_object_unref(store);
         1006   gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(tv), FALSE);
         1007   treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv));
         1008   gtk_tree_selection_set_mode(treesel, GTK_SELECTION_SINGLE);
         1009 
         1010   FillSoundsList(GTK_TREE_VIEW(tv));
         1011   g_signal_connect(G_OBJECT(treesel), "changed",
         1012                    G_CALLBACK(sound_sel_changed), NULL);
         1013 
         1014   clists = g_slist_append(clists, tv);
         1015 
         1016   gtk_box_pack_start(GTK_BOX(vbox2), scrollwin, TRUE, TRUE, 0);
         1017 
         1018   hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
         1019   label = gtk_label_new(_("Sound file"));
         1020   gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
         1021 
         1022   entry = gtk_entry_new();
         1023   g_object_set_data(G_OBJECT(store), "entry", entry);
         1024   gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
         1025 
         1026   button = gtk_button_new_with_label(_("Browse..."));
         1027   g_signal_connect_swapped(G_OBJECT(button), "clicked",
         1028                            G_CALLBACK(BrowseSound), G_OBJECT(entry));
         1029   gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
         1030 
         1031   button = gtk_button_new_with_label(_("Play"));
         1032   g_signal_connect_swapped(G_OBJECT(button), "clicked",
         1033                            G_CALLBACK(TestPlaySound), G_OBJECT(entry));
         1034   gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
         1035 
         1036   gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
         1037 
         1038   label = gtk_label_new(_("Sounds"));
         1039   gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, label);
         1040 
         1041   gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 0);
         1042 
         1043   gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
         1044 
         1045   hsep = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
         1046   gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0);
         1047 
         1048   hbbox = my_hbbox_new();
         1049 
         1050   button = gtk_button_new_with_mnemonic(_("_OK"));
         1051   g_signal_connect(G_OBJECT(button), "clicked",
         1052                    G_CALLBACK(OKCallback), (gpointer)dialog);
         1053   my_gtk_box_pack_start_defaults(GTK_BOX(hbbox), button);
         1054 
         1055   button = gtk_button_new_with_mnemonic(_("_Help"));
         1056   g_signal_connect(G_OBJECT(button), "clicked",
         1057                    G_CALLBACK(HelpCallback), (gpointer)notebook);
         1058   my_gtk_box_pack_start_defaults(GTK_BOX(hbbox), button);
         1059 
         1060   button = gtk_button_new_with_mnemonic(_("_Cancel"));
         1061   g_signal_connect_swapped(G_OBJECT(button), "clicked",
         1062                            G_CALLBACK(gtk_widget_destroy),
         1063                            G_OBJECT(dialog));
         1064   g_signal_connect(G_OBJECT(dialog), "destroy",
         1065                    G_CALLBACK(FinishOptDialog), NULL);
         1066   my_gtk_box_pack_start_defaults(GTK_BOX(hbbox), button);
         1067 
         1068   gtk_box_pack_start(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
         1069 
         1070   gtk_container_add(GTK_CONTAINER(dialog), vbox);
         1071 
         1072   gtk_widget_show_all(dialog);
         1073 }