[gtk/wip/otte/canvas: 5/8] demos: Add a puzzle demo




commit eb97b4a9ce541a15d3e8f570e5937acbf91e1e0c
Author: Benjamin Otte <otte redhat com>
Date:   Wed Jun 29 00:33:14 2022 +0200

    demos: Add a puzzle demo

 demos/gtk-demo/canvas_puzzle.c    | 125 ++++++++++++++++++++++++++++----------
 demos/gtk-demo/demo.gresource.xml |   1 +
 demos/gtk-demo/meson.build        |   1 +
 3 files changed, 94 insertions(+), 33 deletions(-)
---
diff --git a/demos/gtk-demo/canvas_puzzle.c b/demos/gtk-demo/canvas_puzzle.c
index 8fae9fa177..07b0d5f66d 100644
--- a/demos/gtk-demo/canvas_puzzle.c
+++ b/demos/gtk-demo/canvas_puzzle.c
@@ -7,66 +7,125 @@
 
 #include <gtk/gtk.h>
 
-#define WIDTH 400
-#define HEIGHT 300
+#include "puzzlepiece.h"
 
 static void
-bind_item (GtkListItemFactory *factory,
-           GtkCanvasItem      *ci)
+set_item_position (GtkCanvasItem *ci,
+                   float          x,
+                   float          y)
 {
   GtkCanvasPoint *point;
   GtkCanvasSize *size;
-  GtkCanvasBox *box;
+  GtkCanvasBox *box, *viewport;
 
-  widget = gtk_picture_new_for_paintable (gtk_canvas_item_get_item (ci));
-  gtk_canvas_item_set_widget (ci, widget);
+  x = CLAMP (x, 0, 1);
+  y = CLAMP (y, 0, 1);
+
+  point = gtk_canvas_point_new (0, 0);
+  viewport = gtk_canvas_box_new (point,
+                                 gtk_canvas_get_viewport_size (gtk_canvas_item_get_canvas (ci)),
+                                 0.0, 0.0);
+  gtk_canvas_point_free (point);
+
+  point = gtk_canvas_point_new_from_box (viewport, x, y, 0, 0);
+  gtk_canvas_box_free (viewport);
+  size = gtk_canvas_size_new (0, 0);
+  box = gtk_canvas_box_new (point, size, x, y);
+  gtk_canvas_point_free (point);
+  gtk_canvas_size_free (size);
 
-  /* Also cener the item, so we do something interesting */
-  point = gtk_canvas_point_new (WIDTH / 2.0, HEIGHT / 2.0);
-  size = gtk_canvas_size_new_measure_item (ci, GTK_CANVAS_ITEM_MEASURE_MIN_FOR_MIN);
-  box = gtk_canvas_box_new (point, size, 0.5, 0.5);
   gtk_canvas_item_set_bounds (ci, box);
   gtk_canvas_box_free (box);
-  gtk_canvas_size_free (size);
-  gtk_canvas_point_free (point);
+}
+
+static void
+move_item (GtkGestureDrag *gesture,
+           double          x,
+           double          y,
+           GtkCanvasItem  *ci)
+{
+  GtkCanvas *canvas = gtk_canvas_item_get_canvas (ci);
+  graphene_rect_t bounds;
+
+  if (!gtk_canvas_box_eval (gtk_canvas_item_get_bounds (ci), &bounds))
+    return;
+
+  set_item_position (ci,
+                     (bounds.origin.x + x) / (gtk_widget_get_width (GTK_WIDGET (canvas)) - 
bounds.size.width),
+                     (bounds.origin.y + y) / (gtk_widget_get_height (GTK_WIDGET (canvas)) - 
bounds.size.height));
+}
+
+static void
+bind_item (GtkListItemFactory *factory,
+           GtkCanvasItem      *ci)
+{
+  GtkWidget *widget;
+  GtkGesture *gesture;
+
+  widget = gtk_picture_new_for_paintable (gtk_canvas_item_get_item (ci));
+  gtk_picture_set_can_shrink (GTK_PICTURE (widget), FALSE);
+  gesture = gtk_gesture_drag_new ();
+  g_signal_connect (gesture, "drag-update", G_CALLBACK (move_item), ci);
+  g_signal_connect (gesture, "drag-end", G_CALLBACK (move_item), ci);
+  gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (gesture));
+  gtk_canvas_item_set_widget (ci, widget);
+
+  /* Also center the item, so we do something interesting */
+  set_item_position (ci, g_random_double (), g_random_double ());
+}
+
+static GListModel *
+create_puzzle (GdkPaintable *puzzle)
+{
+  GListStore *store = g_list_store_new (GDK_TYPE_PAINTABLE);
+  int width = 5;
+  int height = 5;
+  int x, y;
+
+  /* add a picture for every cell */
+  for (y = 0; y < height; y++)
+    {
+      for (x = 0; x < width; x++)
+        {
+          GdkPaintable *piece;
+
+          piece = gtk_puzzle_piece_new (puzzle,
+                                        x, y,
+                                        width, height);
+          g_list_store_append (store, piece);
+          g_object_unref (piece);
+        }
+    }
+
+  return G_LIST_MODEL (store);
 }
 
 GtkWidget *
-do_canvas_intro (GtkWidget *do_widget)
+do_canvas_puzzle (GtkWidget *do_widget)
 {
   static GtkWidget *window = NULL;
 
   if (!window)
     {
-      GtkWidget *canvas, *widget;
-      GListStore *store;
+      GtkWidget *canvas;
+      GListModel *model;
       GtkListItemFactory *factory;
+      GdkPaintable *puzzle;
 
       window = gtk_window_new ();
       gtk_window_set_display (GTK_WINDOW (window),
                               gtk_widget_get_display (do_widget));
-      gtk_window_set_default_size (GTK_WINDOW (window), WIDTH, HEIGHT);
+      gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
       g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
 
-      /* GtkCanvas manages its items using an external list.
-       * We do a very simple thing and put the widgets in the list
-       * that the canvas should display.
-       */
-      store = g_list_store_new (GTK_TYPE_WIDGET);
-      widget = gtk_label_new ("Hello World");
-      g_list_store_append (store, widget);
-
-      /* GtkCanvas maps the items from the list to the canvas using factories.
-       * Set up a simple factory here that just maps the widget directly
-       * onto the canvas.
-       */
+      puzzle = GDK_PAINTABLE (gdk_texture_new_from_resource ("/sliding_puzzle/portland-rose.jpg"));
+      model = create_puzzle (puzzle);
+      g_object_unref (puzzle);
+
       factory = gtk_signal_list_item_factory_new ();
       g_signal_connect (factory, "bind", G_CALLBACK (bind_item), NULL);
 
-      /* Create the canvas.
-       * We hand it the factory and the model, and then everything happens by itself.
-       */
-      canvas = gtk_canvas_new (G_LIST_MODEL (store), factory);
+      canvas = gtk_canvas_new (model, factory);
       gtk_window_set_child (GTK_WINDOW (window), canvas);
     }
 
diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml
index ef3cb889b6..e1edcf303b 100644
--- a/demos/gtk-demo/demo.gresource.xml
+++ b/demos/gtk-demo/demo.gresource.xml
@@ -255,6 +255,7 @@
     <file>assistant.c</file>
     <file>builder.c</file>
     <file>canvas_intro.c</file>
+    <file>canvas_puzzle.c</file>
     <file>clipboard.c</file>
     <file>combobox.c</file>
     <file>constraints.c</file>
diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build
index 20c1b9e25f..293c488827 100644
--- a/demos/gtk-demo/meson.build
+++ b/demos/gtk-demo/meson.build
@@ -5,6 +5,7 @@ demos = files([
   'assistant.c',
   'builder.c',
   'canvas_intro.c',
+  'canvas_puzzle.c',
   'clipboard.c',
   'combobox.c',
   'constraints.c',


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]