X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/fd1a1a2b902d34e75a47515a564020b0815ddea6..d3a026ed4258c207b6309802cc2c92eb0a812aac:/gtk.c diff --git a/gtk.c b/gtk.c index 9ffc96a..5e51028 100644 --- a/gtk.c +++ b/gtk.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -64,6 +65,9 @@ struct frontend { int timer_active, timer_id; struct font *fonts; int nfonts, fontsize; + config_item *cfg; + int cfgret; + GtkWidget *cfgbox; }; void frontend_default_colour(frontend *fe, float *output) @@ -370,6 +374,250 @@ void activate_timer(frontend *fe) fe->timer_active = TRUE; } +static void window_destroy(GtkWidget *widget, gpointer data) +{ + gtk_main_quit(); +} + +static void errmsg_button_clicked(GtkButton *button, gpointer data) +{ + gtk_widget_destroy(GTK_WIDGET(data)); +} + +void error_box(GtkWidget *parent, char *msg) +{ + GtkWidget *window, *hbox, *text, *ok; + + window = gtk_dialog_new(); + text = gtk_label_new(msg); + gtk_misc_set_alignment(GTK_MISC(text), 0.0, 0.0); + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), text, FALSE, FALSE, 20); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), + hbox, FALSE, FALSE, 20); + gtk_widget_show(text); + gtk_widget_show(hbox); + gtk_window_set_title(GTK_WINDOW(window), "Error"); + gtk_label_set_line_wrap(GTK_LABEL(text), TRUE); + ok = gtk_button_new_with_label("OK"); + gtk_box_pack_end(GTK_BOX(GTK_DIALOG(window)->action_area), + ok, FALSE, FALSE, 0); + gtk_widget_show(ok); + GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT); + gtk_window_set_default(GTK_WINDOW(window), ok); + gtk_signal_connect(GTK_OBJECT(ok), "clicked", + GTK_SIGNAL_FUNC(errmsg_button_clicked), window); + gtk_signal_connect(GTK_OBJECT(window), "destroy", + GTK_SIGNAL_FUNC(window_destroy), NULL); + gtk_window_set_modal(GTK_WINDOW(window), TRUE); + gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(parent)); + //set_transient_window_pos(parent, window); + gtk_widget_show(window); + gtk_main(); +} + +static void config_ok_button_clicked(GtkButton *button, gpointer data) +{ + frontend *fe = (frontend *)data; + char *err; + + err = midend_set_config(fe->me, fe->cfg); + + if (err) + error_box(fe->cfgbox, err); + else { + fe->cfgret = TRUE; + gtk_widget_destroy(fe->cfgbox); + } +} + +static void config_cancel_button_clicked(GtkButton *button, gpointer data) +{ + frontend *fe = (frontend *)data; + + gtk_widget_destroy(fe->cfgbox); +} + +static void editbox_changed(GtkEditable *ed, gpointer data) +{ + config_item *i = (config_item *)data; + + sfree(i->sval); + i->sval = dupstr(gtk_entry_get_text(GTK_ENTRY(ed))); +} + +static void button_toggled(GtkToggleButton *tb, gpointer data) +{ + config_item *i = (config_item *)data; + + i->ival = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tb)); +} + +static void droplist_sel(GtkMenuItem *item, gpointer data) +{ + config_item *i = (config_item *)data; + + i->ival = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(item), + "user-data")); +} + +static int get_config(frontend *fe) +{ + GtkWidget *w, *table; + config_item *i; + int y; + + fe->cfg = midend_get_config(fe->me); + fe->cfgret = FALSE; + + fe->cfgbox = gtk_dialog_new(); + gtk_window_set_title(GTK_WINDOW(fe->cfgbox), "Configure"); + + w = gtk_button_new_with_label("OK"); + gtk_box_pack_end(GTK_BOX(GTK_DIALOG(fe->cfgbox)->action_area), + w, FALSE, FALSE, 0); + gtk_widget_show(w); + GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT); + gtk_window_set_default(GTK_WINDOW(fe->cfgbox), w); + gtk_signal_connect(GTK_OBJECT(w), "clicked", + GTK_SIGNAL_FUNC(config_ok_button_clicked), fe); + + w = gtk_button_new_with_label("Cancel"); + gtk_box_pack_end(GTK_BOX(GTK_DIALOG(fe->cfgbox)->action_area), + w, FALSE, FALSE, 0); + gtk_widget_show(w); + gtk_signal_connect(GTK_OBJECT(w), "clicked", + GTK_SIGNAL_FUNC(config_cancel_button_clicked), fe); + + table = gtk_table_new(1, 2, FALSE); + y = 0; + gtk_box_pack_end(GTK_BOX(GTK_DIALOG(fe->cfgbox)->vbox), + table, FALSE, FALSE, 0); + gtk_widget_show(table); + + for (i = fe->cfg; i->type != C_END; i++) { + gtk_table_resize(GTK_TABLE(table), y+1, 2); + + switch (i->type) { + case C_STRING: + /* + * Edit box with a label beside it. + */ + + w = gtk_label_new(i->name); + gtk_misc_set_alignment(GTK_MISC(w), 0.0, 0.5); + gtk_table_attach(GTK_TABLE(table), w, 0, 1, y, y+1, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + 3, 3); + gtk_widget_show(w); + + w = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), w, 1, 2, y, y+1, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + 3, 3); + gtk_entry_set_text(GTK_ENTRY(w), i->sval); + gtk_signal_connect(GTK_OBJECT(w), "changed", + GTK_SIGNAL_FUNC(editbox_changed), i); + gtk_widget_show(w); + + break; + + case C_BOOLEAN: + /* + * Simple checkbox. + */ + w = gtk_check_button_new_with_label(i->name); + gtk_signal_connect(GTK_OBJECT(w), "toggled", + GTK_SIGNAL_FUNC(button_toggled), i); + gtk_table_attach(GTK_TABLE(table), w, 0, 2, y, y+1, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + 3, 3); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), i->ival); + gtk_widget_show(w); + break; + + case C_CHOICES: + /* + * Drop-down list (GtkOptionMenu). + */ + + w = gtk_label_new(i->name); + gtk_misc_set_alignment(GTK_MISC(w), 0.0, 0.5); + gtk_table_attach(GTK_TABLE(table), w, 0, 1, y, y+1, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + 3, 3); + gtk_widget_show(w); + + w = gtk_option_menu_new(); + gtk_table_attach(GTK_TABLE(table), w, 1, 2, y, y+1, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + 3, 3); + gtk_widget_show(w); + + { + int c, val; + char *p, *q, *name; + GtkWidget *menuitem; + GtkWidget *menu = gtk_menu_new(); + + gtk_option_menu_set_menu(GTK_OPTION_MENU(w), menu); + + c = *i->sval; + p = i->sval+1; + val = 0; + + while (*p) { + q = p; + while (*q && *q != c) + q++; + + name = snewn(q-p+1, char); + strncpy(name, p, q-p); + name[q-p] = '\0'; + + if (*q) q++; /* eat delimiter */ + + menuitem = gtk_menu_item_new_with_label(name); + gtk_container_add(GTK_CONTAINER(menu), menuitem); + gtk_object_set_data(GTK_OBJECT(menuitem), "user-data", + GINT_TO_POINTER(val)); + gtk_signal_connect(GTK_OBJECT(menuitem), "activate", + GTK_SIGNAL_FUNC(droplist_sel), i); + gtk_widget_show(menuitem); + + val++; + + p = q; + } + + gtk_option_menu_set_history(GTK_OPTION_MENU(w), i->ival); + } + + break; + } + + y++; + } + + gtk_signal_connect(GTK_OBJECT(fe->cfgbox), "destroy", + GTK_SIGNAL_FUNC(window_destroy), NULL); + gtk_window_set_modal(GTK_WINDOW(fe->cfgbox), TRUE); + gtk_window_set_transient_for(GTK_WINDOW(fe->cfgbox), + GTK_WINDOW(fe->window)); + //set_transient_window_pos(fe->window, fe->cfgbox); + gtk_widget_show(fe->cfgbox); + gtk_main(); + + free_cfg(fe->cfg); + + return fe->cfgret; +} + static void menu_key_event(GtkMenuItem *menuitem, gpointer data) { frontend *fe = (frontend *)data; @@ -394,6 +642,21 @@ static void menu_preset_event(GtkMenuItem *menuitem, gpointer data) fe->h = y; } +static void menu_config_event(GtkMenuItem *menuitem, gpointer data) +{ + frontend *fe = (frontend *)data; + int x, y; + + if (!get_config(fe)) + return; + + midend_new_game(fe->me, NULL); + midend_size(fe->me, &x, &y); + gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y); + fe->w = x; + fe->h = y; +} + static GtkWidget *add_menu_item_with_key(frontend *fe, GtkContainer *cont, char *text, int key) { @@ -451,12 +714,12 @@ static frontend *new_window(void) add_menu_item_with_key(fe, GTK_CONTAINER(menu), "New", 'n'); add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Restart", 'r'); - if ((n = midend_num_presets(fe->me)) > 0) { + if ((n = midend_num_presets(fe->me)) > 0 || game_can_configure) { GtkWidget *submenu; int i; menuitem = gtk_menu_item_new_with_label("Type"); - gtk_container_add(GTK_CONTAINER(menu), menuitem); + gtk_container_add(GTK_CONTAINER(menubar), menuitem); gtk_widget_show(menuitem); submenu = gtk_menu_new(); @@ -475,6 +738,14 @@ static frontend *new_window(void) GTK_SIGNAL_FUNC(menu_preset_event), fe); gtk_widget_show(menuitem); } + + if (game_can_configure) { + menuitem = gtk_menu_item_new_with_label("Custom..."); + gtk_container_add(GTK_CONTAINER(submenu), menuitem); + gtk_signal_connect(GTK_OBJECT(menuitem), "activate", + GTK_SIGNAL_FUNC(menu_config_event), fe); + gtk_widget_show(menuitem); + } } add_menu_separator(GTK_CONTAINER(menu)); @@ -510,13 +781,25 @@ static frontend *new_window(void) } if (midend_wants_statusbar(fe->me)) { + GtkWidget *viewport; + GtkRequisition req; + + viewport = gtk_viewport_new(NULL, NULL); + gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE); fe->statusbar = gtk_statusbar_new(); - gtk_box_pack_end(vbox, fe->statusbar, FALSE, FALSE, 0); + gtk_container_add(GTK_CONTAINER(viewport), fe->statusbar); + gtk_widget_show(viewport); + gtk_box_pack_end(vbox, viewport, FALSE, FALSE, 0); gtk_widget_show(fe->statusbar); fe->statusctx = gtk_statusbar_get_context_id (GTK_STATUSBAR(fe->statusbar), "game"); gtk_statusbar_push(GTK_STATUSBAR(fe->statusbar), fe->statusctx, - ""); + "test"); + gtk_widget_size_request(fe->statusbar, &req); +#if 0 + /* For GTK 2.0, should we be using gtk_widget_set_size_request? */ +#endif + gtk_widget_set_usize(viewport, x, req.height); } else fe->statusbar = NULL;