Add tweaks
authorMatthias Clasen <mclasen@redhat.com>
Wed, 6 Jun 2018 01:02:57 +0000 (21:02 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Fri, 8 Jun 2018 01:47:30 +0000 (21:47 -0400)
Allow setting the puzzle size, and allow chosing between
the rose and the radioactive animation. Change the default
size to 3. 6 is just too hard.

demos/gtk-demo/sliding_puzzle.c

index f7615fc15eab0a9440cf0041f7caa9b4f933707c..09671024dcbee8b74e7d893419e472b3a53d4681 100644 (file)
 
 /* Include the header for the puzzle piece */
 #include "puzzlepiece.h"
+#include "paintable.h"
+
+#define ICON_TYPE_PAINTABLE (icon_paintable_get_type ())
+
+G_DECLARE_FINAL_TYPE (IconPaintable, icon_paintable, ICON, PAINTABLE, GObject)
+
+GdkPaintable *  icon_paintable_new                  (GdkPaintable *paintable,
+                                                     double        height);
+
+struct _IconPaintable
+{
+  GObject parent_instance;
+
+  GdkPaintable *paintable;
+  double height;
+  double scale_factor;
+};
+
+struct _IconPaintableClass
+{
+  GObjectClass parent_class;
+};
+
+
+static void
+icon_paintable_paintable_snapshot (GdkPaintable *paintable,
+                                   GdkSnapshot  *snapshot,
+                                   double        width,
+                                   double        height)
+{
+  IconPaintable *self = ICON_PAINTABLE (paintable);
+
+  if (self->scale_factor == 1.0)
+    {
+      gdk_paintable_snapshot (self->paintable, snapshot, width, height);
+    }
+  else
+    {
+      graphene_matrix_t scale_matrix;
+
+      graphene_matrix_init_scale (&scale_matrix, 1.0 / self->scale_factor, 1.0 / self->scale_factor, 1.0);
+      gtk_snapshot_push_transform (snapshot, &scale_matrix);
+      gdk_paintable_snapshot (self->paintable,
+                              snapshot,
+                              width * self->scale_factor,
+                              height * self->scale_factor);
+      gtk_snapshot_pop (snapshot);
+    }
+}
+
+static GdkPaintable *
+icon_paintable_paintable_get_current_image (GdkPaintable *paintable)
+{
+  IconPaintable *self = ICON_PAINTABLE (paintable);
+  GdkPaintable *current_paintable, *current_self;
+
+  current_paintable = gdk_paintable_get_current_image (self->paintable);
+  current_self = icon_paintable_new (current_paintable, self->height);
+  g_object_unref (current_paintable);
+
+  return current_self;
+}
+
+static GdkPaintableFlags
+icon_paintable_paintable_get_flags (GdkPaintable *paintable)
+{
+  IconPaintable *self = ICON_PAINTABLE (paintable);
+
+  return gdk_paintable_get_flags (self->paintable);
+}
+
+static int
+icon_paintable_paintable_get_intrinsic_width (GdkPaintable *paintable)
+{
+  IconPaintable *self = ICON_PAINTABLE (paintable);
+
+  return gdk_paintable_get_intrinsic_width (self->paintable) / self->scale_factor;
+}
+
+static int
+icon_paintable_paintable_get_intrinsic_height (GdkPaintable *paintable)
+{
+  IconPaintable *self = ICON_PAINTABLE (paintable);
+
+  return gdk_paintable_get_intrinsic_height (self->paintable) / self->scale_factor;
+}
+
+static double icon_paintable_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
+{
+  IconPaintable *self = ICON_PAINTABLE (paintable);
+
+  return gdk_paintable_get_intrinsic_aspect_ratio (self->paintable);
+};
+
+static void
+icon_paintable_paintable_init (GdkPaintableInterface *iface)
+{
+  iface->snapshot = icon_paintable_paintable_snapshot;
+  iface->get_current_image = icon_paintable_paintable_get_current_image;
+  iface->get_flags = icon_paintable_paintable_get_flags;
+  iface->get_intrinsic_width = icon_paintable_paintable_get_intrinsic_width;
+  iface->get_intrinsic_height = icon_paintable_paintable_get_intrinsic_height;
+  iface->get_intrinsic_aspect_ratio = icon_paintable_paintable_get_intrinsic_aspect_ratio;
+}
+
+G_DEFINE_TYPE_EXTENDED (IconPaintable, icon_paintable, G_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
+                                               icon_paintable_paintable_init))
+
+static void
+icon_paintable_dispose (GObject *object)
+{
+  IconPaintable *self = ICON_PAINTABLE (object);
+
+  if (self->paintable)
+    {
+      g_signal_handlers_disconnect_by_func (self->paintable, gdk_paintable_invalidate_contents, self);
+      g_signal_handlers_disconnect_by_func (self->paintable, gdk_paintable_invalidate_size, self);
+      g_clear_object (&self->paintable);
+    }
+
+  G_OBJECT_CLASS (icon_paintable_parent_class)->dispose (object);
+}
+
+static void
+icon_paintable_class_init (IconPaintableClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->dispose = icon_paintable_dispose;
+}
+
+static void
+icon_paintable_init (IconPaintable *self)
+{
+  self->scale_factor = 1.0;
+}
+
+GdkPaintable *
+icon_paintable_new (GdkPaintable *paintable,
+                    double        height)
+{
+  IconPaintable *self;
+
+  g_return_val_if_fail (GDK_IS_PAINTABLE (paintable), NULL);
+  g_return_val_if_fail (height > 0.0, NULL);
+
+  self = g_object_new (ICON_TYPE_PAINTABLE, NULL);
+
+  self->paintable = g_object_ref (paintable);
+  g_signal_connect_swapped (paintable, "invalidate-contents", G_CALLBACK (gdk_paintable_invalidate_contents), self);
+  g_signal_connect_swapped (paintable, "invalidate-size", G_CALLBACK (gdk_paintable_invalidate_size), self);
+  self->height = height;
+  if (gdk_paintable_get_intrinsic_height (paintable) == 0)
+    self->scale_factor = 1.0;
+  else
+    self->scale_factor = gdk_paintable_get_intrinsic_height (paintable) / height;
+
+  return GDK_PAINTABLE (self);
+}
+
 
 static GtkWidget *window = NULL;
 static GtkWidget *frame = NULL;
+static GtkWidget *size_spin = NULL;
+static GtkWidget *rose_button = NULL;
+static GdkPaintable *puzzle = NULL;
+static GdkPaintable *rose = NULL;
+static GdkPaintable *atom = NULL;
 
 static gboolean solved = TRUE;
-static guint width = 6;
-static guint height = 6;
+static guint width = 3;
+static guint height = 3;
 static guint pos_x;
 static guint pos_y;
 
@@ -280,24 +446,98 @@ reshuffle (void)
   GtkWidget *grid;
 
   grid = gtk_bin_get_child (GTK_BIN (frame));
-  shuffle_puzzle (grid);
+  if (solved)
+    start_puzzle (puzzle);
+  else
+    shuffle_puzzle (grid);
+  gtk_widget_grab_focus (grid);
+}
+
+static void
+reconfigure (void)
+{
+  GtkWidget *popover;
+  GtkWidget *grid;
+
+  width = height = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (size_spin));
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rose_button)))
+    puzzle = rose;
+  else
+    puzzle= atom;
+
+  start_puzzle (puzzle); 
+  popover = gtk_widget_get_ancestor (size_spin, GTK_TYPE_POPOVER);
+  gtk_popover_popdown (GTK_POPOVER (popover));
+  grid = gtk_bin_get_child (GTK_BIN (frame));
+  gtk_widget_grab_focus (grid);
 }
 
 GtkWidget *
 do_sliding_puzzle (GtkWidget *do_widget)
 {
-  GdkPaintable *puzzle;
-
   if (!window)
     {
       GtkWidget *header;
       GtkWidget *restart;
-
+      GtkWidget *tweak;
+      GtkWidget *popover;
+      GtkWidget *tweaks;
+      GtkWidget *apply;
+      GtkWidget *image;
+      GtkWidget *button;
+      GtkWidget *label;
+
+      rose = GDK_PAINTABLE (gdk_texture_new_from_resource ("/sliding_puzzle/portland-rose.jpg"));
+      atom = gtk_nuclear_animation_new ();
+
+      puzzle = rose;
+
+      tweaks = gtk_grid_new ();
+      gtk_grid_set_row_spacing (GTK_GRID (tweaks), 10);
+      gtk_grid_set_column_spacing (GTK_GRID (tweaks), 10);
+      g_object_set (tweaks, "margin", 10, NULL);
+
+      rose_button = button = gtk_radio_button_new (NULL);
+      image = gtk_image_new_from_paintable (icon_paintable_new (rose, 40));
+      gtk_image_set_can_shrink (GTK_IMAGE (image), TRUE);
+      gtk_widget_set_size_request (image, 40, 40);
+      gtk_container_add (GTK_CONTAINER (button), image);
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
+      gtk_grid_attach (GTK_GRID (tweaks), button, 0, 0, 1, 1);
+
+      button = gtk_radio_button_new_from_widget (button);
+      image = gtk_image_new_from_paintable (icon_paintable_new (atom, 40));
+      gtk_image_set_can_shrink (GTK_IMAGE (image), TRUE);
+      gtk_widget_set_size_request (image, 40, 40);
+      gtk_container_add (GTK_CONTAINER (button), image);
+      gtk_widget_set_halign (button, GTK_ALIGN_CENTER);
+      gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
+      gtk_grid_attach (GTK_GRID (tweaks), button, 1, 0, 1, 1);
+
+      label = gtk_label_new ("Size");
+      gtk_label_set_xalign (label, 0.0);
+      gtk_grid_attach (GTK_GRID (tweaks), label, 0, 1, 1, 1);
+      size_spin = gtk_spin_button_new_with_range (2, 10, 1);
+      gtk_spin_button_set_value (GTK_SPIN_BUTTON (size_spin), width);
+      gtk_grid_attach (GTK_GRID (tweaks), size_spin, 1, 1, 1, 1);
+
+      apply = gtk_button_new_with_label ("Apply");
+      gtk_widget_set_halign (apply, GTK_ALIGN_END);
+      gtk_grid_attach (GTK_GRID (tweaks), apply, 1, 2, 1, 1);
+      g_signal_connect (apply, "clicked", G_CALLBACK (reconfigure), NULL);
+      popover = gtk_popover_new (NULL);
+      gtk_popover_set_modal (GTK_POPOVER (popover), TRUE);
+      gtk_container_add (GTK_CONTAINER (popover), tweaks);
       restart = gtk_button_new_from_icon_name ("view-refresh-symbolic");
       g_signal_connect (restart, "clicked", G_CALLBACK (reshuffle), NULL);
+      tweak = gtk_menu_button_new ();
+      gtk_menu_button_set_popover (GTK_MENU_BUTTON (tweak), popover);
+      gtk_button_set_icon_name (tweak, "emblem-system-symbolic");
+
       header = gtk_header_bar_new ();
       gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
       gtk_header_bar_pack_start (GTK_HEADER_BAR (header), restart);
+      gtk_header_bar_pack_end (GTK_HEADER_BAR (header), tweak);
       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
       gtk_window_set_display (GTK_WINDOW (window),
                               gtk_widget_get_display (do_widget));
@@ -307,15 +547,10 @@ do_sliding_puzzle (GtkWidget *do_widget)
       g_signal_connect (window, "destroy",
                         G_CALLBACK (gtk_widget_destroyed), &window);
 
-      puzzle = GDK_PAINTABLE (gdk_texture_new_from_resource ("/sliding_puzzle/portland-rose.jpg"));
-
       frame = gtk_aspect_frame_new (NULL, 0.5, 0.5, (float) gdk_paintable_get_intrinsic_aspect_ratio (puzzle), FALSE);
       gtk_container_add (GTK_CONTAINER (window), frame);
 
-      /* Start a puzzle with a default image */
-      
       start_puzzle (puzzle);
-      g_object_unref (puzzle);
     }
 
   if (!gtk_widget_get_visible (window))