From e5247b7cbb03e73dfbea4942fefbeef5ccda37e0 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 9 Aug 2020 18:27:18 -0400 Subject: [PATCH] gtk-demo: Finish peg solitaire demo The restart button was simply not implemented. While we are at it, make the pegs a bit bigger, so clicking them is easier. --- demos/gtk-demo/peg_solitaire.c | 162 +++++++++++++++++++-------------- 1 file changed, 96 insertions(+), 66 deletions(-) diff --git a/demos/gtk-demo/peg_solitaire.c b/demos/gtk-demo/peg_solitaire.c index 6532cce254..81f9a5c4c5 100644 --- a/demos/gtk-demo/peg_solitaire.c +++ b/demos/gtk-demo/peg_solitaire.c @@ -6,8 +6,6 @@ #include -static GtkWidget *window = NULL; - /* Create an object for the pegs that get moved around in the game. * * We implement the GdkPaintable interface for them, so we can use GtkPicture @@ -56,11 +54,25 @@ solitaire_peg_get_flags (GdkPaintable *paintable) return GDK_PAINTABLE_STATIC_CONTENTS | GDK_PAINTABLE_STATIC_SIZE; } +static int +solitaire_peg_get_intrinsic_width (GdkPaintable *paintable) +{ + return 32; +} + +static int +solitaire_peg_get_intrinsic_height (GdkPaintable *paintable) +{ + return 32; +} + static void solitaire_peg_paintable_init (GdkPaintableInterface *iface) { iface->snapshot = solitaire_peg_snapshot; iface->get_flags = solitaire_peg_get_flags; + iface->get_intrinsic_width = solitaire_peg_get_intrinsic_width; + iface->get_intrinsic_height = solitaire_peg_get_intrinsic_height; } /* When defining the GType, we need to implement the GdkPaintable interface */ @@ -259,25 +271,99 @@ drop_drop (GtkDropTarget *target, return TRUE; } +static void +create_board (GtkWidget *window) +{ + GtkWidget *grid; + GtkWidget *image; + int x, y; + GtkDragSource *source; + GtkDropTarget *target; + + grid = gtk_grid_new (); + gtk_widget_set_halign (grid, GTK_ALIGN_CENTER); + gtk_widget_set_valign (grid, GTK_ALIGN_CENTER); + gtk_grid_set_row_spacing (GTK_GRID (grid), 6); + gtk_grid_set_column_spacing (GTK_GRID (grid), 6); + gtk_grid_set_row_homogeneous (GTK_GRID (grid), TRUE); + gtk_grid_set_column_homogeneous (GTK_GRID (grid), TRUE); + gtk_window_set_child (GTK_WINDOW (window), grid); + + for (x = 0; x < 7; x++) + { + for (y = 0; y < 7; y++) + { + if ((x < 2 || x >= 5) && (y < 2 || y >= 5)) + continue; + + image = gtk_image_new (); + gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE); + if (x != 3 || y != 3) + { + SolitairePeg *peg = solitaire_peg_new (); + solitaire_peg_set_position (peg, x, y); + gtk_image_set_from_paintable (GTK_IMAGE (image), GDK_PAINTABLE (peg)); + } + + gtk_grid_attach (GTK_GRID (grid), image, x, y, 1, 1); + + /* Set up the drag source. + * This is rather straightforward: Set the supported actions + * (in our case, pegs can only be moved) and connect all the + * relevant signals. + * And because all drag'n'drop handling is done via event controllers, + * we need to add the controller to the widget. + */ + source = gtk_drag_source_new (); + gtk_drag_source_set_actions (source, GDK_ACTION_MOVE); + g_signal_connect (source, "prepare", G_CALLBACK (drag_prepare), image); + g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), image); + g_signal_connect (source, "drag-end", G_CALLBACK (drag_end), image); + gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source)); + + /* Set up the drop target. + * This is more involved, because the game logic goes here. + */ + + /* First we specify the data we accept: pegs. + * And we only want moves. + */ + target = gtk_drop_target_new (SOLITAIRE_TYPE_PEG, GDK_ACTION_MOVE); + /* Then we connect our signals. + */ + g_signal_connect (target, "accept", G_CALLBACK (drop_accept), image); + g_signal_connect (target, "drop", G_CALLBACK (drop_drop), image); + /* Finally, like above, we add it to the widget. + */ + gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (target)); + } + } +} + +static void +restart_game (GtkButton *button, + GtkWidget *window) +{ + create_board (window); +} + GtkWidget * do_peg_solitaire (GtkWidget *do_widget) { + static GtkWidget *window = NULL; + if (!window) { GtkWidget *header; GtkWidget *restart; - GtkWidget *grid; - GtkWidget *image; - int x, y; - GtkDragSource *source; - GtkDropTarget *target; + + window = gtk_window_new (); restart = gtk_button_new_from_icon_name ("view-refresh-symbolic"); - g_signal_connect (restart, "clicked", G_CALLBACK (restart), NULL); + g_signal_connect (restart, "clicked", G_CALLBACK (restart_game), window); header = gtk_header_bar_new (); gtk_header_bar_pack_start (GTK_HEADER_BAR (header), restart); - window = gtk_window_new (); gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget)); gtk_window_set_title (GTK_WINDOW (window), "Peg Solitaire"); @@ -285,63 +371,7 @@ do_peg_solitaire (GtkWidget *do_widget) gtk_window_set_default_size (GTK_WINDOW (window), 400, 300); g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window); - grid = gtk_grid_new (); - gtk_widget_set_halign (grid, GTK_ALIGN_CENTER); - gtk_widget_set_valign (grid, GTK_ALIGN_CENTER); - gtk_grid_set_row_spacing (GTK_GRID (grid), 6); - gtk_grid_set_column_spacing (GTK_GRID (grid), 6); - gtk_grid_set_row_homogeneous (GTK_GRID (grid), TRUE); - gtk_grid_set_column_homogeneous (GTK_GRID (grid), TRUE); - gtk_window_set_child (GTK_WINDOW (window), grid); - - for (x = 0; x < 7; x++) - { - for (y = 0; y < 7; y++) - { - if ((x < 2 || x >= 5) && (y < 2 || y >= 5)) - continue; - - image = gtk_image_new (); - if (x != 3 || y != 3) - { - SolitairePeg *peg = solitaire_peg_new (); - solitaire_peg_set_position (peg, x, y); - gtk_image_set_from_paintable (GTK_IMAGE (image), GDK_PAINTABLE (peg)); - } - - gtk_grid_attach (GTK_GRID (grid), image, x, y, 1, 1); - - /* Set up the drag source. - * This is rather straightforward: Set the supported actions - * (in our case, pegs can only be moved) and connect all the - * relevant signals. - * And because all drag'n'drop handling is done via event controllers, - * we need to add the controller to the widget. - */ - source = gtk_drag_source_new (); - gtk_drag_source_set_actions (source, GDK_ACTION_MOVE); - g_signal_connect (source, "prepare", G_CALLBACK (drag_prepare), image); - g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), image); - g_signal_connect (source, "drag-end", G_CALLBACK (drag_end), image); - gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source)); - - /* Set up the drop target. - * This is more involved, because the game logic goes here. - */ - - /* First we specify the data we accept: pegs. - * And we only want moves. - */ - target = gtk_drop_target_new (SOLITAIRE_TYPE_PEG, GDK_ACTION_MOVE); - /* Then we connect our signals. - */ - g_signal_connect (target, "accept", G_CALLBACK (drop_accept), image); - g_signal_connect (target, "drop", G_CALLBACK (drop_drop), image); - /* Finally, like above, we add it to the widget. - */ - gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (target)); - } - } + create_board (window); } if (!gtk_widget_get_visible (window))