X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/2ef96bd6ebb0e89bc054d2edb1ef280c97faa955..b0f067190f385284449015d12d592b3f385b6a11:/gtk.c?ds=sidebyside diff --git a/gtk.c b/gtk.c index ec086fc..8a26730 100644 --- a/gtk.c +++ b/gtk.c @@ -1,9 +1,5 @@ /* * gtk.c: GTK front end for my puzzle collection. - * - * TODO: - * - * - Handle resizing, probably just by forbidding it. */ #include @@ -12,6 +8,7 @@ #include #include +#include #include "puzzles.h" @@ -55,7 +52,7 @@ struct frontend { midend_data *me; GdkGC *gc; int bbox_l, bbox_r, bbox_u, bbox_d; - int timer_active; + int timer_active, timer_id; }; void frontend_default_colour(frontend *fe, float *output) @@ -135,12 +132,38 @@ static void destroy(GtkWidget *widget, gpointer data) static gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) { frontend *fe = (frontend *)data; + int keyval; if (!fe->pixmap) return TRUE; - if (event->string[0] && !event->string[1] && - !midend_process_key(fe->me, 0, 0, event->string[0])) + if (event->string[0] && !event->string[1]) + keyval = (unsigned char)event->string[0]; + else if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up || + event->keyval == GDK_KP_8) + keyval = CURSOR_UP; + else if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down || + event->keyval == GDK_KP_2) + keyval = CURSOR_DOWN; + else if (event->keyval == GDK_Left || event->keyval == GDK_KP_Left || + event->keyval == GDK_KP_4) + keyval = CURSOR_LEFT; + else if (event->keyval == GDK_Right || event->keyval == GDK_KP_Right || + event->keyval == GDK_KP_6) + keyval = CURSOR_RIGHT; + else if (event->keyval == GDK_KP_Home || event->keyval == GDK_KP_7) + keyval = CURSOR_UP_LEFT; + else if (event->keyval == GDK_KP_End || event->keyval == GDK_KP_1) + keyval = CURSOR_DOWN_LEFT; + else if (event->keyval == GDK_KP_Page_Up || event->keyval == GDK_KP_9) + keyval = CURSOR_UP_RIGHT; + else if (event->keyval == GDK_KP_Page_Down || event->keyval == GDK_KP_3) + keyval = CURSOR_DOWN_RIGHT; + else + keyval = -1; + + if (keyval >= 0 && + !midend_process_key(fe->me, 0, 0, keyval)) gtk_widget_destroy(fe->window); return TRUE; @@ -158,10 +181,10 @@ static gint button_event(GtkWidget *widget, GdkEventButton *event, if (event->type != GDK_BUTTON_PRESS) return TRUE; - if (event->button == 1) - button = LEFT_BUTTON; - else if (event->button == 2) + if (event->button == 2 || (event->state & GDK_SHIFT_MASK)) button = MIDDLE_BUTTON; + else if (event->button == 1) + button = LEFT_BUTTON; else if (event->button == 3) button = RIGHT_BUTTON; else @@ -195,6 +218,9 @@ static gint configure_area(GtkWidget *widget, frontend *fe = (frontend *)data; GdkGC *gc; + if (fe->pixmap) + gdk_pixmap_unref(fe->pixmap); + fe->pixmap = gdk_pixmap_new(widget->window, fe->w, fe->h, -1); gc = gdk_gc_new(fe->area->window); @@ -219,19 +245,68 @@ static gint timer_func(gpointer data) void deactivate_timer(frontend *fe) { + if (fe->timer_active) + gtk_timeout_remove(fe->timer_id); fe->timer_active = FALSE; } void activate_timer(frontend *fe) { - gtk_timeout_add(20, timer_func, fe); + if (!fe->timer_active) + fe->timer_id = gtk_timeout_add(20, timer_func, fe); fe->timer_active = TRUE; } +static void menu_key_event(GtkMenuItem *menuitem, gpointer data) +{ + frontend *fe = (frontend *)data; + int key = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(menuitem), + "user-data")); + if (!midend_process_key(fe->me, 0, 0, key)) + gtk_widget_destroy(fe->window); +} + +static void menu_preset_event(GtkMenuItem *menuitem, gpointer data) +{ + frontend *fe = (frontend *)data; + game_params *params = + (game_params *)gtk_object_get_data(GTK_OBJECT(menuitem), "user-data"); + int x, y; + + midend_set_params(fe->me, params); + 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) +{ + GtkWidget *menuitem = gtk_menu_item_new_with_label(text); + gtk_container_add(cont, menuitem); + gtk_object_set_data(GTK_OBJECT(menuitem), "user-data", + GINT_TO_POINTER(key)); + gtk_signal_connect(GTK_OBJECT(menuitem), "activate", + GTK_SIGNAL_FUNC(menu_key_event), fe); + gtk_widget_show(menuitem); + return menuitem; +} + +static void add_menu_separator(GtkContainer *cont) +{ + GtkWidget *menuitem = gtk_menu_item_new(); + gtk_container_add(cont, menuitem); + gtk_widget_show(menuitem); +} + static frontend *new_window(void) { frontend *fe; - int x, y; + GtkBox *vbox; + GtkWidget *menubar, *menu, *menuitem; + int x, y, n; fe = snew(frontend); @@ -239,6 +314,60 @@ static frontend *new_window(void) midend_new_game(fe->me, NULL); fe->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); +#if 0 + gtk_window_set_resizable(GTK_WINDOW(fe->window), FALSE); +#else + gtk_window_set_policy(GTK_WINDOW(fe->window), FALSE, FALSE, TRUE); +#endif + vbox = GTK_BOX(gtk_vbox_new(FALSE, 0)); + gtk_container_add(GTK_CONTAINER(fe->window), GTK_WIDGET(vbox)); + gtk_widget_show(GTK_WIDGET(vbox)); + + menubar = gtk_menu_bar_new(); + gtk_box_pack_start(vbox, menubar, FALSE, FALSE, 0); + gtk_widget_show(menubar); + + menuitem = gtk_menu_item_new_with_label("Game"); + gtk_container_add(GTK_CONTAINER(menubar), menuitem); + gtk_widget_show(menuitem); + + menu = gtk_menu_new(); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu); + + 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) { + GtkWidget *submenu; + int i; + + menuitem = gtk_menu_item_new_with_label("Type"); + gtk_container_add(GTK_CONTAINER(menu), menuitem); + gtk_widget_show(menuitem); + + submenu = gtk_menu_new(); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu); + + for (i = 0; i < n; i++) { + char *name; + game_params *params; + + midend_fetch_preset(fe->me, i, &name, ¶ms); + + menuitem = gtk_menu_item_new_with_label(name); + gtk_container_add(GTK_CONTAINER(submenu), menuitem); + gtk_object_set_data(GTK_OBJECT(menuitem), "user-data", params); + gtk_signal_connect(GTK_OBJECT(menuitem), "activate", + GTK_SIGNAL_FUNC(menu_preset_event), fe); + gtk_widget_show(menuitem); + } + } + + 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", '\x12'); + add_menu_separator(GTK_CONTAINER(menu)); + add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Exit", 'q'); { int i, ncolours; @@ -272,10 +401,12 @@ static frontend *new_window(void) fe->w = x; fe->h = y; - gtk_container_add(GTK_CONTAINER(fe->window), fe->area); + gtk_box_pack_end(vbox, fe->area, FALSE, FALSE, 0); fe->pixmap = NULL; + fe->timer_active = FALSE; + gtk_signal_connect(GTK_OBJECT(fe->window), "destroy", GTK_SIGNAL_FUNC(destroy), fe); gtk_signal_connect(GTK_OBJECT(fe->window), "key_press_event",