[gtk+/wip/matthiasc/font-variations: 9/14] Add another fun demo



commit ba92738f0afccb5f4e55a060956e3707416e9168
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Dec 18 22:51:52 2017 -0500

    Add another fun demo
    
    Explore the weight-width plane freely.

 demos/gtk-demo/demo.gresource.xml |    2 +
 demos/gtk-demo/font_explorer.c    |  367 +++++++++++++++++++++++++++++++++++++
 demos/gtk-demo/fontplane.c        |  315 +++++++++++++++++++++++++++++++
 demos/gtk-demo/fontplane.h        |   65 +++++++
 demos/gtk-demo/meson.build        |    4 +-
 5 files changed, 751 insertions(+), 2 deletions(-)
---
diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml
index 4539b40..eab8524 100644
--- a/demos/gtk-demo/demo.gresource.xml
+++ b/demos/gtk-demo/demo.gresource.xml
@@ -162,7 +162,9 @@
     <file>widgetbowl.c</file>
     <file>flowbox.c</file>
     <file>foreigndrawing.c</file>
+    <file>font_explorer.c</file>
     <file>font_features.c</file>
+    <file>fontplane.c</file>
     <file>gestures.c</file>
     <file>glarea.c</file>
     <file>headerbar.c</file>
diff --git a/demos/gtk-demo/font_explorer.c b/demos/gtk-demo/font_explorer.c
new file mode 100644
index 0000000..e76ca77
--- /dev/null
+++ b/demos/gtk-demo/font_explorer.c
@@ -0,0 +1,367 @@
+/* Pango/Font Explorer
+ *
+ * Explore the width and weight axes simultaneously.
+ */
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include <pango/pangofc-font.h>
+#include <hb-ot.h>
+#include <freetype/ftmm.h>
+
+#include "fontplane.h"
+
+#define MAKE_TAG(a,b,c,d) (unsigned int)(((a) << 24) | ((b) << 16) | ((c) <<  8) | (d))
+
+#define FixedToFloat(f) (((float)(f))/65536.0)
+
+static GtkWidget *window = NULL;
+static GtkWidget *scale = NULL;
+static GtkWidget *entry = NULL;
+static GtkWidget *axis_grid = NULL;
+static char *font = NULL;
+static char *variations = NULL;
+static double size = 0;
+
+static void
+update_entry (void)
+{
+  PangoFontDescription *desc;
+  PangoFontDescription *desc2;
+  PangoAttrList *attrs;
+
+  desc = pango_font_description_from_string (font);
+  if (pango_font_description_get_size_is_absolute (desc))
+    pango_font_description_set_absolute_size (desc, size * PANGO_SCALE);
+  else
+    pango_font_description_set_size (desc, size * PANGO_SCALE);
+  desc2 = pango_font_description_from_string (variations);
+  pango_font_description_merge (desc, desc2, TRUE);
+
+  attrs = pango_attr_list_new ();
+
+  pango_attr_list_insert (attrs, pango_attr_font_desc_new (desc));
+
+  gtk_entry_set_attributes (GTK_ENTRY (entry), attrs);
+
+  pango_attr_list_unref (attrs);
+  pango_font_description_free (desc);
+  pango_font_description_free (desc2);
+}
+
+static void
+update_scale (void)
+{
+  gtk_range_set_value (GTK_RANGE (scale), size);
+}
+
+static void
+size_changed (GtkAdjustment *adj, gpointer data)
+{
+  double value;
+
+  value = gtk_adjustment_get_value (adj);
+  if (fabs (value - size) > 0.001)
+    {
+      size = value;
+      update_entry ();
+    }
+}
+
+typedef struct {
+  guint32 tag;
+  GtkAdjustment *adjustment;
+} Axis;
+
+static GHashTable *axes;
+
+
+static void
+add_font_variations (GString *s)
+{
+  GHashTableIter iter;
+  Axis *axis;
+  char buf[G_ASCII_DTOSTR_BUF_SIZE];
+  char *sep = " @";
+
+  g_hash_table_iter_init (&iter, axes);
+  while (g_hash_table_iter_next (&iter, (gpointer *)NULL, (gpointer *)&axis))
+    {
+      char tag[5];
+      double value;
+
+      hb_tag_to_string (axis->tag, tag);
+      tag[4] = '\0';
+      value = gtk_adjustment_get_value (axis->adjustment);
+
+      g_string_append_printf (s, "%s%s=%s", sep, tag, g_ascii_dtostr (buf, sizeof (buf), value));
+      sep = ",";
+    }
+}
+
+static guint
+axes_hash (gconstpointer v)
+{
+  const Axis *p = v;
+
+  return p->tag;
+}
+
+static gboolean
+axes_equal (gconstpointer v1, gconstpointer v2)
+{
+  const Axis *p1 = v1;
+  const Axis *p2 = v2;
+
+  return p1->tag == p2->tag;
+}
+
+static void
+collect_variations (void)
+{
+  GString *s;
+
+  s = g_string_new ("");
+  add_font_variations (s);
+
+  g_free (variations);
+  variations = g_string_free (s, FALSE);
+}
+
+static void
+adjustment_changed (GtkAdjustment *adjustment,
+                    GtkEntry      *entry)
+{
+  char *str;
+
+  if (entry)
+    {
+      str = g_strdup_printf ("%g", gtk_adjustment_get_value (adjustment));
+      gtk_entry_set_text (GTK_ENTRY (entry), str);
+      g_free (str);
+    }
+
+  collect_variations ();
+  update_entry ();
+}
+
+static void
+entry_activated (GtkEntry *entry,
+                 GtkAdjustment *adjustment)
+{
+  gdouble value;
+  gchar *err = NULL;
+
+  value = g_strtod (gtk_entry_get_text (entry), &err);
+  if (err != NULL)
+    gtk_adjustment_set_value (adjustment, value);
+}
+
+static void
+add_axis (FT_Var_Axis *ax, FT_Fixed value, int i)
+{
+  GtkWidget *axis_label;
+  GtkWidget *axis_entry;
+  GtkWidget *axis_scale;
+  GtkAdjustment *adjustment;
+  Axis *axis;
+
+  axis_label = gtk_label_new (ax->name);
+  gtk_widget_set_halign (axis_label, GTK_ALIGN_START);
+  gtk_widget_set_valign (axis_label, GTK_ALIGN_BASELINE);
+  gtk_grid_attach (GTK_GRID (axis_grid), axis_label, 0, i, 1, 1);
+  adjustment = gtk_adjustment_new ((double)FixedToFloat(value),
+                                   (double)FixedToFloat(ax->minimum),
+                                   (double)FixedToFloat(ax->maximum),
+                                   1.0, 10.0, 0.0);
+  axis_scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, adjustment);
+  gtk_scale_add_mark (GTK_SCALE (axis_scale), (double)FixedToFloat(ax->def), GTK_POS_TOP, NULL);
+  gtk_widget_set_valign (axis_scale, GTK_ALIGN_BASELINE);
+  gtk_widget_set_hexpand (axis_scale, TRUE);
+  gtk_widget_set_size_request (axis_scale, 100, -1);
+  gtk_scale_set_draw_value (GTK_SCALE (axis_scale), FALSE);
+  gtk_grid_attach (GTK_GRID (axis_grid), axis_scale, 1, i, 1, 1);
+  axis_entry = gtk_entry_new ();
+  gtk_widget_set_valign (axis_entry, GTK_ALIGN_BASELINE);
+  gtk_entry_set_width_chars (GTK_ENTRY (axis_entry), 4);
+  gtk_grid_attach (GTK_GRID (axis_grid), axis_entry, 2, i, 1, 1);
+
+  axis = g_new (Axis, 1);
+  axis->tag = ax->tag;
+  axis->adjustment = adjustment;
+  g_hash_table_add (axes, axis);
+
+  adjustment_changed (adjustment, GTK_ENTRY (axis_entry));
+
+  g_signal_connect (adjustment, "value-changed", G_CALLBACK (adjustment_changed), axis_entry);
+  g_signal_connect (axis_entry, "activate", G_CALLBACK (entry_activated), adjustment);
+}
+
+static void
+remove_all_axes (void)
+{
+  GList *children, *l;
+
+  children = gtk_container_get_children (GTK_CONTAINER (axis_grid));
+  for (l = children; l; l = l->next)
+    gtk_widget_destroy (GTK_WIDGET (l->data));
+  g_list_free (children);
+
+  g_hash_table_remove_all (axes);
+}
+
+static void
+add_font_plane (int i)
+{
+  GtkWidget *plane;
+  Axis *weight_axis;
+  Axis *width_axis;
+
+  Axis key;
+
+  key.tag = MAKE_TAG('w','g','h','t');
+  weight_axis = g_hash_table_lookup (axes, &key);
+  key.tag = MAKE_TAG('w','d','t','h');
+  width_axis = g_hash_table_lookup (axes, &key);
+
+  g_assert (weight_axis && width_axis);
+
+  plane = gtk_font_plane_new (weight_axis->adjustment,
+                              width_axis->adjustment);
+
+  gtk_widget_set_size_request (plane, 300, 300);
+  gtk_widget_set_halign (plane, GTK_ALIGN_CENTER);
+  gtk_grid_attach (GTK_GRID (axis_grid), plane, 0, i, 3, 1);
+}
+
+static void
+update_axes (void)
+{
+  PangoFontDescription *desc;
+  PangoContext *context;
+  PangoFont *pango_font;
+  FT_Face ft_face;
+  FT_MM_Var *ft_mm_var;
+  FT_Error res;
+
+  remove_all_axes ();
+
+  desc = pango_font_description_from_string (font);
+  context = gtk_widget_get_pango_context (window);
+  pango_font = pango_context_load_font (context, desc);
+  ft_face = pango_fc_font_lock_face (PANGO_FC_FONT (pango_font));
+
+  res = FT_Get_MM_Var (ft_face, &ft_mm_var);
+  if (res == 0)
+    {
+      unsigned int i;
+      FT_Fixed *coords;
+
+      coords = g_new (FT_Fixed, ft_mm_var->num_axis);
+      res = FT_Get_Var_Design_Coordinates (ft_face, ft_mm_var->num_axis, coords);
+
+      if (res == 0)
+        {
+          int weight = -1;
+          int width = -1;
+
+          for (i = 0; i < ft_mm_var->num_axis; i++)
+            {
+              if (ft_mm_var->axis[i].tag == MAKE_TAG('w', 'g', 'h', 't'))
+                weight = i;
+              if (ft_mm_var->axis[i].tag == MAKE_TAG('w', 'd', 't', 'h'))
+                width = i;
+              add_axis (&ft_mm_var->axis[i], coords[i], i);
+            }
+
+          if (weight >= 0 && width >= 0)
+            add_font_plane (i);
+        }
+
+      g_free (coords);
+      free (ft_mm_var);
+    }
+
+  pango_fc_font_unlock_face (PANGO_FC_FONT (pango_font));
+  g_object_unref (pango_font);
+  pango_font_description_free (desc);
+}
+
+static void
+font_set (GtkFontButton *button, gpointer data)
+{
+  g_free (font);
+  font = gtk_font_chooser_get_font (GTK_FONT_CHOOSER (button));
+  size = ((double)gtk_font_chooser_get_font_size (GTK_FONT_CHOOSER (button)))/PANGO_SCALE;
+
+  update_scale ();
+  update_entry ();
+  update_axes ();
+}
+
+GtkWidget *
+do_font_explorer (GtkWidget *do_widget)
+{
+  GtkWidget *box;
+  GtkWidget *chooser;
+  char *fontname;
+
+  if (!window)
+    {
+      if (axes == NULL)
+        axes = g_hash_table_new_full (axes_hash, axes_equal, NULL, g_free);
+      else
+        g_hash_table_remove_all (axes);
+
+      font = g_strdup ("Voto Serif GX");
+      variations = g_strdup ("");
+      size = 11;
+
+      window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+      gtk_window_set_title (GTK_WINDOW (window), "Font Explorer");
+      box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
+      g_object_set (box, "margin", 10, NULL);
+      gtk_container_add (GTK_CONTAINER (window), box);
+
+      chooser = gtk_font_button_new ();
+      gtk_widget_set_halign (chooser, GTK_ALIGN_START);
+      g_signal_connect (chooser, "font-set",
+                        G_CALLBACK (font_set), NULL);
+      gtk_container_add (GTK_CONTAINER (box), chooser);
+
+      fontname = g_strdup_printf ("%s %g", font, size);
+      gtk_font_chooser_set_font (GTK_FONT_CHOOSER (chooser), fontname);
+      g_free (fontname);
+
+      axis_grid = gtk_grid_new ();
+      gtk_grid_set_row_spacing (GTK_GRID (axis_grid), 10);
+      gtk_grid_set_column_spacing (GTK_GRID (axis_grid), 10);
+      gtk_container_add (GTK_CONTAINER (box), axis_grid);
+
+      scale = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 1, 100, 1);
+      g_signal_connect (gtk_range_get_adjustment (GTK_RANGE (scale)),
+                        "value-changed",
+                        G_CALLBACK (size_changed), NULL);
+
+      gtk_widget_set_halign (scale, GTK_ALIGN_FILL);
+      gtk_container_add (GTK_CONTAINER (box), scale);
+
+      entry = gtk_entry_new ();
+      gtk_widget_set_halign (entry, GTK_ALIGN_FILL);
+      gtk_container_add (GTK_CONTAINER (box), entry);
+
+      gtk_entry_set_text (GTK_ENTRY (entry), "The fonts are upon us!");
+
+      update_scale ();
+      update_entry ();
+      update_axes ();
+    }
+
+  if (!gtk_widget_get_visible (window))
+    gtk_widget_show (window);
+  else
+    gtk_widget_destroy (window);
+
+  return window;
+}
diff --git a/demos/gtk-demo/fontplane.c b/demos/gtk-demo/fontplane.c
new file mode 100644
index 0000000..9f04bd3
--- /dev/null
+++ b/demos/gtk-demo/fontplane.c
@@ -0,0 +1,315 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "fontplane.h"
+
+#include "gtk.h"
+
+enum {
+  PROP_0,
+  PROP_WEIGHT_ADJUSTMENT,
+  PROP_WIDTH_ADJUSTMENT
+};
+
+G_DEFINE_TYPE (GtkFontPlane, gtk_font_plane, GTK_TYPE_WIDGET)
+
+static double
+adjustment_get_normalized_value (GtkAdjustment *adj)
+{
+  return (gtk_adjustment_get_value (adj) - gtk_adjustment_get_lower (adj)) /
+        (gtk_adjustment_get_upper (adj) - gtk_adjustment_get_lower (adj));
+}
+
+static void
+val_to_xy (GtkFontPlane *plane,
+           gint          *x,
+           gint          *y)
+{
+  gdouble u, v;
+  gint width, height;
+
+  width = gtk_widget_get_allocated_width (GTK_WIDGET (plane));
+  height = gtk_widget_get_allocated_height (GTK_WIDGET (plane));
+
+  u = adjustment_get_normalized_value (plane->width_adj);
+  v = adjustment_get_normalized_value (plane->weight_adj);
+
+  *x = CLAMP (width * u, 0, width - 1);
+  *y = CLAMP (height * (1 - v), 0, height - 1);
+}
+
+static void
+plane_snapshot (GtkWidget   *widget,
+                GtkSnapshot *snapshot)
+{
+  GtkFontPlane *plane = GTK_FONT_PLANE (widget);
+  gint x, y;
+  gint width, height;
+  cairo_t *cr;
+
+  val_to_xy (plane, &x, &y);
+  width = gtk_widget_get_allocated_width (widget);
+  height = gtk_widget_get_allocated_height (widget);
+
+  cr = gtk_snapshot_append_cairo (snapshot,
+                                  &GRAPHENE_RECT_INIT (0, 0, width, height),
+                                  "FontPlane");
+
+  cairo_set_source_rgb (cr, 0, 0, 0);
+  cairo_rectangle (cr, 0, 0, width, height);
+  cairo_paint (cr);
+
+  cairo_move_to (cr, 0,     y + 0.5);
+  cairo_line_to (cr, width, y + 0.5);
+
+  cairo_move_to (cr, x + 0.5, 0);
+  cairo_line_to (cr, x + 0.5, height);
+
+  if (gtk_widget_has_visible_focus (widget))
+    {
+      cairo_set_line_width (cr, 3.0);
+      cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.6);
+      cairo_stroke_preserve (cr);
+
+      cairo_set_line_width (cr, 1.0);
+      cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.8);
+      cairo_stroke (cr);
+    }
+  else
+    {
+      cairo_set_line_width (cr, 1.0);
+      cairo_set_source_rgba (cr, 0.8, 0.8, 0.8, 0.8);
+      cairo_stroke (cr);
+    }
+
+  cairo_destroy (cr);
+}
+
+static void
+set_cross_cursor (GtkWidget *widget,
+                  gboolean   enabled)
+{
+  if (enabled)
+    gtk_widget_set_cursor_from_name (widget, "crosshair");
+  else
+    gtk_widget_set_cursor (widget, NULL);
+}
+
+static void
+adj_changed (GtkFontPlane *plane)
+{
+  gtk_widget_queue_draw (GTK_WIDGET (plane));
+}
+
+static void
+adjustment_set_normalized_value (GtkAdjustment *adj,
+                                 double         val)
+{
+  gtk_adjustment_set_value (adj,
+      gtk_adjustment_get_lower (adj) +
+          val * (gtk_adjustment_get_upper (adj) - gtk_adjustment_get_lower (adj)));
+}
+
+static void
+update_value (GtkFontPlane *plane,
+              gint           x,
+              gint           y)
+{
+  GtkWidget *widget = GTK_WIDGET (plane);
+  gdouble u, v;
+
+  u = CLAMP (x * (1.0 / gtk_widget_get_allocated_width (widget)), 0, 1);
+  v = CLAMP (1 - y * (1.0 / gtk_widget_get_allocated_height (widget)), 0, 1);
+
+  adjustment_set_normalized_value (plane->width_adj, u);
+  adjustment_set_normalized_value (plane->weight_adj, v);
+
+  gtk_widget_queue_draw (widget);
+}
+
+static void
+hold_action (GtkGestureLongPress *gesture,
+             gdouble              x,
+             gdouble              y,
+             GtkFontPlane       *plane)
+{
+  gboolean handled;
+
+  g_signal_emit_by_name (plane, "popup-menu", &handled);
+}
+
+static void
+plane_drag_gesture_begin (GtkGestureDrag *gesture,
+                          gdouble         start_x,
+                          gdouble         start_y,
+                          GtkFontPlane  *plane)
+{
+  guint button;
+
+  button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
+
+  if (button == GDK_BUTTON_SECONDARY)
+    {
+      gboolean handled;
+
+      g_signal_emit_by_name (plane, "popup-menu", &handled);
+    }
+
+  if (button != GDK_BUTTON_PRIMARY)
+    {
+      gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
+      return;
+    }
+
+  set_cross_cursor (GTK_WIDGET (plane), TRUE);
+  update_value (plane, start_x, start_y);
+  gtk_widget_grab_focus (GTK_WIDGET (plane));
+  gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
+}
+
+static void
+plane_drag_gesture_update (GtkGestureDrag *gesture,
+                           gdouble         offset_x,
+                           gdouble         offset_y,
+                           GtkFontPlane  *plane)
+{
+  gdouble start_x, start_y;
+
+  gtk_gesture_drag_get_start_point (GTK_GESTURE_DRAG (gesture),
+                                    &start_x, &start_y);
+  update_value (plane, start_x + offset_x, start_y + offset_y);
+}
+
+static void
+plane_drag_gesture_end (GtkGestureDrag *gesture,
+                        gdouble         offset_x,
+                        gdouble         offset_y,
+                        GtkFontPlane  *plane)
+{
+  set_cross_cursor (GTK_WIDGET (plane), FALSE);
+}
+
+static void
+gtk_font_plane_init (GtkFontPlane *plane)
+{
+  gtk_widget_set_has_window (GTK_WIDGET (plane), FALSE);
+  gtk_widget_set_can_focus (GTK_WIDGET (plane), TRUE);
+
+  plane->drag_gesture = gtk_gesture_drag_new (GTK_WIDGET (plane));
+  g_signal_connect (plane->drag_gesture, "drag-begin",
+                   G_CALLBACK (plane_drag_gesture_begin), plane);
+  g_signal_connect (plane->drag_gesture, "drag-update",
+                   G_CALLBACK (plane_drag_gesture_update), plane);
+  g_signal_connect (plane->drag_gesture, "drag-end",
+                   G_CALLBACK (plane_drag_gesture_end), plane);
+  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (plane->drag_gesture), 0);
+
+  plane->long_press_gesture = gtk_gesture_long_press_new (GTK_WIDGET (plane));
+  g_signal_connect (plane->long_press_gesture, "pressed",
+                    G_CALLBACK (hold_action), plane);
+  gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (plane->long_press_gesture),
+                                     TRUE);
+}
+
+static void
+plane_finalize (GObject *object)
+{
+  GtkFontPlane *plane = GTK_FONT_PLANE (object);
+
+  g_clear_object (&plane->weight_adj);
+  g_clear_object (&plane->width_adj);
+
+  g_clear_object (&plane->drag_gesture);
+  g_clear_object (&plane->long_press_gesture);
+
+  G_OBJECT_CLASS (gtk_font_plane_parent_class)->finalize (object);
+}
+
+static void
+plane_set_property (GObject      *object,
+                   guint         prop_id,
+                   const GValue *value,
+                   GParamSpec   *pspec)
+{
+  GtkFontPlane *plane = GTK_FONT_PLANE (object);
+  GObject *adjustment;
+
+  switch (prop_id)
+    {
+    case PROP_WEIGHT_ADJUSTMENT:
+      adjustment = g_value_get_object (value);
+      if (adjustment)
+       {
+         plane->weight_adj = g_object_ref_sink (adjustment);
+         g_signal_connect_swapped (adjustment, "value-changed", G_CALLBACK (adj_changed), plane);
+       }
+      break;
+    case PROP_WIDTH_ADJUSTMENT:
+      adjustment = g_value_get_object (value);
+      if (adjustment)
+       {
+         plane->width_adj = g_object_ref_sink (adjustment);
+         g_signal_connect_swapped (adjustment, "value-changed", G_CALLBACK (adj_changed), plane);
+       }
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_font_plane_class_init (GtkFontPlaneClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+
+  object_class->finalize = plane_finalize;
+  object_class->set_property = plane_set_property;
+
+  widget_class->snapshot = plane_snapshot;
+
+  g_object_class_install_property (object_class,
+                                   PROP_WEIGHT_ADJUSTMENT,
+                                   g_param_spec_object ("weight-adjustment",
+                                                        NULL,
+                                                        NULL,
+                                                       GTK_TYPE_ADJUSTMENT,
+                                                       G_PARAM_WRITABLE |
+                                                       G_PARAM_CONSTRUCT_ONLY));
+
+  g_object_class_install_property (object_class,
+                                   PROP_WIDTH_ADJUSTMENT,
+                                   g_param_spec_object ("width-adjustment",
+                                                        NULL,
+                                                        NULL,
+                                                       GTK_TYPE_ADJUSTMENT,
+                                                       G_PARAM_WRITABLE |
+                                                       G_PARAM_CONSTRUCT_ONLY));
+}
+
+GtkWidget *
+gtk_font_plane_new (GtkAdjustment *weight_adj,
+                     GtkAdjustment *width_adj)
+{
+  return g_object_new (GTK_TYPE_FONT_PLANE,
+                       "weight-adjustment", weight_adj,
+                       "width-adjustment", width_adj,
+                       NULL);
+}
diff --git a/demos/gtk-demo/fontplane.h b/demos/gtk-demo/fontplane.h
new file mode 100644
index 0000000..e9983a1
--- /dev/null
+++ b/demos/gtk-demo/fontplane.h
@@ -0,0 +1,65 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GTK_FONT_PLANE_H__
+#define __GTK_FONT_PLANE_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_FONT_PLANE            (gtk_font_plane_get_type ())
+#define GTK_FONT_PLANE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FONT_PLANE, 
GtkFontPlane))
+#define GTK_FONT_PLANE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FONT_PLANE, 
GtkFontPlaneClass))
+#define GTK_IS_FONT_PLANE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COLOR_PLANE))
+#define GTK_IS_FONT_PLANE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COLOR_PLANE))
+#define GTK_FONT_PLANE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FONT_PLANE, 
GtkFontPlaneClass))
+
+
+typedef struct _GtkFontPlane         GtkFontPlane;
+typedef struct _GtkFontPlaneClass    GtkFontPlaneClass;
+
+struct _GtkFontPlane
+{
+  GtkWidget parent_instance;
+
+  GtkAdjustment *weight_adj;
+  GtkAdjustment *width_adj;
+
+  GtkGesture *drag_gesture;
+  GtkGesture *long_press_gesture;
+};
+
+struct _GtkFontPlaneClass
+{
+  GtkWidgetClass parent_class;
+
+  /* Padding for future expansion */
+  void (*_gtk_reserved1) (void);
+  void (*_gtk_reserved2) (void);
+  void (*_gtk_reserved3) (void);
+  void (*_gtk_reserved4) (void);
+};
+
+
+GType       gtk_font_plane_get_type (void) G_GNUC_CONST;
+GtkWidget * gtk_font_plane_new      (GtkAdjustment *width_adj,
+                                     GtkAdjustment *weight_adj);
+
+G_END_DECLS
+
+#endif /* __GTK_FONT_PLANE_H__ */
diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build
index 0d57447..d68846e 100644
--- a/demos/gtk-demo/meson.build
+++ b/demos/gtk-demo/meson.build
@@ -74,7 +74,7 @@ demos = files([
 gtkdemo_deps = [ libgtk_dep, ]
 
 if harfbuzz_dep.found() and pangoft_dep.found()
-  demos += files('font_features.c')
+  demos += files('font_features.c', 'font_explorer.c')
   gtkdemo_deps += [ harfbuzz_dep, ]
 endif
 
@@ -94,7 +94,7 @@ gtkdemo_resources = gnome.compile_resources('gtkdemo_resources',
                                             source_dir: '.')
 
 executable('gtk4-demo',
-           'main.c', 'gtkfishbowl.c', demos, demos_h, gtkdemo_resources,
+           'main.c', 'gtkfishbowl.c', 'fontplane.c', demos, demos_h, gtkdemo_resources,
            c_args: gtkdemo_args,
            dependencies: gtkdemo_deps,
            include_directories: confinc,


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