X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/f52166e6af5dfc34f1acb7239939c69e0c35944a..f5e8f79dac020bcb0b19e3a7d674412befec0280:/gtk.c diff --git a/gtk.c b/gtk.c index 5761e8d..0fd351b 100644 --- a/gtk.c +++ b/gtk.c @@ -134,9 +134,10 @@ struct frontend { #ifdef OLD_FILESEL char *filesel_name; #endif - int npresets; - GtkWidget **preset_bullets; - GtkWidget *preset_custom_bullet; + GSList *preset_radio; + int n_preset_menu_items; + int preset_threaded; + GtkWidget *preset_custom; GtkWidget *copy_menu_item; }; @@ -498,6 +499,17 @@ void gtk_end_draw(void *handle) } } +#ifdef USE_PANGO +char *gtk_text_fallback(void *handle, const char *const *strings, int nstrings) +{ + /* + * We assume Pango can cope with any UTF-8 likely to be emitted + * by a puzzle. + */ + return dupstr(strings[0]); +} +#endif + const struct drawing_api gtk_drawing = { gtk_draw_text, gtk_draw_rect, @@ -515,7 +527,12 @@ const struct drawing_api gtk_drawing = { gtk_blitter_save, gtk_blitter_load, NULL, NULL, NULL, NULL, NULL, NULL, /* {begin,end}_{doc,page,puzzle} */ - NULL, /* line_width */ + NULL, NULL, /* line_width, line_dotted */ +#ifdef USE_PANGO + gtk_text_fallback, +#else + NULL, +#endif }; static void destroy(GtkWidget *widget, gpointer data) @@ -646,6 +663,11 @@ static gint motion_event(GtkWidget *widget, GdkEventMotion *event, if (!midend_process_key(fe->me, event->x - fe->ox, event->y - fe->oy, button)) gtk_widget_destroy(fe->window); +#if GTK_CHECK_VERSION(2,12,0) + gdk_event_request_motions(event); +#else + gdk_window_get_pointer(widget->window, NULL, NULL, NULL); +#endif return TRUE; } @@ -969,7 +991,7 @@ static int get_config(frontend *fe, int which) 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_SHRINK | GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 3, 3); gtk_widget_show(w); @@ -1011,8 +1033,8 @@ static int get_config(frontend *fe, int which) 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, + GTK_SHRINK | GTK_FILL, + GTK_EXPAND | GTK_SHRINK | GTK_FILL , 3, 3); gtk_widget_show(w); @@ -1121,15 +1143,6 @@ static void get_size(frontend *fe, int *px, int *py) gdk_window_resize(GTK_WIDGET(win)->window, x, y) #endif -static void update_menuitem_bullet(GtkWidget *label, int visible) -{ - if (visible) { - gtk_label_set_text(GTK_LABEL(label), "\xE2\x80\xA2"); - } else { - gtk_label_set_text(GTK_LABEL(label), ""); - } -} - /* * Called when any other code in this file has changed the * selected game parameters. @@ -1137,18 +1150,30 @@ static void update_menuitem_bullet(GtkWidget *label, int visible) static void changed_preset(frontend *fe) { int n = midend_which_preset(fe->me); - int i; - /* - * Update the tick mark in the Type menu. - */ - if (fe->preset_bullets) { - for (i = 0; i < fe->npresets; i++) - update_menuitem_bullet(fe->preset_bullets[i], n == i); - } - if (fe->preset_custom_bullet) { - update_menuitem_bullet(fe->preset_custom_bullet, n < 0); + fe->preset_threaded = TRUE; + if (n < 0 && fe->preset_custom) { + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(fe->preset_custom), + TRUE); + } else { + GSList *gs = fe->preset_radio; + int i = fe->n_preset_menu_items - 1 - n; + if (fe->preset_custom) + gs = gs->next; + while (i && gs) { + i--; + gs = gs->next; + } + if (gs) { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gs->data), + TRUE); + } else for (gs = fe->preset_radio; gs; gs = gs->next) { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gs->data), + FALSE); + } } + fe->preset_threaded = FALSE; /* * Update the greying on the Copy menu option. @@ -1186,6 +1211,10 @@ static void menu_preset_event(GtkMenuItem *menuitem, gpointer data) game_params *params = (game_params *)gtk_object_get_data(GTK_OBJECT(menuitem), "user-data"); + if (fe->preset_threaded || + (GTK_IS_CHECK_MENU_ITEM(menuitem) && + !gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem)))) + return; midend_set_params(fe->me, params); midend_new_game(fe->me); changed_preset(fe); @@ -1496,6 +1525,11 @@ static void menu_config_event(GtkMenuItem *menuitem, gpointer data) int which = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(menuitem), "user-data")); + if (fe->preset_threaded || + (GTK_IS_CHECK_MENU_ITEM(menuitem) && + !gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem)))) + return; + changed_preset(fe); /* Put the old preset back! */ if (!get_config(fe, which)) return; @@ -1558,38 +1592,10 @@ static void add_menu_separator(GtkContainer *cont) enum { ARG_EITHER, ARG_SAVE, ARG_ID }; /* for argtype */ -static GtkWidget *make_preset_menuitem(GtkWidget **bulletlabel, - const char *name) -{ - GtkWidget *hbox, *lab1, *lab2, *menuitem; - GtkRequisition req; - - hbox = gtk_hbox_new(FALSE, 0); - gtk_widget_show(hbox); - lab1 = gtk_label_new("\xE2\x80\xA2 "); - gtk_widget_show(lab1); - gtk_box_pack_start(GTK_BOX(hbox), lab1, FALSE, FALSE, 0); - gtk_misc_set_alignment(GTK_MISC(lab1), 0.0, 0.0); - lab2 = gtk_label_new(name); - gtk_widget_show(lab2); - gtk_box_pack_start(GTK_BOX(hbox), lab2, TRUE, TRUE, 0); - gtk_misc_set_alignment(GTK_MISC(lab2), 0.0, 0.0); - - gtk_widget_size_request(lab1, &req); - gtk_widget_set_usize(lab1, req.width, -1); - gtk_label_set_text(GTK_LABEL(lab1), ""); - - menuitem = gtk_menu_item_new(); - gtk_container_add(GTK_CONTAINER(menuitem), hbox); - - *bulletlabel = lab1; - return menuitem; -} - static frontend *new_window(char *arg, int argtype, char **error) { frontend *fe; - GtkBox *vbox; + GtkBox *vbox, *hbox; GtkWidget *menubar, *menu, *menuitem; GdkPixmap *iconpm; GList *iconlist; @@ -1675,8 +1681,12 @@ static frontend *new_window(char *arg, int argtype, char **error) fe->accelgroup = gtk_accel_group_new(); gtk_window_add_accel_group(GTK_WINDOW(fe->window), fe->accelgroup); + hbox = GTK_BOX(gtk_hbox_new(FALSE, 0)); + gtk_box_pack_start(vbox, GTK_WIDGET(hbox), FALSE, FALSE, 0); + gtk_widget_show(GTK_WIDGET(hbox)); + menubar = gtk_menu_bar_new(); - gtk_box_pack_start(vbox, menubar, FALSE, FALSE, 0); + gtk_box_pack_start(hbox, menubar, TRUE, TRUE, 0); gtk_widget_show(menubar); menuitem = gtk_menu_item_new_with_mnemonic("_Game"); @@ -1710,6 +1720,10 @@ static frontend *new_window(char *arg, int argtype, char **error) GTK_SIGNAL_FUNC(menu_config_event), fe); gtk_widget_show(menuitem); + fe->preset_radio = NULL; + fe->preset_custom = NULL; + fe->n_preset_menu_items = 0; + fe->preset_threaded = FALSE; if ((n = midend_num_presets(fe->me)) > 0 || thegame.can_configure) { GtkWidget *submenu; int i; @@ -1721,17 +1735,17 @@ static frontend *new_window(char *arg, int argtype, char **error) submenu = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu); - fe->npresets = n; - fe->preset_bullets = snewn(n, GtkWidget *); - for (i = 0; i < n; i++) { char *name; game_params *params; midend_fetch_preset(fe->me, i, &name, ¶ms); - menuitem = make_preset_menuitem(&fe->preset_bullets[i], name); - + menuitem = + gtk_radio_menu_item_new_with_label(fe->preset_radio, name); + fe->preset_radio = + gtk_radio_menu_item_group(GTK_RADIO_MENU_ITEM(menuitem)); + fe->n_preset_menu_items++; gtk_container_add(GTK_CONTAINER(submenu), menuitem); gtk_object_set_data(GTK_OBJECT(menuitem), "user-data", params); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", @@ -1740,22 +1754,19 @@ static frontend *new_window(char *arg, int argtype, char **error) } if (thegame.can_configure) { - menuitem = make_preset_menuitem(&fe->preset_custom_bullet, - "Custom..."); - + menuitem = fe->preset_custom = + gtk_radio_menu_item_new_with_label(fe->preset_radio, + "Custom..."); + fe->preset_radio = + gtk_radio_menu_item_group(GTK_RADIO_MENU_ITEM(menuitem)); gtk_container_add(GTK_CONTAINER(submenu), menuitem); gtk_object_set_data(GTK_OBJECT(menuitem), "user-data", GPOINTER_TO_INT(CFG_SETTINGS)); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", GTK_SIGNAL_FUNC(menu_config_event), fe); gtk_widget_show(menuitem); - } else - fe->preset_custom_bullet = NULL; + } - } else { - fe->npresets = 0; - fe->preset_bullets = NULL; - fe->preset_custom_bullet = NULL; } add_menu_separator(GTK_CONTAINER(menu)); @@ -1769,9 +1780,11 @@ static frontend *new_window(char *arg, int argtype, char **error) gtk_signal_connect(GTK_OBJECT(menuitem), "activate", GTK_SIGNAL_FUNC(menu_save_event), fe); gtk_widget_show(menuitem); +#ifndef STYLUS_BASED add_menu_separator(GTK_CONTAINER(menu)); add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Undo", 'u'); add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Redo", 'r'); +#endif if (thegame.can_format_as_text_ever) { add_menu_separator(GTK_CONTAINER(menu)); menuitem = gtk_menu_item_new_with_label("Copy"); @@ -1807,6 +1820,42 @@ static frontend *new_window(char *arg, int argtype, char **error) GTK_SIGNAL_FUNC(menu_about_event), fe); gtk_widget_show(menuitem); +#ifdef STYLUS_BASED + menuitem=gtk_button_new_with_mnemonic("_Redo"); + gtk_object_set_data(GTK_OBJECT(menuitem), "user-data", + GINT_TO_POINTER((int)('r'))); + gtk_signal_connect(GTK_OBJECT(menuitem), "clicked", + GTK_SIGNAL_FUNC(menu_key_event), fe); + gtk_box_pack_end(hbox, menuitem, FALSE, FALSE, 0); + gtk_widget_show(menuitem); + + menuitem=gtk_button_new_with_mnemonic("_Undo"); + gtk_object_set_data(GTK_OBJECT(menuitem), "user-data", + GINT_TO_POINTER((int)('u'))); + gtk_signal_connect(GTK_OBJECT(menuitem), "clicked", + GTK_SIGNAL_FUNC(menu_key_event), fe); + gtk_box_pack_end(hbox, menuitem, FALSE, FALSE, 0); + gtk_widget_show(menuitem); + + if (thegame.flags & REQUIRE_NUMPAD) { + hbox = GTK_BOX(gtk_hbox_new(FALSE, 0)); + gtk_box_pack_start(vbox, GTK_WIDGET(hbox), FALSE, FALSE, 0); + gtk_widget_show(GTK_WIDGET(hbox)); + + *((int*)errbuf)=0; + errbuf[1]='\0'; + for(errbuf[0]='0';errbuf[0]<='9';errbuf[0]++) { + menuitem=gtk_button_new_with_label(errbuf); + gtk_object_set_data(GTK_OBJECT(menuitem), "user-data", + GINT_TO_POINTER((int)(errbuf[0]))); + gtk_signal_connect(GTK_OBJECT(menuitem), "clicked", + GTK_SIGNAL_FUNC(menu_key_event), fe); + gtk_box_pack_start(hbox, menuitem, TRUE, TRUE, 0); + gtk_widget_show(menuitem); + } + } +#endif /* STYLUS_BASED */ + changed_preset(fe); { @@ -1898,7 +1947,8 @@ static frontend *new_window(char *arg, int argtype, char **error) gtk_widget_add_events(GTK_WIDGET(fe->area), GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | - GDK_BUTTON_MOTION_MASK); + GDK_BUTTON_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); if (n_xpm_icons) { gtk_widget_realize(fe->window);