Add a mask node demo
authorMatthias Clasen <mclasen@redhat.com>
Sun, 12 Feb 2023 02:38:42 +0000 (21:38 -0500)
committerMatthias Clasen <mclasen@redhat.com>
Sun, 12 Feb 2023 13:35:25 +0000 (08:35 -0500)
demos/gtk-demo/demo.gresource.xml
demos/gtk-demo/demo4widget.c [new file with mode: 0644]
demos/gtk-demo/demo4widget.h [new file with mode: 0644]
demos/gtk-demo/hsla.c [new file with mode: 0644]
demos/gtk-demo/hsla.h [new file with mode: 0644]
demos/gtk-demo/mask.c [new file with mode: 0644]
demos/gtk-demo/meson.build

index 9eca1c16a77926045dc1722e0c6c2cf409e35000..3db485748a1e10f9dca147c14becca6152544c20 100644 (file)
     <file>demo3widget.h</file>
     <file>demo3widget.ui</file>
   </gresource>
+  <gresource prefix="/mask">
+    <file>demo4widget.c</file>
+    <file>demo4widget.h</file>
+    <file>hsla.h</file>
+    <file>hsla.c</file>
+  </gresource>
   <gresource prefix="/paintable_svg">
     <file>svgpaintable.h</file>
     <file>svgpaintable.c</file>
     <file>list_store.c</file>
     <file>main.c</file>
     <file>markup.c</file>
+    <file>mask.c</file>
     <file>menu.c</file>
     <file>overlay.c</file>
     <file>overlay_decorative.c</file>
diff --git a/demos/gtk-demo/demo4widget.c b/demos/gtk-demo/demo4widget.c
new file mode 100644 (file)
index 0000000..3478272
--- /dev/null
@@ -0,0 +1,123 @@
+#include <math.h>
+#include "demo4widget.h"
+#include "hsla.h"
+
+struct _Demo4Widget
+{
+  GtkWidget parent_instance;
+  PangoLayout *layout;
+  GskColorStop stops[8];
+  gsize n_stops;
+
+  guint tick;
+};
+
+struct _Demo4WidgetClass
+{
+  GtkWidgetClass parent_class;
+};
+
+G_DEFINE_TYPE (Demo4Widget, demo4_widget, GTK_TYPE_WIDGET)
+
+static void
+rotate_color (GdkRGBA *rgba)
+{
+  GdkHSLA hsla;
+
+  _gdk_hsla_init_from_rgba (&hsla, rgba);
+  hsla.hue -= 1;
+  _gdk_rgba_init_from_hsla (rgba, &hsla);
+}
+
+static gboolean
+rotate_colors (GtkWidget     *widget,
+               GdkFrameClock *clock,
+               gpointer       user_data)
+{
+  Demo4Widget *self = DEMO4_WIDGET (widget);
+
+  for (unsigned int i = 0; i < self->n_stops; i++)
+    rotate_color (&self->stops[i].color);
+
+  gtk_widget_queue_draw (widget);
+
+  return G_SOURCE_CONTINUE;
+}
+
+static void
+demo4_widget_init (Demo4Widget *self)
+{
+  PangoFontDescription *desc;
+
+  self->n_stops = 8;
+  self->stops[0].offset = 0;
+  self->stops[0].color = (GdkRGBA) { 1, 0, 0, 1 };
+
+  for (unsigned int i = 1; i < self->n_stops; i++)
+    {
+      GdkHSLA hsla;
+
+      self->stops[i].offset = i / (double)(self->n_stops - 1);
+      _gdk_hsla_init_from_rgba (&hsla, &self->stops[i - 1].color);
+      hsla.hue += 360.0 / (double)(self->n_stops - 1);
+      _gdk_rgba_init_from_hsla (&self->stops[i].color, &hsla);
+    }
+
+  self->layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), "123");
+  desc = pango_font_description_from_string ("Cantarell Bold 210");
+  pango_layout_set_font_description (self->layout, desc);
+  pango_font_description_free (desc);
+
+  self->tick = gtk_widget_add_tick_callback (GTK_WIDGET (self), rotate_colors, NULL, NULL);
+}
+
+static void
+demo4_widget_dispose (GObject *object)
+{
+  Demo4Widget *self = DEMO4_WIDGET (object);
+
+  g_clear_object (&self->layout);
+  gtk_widget_remove_tick_callback (GTK_WIDGET (self), self->tick);
+
+  G_OBJECT_CLASS (demo4_widget_parent_class)->dispose (object);
+}
+
+static void
+demo4_widget_snapshot (GtkWidget   *widget,
+                       GtkSnapshot *snapshot)
+{
+  Demo4Widget *self = DEMO4_WIDGET (widget);
+  int width, height;
+
+  width = gtk_widget_get_width (widget);
+  height = gtk_widget_get_height (widget);
+
+  gtk_snapshot_push_mask (snapshot);
+  gtk_snapshot_append_layout (snapshot, self->layout, &(GdkRGBA) { 0, 0, 0, 1 });
+  gtk_snapshot_pop (snapshot);
+
+  gtk_snapshot_append_linear_gradient (snapshot,
+                                       &GRAPHENE_RECT_INIT (0, 0, width, height),
+                                       &GRAPHENE_POINT_INIT (0, 0),
+                                       &GRAPHENE_POINT_INIT (width, height),
+                                       self->stops,
+                                       self->n_stops);
+  gtk_snapshot_pop (snapshot);
+}
+
+static void
+demo4_widget_class_init (Demo4WidgetClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+
+  object_class->dispose = demo4_widget_dispose;
+
+  widget_class->snapshot = demo4_widget_snapshot;
+}
+
+GtkWidget *
+demo4_widget_new (void)
+{
+  return g_object_new (DEMO4_TYPE_WIDGET, NULL);
+}
diff --git a/demos/gtk-demo/demo4widget.h b/demos/gtk-demo/demo4widget.h
new file mode 100644 (file)
index 0000000..4546a4c
--- /dev/null
@@ -0,0 +1,8 @@
+#pragma once
+
+#include <gtk/gtk.h>
+
+#define DEMO4_TYPE_WIDGET (demo4_widget_get_type ())
+G_DECLARE_FINAL_TYPE (Demo4Widget, demo4_widget, DEMO4, WIDGET, GtkWidget)
+
+GtkWidget * demo4_widget_new (void);
diff --git a/demos/gtk-demo/hsla.c b/demos/gtk-demo/hsla.c
new file mode 100644 (file)
index 0000000..abf635e
--- /dev/null
@@ -0,0 +1,146 @@
+#include <gdk/gdk.h>
+#include "hsla.h"
+
+void
+_gdk_hsla_init_from_rgba (GdkHSLA       *hsla,
+                          const GdkRGBA *rgba)
+{
+  float min;
+  float max;
+  float red;
+  float green;
+  float blue;
+  float delta;
+
+  g_return_if_fail (hsla != NULL);
+  g_return_if_fail (rgba != NULL);
+
+  red = rgba->red;
+  green = rgba->green;
+  blue = rgba->blue;
+
+  if (red > green)
+    {
+      if (red > blue)
+        max = red;
+      else
+        max = blue;
+
+      if (green < blue)
+        min = green;
+      else
+        min = blue;
+    }
+  else
+    {
+      if (green > blue)
+        max = green;
+      else
+        max = blue;
+
+      if (red < blue)
+        min = red;
+      else
+        min = blue;
+    }
+
+  hsla->lightness = (max + min) / 2;
+  hsla->saturation = 0;
+  hsla->hue = 0;
+  hsla->alpha = rgba->alpha;
+
+  if (max != min)
+    {
+      if (hsla->lightness <= 0.5)
+        hsla->saturation = (max - min) / (max + min);
+      else
+        hsla->saturation = (max - min) / (2 - max - min);
+
+      delta = max -min;
+      if (red == max)
+        hsla->hue = (green - blue) / delta;
+      else if (green == max)
+        hsla->hue = 2 + (blue - red) / delta;
+      else if (blue == max)
+        hsla->hue = 4 + (red - green) / delta;
+
+      hsla->hue *= 60;
+      if (hsla->hue < 0.0)
+        hsla->hue += 360;
+    }
+}
+
+void
+_gdk_rgba_init_from_hsla (GdkRGBA       *rgba,
+                          const GdkHSLA *hsla)
+{
+  float hue;
+  float lightness;
+  float saturation;
+  float m1, m2;
+
+  lightness = hsla->lightness;
+  saturation = hsla->saturation;
+
+  if (lightness <= 0.5)
+    m2 = lightness * (1 + saturation);
+  else
+    m2 = lightness + saturation - lightness * saturation;
+  m1 = 2 * lightness - m2;
+
+  rgba->alpha = hsla->alpha;
+
+  if (saturation == 0)
+    {
+      rgba->red = lightness;
+      rgba->green = lightness;
+      rgba->blue = lightness;
+    }
+  else
+    {
+      hue = hsla->hue + 120;
+      while (hue > 360)
+        hue -= 360;
+      while (hue < 0)
+        hue += 360;
+
+      if (hue < 60)
+        rgba->red = m1 + (m2 - m1) * hue / 60;
+      else if (hue < 180)
+        rgba->red = m2;
+      else if (hue < 240)
+        rgba->red = m1 + (m2 - m1) * (240 - hue) / 60;
+      else
+        rgba->red = m1;
+
+      hue = hsla->hue;
+      while (hue > 360)
+        hue -= 360;
+      while (hue < 0)
+        hue += 360;
+
+      if (hue < 60)
+        rgba->green = m1 + (m2 - m1) * hue / 60;
+      else if (hue < 180)
+        rgba->green = m2;
+      else if (hue < 240)
+        rgba->green = m1 + (m2 - m1) * (240 - hue) / 60;
+      else
+        rgba->green = m1;
+
+      hue = hsla->hue - 120;
+      while (hue > 360)
+        hue -= 360;
+      while (hue < 0)
+        hue += 360;
+
+      if (hue < 60)
+        rgba->blue = m1 + (m2 - m1) * hue / 60;
+      else if (hue < 180)
+        rgba->blue = m2;
+      else if (hue < 240)
+        rgba->blue = m1 + (m2 - m1) * (240 - hue) / 60;
+      else
+        rgba->blue = m1;
+    }
+}
diff --git a/demos/gtk-demo/hsla.h b/demos/gtk-demo/hsla.h
new file mode 100644 (file)
index 0000000..52c6bdc
--- /dev/null
@@ -0,0 +1,15 @@
+#pragma once
+
+typedef struct _GdkHSLA GdkHSLA;
+
+struct _GdkHSLA {
+  float hue;
+  float saturation;
+  float lightness;
+  float alpha;
+};
+
+void            _gdk_hsla_init_from_rgba    (GdkHSLA          *hsla,
+                                             const GdkRGBA    *rgba);
+void            _gdk_rgba_init_from_hsla    (GdkRGBA          *rgba,
+                                             const GdkHSLA    *hsla);
diff --git a/demos/gtk-demo/mask.c b/demos/gtk-demo/mask.c
new file mode 100644 (file)
index 0000000..4266b44
--- /dev/null
@@ -0,0 +1,46 @@
+/* Masking
+ *
+ * Demonstrates mask nodes.
+ *
+ * This demo uses a text node as mask for
+ * an animated linear gradient.
+ */
+
+#include <gtk/gtk.h>
+#include "demo4widget.h"
+
+
+GtkWidget *
+do_mask (GtkWidget *do_widget)
+{
+  static GtkWidget *window = NULL;
+
+  if (!window)
+    {
+      GtkWidget *box;
+      GtkWidget *widget;
+
+      window = gtk_window_new ();
+      gtk_window_set_title (GTK_WINDOW (window), "Mask Nodes");
+      gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
+      gtk_window_set_display (GTK_WINDOW (window),
+                              gtk_widget_get_display (do_widget));
+      g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
+
+      box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+      gtk_window_set_child (GTK_WINDOW (window), box);
+
+      widget = demo4_widget_new ();
+      gtk_widget_set_hexpand (widget, TRUE);
+      gtk_widget_set_vexpand (widget, TRUE);
+
+      gtk_box_append (GTK_BOX (box), widget);
+    }
+
+  if (!gtk_widget_get_visible (window))
+    gtk_widget_set_visible (window, TRUE);
+  else
+    gtk_window_destroy (GTK_WINDOW (window));
+
+  return window;
+}
index 5537cf20a5577c86c4d7883203436920a748f038..b1c21a9f9bcfeb397c5e5f1a261a3317faf27206 100644 (file)
@@ -46,6 +46,7 @@ demos = files([
   'links.c',
   'listbox.c',
   'listbox_controls.c',
+  'mask.c',
   'menu.c',
   'flowbox.c',
   'list_store.c',
@@ -114,6 +115,7 @@ extra_demo_sources = files([
   'gtkshadertoy.c',
   'gtkshaderstack.c',
   'gskshaderpaintable.c',
+  'hsla.c',
   'puzzlepiece.c',
   'bluroverlay.c',
   'demoimage.c',
@@ -126,6 +128,7 @@ extra_demo_sources = files([
   'four_point_transform.c',
   'demo2widget.c',
   'demo3widget.c',
+  'demo4widget.c',
   'pixbufpaintable.c',
   'script-names.c',
   'unicode-names.c',