[gtk/pango2] fontexplorer: Some refactoring
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/pango2] fontexplorer: Some refactoring
- Date: Sun, 10 Jul 2022 15:40:56 +0000 (UTC)
commit 2a3cd0364866560ea99292004a8d5f3102bc3747
Author: Matthias Clasen <mclasen redhat com>
Date: Sun Jul 10 09:08:59 2022 -0400
fontexplorer: Some refactoring
Break the FontView class into individual views.
demos/font-explorer/fontexplorer.css | 18 +-
demos/font-explorer/fontexplorer.gresource.xml | 12 +-
demos/font-explorer/fontexplorerwin.c | 188 ++++--
demos/font-explorer/fontexplorerwin.h | 2 +-
demos/font-explorer/fontexplorerwin.ui | 146 ++++-
demos/font-explorer/fontview.c | 774 -------------------------
demos/font-explorer/fontview.h | 17 -
demos/font-explorer/fontview.ui | 145 -----
demos/font-explorer/glyphsview.c | 238 ++++++++
demos/font-explorer/glyphsview.h | 14 +
demos/font-explorer/glyphsview.ui | 26 +
demos/font-explorer/infoview.c | 416 +++++++++++++
demos/font-explorer/infoview.h | 14 +
demos/font-explorer/infoview.ui | 23 +
demos/font-explorer/meson.build | 18 +-
demos/font-explorer/plainview.c | 342 +++++++++++
demos/font-explorer/plainview.h | 14 +
demos/font-explorer/plainview.ui | 32 +
demos/font-explorer/sampleeditor.c | 161 +++++
demos/font-explorer/sampleeditor.h | 14 +
demos/font-explorer/sampleeditor.ui | 21 +
demos/font-explorer/waterfallview.c | 362 ++++++++++++
demos/font-explorer/waterfallview.h | 14 +
demos/font-explorer/waterfallview.ui | 31 +
24 files changed, 2038 insertions(+), 1004 deletions(-)
---
diff --git a/demos/font-explorer/fontexplorer.css b/demos/font-explorer/fontexplorer.css
index fa8da5f49c..9e6ae9d9f8 100644
--- a/demos/font-explorer/fontexplorer.css
+++ b/demos/font-explorer/fontexplorer.css
@@ -14,7 +14,23 @@ fontcolors > grid {
samplechooser {
border-spacing: 10px;
}
-fontview {
+plainview {
+ padding: 10px;
+ border-spacing: 10px;
+}
+waterfallview {
+ padding: 10px;
+ border-spacing: 10px;
+}
+infoview {
+ padding: 10px;
+ border-spacing: 10px;
+}
+glyphsview {
+ padding: 10px;
+ border-spacing: 10px;
+}
+sampleeditor {
padding: 10px;
border-spacing: 10px;
}
diff --git a/demos/font-explorer/fontexplorer.gresource.xml b/demos/font-explorer/fontexplorer.gresource.xml
index 8715abd461..052a0475e2 100644
--- a/demos/font-explorer/fontexplorer.gresource.xml
+++ b/demos/font-explorer/fontexplorer.gresource.xml
@@ -1,14 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gtk/fontexplorer">
- <file preprocess="xml-stripblanks">fontexplorerwin.ui</file>
- <file preprocess="xml-stripblanks">fontview.ui</file>
- <file preprocess="xml-stripblanks">fontcontrols.ui</file>
- <file preprocess="xml-stripblanks">samplechooser.ui</file>
<file preprocess="xml-stripblanks">fontcolors.ui</file>
+ <file preprocess="xml-stripblanks">fontcontrols.ui</file>
+ <file preprocess="xml-stripblanks">fontexplorerwin.ui</file>
<file preprocess="xml-stripblanks">fontfeatures.ui</file>
<file preprocess="xml-stripblanks">fontvariations.ui</file>
+ <file preprocess="xml-stripblanks">glyphsview.ui</file>
+ <file preprocess="xml-stripblanks">infoview.ui</file>
+ <file preprocess="xml-stripblanks">plainview.ui</file>
<file preprocess="xml-stripblanks">rangeedit.ui</file>
+ <file preprocess="xml-stripblanks">samplechooser.ui</file>
+ <file preprocess="xml-stripblanks">sampleeditor.ui</file>
+ <file preprocess="xml-stripblanks">waterfallview.ui</file>
<file>fontexplorer.css</file>
</gresource>
</gresources>
diff --git a/demos/font-explorer/fontexplorerwin.c b/demos/font-explorer/fontexplorerwin.c
index a0d8eecebb..e6432e1b33 100644
--- a/demos/font-explorer/fontexplorerwin.c
+++ b/demos/font-explorer/fontexplorerwin.c
@@ -1,11 +1,16 @@
-#include "fontexplorerapp.h"
#include "fontexplorerwin.h"
-#include "fontview.h"
-#include "fontcontrols.h"
-#include "samplechooser.h"
+
#include "fontcolors.h"
+#include "fontcontrols.h"
+#include "fontexplorerapp.h"
#include "fontfeatures.h"
#include "fontvariations.h"
+#include "glyphsview.h"
+#include "infoview.h"
+#include "plainview.h"
+#include "samplechooser.h"
+#include "sampleeditor.h"
+#include "waterfallview.h"
#include <gtk/gtk.h>
#include <string.h>
@@ -15,12 +20,19 @@ struct _FontExplorerWindow
{
GtkApplicationWindow parent;
+ Pango2FontMap *font_map;
+
GtkFontButton *fontbutton;
FontControls *controls;
FontFeatures *features;
FontVariations *variations;
FontColors *colors;
- FontView *view;
+ GtkStack *stack;
+ GtkToggleButton *plain_toggle;
+ GtkToggleButton *waterfall_toggle;
+ GtkToggleButton *glyphs_toggle;
+ GtkToggleButton *info_toggle;
+ GtkToggleButton *edit_toggle;
};
struct _FontExplorerWindowClass
@@ -28,57 +40,120 @@ struct _FontExplorerWindowClass
GtkApplicationWindowClass parent_class;
};
+enum {
+ PROP_FONT_MAP = 1,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
+
G_DEFINE_TYPE(FontExplorerWindow, font_explorer_window, GTK_TYPE_APPLICATION_WINDOW);
static void
reset (GSimpleAction *action,
GVariant *parameter,
- FontExplorerWindow *win)
+ FontExplorerWindow *self)
{
- g_action_activate (font_controls_get_reset_action (win->controls), NULL);
- g_action_activate (font_features_get_reset_action (win->features), NULL);
- g_action_activate (font_variations_get_reset_action (win->variations), NULL);
- g_action_activate (font_colors_get_reset_action (win->colors), NULL);
+ g_action_activate (font_controls_get_reset_action (self->controls), NULL);
+ g_action_activate (font_features_get_reset_action (self->features), NULL);
+ g_action_activate (font_variations_get_reset_action (self->variations), NULL);
+ g_action_activate (font_colors_get_reset_action (self->colors), NULL);
}
static void
update_reset (GSimpleAction *action,
GParamSpec *pspec,
- FontExplorerWindow *win)
+ FontExplorerWindow *self)
{
gboolean enabled;
GAction *reset_action;
- enabled = g_action_get_enabled (font_controls_get_reset_action (win->controls)) ||
- g_action_get_enabled (font_features_get_reset_action (win->features)) ||
- g_action_get_enabled (font_variations_get_reset_action (win->variations)) ||
- g_action_get_enabled (font_colors_get_reset_action (win->colors));
+ enabled = g_action_get_enabled (font_controls_get_reset_action (self->controls)) ||
+ g_action_get_enabled (font_features_get_reset_action (self->features)) ||
+ g_action_get_enabled (font_variations_get_reset_action (self->variations)) ||
+ g_action_get_enabled (font_colors_get_reset_action (self->colors));
- reset_action = g_action_map_lookup_action (G_ACTION_MAP (win), "reset");
+ reset_action = g_action_map_lookup_action (G_ACTION_MAP (self), "reset");
g_simple_action_set_enabled (G_SIMPLE_ACTION (reset_action), enabled);
}
static void
-font_explorer_window_init (FontExplorerWindow *win)
+font_explorer_window_init (FontExplorerWindow *self)
{
GSimpleAction *reset_action;
- gtk_widget_init_template (GTK_WIDGET (win));
+ self->font_map = g_object_ref (pango2_font_map_get_default ());
+
+ gtk_widget_init_template (GTK_WIDGET (self));
reset_action = g_simple_action_new ("reset", NULL);
- g_signal_connect (reset_action, "activate", G_CALLBACK (reset), win);
- g_signal_connect (font_controls_get_reset_action (win->controls),
- "notify::enabled", G_CALLBACK (update_reset), win);
- g_signal_connect (font_variations_get_reset_action (win->variations),
- "notify::enabled", G_CALLBACK (update_reset), win);
- g_signal_connect (font_colors_get_reset_action (win->colors),
- "notify::enabled", G_CALLBACK (update_reset), win);
- g_signal_connect (font_features_get_reset_action (win->features),
- "notify::enabled", G_CALLBACK (update_reset), win);
-
- g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (reset_action));
- update_reset (NULL, NULL, win);
+ g_signal_connect (reset_action, "activate", G_CALLBACK (reset), self);
+ g_signal_connect (font_controls_get_reset_action (self->controls),
+ "notify::enabled", G_CALLBACK (update_reset), self);
+ g_signal_connect (font_variations_get_reset_action (self->variations),
+ "notify::enabled", G_CALLBACK (update_reset), self);
+ g_signal_connect (font_colors_get_reset_action (self->colors),
+ "notify::enabled", G_CALLBACK (update_reset), self);
+ g_signal_connect (font_features_get_reset_action (self->features),
+ "notify::enabled", G_CALLBACK (update_reset), self);
+
+ g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (reset_action));
+ update_reset (NULL, NULL, self);
+}
+
+static void
+update_view (GtkToggleButton *button,
+ FontExplorerWindow *self)
+{
+ if (gtk_toggle_button_get_active (self->edit_toggle))
+ gtk_stack_set_visible_child_name (self->stack, "edit");
+ else if (gtk_toggle_button_get_active (self->plain_toggle))
+ gtk_stack_set_visible_child_name (self->stack, "plain");
+ else if (gtk_toggle_button_get_active (self->waterfall_toggle))
+ gtk_stack_set_visible_child_name (self->stack, "waterfall");
+ else if (gtk_toggle_button_get_active (self->glyphs_toggle))
+ gtk_stack_set_visible_child_name (self->stack, "glyphs");
+ else if (gtk_toggle_button_get_active (self->info_toggle))
+ gtk_stack_set_visible_child_name (self->stack, "info");
+}
+
+static void
+font_explorer_window_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ FontExplorerWindow *self = FONT_EXPLORER_WINDOW (object);
+
+ switch (prop_id)
+ {
+ case PROP_FONT_MAP:
+ g_set_object (&self->font_map, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+font_explorer_window_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ FontExplorerWindow *self = FONT_EXPLORER_WINDOW (object);
+
+ switch (prop_id)
+ {
+ case PROP_FONT_MAP:
+ g_value_set_object (value, self->font_map);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
}
static void
@@ -92,7 +167,9 @@ font_explorer_window_dispose (GObject *object)
static void
font_explorer_window_finalize (GObject *object)
{
-// FontExplorerWindow *win = FONT_EXPLORER_WINDOW (object);
+ FontExplorerWindow *self = FONT_EXPLORER_WINDOW (object);
+
+ g_clear_object (&self->font_map);
G_OBJECT_CLASS (font_explorer_window_parent_class)->finalize (object);
}
@@ -102,16 +179,29 @@ font_explorer_window_class_init (FontExplorerWindowClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
- g_type_ensure (FONT_VIEW_TYPE);
- g_type_ensure (FONT_CONTROLS_TYPE);
- g_type_ensure (SAMPLE_CHOOSER_TYPE);
- g_type_ensure (FONT_VARIATIONS_TYPE);
g_type_ensure (FONT_COLORS_TYPE);
+ g_type_ensure (FONT_CONTROLS_TYPE);
g_type_ensure (FONT_FEATURES_TYPE);
+ g_type_ensure (FONT_VARIATIONS_TYPE);
+ g_type_ensure (GLYPHS_VIEW_TYPE);
+ g_type_ensure (INFO_VIEW_TYPE);
+ g_type_ensure (PLAIN_VIEW_TYPE);
+ g_type_ensure (SAMPLE_CHOOSER_TYPE);
+ g_type_ensure (SAMPLE_EDITOR_TYPE);
+ g_type_ensure (WATERFALL_VIEW_TYPE);
+ object_class->set_property = font_explorer_window_set_property;
+ object_class->get_property = font_explorer_window_get_property;
object_class->dispose = font_explorer_window_dispose;
object_class->finalize = font_explorer_window_finalize;
+ properties[PROP_FONT_MAP] =
+ g_param_spec_object ("font-map", "", "",
+ PANGO2_TYPE_FONT_MAP,
+ G_PARAM_READWRITE);
+
+ g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
+
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/fontexplorerwin.ui");
@@ -120,8 +210,16 @@ font_explorer_window_class_init (FontExplorerWindowClass *class)
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, variations);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, colors);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, features);
- gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, view);
+ gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, stack);
+ gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, plain_toggle);
+ gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, waterfall_toggle);
+ gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, glyphs_toggle);
+ gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, info_toggle);
+ gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, edit_toggle);
+ gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), update_view);
+
+ gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "fontexplorer");
}
FontExplorerWindow *
@@ -131,7 +229,7 @@ font_explorer_window_new (FontExplorerApp *app)
}
void
-font_explorer_window_load (FontExplorerWindow *win,
+font_explorer_window_load (FontExplorerWindow *self,
GFile *file)
{
const char *path;
@@ -149,21 +247,23 @@ font_explorer_window_load (FontExplorerWindow *win,
pango2_font_map_add_face (map, PANGO2_FONT_FACE (face));
pango2_font_map_set_fallback (map, pango2_font_map_get_default ());
- font_features_set_font_map (win->features, map);
- font_variations_set_font_map (win->variations, map);
- font_colors_set_font_map (win->colors, map);
- font_view_set_font_map (win->view, map);
+ font_features_set_font_map (self->features, map);
+ font_variations_set_font_map (self->variations, map);
+ font_colors_set_font_map (self->colors, map);
+
+ g_set_object (&self->font_map, map);
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FONT_MAP]);
g_object_unref (map);
- gtk_font_chooser_set_font_desc (GTK_FONT_CHOOSER (win->fontbutton), desc);
+ gtk_font_chooser_set_font_desc (GTK_FONT_CHOOSER (self->fontbutton), desc);
- gtk_widget_hide (GTK_WIDGET (win->fontbutton));
+ gtk_widget_hide (GTK_WIDGET (self->fontbutton));
title = g_strdup_printf ("%s — %s",
pango2_font_description_get_family (desc),
path);
- gtk_window_set_title (GTK_WINDOW (win), title);
+ gtk_window_set_title (GTK_WINDOW (self), title);
g_free (title);
pango2_font_description_free (desc);
diff --git a/demos/font-explorer/fontexplorerwin.h b/demos/font-explorer/fontexplorerwin.h
index 130b216710..6a86c11bb0 100644
--- a/demos/font-explorer/fontexplorerwin.h
+++ b/demos/font-explorer/fontexplorerwin.h
@@ -14,5 +14,5 @@ typedef struct _FontExplorerWindowClass FontExplorerWindowClass;
GType font_explorer_window_get_type (void);
FontExplorerWindow * font_explorer_window_new (FontExplorerApp *app);
-void font_explorer_window_load (FontExplorerWindow *win,
+void font_explorer_window_load (FontExplorerWindow *self,
GFile *file);
diff --git a/demos/font-explorer/fontexplorerwin.ui b/demos/font-explorer/fontexplorerwin.ui
index 68c6ad0b26..67b946634c 100644
--- a/demos/font-explorer/fontexplorerwin.ui
+++ b/demos/font-explorer/fontexplorerwin.ui
@@ -80,17 +80,141 @@
</object>
</child>
<child>
- <object class="FontView" id="view">
- <property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
- <property name="size" bind-source="controls" bind-flags="sync-create"/>
- <property name="letterspacing" bind-source="controls" bind-flags="sync-create"/>
- <property name="line-height" bind-source="controls" bind-flags="sync-create"/>
- <property name="foreground" bind-source="controls" bind-flags="sync-create"/>
- <property name="background" bind-source="controls" bind-flags="sync-create"/>
- <property name="sample-text" bind-source="samplechooser" bind-flags="sync-create"/>
- <property name="features" bind-source="features" bind-flags="sync-create"/>
- <property name="variations" bind-source="variations" bind-flags="sync-create"/>
- <property name="palette" bind-source="colors" bind-flags="sync-create"/>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkStack" id="stack">
+ <property name="hexpand">1</property>
+ <child>
+ <object class="GtkStackPage">
+ <property name="name">plain</property>
+ <property name="child">
+ <object class="PlainView">
+ <property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
+ <property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
+ <property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
+ <property name="size" bind-source="controls" bind-flags="sync-create"/>
+ <property name="letterspacing" bind-source="controls" bind-flags="sync-create"/>
+ <property name="line-height" bind-source="controls" bind-flags="sync-create"/>
+ <property name="foreground" bind-source="controls" bind-flags="sync-create"/>
+ <property name="background" bind-source="controls" bind-flags="sync-create"/>
+ <property name="sample-text" bind-source="sampleeditor" bind-flags="sync-create"/>
+ <property name="features" bind-source="features" bind-flags="sync-create"/>
+ <property name="variations" bind-source="variations" bind-flags="sync-create"/>
+ <property name="palette" bind-source="colors" bind-flags="sync-create"/>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStackPage">
+ <property name="name">waterfall</property>
+ <property name="child">
+ <object class="WaterfallView">
+ <property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
+ <property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
+ <property name="size" bind-source="controls" bind-flags="sync-create"/>
+ <property name="letterspacing" bind-source="controls" bind-flags="sync-create"/>
+ <property name="line-height" bind-source="controls" bind-flags="sync-create"/>
+ <property name="foreground" bind-source="controls" bind-flags="sync-create"/>
+ <property name="background" bind-source="controls" bind-flags="sync-create"/>
+ <property name="sample-text" bind-source="sampleeditor" bind-flags="sync-create"/>
+ <property name="features" bind-source="features" bind-flags="sync-create"/>
+ <property name="variations" bind-source="variations" bind-flags="sync-create"/>
+ <property name="palette" bind-source="colors" bind-flags="sync-create"/>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStackPage">
+ <property name="name">glyphs</property>
+ <property name="child">
+ <object class="GlyphsView">
+ <property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
+ <property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
+ <property name="variations" bind-source="variations" bind-flags="sync-create"/>
+ <property name="palette" bind-source="colors" bind-flags="sync-create"/>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStackPage">
+ <property name="name">info</property>
+ <property name="child">
+ <object class="InfoView">
+ <property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
+ <property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
+ <property name="size" bind-source="controls" bind-flags="sync-create"/>
+ <property name="variations" bind-source="variations" bind-flags="sync-create"/>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStackPage">
+ <property name="name">edit</property>
+ <property name="child">
+ <object class="SampleEditor" id="sampleeditor">
+ <property name="sample-text" bind-source="samplechooser" bind-flags="sync-create"/>
+ <property name="editing" bind-source="edit_toggle" bind-property="active"
bind-flags="sync-create"/>
+ </object>
+ </property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+ <style>
+ <class name="linked"/>
+ </style>
+ <child>
+ <object class="GtkToggleButton" id="plain_toggle">
+ <property name="label">Plain</property>
+ <property name="active">1</property>
+ <signal name="toggled" handler="update_view"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="waterfall_toggle">
+ <property name="label">Waterfall</property>
+ <property name="group">plain_toggle</property>
+ <signal name="toggled" handler="update_view"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="glyphs_toggle">
+ <property name="label">Glyphs</property>
+ <property name="group">plain_toggle</property>
+ <signal name="toggled" handler="update_view"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="info_toggle">
+ <property name="label">Info</property>
+ <property name="group">plain_toggle</property>
+ <signal name="toggled" handler="update_view"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="edit_toggle">
+ <property name="hexpand">1</property>
+ <property name="halign">end</property>
+ <property name="icon-name">document-edit-symbolic</property>
+ <property name="tooltip-text" translatable="yes">Edit the sample</property>
+ <signal name="toggled" handler="update_view"/>
+ </object>
+ </child>
+ </object>
+ </child>
</object>
</child>
</object>
diff --git a/demos/font-explorer/glyphsview.c b/demos/font-explorer/glyphsview.c
new file mode 100644
index 0000000000..4ef0b44d47
--- /dev/null
+++ b/demos/font-explorer/glyphsview.c
@@ -0,0 +1,238 @@
+#include "glyphsview.h"
+#include "glyphitem.h"
+#include "glyphmodel.h"
+#include "glyphview.h"
+#include <gtk/gtk.h>
+
+#include <hb-ot.h>
+
+enum {
+ PROP_FONT_MAP = 1,
+ PROP_FONT_DESC,
+ PROP_VARIATIONS,
+ PROP_PALETTE,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
+
+struct _GlyphsView
+{
+ GtkWidget parent;
+
+ Pango2FontMap *font_map;
+ GtkGridView *glyphs;
+
+ Pango2FontDescription *font_desc;
+ char *variations;
+ char *palette;
+ GQuark palette_quark;
+};
+
+struct _GlyphsViewClass
+{
+ GtkWidgetClass parent_class;
+};
+
+G_DEFINE_TYPE(GlyphsView, glyphs_view, GTK_TYPE_WIDGET);
+
+static void
+glyphs_view_init (GlyphsView *self)
+{
+ self->font_map = g_object_ref (pango2_font_map_get_default ());
+ self->font_desc = pango2_font_description_from_string ("sans 12");
+ self->variations = g_strdup ("");
+ self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
+ self->palette_quark = g_quark_from_string (self->palette);
+
+ gtk_widget_set_layout_manager (GTK_WIDGET (self),
+ gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
+
+ gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+static void
+glyphs_view_dispose (GObject *object)
+{
+ gtk_widget_clear_template (GTK_WIDGET (object), GLYPHS_VIEW_TYPE);
+
+ G_OBJECT_CLASS (glyphs_view_parent_class)->dispose (object);
+}
+
+static void
+glyphs_view_finalize (GObject *object)
+{
+ GlyphsView *self = GLYPHS_VIEW (object);
+
+ g_clear_object (&self->font_map);
+ pango2_font_description_free (self->font_desc);
+ g_free (self->variations);
+ g_free (self->palette);
+
+ G_OBJECT_CLASS (glyphs_view_parent_class)->finalize (object);
+}
+
+static Pango2Font *
+get_font (GlyphsView *self,
+ int size)
+{
+ Pango2Context *context;
+ Pango2FontDescription *desc;
+ Pango2Font *font;
+
+ context = pango2_context_new_with_font_map (self->font_map);
+ desc = pango2_font_description_copy_static (self->font_desc);
+ pango2_font_description_set_variations (desc, self->variations);
+ pango2_font_description_set_size (desc, size);
+ font = pango2_context_load_font (context, desc);
+ pango2_font_description_free (desc);
+ g_object_unref (context);
+
+ return font;
+}
+
+static void
+update_glyph_model (GlyphsView *self)
+{
+ Pango2Font *font = get_font (self, 60 * PANGO2_SCALE);
+ GlyphModel *gm;
+ GtkSelectionModel *model;
+
+ gm = glyph_model_new (font);
+ model = GTK_SELECTION_MODEL (gtk_no_selection_new (G_LIST_MODEL (gm)));
+ gtk_grid_view_set_model (self->glyphs, model);
+ g_object_unref (model);
+ g_object_unref (font);
+}
+
+static void
+setup_glyph (GtkSignalListItemFactory *factory,
+ GObject *listitem)
+{
+ gtk_list_item_set_child (GTK_LIST_ITEM (listitem), GTK_WIDGET (glyph_view_new ()));
+}
+
+static void
+bind_glyph (GtkSignalListItemFactory *factory,
+ GObject *listitem,
+ GlyphsView *self)
+{
+ GlyphView *view;
+ GObject *item;
+
+ view = GLYPH_VIEW (gtk_list_item_get_child (GTK_LIST_ITEM (listitem)));
+ item = gtk_list_item_get_item (GTK_LIST_ITEM (listitem));
+ glyph_view_set_font (view, glyph_item_get_font (GLYPH_ITEM (item)));
+ glyph_view_set_glyph (view, glyph_item_get_glyph (GLYPH_ITEM (item)));
+ glyph_view_set_palette (view, self->palette_quark);
+}
+
+static void
+glyphs_view_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GlyphsView *self = GLYPHS_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_FONT_MAP:
+ g_set_object (&self->font_map, g_value_get_object (value));
+ break;
+
+ case PROP_FONT_DESC:
+ pango2_font_description_free (self->font_desc);
+ self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
+ break;
+
+ case PROP_VARIATIONS:
+ g_free (self->variations);
+ self->variations = g_strdup (g_value_get_string (value));
+ break;
+
+ case PROP_PALETTE:
+ g_free (self->palette);
+ self->palette = g_strdup (g_value_get_string (value));
+ self->palette_quark = g_quark_from_string (self->palette);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+
+ update_glyph_model (self);
+}
+
+static void
+glyphs_view_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GlyphsView *self = GLYPHS_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_FONT_MAP:
+ g_value_set_object (value, self->font_map);
+ break;
+
+ case PROP_FONT_DESC:
+ g_value_set_boxed (value, self->font_desc);
+ break;
+
+ case PROP_VARIATIONS:
+ g_value_set_string (value, self->variations);
+ break;
+
+ case PROP_PALETTE:
+ g_value_set_string (value, self->palette);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+glyphs_view_class_init (GlyphsViewClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->dispose = glyphs_view_dispose;
+ object_class->finalize = glyphs_view_finalize;
+ object_class->get_property = glyphs_view_get_property;
+ object_class->set_property = glyphs_view_set_property;
+
+ properties[PROP_FONT_MAP] =
+ g_param_spec_object ("font-map", "", "",
+ PANGO2_TYPE_FONT_MAP,
+ G_PARAM_READWRITE);
+
+ properties[PROP_FONT_DESC] =
+ g_param_spec_boxed ("font-desc", "", "",
+ PANGO2_TYPE_FONT_DESCRIPTION,
+ G_PARAM_READWRITE);
+
+ properties[PROP_VARIATIONS] =
+ g_param_spec_string ("variations", "", "",
+ "",
+ G_PARAM_READWRITE);
+
+ properties[PROP_PALETTE] =
+ g_param_spec_string ("palette", "", "",
+ PANGO2_COLOR_PALETTE_DEFAULT,
+ G_PARAM_READWRITE);
+
+ g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
+
+ gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
+ "/org/gtk/fontexplorer/glyphsview.ui");
+
+ gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), GlyphsView, glyphs);
+ gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), setup_glyph);
+ gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), bind_glyph);
+
+ gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "glyphsview");
+}
diff --git a/demos/font-explorer/glyphsview.h b/demos/font-explorer/glyphsview.h
new file mode 100644
index 0000000000..d6935ffe1f
--- /dev/null
+++ b/demos/font-explorer/glyphsview.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <gtk/gtk.h>
+
+
+#define GLYPHS_VIEW_TYPE (glyphs_view_get_type ())
+#define GLYPHS_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLYPHS_VIEW_TYPE, GlyphsView))
+
+
+typedef struct _GlyphsView GlyphsView;
+typedef struct _GlyphsViewClass GlyphsViewClass;
+
+
+GType glyphs_view_get_type (void);
diff --git a/demos/font-explorer/glyphsview.ui b/demos/font-explorer/glyphsview.ui
new file mode 100644
index 0000000000..344d8d36d9
--- /dev/null
+++ b/demos/font-explorer/glyphsview.ui
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GlyphsView" parent="GtkWidget">
+ <style>
+ <class name="view"/>
+ </style>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="hexpand">1</property>
+ <property name="vexpand">1</property>
+ <property name="hscrollbar-policy">never</property>
+ <property name="vscrollbar-policy">automatic</property>
+ <child>
+ <object class="GtkGridView" id="glyphs">
+ <property name="factory">
+ <object class="GtkSignalListItemFactory">
+ <signal name="setup" handler="setup_glyph"/>
+ <signal name="bind" handler="bind_glyph"/>
+ </object>
+ </property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/demos/font-explorer/infoview.c b/demos/font-explorer/infoview.c
new file mode 100644
index 0000000000..40464bf397
--- /dev/null
+++ b/demos/font-explorer/infoview.c
@@ -0,0 +1,416 @@
+#include "infoview.h"
+#include <gtk/gtk.h>
+
+#include <hb-ot.h>
+
+enum {
+ PROP_FONT_MAP = 1,
+ PROP_FONT_DESC,
+ PROP_SIZE,
+ PROP_VARIATIONS,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
+
+struct _InfoView
+{
+ GtkWidget parent;
+
+ GtkGrid *info;
+
+ Pango2FontMap *font_map;
+ Pango2FontDescription *font_desc;
+ float size;
+ char *variations;
+};
+
+struct _InfoViewClass
+{
+ GtkWidgetClass parent_class;
+};
+
+G_DEFINE_TYPE(InfoView, info_view, GTK_TYPE_WIDGET);
+
+static void
+info_view_init (InfoView *self)
+{
+ self->font_map = g_object_ref (pango2_font_map_get_default ());
+ self->font_desc = pango2_font_description_from_string ("sans 12");
+ self->size = 12.;
+ self->variations = g_strdup ("");
+
+ gtk_widget_set_layout_manager (GTK_WIDGET (self),
+ gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
+ gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+static void
+info_view_dispose (GObject *object)
+{
+ gtk_widget_clear_template (GTK_WIDGET (object), INFO_VIEW_TYPE);
+
+ G_OBJECT_CLASS (info_view_parent_class)->dispose (object);
+}
+
+static void
+info_view_finalize (GObject *object)
+{
+ InfoView *self = INFO_VIEW (object);
+
+ g_clear_object (&self->font_map);
+ pango2_font_description_free (self->font_desc);
+ g_free (self->variations);
+
+ G_OBJECT_CLASS (info_view_parent_class)->finalize (object);
+}
+
+static Pango2Font *
+get_font (InfoView *self,
+ int size)
+{
+ Pango2Context *context;
+ Pango2FontDescription *desc;
+ Pango2Font *font;
+
+ context = pango2_context_new_with_font_map (self->font_map);
+ desc = pango2_font_description_copy_static (self->font_desc);
+ pango2_font_description_set_variations (desc, self->variations);
+ pango2_font_description_set_size (desc, size);
+ font = pango2_context_load_font (context, desc);
+ pango2_font_description_free (desc);
+ g_object_unref (context);
+
+ return font;
+}
+
+static GtkWidget *
+make_title_label (const char *title)
+{
+ GtkWidget *label;
+
+ label = gtk_label_new (title);
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+ gtk_widget_set_halign (label, GTK_ALIGN_START);
+ g_object_set (label, "margin-top", 10, "margin-bottom", 10, NULL);
+ gtk_widget_add_css_class (label, "heading");
+
+ return label;
+}
+
+static void
+add_misc_line (InfoView *self,
+ const char *title,
+ const char *value,
+ int row)
+{
+ GtkWidget *label;
+
+ label = gtk_label_new (title);
+ gtk_widget_set_halign (label, GTK_ALIGN_START);
+ gtk_widget_set_valign (label, GTK_ALIGN_START);
+ gtk_label_set_xalign (GTK_LABEL (label), 0);
+ gtk_widget_set_hexpand (label, TRUE);
+ gtk_grid_attach (self->info, label, 0, row, 1, 1);
+
+ label = gtk_label_new (value);
+ gtk_widget_set_halign (label, GTK_ALIGN_END);
+ gtk_widget_set_valign (label, GTK_ALIGN_START);
+ gtk_label_set_xalign (GTK_LABEL (label), 1);
+ gtk_label_set_wrap (GTK_LABEL (label), TRUE);
+ gtk_label_set_width_chars (GTK_LABEL (label), 40);
+ gtk_label_set_max_width_chars (GTK_LABEL (label), 40);
+ gtk_grid_attach (self->info, label, 1, row, 1, 1);
+}
+
+static void
+add_info_line (InfoView *self,
+ hb_face_t *face,
+ hb_ot_name_id_t name_id,
+ const char *title,
+ int row)
+{
+ char info[256];
+ unsigned int len = sizeof (info);
+
+ if (hb_ot_name_get_utf8 (face, name_id, HB_LANGUAGE_INVALID, &len, info) > 0)
+ add_misc_line (self, title, info, row);
+}
+
+static void
+add_metrics_line (InfoView *self,
+ hb_font_t *font,
+ hb_ot_metrics_tag_t metrics_tag,
+ const char *title,
+ int row)
+{
+ hb_position_t pos;
+
+ if (hb_ot_metrics_get_position (font, metrics_tag, &pos))
+ {
+ char buf[128];
+
+ g_snprintf (buf, sizeof (buf), "%d", pos);
+ add_misc_line (self, title, buf, row);
+ }
+}
+
+static void
+add_style_line (InfoView *self,
+ hb_font_t *font,
+ hb_style_tag_t style_tag,
+ const char *title,
+ int row)
+{
+ float value;
+ char buf[16];
+
+ value = hb_style_get_value (font, style_tag);
+ g_snprintf (buf, sizeof (buf), "%.2f", value);
+ add_misc_line (self, title, buf, row);
+}
+
+static void
+update_info (InfoView *self)
+{
+ GtkWidget *child;
+ int size = pango2_font_description_get_size (self->font_desc);
+ Pango2Font *pango_font = get_font (self, MAX (size, 10 * PANGO2_SCALE));
+ hb_font_t *font1 = pango2_font_get_hb_font (pango_font);
+ hb_face_t *face = hb_font_get_face (font1);
+ hb_font_t *font = hb_font_create_sub_font (font1);
+ int row = 0;
+ char buf[128];
+ unsigned int count;
+ GString *s;
+ hb_tag_t *tables;
+
+ hb_font_set_scale (font, hb_face_get_upem (face), hb_face_get_upem (face));
+
+ while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->info))) != NULL)
+ gtk_widget_unparent (child);
+
+ gtk_grid_attach (self->info, make_title_label ("General Info"), 0, row++, 2, 1);
+ add_info_line (self, face, HB_OT_NAME_ID_FONT_FAMILY, "Font Family Name", row++);
+ add_info_line (self, face, HB_OT_NAME_ID_FONT_SUBFAMILY, "Font Subfamily Name", row++);
+ add_info_line (self, face, HB_OT_NAME_ID_UNIQUE_ID, "Unique Font Identifier", row++);
+ add_info_line (self, face, HB_OT_NAME_ID_FULL_NAME, "Full Name", row++);
+ add_info_line (self, face, HB_OT_NAME_ID_VERSION_STRING, "Version", row++);
+ add_info_line (self, face, HB_OT_NAME_ID_POSTSCRIPT_NAME, "Postscript Name", row++);
+ add_info_line (self, face, HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY, "Typographic Family Name", row++);
+ add_info_line (self, face, HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY, "Typographic Subfamily Name", row++);
+ add_info_line (self, face, HB_OT_NAME_ID_MANUFACTURER, "Vendor ID", row++);
+ add_info_line (self, face, HB_OT_NAME_ID_DESIGNER, "Designer", row++);
+ add_info_line (self, face, HB_OT_NAME_ID_DESCRIPTION, "Description", row++);
+ add_info_line (self, face, HB_OT_NAME_ID_COPYRIGHT, "Copyright", row++);
+
+ gtk_grid_attach (self->info, make_title_label ("Metrics"), 0, row++, 2, 1);
+ g_snprintf (buf, sizeof (buf), "%d", hb_face_get_upem (face));
+ add_misc_line (self, "Units per Em", buf, row++);
+ add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, "Ascender", row++);
+ add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, "Descender", row++);
+ add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, "Line Gap", row++);
+ add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE, "Caret Rise", row++);
+ add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN, "Caret Run", row++);
+ add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET, "Caret Offset", row++);
+ add_metrics_line (self, font, HB_OT_METRICS_TAG_X_HEIGHT, "x Height", row++);
+ add_metrics_line (self, font, HB_OT_METRICS_TAG_CAP_HEIGHT, "Cap Height", row++);
+
+ add_metrics_line (self, font, HB_OT_METRICS_TAG_STRIKEOUT_SIZE, "Strikeout Size", row++);
+ add_metrics_line (self, font, HB_OT_METRICS_TAG_STRIKEOUT_OFFSET, "Strikeout Offset", row++);
+ add_metrics_line (self, font, HB_OT_METRICS_TAG_STRIKEOUT_SIZE, "Underline Size", row++);
+ add_metrics_line (self, font, HB_OT_METRICS_TAG_STRIKEOUT_OFFSET, "Underline Offset", row++);
+
+ gtk_grid_attach (self->info, make_title_label ("Style"), 0, row++, 2, 1);
+
+ add_style_line (self, font, HB_STYLE_TAG_ITALIC, "Italic", row++);
+ add_style_line (self, font, HB_STYLE_TAG_OPTICAL_SIZE, "Optical Size", row++);
+ add_style_line (self, font, HB_STYLE_TAG_SLANT_ANGLE, "Slant Angle", row++);
+ add_style_line (self, font, HB_STYLE_TAG_WIDTH, "Width", row++);
+ add_style_line (self, font, HB_STYLE_TAG_WEIGHT, "Weight", row++);
+
+ gtk_grid_attach (self->info, make_title_label ("Miscellaneous"), 0, row++, 2, 1);
+
+ count = hb_face_get_glyph_count (face);
+ g_snprintf (buf, sizeof (buf), "%d", count);
+ add_misc_line (self, "Glyph Count", buf, row++);
+
+ if (hb_ot_var_get_axis_count (face) > 0)
+ {
+ s = g_string_new ("");
+ hb_ot_var_axis_info_t *axes;
+
+ axes = g_newa (hb_ot_var_axis_info_t, hb_ot_var_get_axis_count (face));
+ count = hb_ot_var_get_axis_count (face);
+ hb_ot_var_get_axis_infos (face, 0, &count, axes);
+ for (int i = 0; i < count; i++)
+ {
+ char name[256];
+ unsigned int len;
+
+ len = sizeof (buf);
+ hb_ot_name_get_utf8 (face, axes[i].name_id, HB_LANGUAGE_INVALID, &len, name);
+ if (s->len > 0)
+ g_string_append (s, ", ");
+ g_string_append (s, name);
+ }
+ add_misc_line (self, "Axes", s->str, row++);
+ g_string_free (s, TRUE);
+ }
+
+ if (hb_ot_var_get_named_instance_count (face) > 0)
+ {
+ s = g_string_new ("");
+ for (int i = 0; i < hb_ot_var_get_named_instance_count (face); i++)
+ {
+ hb_ot_name_id_t name_id;
+ char name[256];
+ unsigned int len;
+
+ name_id = hb_ot_var_named_instance_get_subfamily_name_id (face, i);
+ len = sizeof (buf);
+ hb_ot_name_get_utf8 (face, name_id, HB_LANGUAGE_INVALID, &len, name);
+ if (s->len > 0)
+ g_string_append (s, ", ");
+ g_string_append (s, name);
+ }
+ add_misc_line (self, "Named Instances", s->str, row++);
+ g_string_free (s, TRUE);
+ }
+
+ s = g_string_new ("");
+ count = hb_face_get_table_tags (face, 0, NULL, NULL);
+ tables = g_newa (hb_tag_t, count);
+ hb_face_get_table_tags (face, 0, &count, tables);
+ for (int i = 0; i < count; i++)
+ {
+ memset (buf, 0, sizeof (buf));
+ hb_tag_to_string (tables[i], buf);
+ if (s->len > 0)
+ g_string_append (s, ", ");
+ g_string_append (s, buf);
+ }
+ add_misc_line (self, "Tables", s->str, row++);
+ g_string_free (s, TRUE);
+
+ s = g_string_new ("");
+ if (hb_ot_color_has_palettes (face))
+ g_string_append_printf (s, "%s", "Palettes");
+ if (hb_ot_color_has_layers (face))
+ g_string_append_printf (s, "%s%s", s->len > 0 ? ", " : "", "Layers");
+ if (hb_ot_color_has_svg (face))
+ g_string_append_printf (s, "%s%s", s->len > 0 ? ", " : "", "SVG");
+ if (hb_ot_color_has_png (face))
+ g_string_append_printf (s, "%s%s", s->len > 0 ? ", " : "", "PNG");
+ if (s->len > 0)
+ add_misc_line (self, "Color", s->str, row++);
+ g_string_free (s, TRUE);
+
+ hb_font_destroy (font);
+}
+
+static void
+info_view_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ InfoView *self = INFO_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_FONT_MAP:
+ g_set_object (&self->font_map, g_value_get_object (value));
+ break;
+
+ case PROP_FONT_DESC:
+ pango2_font_description_free (self->font_desc);
+ self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
+ break;
+
+ case PROP_SIZE:
+ self->size = g_value_get_float (value);
+ break;
+
+ case PROP_VARIATIONS:
+ g_free (self->variations);
+ self->variations = g_strdup (g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+
+ update_info (self);
+}
+
+static void
+info_view_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ InfoView *self = INFO_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_FONT_MAP:
+ g_value_set_object (value, self->font_map);
+ break;
+
+ case PROP_FONT_DESC:
+ g_value_set_boxed (value, self->font_desc);
+ break;
+
+ case PROP_SIZE:
+ g_value_set_float (value, self->size);
+ break;
+
+ case PROP_VARIATIONS:
+ g_value_set_string (value, self->variations);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+info_view_class_init (InfoViewClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->dispose = info_view_dispose;
+ object_class->finalize = info_view_finalize;
+ object_class->get_property = info_view_get_property;
+ object_class->set_property = info_view_set_property;
+
+ properties[PROP_FONT_MAP] =
+ g_param_spec_object ("font-map", "", "",
+ PANGO2_TYPE_FONT_MAP,
+ G_PARAM_READWRITE);
+
+ properties[PROP_FONT_DESC] =
+ g_param_spec_boxed ("font-desc", "", "",
+ PANGO2_TYPE_FONT_DESCRIPTION,
+ G_PARAM_READWRITE);
+
+ properties[PROP_SIZE] =
+ g_param_spec_float ("size", "", "",
+ 0., 100., 12.,
+ G_PARAM_READWRITE);
+
+ properties[PROP_VARIATIONS] =
+ g_param_spec_string ("variations", "", "",
+ "",
+ G_PARAM_READWRITE);
+
+ g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
+
+ gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
+ "/org/gtk/fontexplorer/infoview.ui");
+
+ gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), InfoView, info);
+
+ gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "infoview");
+}
diff --git a/demos/font-explorer/infoview.h b/demos/font-explorer/infoview.h
new file mode 100644
index 0000000000..f21142ef9f
--- /dev/null
+++ b/demos/font-explorer/infoview.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <gtk/gtk.h>
+
+
+#define INFO_VIEW_TYPE (info_view_get_type ())
+#define INFO_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INFO_VIEW_TYPE, InfoView))
+
+
+typedef struct _InfoView InfoView;
+typedef struct _InfoViewClass InfoViewClass;
+
+
+GType info_view_get_type (void);
diff --git a/demos/font-explorer/infoview.ui b/demos/font-explorer/infoview.ui
new file mode 100644
index 0000000000..ad34072dbe
--- /dev/null
+++ b/demos/font-explorer/infoview.ui
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="InfoView" parent="GtkWidget">
+ <style>
+ <class name="view"/>
+ </style>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="hscrollbar-policy">never</property>
+ <property name="vscrollbar-policy">automatic</property>
+ <property name="hexpand">1</property>
+ <property name="vexpand">1</property>
+ <child>
+ <object class="GtkGrid" id="info">
+ <style>
+ <class name="fontinfo"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/demos/font-explorer/meson.build b/demos/font-explorer/meson.build
index d552853990..d08eebac1e 100644
--- a/demos/font-explorer/meson.build
+++ b/demos/font-explorer/meson.build
@@ -1,18 +1,22 @@
fontexplorer_sources = [
- 'main.c',
+ 'fontcolors.c',
+ 'fontcontrols.c',
'fontexplorerapp.c',
'fontexplorerwin.c',
- 'fontcontrols.c',
- 'samplechooser.c',
- 'fontcolors.c',
'fontfeatures.c',
'fontvariations.c',
- 'fontview.c',
- 'rangeedit.c',
- 'language-names.c',
'glyphitem.c',
'glyphmodel.c',
+ 'glyphsview.c',
'glyphview.c',
+ 'infoview.c',
+ 'language-names.c',
+ 'main.c',
+ 'plainview.c',
+ 'rangeedit.c',
+ 'samplechooser.c',
+ 'sampleeditor.c',
+ 'waterfallview.c',
]
fontexplorer_resources = gnome.compile_resources('fontexplorer_resources',
diff --git a/demos/font-explorer/plainview.c b/demos/font-explorer/plainview.c
new file mode 100644
index 0000000000..1c5fe12b50
--- /dev/null
+++ b/demos/font-explorer/plainview.c
@@ -0,0 +1,342 @@
+#include "plainview.h"
+#include "glyphitem.h"
+#include "glyphmodel.h"
+#include "glyphview.h"
+#include <gtk/gtk.h>
+
+#include <hb-ot.h>
+
+enum {
+ PROP_FONT_MAP = 1,
+ PROP_FONT_DESC,
+ PROP_SIZE,
+ PROP_LETTERSPACING,
+ PROP_LINE_HEIGHT,
+ PROP_FOREGROUND,
+ PROP_BACKGROUND,
+ PROP_VARIATIONS,
+ PROP_FEATURES,
+ PROP_PALETTE,
+ PROP_SAMPLE_TEXT,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
+
+struct _PlainView
+{
+ GtkWidget parent;
+
+ GtkLabel *content;
+ GtkScrolledWindow *swin;
+
+ Pango2FontMap *font_map;
+ Pango2FontDescription *font_desc;
+ float size;
+ char *variations;
+ char *features;
+ char *palette;
+ GQuark palette_quark;
+ int letterspacing;
+ float line_height;
+ GdkRGBA foreground;
+ GdkRGBA background;
+ GtkCssProvider *bg_provider;
+ char *sample_text;
+};
+
+struct _PlainViewClass
+{
+ GtkWidgetClass parent_class;
+};
+
+G_DEFINE_TYPE(PlainView, plain_view, GTK_TYPE_WIDGET);
+
+static void
+plain_view_init (PlainView *self)
+{
+ self->font_map = g_object_ref (pango2_font_map_get_default ());
+ self->font_desc = pango2_font_description_from_string ("sans 12");
+ self->size = 12.;
+ self->letterspacing = 0;
+ self->line_height = 1.;
+ self->variations = g_strdup ("");
+ self->features = g_strdup ("");
+ self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
+ self->palette_quark = g_quark_from_string (self->palette);
+ self->foreground = (GdkRGBA){0., 0., 0., 1. };
+ self->background = (GdkRGBA){1., 1., 1., 1. };
+ self->sample_text = g_strdup ("Some sample text is better than other sample text");
+
+ gtk_widget_set_layout_manager (GTK_WIDGET (self),
+ gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ self->bg_provider = gtk_css_provider_new ();
+ gtk_style_context_add_provider (gtk_widget_get_style_context (GTK_WIDGET (self->content)),
+ GTK_STYLE_PROVIDER (self->bg_provider), 800);
+}
+
+static void
+plain_view_dispose (GObject *object)
+{
+ gtk_widget_clear_template (GTK_WIDGET (object), PLAIN_VIEW_TYPE);
+
+ G_OBJECT_CLASS (plain_view_parent_class)->dispose (object);
+}
+
+static void
+plain_view_finalize (GObject *object)
+{
+ PlainView *self = PLAIN_VIEW (object);
+
+ g_clear_object (&self->font_map);
+ pango2_font_description_free (self->font_desc);
+ g_free (self->variations);
+ g_free (self->features);
+ g_free (self->palette);
+
+ G_OBJECT_CLASS (plain_view_parent_class)->finalize (object);
+}
+
+static void
+update_view (PlainView *self)
+{
+ Pango2FontDescription *desc;
+ Pango2AttrList *attrs;
+ char *fg, *bg, *css;
+
+ desc = pango2_font_description_copy_static (self->font_desc);
+ pango2_font_description_set_size (desc, 12 * PANGO2_SCALE);
+ pango2_font_description_set_variations (desc, self->variations);
+
+ attrs = pango2_attr_list_new ();
+ pango2_attr_list_insert (attrs, pango2_attr_font_desc_new (desc));
+ pango2_attr_list_insert (attrs, pango2_attr_size_new (self->size * PANGO2_SCALE));
+ pango2_attr_list_insert (attrs, pango2_attr_letter_spacing_new (self->letterspacing));
+ pango2_attr_list_insert (attrs, pango2_attr_line_height_new (self->line_height));
+ pango2_attr_list_insert (attrs, pango2_attr_foreground_new (&(Pango2Color){65535 * self->foreground.red,
+ 65535 * self->foreground.green,
+ 65535 * self->foreground.blue,
+ 65535 *
self->foreground.alpha}));
+ pango2_attr_list_insert (attrs, pango2_attr_font_features_new (self->features));
+ pango2_attr_list_insert (attrs, pango2_attr_palette_new (self->palette));
+
+ pango2_font_description_free (desc);
+
+ gtk_label_set_label (self->content, self->sample_text);
+ gtk_label_set_attributes (self->content, attrs);
+
+ pango2_attr_list_unref (attrs);
+
+ fg = gdk_rgba_to_string (&self->foreground);
+ bg = gdk_rgba_to_string (&self->background);
+ css = g_strdup_printf (".view_background { caret-color: %s; background-color: %s; }", fg, bg);
+ gtk_css_provider_load_from_data (self->bg_provider, css, strlen (css));
+ g_free (css);
+ g_free (fg);
+ g_free (bg);
+}
+
+static void
+plain_view_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PlainView *self = PLAIN_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_FONT_MAP:
+ g_set_object (&self->font_map, g_value_get_object (value));
+ gtk_widget_set_font_map (GTK_WIDGET (self->content), self->font_map);
+ break;
+
+ case PROP_FONT_DESC:
+ pango2_font_description_free (self->font_desc);
+ self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
+ break;
+
+ case PROP_SIZE:
+ self->size = g_value_get_float (value);
+ break;
+
+ case PROP_LETTERSPACING:
+ self->letterspacing = g_value_get_int (value);
+ break;
+
+ case PROP_LINE_HEIGHT:
+ self->line_height = g_value_get_float (value);
+ break;
+
+ case PROP_FOREGROUND:
+ self->foreground = *(GdkRGBA *)g_value_get_boxed (value);
+ break;
+
+ case PROP_BACKGROUND:
+ self->background = *(GdkRGBA *)g_value_get_boxed (value);
+ break;
+
+ case PROP_VARIATIONS:
+ g_free (self->variations);
+ self->variations = g_strdup (g_value_get_string (value));
+ break;
+
+ case PROP_FEATURES:
+ g_free (self->features);
+ self->features = g_strdup (g_value_get_string (value));
+ break;
+
+ case PROP_PALETTE:
+ g_free (self->palette);
+ self->palette = g_strdup (g_value_get_string (value));
+ self->palette_quark = g_quark_from_string (self->palette);
+ break;
+
+ case PROP_SAMPLE_TEXT:
+ g_free (self->sample_text);
+ self->sample_text = g_strdup (g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+
+ update_view (self);
+}
+
+static void
+plain_view_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PlainView *self = PLAIN_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_FONT_MAP:
+ g_value_set_object (value, self->font_map);
+ break;
+
+ case PROP_FONT_DESC:
+ g_value_set_boxed (value, self->font_desc);
+ break;
+
+ case PROP_SIZE:
+ g_value_set_float (value, self->size);
+ break;
+
+ case PROP_LETTERSPACING:
+ g_value_set_int (value, self->letterspacing);
+ break;
+
+ case PROP_LINE_HEIGHT:
+ g_value_set_float (value, self->line_height);
+ break;
+
+ case PROP_FOREGROUND:
+ g_value_set_boxed (value, &self->foreground);
+ break;
+
+ case PROP_BACKGROUND:
+ g_value_set_boxed (value, &self->background);
+ break;
+
+ case PROP_VARIATIONS:
+ g_value_set_string (value, self->variations);
+ break;
+
+ case PROP_FEATURES:
+ g_value_set_string (value, self->features);
+ break;
+
+ case PROP_PALETTE:
+ g_value_set_string (value, self->palette);
+ break;
+
+ case PROP_SAMPLE_TEXT:
+ g_value_set_string (value, self->sample_text);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+plain_view_class_init (PlainViewClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->dispose = plain_view_dispose;
+ object_class->finalize = plain_view_finalize;
+ object_class->get_property = plain_view_get_property;
+ object_class->set_property = plain_view_set_property;
+
+ properties[PROP_FONT_MAP] =
+ g_param_spec_object ("font-map", "", "",
+ PANGO2_TYPE_FONT_MAP,
+ G_PARAM_READWRITE);
+
+ properties[PROP_FONT_DESC] =
+ g_param_spec_boxed ("font-desc", "", "",
+ PANGO2_TYPE_FONT_DESCRIPTION,
+ G_PARAM_READWRITE);
+
+ properties[PROP_SIZE] =
+ g_param_spec_float ("size", "", "",
+ 0., 100., 12.,
+ G_PARAM_READWRITE);
+
+ properties[PROP_LETTERSPACING] =
+ g_param_spec_int ("letterspacing", "", "",
+ -G_MAXINT, G_MAXINT, 0,
+ G_PARAM_READWRITE);
+
+ properties[PROP_LINE_HEIGHT] =
+ g_param_spec_float ("line-height", "", "",
+ 0., 100., 1.,
+ G_PARAM_READWRITE);
+
+ properties[PROP_FOREGROUND] =
+ g_param_spec_boxed ("foreground", "", "",
+ GDK_TYPE_RGBA,
+ G_PARAM_READWRITE);
+
+ properties[PROP_BACKGROUND] =
+ g_param_spec_boxed ("background", "", "",
+ GDK_TYPE_RGBA,
+ G_PARAM_READWRITE);
+
+ properties[PROP_VARIATIONS] =
+ g_param_spec_string ("variations", "", "",
+ "",
+ G_PARAM_READWRITE);
+
+ properties[PROP_FEATURES] =
+ g_param_spec_string ("features", "", "",
+ "",
+ G_PARAM_READWRITE);
+
+ properties[PROP_PALETTE] =
+ g_param_spec_string ("palette", "", "",
+ PANGO2_COLOR_PALETTE_DEFAULT,
+ G_PARAM_READWRITE);
+
+ properties[PROP_SAMPLE_TEXT] =
+ g_param_spec_string ("sample-text", "", "",
+ "",
+ G_PARAM_READWRITE);
+
+ g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
+
+ gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
+ "/org/gtk/fontexplorer/plainview.ui");
+
+ gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), PlainView, swin);
+ gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), PlainView, content);
+
+ gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "plainview");
+}
diff --git a/demos/font-explorer/plainview.h b/demos/font-explorer/plainview.h
new file mode 100644
index 0000000000..8996efe0e9
--- /dev/null
+++ b/demos/font-explorer/plainview.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <gtk/gtk.h>
+
+
+#define PLAIN_VIEW_TYPE (plain_view_get_type ())
+#define PLAIN_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLAIN_VIEW_TYPE, PlainView))
+
+
+typedef struct _PlainView PlainView;
+typedef struct _PlainViewClass PlainViewClass;
+
+
+GType plain_view_get_type (void);
diff --git a/demos/font-explorer/plainview.ui b/demos/font-explorer/plainview.ui
new file mode 100644
index 0000000000..462ffe3882
--- /dev/null
+++ b/demos/font-explorer/plainview.ui
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="PlainView" parent="GtkWidget">
+ <property name="hexpand">1</property>
+ <property name="vexpand">1</property>
+ <style>
+ <class name="view"/>
+ </style>
+ <child>
+ <object class="GtkScrolledWindow" id="swin">
+ <property name="hscrollbar-policy">never</property>
+ <property name="vscrollbar-policy">automatic</property>
+ <child>
+ <object class="GtkLabel" id="content">
+ <property name="label">Content</property>
+ <property name="wrap">1</property>
+ <property name="wrap-mode">word-char</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="hexpand">1</property>
+ <property name="vexpand">1</property>
+ <property name="halign">fill</property>
+ <property name="valign">fill</property>
+ <style>
+ <class name="view_background"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/demos/font-explorer/sampleeditor.c b/demos/font-explorer/sampleeditor.c
new file mode 100644
index 0000000000..8ec68e0a38
--- /dev/null
+++ b/demos/font-explorer/sampleeditor.c
@@ -0,0 +1,161 @@
+#include "sampleeditor.h"
+#include <gtk/gtk.h>
+
+enum {
+ PROP_SAMPLE_TEXT = 1,
+ PROP_EDITING,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
+
+struct _SampleEditor
+{
+ GtkWidget parent;
+
+ GtkTextView *edit;
+ char *sample_text;
+ gboolean editing;
+};
+
+struct _SampleEditorClass
+{
+ GtkWidgetClass parent_class;
+};
+
+G_DEFINE_TYPE(SampleEditor, sample_editor, GTK_TYPE_WIDGET);
+
+static void
+sample_editor_init (SampleEditor *self)
+{
+ self->sample_text = g_strdup ("Some sample text is better than other sample text");
+ self->editing = FALSE;
+
+ gtk_widget_set_layout_manager (GTK_WIDGET (self),
+ gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
+ gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+static void
+sample_editor_dispose (GObject *object)
+{
+ gtk_widget_clear_template (GTK_WIDGET (object), SAMPLE_EDITOR_TYPE);
+
+ G_OBJECT_CLASS (sample_editor_parent_class)->dispose (object);
+}
+
+static void
+sample_editor_finalize (GObject *object)
+{
+ SampleEditor *self = SAMPLE_EDITOR (object);
+
+ g_free (self->sample_text);
+
+ G_OBJECT_CLASS (sample_editor_parent_class)->finalize (object);
+}
+
+static void
+update_editing (SampleEditor *self,
+ gboolean editing)
+{
+ GtkTextBuffer *buffer;
+
+ if (self->editing == editing)
+ return;
+
+ self->editing = editing;
+
+ buffer = gtk_text_view_get_buffer (self->edit);
+
+ if (self->editing)
+ {
+ gtk_text_buffer_set_text (buffer, self->sample_text, -1);
+ gtk_widget_grab_focus (GTK_WIDGET (self->edit));
+ }
+ else
+ {
+ GtkTextIter start, end;
+
+ g_free (self->sample_text);
+ gtk_text_buffer_get_bounds (buffer, &start, &end);
+ self->sample_text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SAMPLE_TEXT]);
+ }
+}
+
+static void
+sample_editor_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ SampleEditor *self = SAMPLE_EDITOR (object);
+
+ switch (prop_id)
+ {
+ case PROP_SAMPLE_TEXT:
+ g_free (self->sample_text);
+ self->sample_text = g_strdup (g_value_get_string (value));
+ break;
+
+ case PROP_EDITING:
+ update_editing (self, g_value_get_boolean (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+sample_editor_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ SampleEditor *self = SAMPLE_EDITOR (object);
+
+ switch (prop_id)
+ {
+ case PROP_SAMPLE_TEXT:
+ g_value_set_string (value, self->sample_text);
+ break;
+
+ case PROP_EDITING:
+ g_value_set_boolean (value, self->editing);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+sample_editor_class_init (SampleEditorClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->dispose = sample_editor_dispose;
+ object_class->finalize = sample_editor_finalize;
+ object_class->get_property = sample_editor_get_property;
+ object_class->set_property = sample_editor_set_property;
+
+ properties[PROP_SAMPLE_TEXT] =
+ g_param_spec_string ("sample-text", "", "",
+ "",
+ G_PARAM_READWRITE);
+
+ properties[PROP_EDITING] =
+ g_param_spec_boolean ("editing", "", "",
+ FALSE,
+ G_PARAM_READWRITE);
+
+ g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
+
+ gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
+ "/org/gtk/fontexplorer/sampleeditor.ui");
+
+ gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), SampleEditor, edit);
+
+ gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "sampleeditor");
+}
diff --git a/demos/font-explorer/sampleeditor.h b/demos/font-explorer/sampleeditor.h
new file mode 100644
index 0000000000..3779b78cff
--- /dev/null
+++ b/demos/font-explorer/sampleeditor.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <gtk/gtk.h>
+
+
+#define SAMPLE_EDITOR_TYPE (sample_editor_get_type ())
+#define SAMPLE_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SAMPLE_EDITOR_TYPE, SampleEditor))
+
+
+typedef struct _SampleEditor SampleEditor;
+typedef struct _SampleEditorClass SampleEditorClass;
+
+
+GType sample_editor_get_type (void);
diff --git a/demos/font-explorer/sampleeditor.ui b/demos/font-explorer/sampleeditor.ui
new file mode 100644
index 0000000000..77d1f71f91
--- /dev/null
+++ b/demos/font-explorer/sampleeditor.ui
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="SampleEditor" parent="GtkWidget">
+ <style>
+ <class name="view"/>
+ </style>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="hscrollbar-policy">never</property>
+ <property name="vscrollbar-policy">automatic</property>
+ <property name="hexpand">1</property>
+ <property name="vexpand">1</property>
+ <child>
+ <object class="GtkTextView" id="edit">
+ <property name="wrap-mode">word-char</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/demos/font-explorer/waterfallview.c b/demos/font-explorer/waterfallview.c
new file mode 100644
index 0000000000..0689a63cdc
--- /dev/null
+++ b/demos/font-explorer/waterfallview.c
@@ -0,0 +1,362 @@
+#include "waterfallview.h"
+#include "glyphitem.h"
+#include "glyphmodel.h"
+#include "glyphview.h"
+#include <gtk/gtk.h>
+
+#include <hb-ot.h>
+
+enum {
+ PROP_FONT_MAP = 1,
+ PROP_FONT_DESC,
+ PROP_SIZE,
+ PROP_LETTERSPACING,
+ PROP_LINE_HEIGHT,
+ PROP_FOREGROUND,
+ PROP_BACKGROUND,
+ PROP_VARIATIONS,
+ PROP_FEATURES,
+ PROP_PALETTE,
+ PROP_SAMPLE_TEXT,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
+
+struct _WaterfallView
+{
+ GtkWidget parent;
+
+ GtkLabel *content;
+ GtkScrolledWindow *swin;
+
+ Pango2FontMap *font_map;
+ Pango2FontDescription *font_desc;
+ float size;
+ char *variations;
+ char *features;
+ char *palette;
+ GQuark palette_quark;
+ int letterspacing;
+ float line_height;
+ GdkRGBA foreground;
+ GdkRGBA background;
+ GtkCssProvider *bg_provider;
+ char *sample_text;
+};
+
+struct _WaterfallViewClass
+{
+ GtkWidgetClass parent_class;
+};
+
+G_DEFINE_TYPE(WaterfallView, waterfall_view, GTK_TYPE_WIDGET);
+
+static void
+waterfall_view_init (WaterfallView *self)
+{
+ self->font_map = g_object_ref (pango2_font_map_get_default ());
+ self->font_desc = pango2_font_description_from_string ("sans 12");
+ self->size = 12.;
+ self->letterspacing = 0;
+ self->line_height = 1.;
+ self->variations = g_strdup ("");
+ self->features = g_strdup ("");
+ self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
+ self->palette_quark = g_quark_from_string (self->palette);
+ self->foreground = (GdkRGBA){0., 0., 0., 1. };
+ self->background = (GdkRGBA){1., 1., 1., 1. };
+ self->sample_text = g_strdup ("Some sample text is better than other sample text");
+
+ gtk_widget_set_layout_manager (GTK_WIDGET (self),
+ gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ self->bg_provider = gtk_css_provider_new ();
+ gtk_style_context_add_provider (gtk_widget_get_style_context (GTK_WIDGET (self->content)),
+ GTK_STYLE_PROVIDER (self->bg_provider), 800);
+}
+
+static void
+waterfall_view_dispose (GObject *object)
+{
+ gtk_widget_clear_template (GTK_WIDGET (object), WATERFALL_VIEW_TYPE);
+
+ G_OBJECT_CLASS (waterfall_view_parent_class)->dispose (object);
+}
+
+static void
+waterfall_view_finalize (GObject *object)
+{
+ WaterfallView *self = WATERFALL_VIEW (object);
+
+ g_clear_object (&self->font_map);
+ pango2_font_description_free (self->font_desc);
+ g_free (self->variations);
+ g_free (self->features);
+ g_free (self->palette);
+
+ G_OBJECT_CLASS (waterfall_view_parent_class)->finalize (object);
+}
+
+static void
+update_view (WaterfallView *self)
+{
+ Pango2FontDescription *desc;
+ Pango2AttrList *attrs;
+ char *fg, *bg, *css;
+ GString *str;
+ int sizes[] = { 7, 8, 9, 10, 12, 14, 16, 20, 24, 30, 40, 50, 60, 70, 90 };
+ int start, end, text_len;
+
+ desc = pango2_font_description_copy_static (self->font_desc);
+ pango2_font_description_set_size (desc, 12 * PANGO2_SCALE);
+ pango2_font_description_set_variations (desc, self->variations);
+
+ attrs = pango2_attr_list_new ();
+ pango2_attr_list_insert (attrs, pango2_attr_font_desc_new (desc));
+ pango2_attr_list_insert (attrs, pango2_attr_size_new (self->size * PANGO2_SCALE));
+ pango2_attr_list_insert (attrs, pango2_attr_letter_spacing_new (self->letterspacing));
+ pango2_attr_list_insert (attrs, pango2_attr_line_height_new (self->line_height));
+ pango2_attr_list_insert (attrs, pango2_attr_foreground_new (&(Pango2Color){65535 * self->foreground.red,
+ 65535 * self->foreground.green,
+ 65535 * self->foreground.blue,
+ 65535 *
self->foreground.alpha}));
+ pango2_attr_list_insert (attrs, pango2_attr_font_features_new (self->features));
+ pango2_attr_list_insert (attrs, pango2_attr_palette_new (self->palette));
+
+ pango2_font_description_free (desc);
+
+ str = g_string_new ("");
+ start = 0;
+ text_len = strlen (self->sample_text);
+ for (int i = 0; i < G_N_ELEMENTS (sizes); i++)
+ {
+ Pango2Attribute *attr;
+
+ g_string_append (str, self->sample_text);
+ g_string_append (str, "
"); /* Unicode line separator */
+ end = start + text_len + strlen ("
");
+
+ attr = pango2_attr_size_new (sizes[i] * PANGO2_SCALE);
+ pango2_attribute_set_range (attr, start, end);
+ pango2_attr_list_insert (attrs, attr);
+ start = end;
+ }
+ gtk_label_set_text (self->content, str->str);
+ gtk_label_set_attributes (self->content, attrs);
+ g_string_free (str, TRUE);
+
+ pango2_attr_list_unref (attrs);
+
+ fg = gdk_rgba_to_string (&self->foreground);
+ bg = gdk_rgba_to_string (&self->background);
+ css = g_strdup_printf (".view_background { caret-color: %s; background-color: %s; }", fg, bg);
+ gtk_css_provider_load_from_data (self->bg_provider, css, strlen (css));
+ g_free (css);
+ g_free (fg);
+ g_free (bg);
+}
+
+static void
+waterfall_view_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ WaterfallView *self = WATERFALL_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_FONT_MAP:
+ g_set_object (&self->font_map, g_value_get_object (value));
+ gtk_widget_set_font_map (GTK_WIDGET (self->content), self->font_map);
+ break;
+
+ case PROP_FONT_DESC:
+ pango2_font_description_free (self->font_desc);
+ self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
+ break;
+
+ case PROP_SIZE:
+ self->size = g_value_get_float (value);
+ break;
+
+ case PROP_LETTERSPACING:
+ self->letterspacing = g_value_get_int (value);
+ break;
+
+ case PROP_LINE_HEIGHT:
+ self->line_height = g_value_get_float (value);
+ break;
+
+ case PROP_FOREGROUND:
+ self->foreground = *(GdkRGBA *)g_value_get_boxed (value);
+ break;
+
+ case PROP_BACKGROUND:
+ self->background = *(GdkRGBA *)g_value_get_boxed (value);
+ break;
+
+ case PROP_VARIATIONS:
+ g_free (self->variations);
+ self->variations = g_strdup (g_value_get_string (value));
+ break;
+
+ case PROP_FEATURES:
+ g_free (self->features);
+ self->features = g_strdup (g_value_get_string (value));
+ break;
+
+ case PROP_PALETTE:
+ g_free (self->palette);
+ self->palette = g_strdup (g_value_get_string (value));
+ self->palette_quark = g_quark_from_string (self->palette);
+ break;
+
+ case PROP_SAMPLE_TEXT:
+ g_free (self->sample_text);
+ self->sample_text = g_strdup (g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+
+ update_view (self);
+}
+
+static void
+waterfall_view_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ WaterfallView *self = WATERFALL_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_FONT_MAP:
+ g_value_set_object (value, self->font_map);
+ break;
+
+ case PROP_FONT_DESC:
+ g_value_set_boxed (value, self->font_desc);
+ break;
+
+ case PROP_SIZE:
+ g_value_set_float (value, self->size);
+ break;
+
+ case PROP_LETTERSPACING:
+ g_value_set_int (value, self->letterspacing);
+ break;
+
+ case PROP_LINE_HEIGHT:
+ g_value_set_float (value, self->line_height);
+ break;
+
+ case PROP_FOREGROUND:
+ g_value_set_boxed (value, &self->foreground);
+ break;
+
+ case PROP_BACKGROUND:
+ g_value_set_boxed (value, &self->background);
+ break;
+
+ case PROP_VARIATIONS:
+ g_value_set_string (value, self->variations);
+ break;
+
+ case PROP_FEATURES:
+ g_value_set_string (value, self->features);
+ break;
+
+ case PROP_PALETTE:
+ g_value_set_string (value, self->palette);
+ break;
+
+ case PROP_SAMPLE_TEXT:
+ g_value_set_string (value, self->sample_text);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+waterfall_view_class_init (WaterfallViewClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->dispose = waterfall_view_dispose;
+ object_class->finalize = waterfall_view_finalize;
+ object_class->get_property = waterfall_view_get_property;
+ object_class->set_property = waterfall_view_set_property;
+
+ properties[PROP_FONT_MAP] =
+ g_param_spec_object ("font-map", "", "",
+ PANGO2_TYPE_FONT_MAP,
+ G_PARAM_READWRITE);
+
+ properties[PROP_FONT_DESC] =
+ g_param_spec_boxed ("font-desc", "", "",
+ PANGO2_TYPE_FONT_DESCRIPTION,
+ G_PARAM_READWRITE);
+
+ properties[PROP_SIZE] =
+ g_param_spec_float ("size", "", "",
+ 0., 100., 12.,
+ G_PARAM_READWRITE);
+
+ properties[PROP_LETTERSPACING] =
+ g_param_spec_int ("letterspacing", "", "",
+ -G_MAXINT, G_MAXINT, 0,
+ G_PARAM_READWRITE);
+
+ properties[PROP_LINE_HEIGHT] =
+ g_param_spec_float ("line-height", "", "",
+ 0., 100., 1.,
+ G_PARAM_READWRITE);
+
+ properties[PROP_FOREGROUND] =
+ g_param_spec_boxed ("foreground", "", "",
+ GDK_TYPE_RGBA,
+ G_PARAM_READWRITE);
+
+ properties[PROP_BACKGROUND] =
+ g_param_spec_boxed ("background", "", "",
+ GDK_TYPE_RGBA,
+ G_PARAM_READWRITE);
+
+ properties[PROP_VARIATIONS] =
+ g_param_spec_string ("variations", "", "",
+ "",
+ G_PARAM_READWRITE);
+
+ properties[PROP_FEATURES] =
+ g_param_spec_string ("features", "", "",
+ "",
+ G_PARAM_READWRITE);
+
+ properties[PROP_PALETTE] =
+ g_param_spec_string ("palette", "", "",
+ PANGO2_COLOR_PALETTE_DEFAULT,
+ G_PARAM_READWRITE);
+
+ properties[PROP_SAMPLE_TEXT] =
+ g_param_spec_string ("sample-text", "", "",
+ "",
+ G_PARAM_READWRITE);
+
+ g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
+
+ gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
+ "/org/gtk/fontexplorer/waterfallview.ui");
+
+ gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), WaterfallView, swin);
+ gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), WaterfallView, content);
+
+ gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "waterfallview");
+}
diff --git a/demos/font-explorer/waterfallview.h b/demos/font-explorer/waterfallview.h
new file mode 100644
index 0000000000..98208178ae
--- /dev/null
+++ b/demos/font-explorer/waterfallview.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <gtk/gtk.h>
+
+
+#define WATERFALL_VIEW_TYPE (waterfall_view_get_type ())
+#define WATERFALL_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), WATERFALL_VIEW_TYPE, WaterfallView))
+
+
+typedef struct _WaterfallView WaterfallView;
+typedef struct _WaterfallViewClass WaterfallViewClass;
+
+
+GType waterfall_view_get_type (void);
diff --git a/demos/font-explorer/waterfallview.ui b/demos/font-explorer/waterfallview.ui
new file mode 100644
index 0000000000..d70c97dddf
--- /dev/null
+++ b/demos/font-explorer/waterfallview.ui
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="WaterfallView" parent="GtkWidget">
+ <property name="hexpand">1</property>
+ <property name="vexpand">1</property>
+ <style>
+ <class name="view"/>
+ </style>
+ <child>
+ <object class="GtkScrolledWindow" id="swin">
+ <property name="hscrollbar-policy">automatic</property>
+ <property name="vscrollbar-policy">automatic</property>
+ <child>
+ <object class="GtkLabel" id="content">
+ <property name="label">Content</property>
+ <property name="wrap">0</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="hexpand">1</property>
+ <property name="vexpand">1</property>
+ <property name="halign">fill</property>
+ <property name="valign">fill</property>
+ <style>
+ <class name="view_background"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]