[gtk/svg-demo: 2/2] gtk-demo: Add an svg paintable demo




commit 5a9547da414bd11e678baf244aa26e48a7289800
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Oct 6 15:12:09 2020 -0400

    gtk-demo: Add an svg paintable demo
    
    It is a little annoying that this demo will not show up
    if we don't find librsvg, but I think showing how easy
    this paintable is outweights the annoyance.

 demos/gtk-demo/demo.gresource.xml                |   4 +
 demos/gtk-demo/meson.build                       |   7 +
 demos/gtk-demo/org.gtk.gtk4.NodeEditor.Devel.svg |  88 +++++++++
 demos/gtk-demo/paintable_svg.c                   | 241 +++++++++++++++++++++++
 4 files changed, 340 insertions(+)
---
diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml
index fa03214cc5..e3f0a034c3 100644
--- a/demos/gtk-demo/demo.gresource.xml
+++ b/demos/gtk-demo/demo.gresource.xml
@@ -204,6 +204,9 @@
     <file>demo3widget.h</file>
     <file>demo3widget.ui</file>
   </gresource>
+  <gresource prefix="/paintable_svg">
+    <file>org.gtk.gtk4.NodeEditor.Devel.svg</file>
+  </gresource>
   <gresource prefix="/shortcuts">
     <file>shortcuts.ui</file>
     <file>shortcuts-builder.ui</file>
@@ -299,6 +302,7 @@
     <file>paintable_animated.c</file>
     <file>paintable_emblem.c</file>
     <file>paintable_mediastream.c</file>
+    <file>paintable_svg.c</file>
     <file>panes.c</file>
     <file>password_entry.c</file>
     <file>peg_solitaire.c</file>
diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build
index 095a64ed63..2d1efc4170 100644
--- a/demos/gtk-demo/meson.build
+++ b/demos/gtk-demo/meson.build
@@ -130,6 +130,13 @@ if os_unix
   demos += files('pagesetup.c')
 endif
 
+librsvg_dep = dependency('librsvg-2.0', version: '>= 2.46.0', required: false)
+
+if librsvg_dep.found()
+  demos += files('paintable_svg.c')
+  gtkdemo_deps += [ librsvg_dep ]
+endif
+
 gtkdemo_args = [ '-DGDK_DISABLE_DEPRECATED', '-DGTK_DISABLE_DEPRECATED', ]
 
 demos_h = custom_target('gtk4 demo header',
diff --git a/demos/gtk-demo/org.gtk.gtk4.NodeEditor.Devel.svg 
b/demos/gtk-demo/org.gtk.gtk4.NodeEditor.Devel.svg
new file mode 100644
index 0000000000..7d693fa8c6
--- /dev/null
+++ b/demos/gtk-demo/org.gtk.gtk4.NodeEditor.Devel.svg
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg height="128px" viewBox="0 0 128 128" width="128px" xmlns="http://www.w3.org/2000/svg"; 
xmlns:xlink="http://www.w3.org/1999/xlink";>
+    <linearGradient id="a" gradientUnits="userSpaceOnUse" x1="43.000351" x2="85.000351" y1="39.000164" 
y2="39.000164">
+        <stop offset="0" stop-color="#26a269"/>
+        <stop offset="0.0934161" stop-color="#84e3b7"/>
+        <stop offset="0.330831" stop-color="#26a269"/>
+        <stop offset="0.686952" stop-color="#26a269"/>
+        <stop offset="0.89736" stop-color="#175e3c"/>
+        <stop offset="1" stop-color="#26a269"/>
+    </linearGradient>
+    <linearGradient id="b" gradientUnits="userSpaceOnUse">
+        <stop offset="0" stop-color="#c0bfbc"/>
+        <stop offset="0.154754" stop-color="#ffffff"/>
+        <stop offset="0.433722" stop-color="#bdbbb5"/>
+        <stop offset="0.650505" stop-color="#c1c0ba"/>
+        <stop offset="0.825253" stop-color="#ffffff"/>
+        <stop offset="1" stop-color="#c0bfbc"/>
+    </linearGradient>
+    <linearGradient id="c" gradientTransform="matrix(0.0811899 -0.046875 0.069079 0.119648 307.03142 
127.069456)" x1="-1710.210571" x2="-1774.45166" xlink:href="#b" y1="-1202.376709" y2="-1202.376709"/>
+    <linearGradient id="d" gradientTransform="matrix(-0.0811899 -0.046875 -0.069079 0.119648 -177.242852 
127.069447)" x1="-1710.210571" x2="-1774.45166" xlink:href="#b" y1="-1202.376709" y2="-1202.376709"/>
+    <linearGradient id="e" gradientUnits="userSpaceOnUse" x1="14" x2="56" y1="94.999964" y2="94.999964">
+        <stop offset="0" stop-color="#813d9c"/>
+        <stop offset="0.109119" stop-color="#b378ca"/>
+        <stop offset="0.241583" stop-color="#813d9c"/>
+        <stop offset="0.731841" stop-color="#813d9c"/>
+        <stop offset="0.872163" stop-color="#4d255d"/>
+        <stop offset="1" stop-color="#813d9c"/>
+    </linearGradient>
+    <linearGradient id="f" gradientUnits="userSpaceOnUse" x1="72" x2="114" y1="94.999964" y2="94.999964">
+        <stop offset="0" stop-color="#e66100"/>
+        <stop offset="0.0678478" stop-color="#ff903e"/>
+        <stop offset="0.168852" stop-color="#e66100"/>
+        <stop offset="0.886626" stop-color="#e66100"/>
+        <stop offset="1" stop-color="#9d4200"/>
+    </linearGradient>
+    <clipPath id="g">
+        <rect height="128" width="128"/>
+    </clipPath>
+    <clipPath id="h">
+        <rect height="128" width="128"/>
+    </clipPath>
+    <filter id="i" height="100%" width="100%" x="0%" y="0%">
+        <feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
+    </filter>
+    <mask id="j">
+        <g clip-path="url(#h)" filter="url(#i)">
+            <g clip-path="url(#g)">
+                <path d="m 51 18 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c 
-4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="url(#a)"/>
+                <path d="m 51 12 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c 
-4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="#57e389"/>
+                <path d="m 76.976562 55.453125 c 1.480469 -0.855469 3.371094 -0.347656 4.226563 1.132813 l 
6.742187 11.679687 c 0.855469 1.480469 0.347657 3.371094 -1.132812 4.226563 c -1.480469 0.851562 -3.371094 
0.347656 -4.226562 -1.132813 l -6.742188 -11.679687 c -0.855469 -1.480469 -0.347656 -3.371094 1.132812 
-4.226563 z m 0 0" fill="url(#c)"/>
+                <path d="m 52.8125 55.453125 c -1.480469 -0.855469 -3.371094 -0.347656 -4.226562 1.132813 l 
-6.742188 11.679687 c -0.855469 1.480469 -0.347656 3.371094 1.132812 4.226563 c 1.480469 0.851562 3.371094 
0.347656 4.226563 -1.132813 l 6.742187 -11.679687 c 0.855469 -1.480469 0.347657 -3.371094 -1.132812 -4.226563 
z m 0 0" fill="url(#d)"/>
+                <path d="m 22 74 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c 
-4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="url(#e)"/>
+                <path d="m 22 68 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c 
-4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="#dc8add"/>
+                <path d="m 80 74 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c 
-4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="url(#f)"/>
+                <path d="m 80 68 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c 
-4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="#ffa348"/>
+            </g>
+        </g>
+    </mask>
+    <mask id="k">
+        <g filter="url(#i)">
+            <rect fill-opacity="0.8" height="128" width="128"/>
+        </g>
+    </mask>
+    <linearGradient id="l" gradientTransform="matrix(0 0.37 -0.98462 0 295.38501 -30.360001)" 
gradientUnits="userSpaceOnUse" x1="300" x2="428" y1="235" y2="235">
+        <stop offset="0" stop-color="#f9f06b"/>
+        <stop offset="1" stop-color="#f5c211"/>
+    </linearGradient>
+    <clipPath id="m">
+        <rect height="128" width="128"/>
+    </clipPath>
+    <clipPath id="n">
+        <rect height="128" width="128"/>
+    </clipPath>
+    <path d="m 51 18 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 
-8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="url(#a)"/>
+    <path d="m 51 12 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 
-8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="#57e389"/>
+    <path d="m 76.976562 55.453125 c 1.480469 -0.855469 3.371094 -0.347656 4.226563 1.132813 l 6.742187 
11.679687 c 0.855469 1.480469 0.347657 3.371094 -1.132812 4.226563 c -1.480469 0.851562 -3.371094 0.347656 
-4.226562 -1.132813 l -6.742188 -11.679687 c -0.855469 -1.480469 -0.347656 -3.371094 1.132812 -4.226563 z m 0 
0" fill="url(#c)"/>
+    <path d="m 52.8125 55.453125 c -1.480469 -0.855469 -3.371094 -0.347656 -4.226562 1.132813 l -6.742188 
11.679687 c -0.855469 1.480469 -0.347656 3.371094 1.132812 4.226563 c 1.480469 0.851562 3.371094 0.347656 
4.226563 -1.132813 l 6.742187 -11.679687 c 0.855469 -1.480469 0.347657 -3.371094 -1.132812 -4.226563 z m 0 0" 
fill="url(#d)"/>
+    <path d="m 22 74 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 
-8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="url(#e)"/>
+    <path d="m 22 68 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 
-8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="#dc8add"/>
+    <path d="m 80 74 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 
-8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="url(#f)"/>
+    <path d="m 80 68 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 
-8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="#ffa348"/>
+    <g clip-path="url(#n)" mask="url(#j)">
+        <g clip-path="url(#m)" mask="url(#k)">
+            <path d="m 128 80.640625 v 47.359375 h -128 v -47.359375 z m 0 0" fill="url(#l)"/>
+            <path d="m 13.308594 80.640625 l 47.355468 47.359375 h 21.214844 l -47.359375 -47.359375 z m 
42.421875 0 l 47.363281 47.359375 h 21.214844 l -47.363282 -47.359375 z m 42.429687 0 l 29.839844 29.839844 v 
-21.210938 l -8.628906 -8.628906 z m -98.160156 7.90625 v 21.214844 l 18.238281 18.238281 h 21.214844 z m 0 
0"/>
+        </g>
+    </g>
+</svg>
diff --git a/demos/gtk-demo/paintable_svg.c b/demos/gtk-demo/paintable_svg.c
new file mode 100644
index 0000000000..b2254a2348
--- /dev/null
+++ b/demos/gtk-demo/paintable_svg.c
@@ -0,0 +1,241 @@
+/* Paintable/SVG
+ *
+ * This demo shows wrapping a librsvg RsvgHandle in a GdkPaintable
+ * to display an SVG image that can be scaled by resizing the window.
+ *
+ * This demo relies on librsvg, which GTK itself does not link against.
+ */
+
+#include <gtk/gtk.h>
+#include <librsvg/rsvg.h>
+
+#define SVG_TYPE_PAINTABLE (svg_paintable_get_type ())
+
+G_DECLARE_FINAL_TYPE (SvgPaintable, svg_paintable, SVG, PAINTABLE, GObject)
+
+struct _SvgPaintable
+{
+  GObject parent_instance;
+  GFile *file;
+  RsvgHandle *handle;
+};
+
+struct _SvgPaintableClass
+{
+  GObjectClass parent_class;
+};
+
+enum {
+  PROP_FILE = 1,
+  NUM_PROPERTIES
+};
+
+static void
+svg_paintable_snapshot (GdkPaintable *paintable,
+                        GdkSnapshot  *snapshot,
+                        double        width,
+                        double        height)
+{
+  SvgPaintable *self = SVG_PAINTABLE (paintable);
+  cairo_t *cr;
+  GError *error = NULL;
+
+  cr = gtk_snapshot_append_cairo (GTK_SNAPSHOT (snapshot),
+                                  &GRAPHENE_RECT_INIT (0, 0, width, height));
+
+  if (!rsvg_handle_render_document (self->handle, cr,
+                                    &(RsvgRectangle) {0, 0, width, height},
+                                    &error))
+    {
+      g_error ("%s", error->message);
+    }
+
+  cairo_destroy (cr);
+}
+
+static int
+svg_paintable_get_intrinsic_width (GdkPaintable *paintable)
+{
+  SvgPaintable *self = SVG_PAINTABLE (paintable);
+  RsvgDimensionData data;
+
+  rsvg_handle_get_dimensions (self->handle, &data);
+
+  return data.width;
+}
+
+static int
+svg_paintable_get_intrinsic_height (GdkPaintable *paintable)
+{
+  SvgPaintable *self = SVG_PAINTABLE (paintable);
+  RsvgDimensionData data;
+
+  rsvg_handle_get_dimensions (self->handle, &data);
+
+  return data.height;
+}
+
+static void
+svg_paintable_init_interface (GdkPaintableInterface *iface)
+{
+  iface->snapshot = svg_paintable_snapshot;
+  iface->get_intrinsic_width = svg_paintable_get_intrinsic_width;
+  iface->get_intrinsic_height = svg_paintable_get_intrinsic_height;
+}
+
+G_DEFINE_TYPE_WITH_CODE (SvgPaintable, svg_paintable, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
+                                                svg_paintable_init_interface))
+
+static void
+svg_paintable_init (SvgPaintable *self)
+{
+}
+
+static void
+svg_paintable_dispose (GObject *object)
+{
+  SvgPaintable *self = SVG_PAINTABLE (object);
+
+  g_clear_object (&self->file);
+  g_clear_object (&self->handle);
+
+  G_OBJECT_CLASS (svg_paintable_parent_class)->dispose (object);
+}
+
+static void
+svg_paintable_set_property (GObject      *object,
+                            guint         prop_id,
+                            const GValue *value,
+                            GParamSpec   *pspec)
+{
+  SvgPaintable *self = SVG_PAINTABLE (object);
+
+  switch (prop_id)
+    {
+    case PROP_FILE:
+      {
+        GFile *file = g_value_get_object (value);
+        RsvgHandle *handle = rsvg_handle_new_from_gfile_sync (file,
+                                                              RSVG_HANDLE_FLAGS_NONE,
+                                                              NULL,
+                                                              NULL);
+        rsvg_handle_set_dpi (handle, 90);
+
+        g_set_object (&self->file, file);
+        g_set_object (&self->handle, handle);
+      }
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+svg_paintable_get_property (GObject    *object,
+                            guint       prop_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+  SvgPaintable *self = SVG_PAINTABLE (object);
+
+  switch (prop_id)
+    {
+    case PROP_FILE:
+      g_value_set_object (value, self->file);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+
+static void
+svg_paintable_class_init (SvgPaintableClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->dispose = svg_paintable_dispose;
+  object_class->set_property = svg_paintable_set_property;
+  object_class->get_property = svg_paintable_get_property;
+
+  g_object_class_install_property (object_class, PROP_FILE,
+                                   g_param_spec_object ("file", "File", "File",
+                                                        G_TYPE_FILE,
+                                                        G_PARAM_READWRITE));
+}
+
+static SvgPaintable *
+svg_paintable_new (GFile *file)
+{
+  return g_object_new (SVG_TYPE_PAINTABLE,
+                       "file", file,
+                       NULL);
+}
+
+static void
+file_set (GtkFileChooserButton *button,
+          GtkWidget            *picture)
+{
+  GFile *file;
+  SvgPaintable *paintable;
+
+  file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (button));
+
+  paintable = svg_paintable_new (file);
+  gtk_picture_set_paintable (GTK_PICTURE (picture), GDK_PAINTABLE (paintable));
+
+  g_object_unref (paintable);
+  g_object_unref (file);
+}
+
+static GtkWidget *window;
+
+GtkWidget *
+do_paintable_svg (GtkWidget *do_widget)
+{
+  GtkWidget *header;
+  GtkWidget *picture;
+  GtkFileFilter *filter;
+  GtkWidget *button;
+  GFile *file;
+  SvgPaintable *paintable;
+
+  if (!window)
+    {
+      window = gtk_window_new ();
+      header = gtk_header_bar_new ();
+      gtk_window_set_titlebar (GTK_WINDOW (window), header);
+      gtk_window_set_default_size (GTK_WINDOW (window), 300, 200);
+      g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
+
+      button = gtk_file_chooser_button_new ("Select an SVG file", GTK_FILE_CHOOSER_ACTION_OPEN);
+      filter = gtk_file_filter_new ();
+      gtk_file_filter_add_mime_type (filter, "image/svg+xml");
+      gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (button), filter);
+      gtk_header_bar_pack_start (GTK_HEADER_BAR (header), button);
+
+      picture = gtk_picture_new ();
+      gtk_picture_set_can_shrink (GTK_PICTURE (picture), TRUE);
+      gtk_widget_set_size_request (picture, 16, 16);
+
+      g_signal_connect (button, "file-set", G_CALLBACK (file_set), picture);
+
+      gtk_window_set_child (GTK_WINDOW (window), picture);
+
+      file = g_file_new_for_uri ("resource:///paintable_svg/org.gtk.gtk4.NodeEditor.Devel.svg");
+      paintable = svg_paintable_new (file);
+      gtk_picture_set_paintable (GTK_PICTURE (picture), GDK_PAINTABLE (paintable));
+      g_object_unref (paintable);
+      g_object_unref (file);
+    }
+
+  if (!gtk_widget_get_visible (window))
+    gtk_window_present (GTK_WINDOW (window));
+  else
+    gtk_window_destroy (GTK_WINDOW (window));
+
+  return window;
+}


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