[gtk/pango2: 88/91] fontchooser: Add palette support




commit 7eb6543858a78d4d9229a6bc5063bb124781fd98
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Jul 3 12:54:15 2022 -0400

    fontchooser: Add palette support
    
    For fonts that have color palettes, optionally
    allow the user to select one.

 gtk/gtkfontbutton.c            | 264 ++++-------------------------------------
 gtk/gtkfontchooser.c           |  31 +++++
 gtk/gtkfontchooser.h           |   6 +-
 gtk/gtkfontchooserdialog.c     |   4 +-
 gtk/gtkfontchooserutils.c      |   3 +
 gtk/gtkfontchooserutils.h      |   1 +
 gtk/gtkfontchooserwidget.c     | 208 ++++++++++++++++++++++++++++----
 gtk/ui/gtkfontchooserwidget.ui |   6 +
 tests/testfontchooserdialog.c  |   5 +
 9 files changed, 262 insertions(+), 266 deletions(-)
---
diff --git a/gtk/gtkfontbutton.c b/gtk/gtkfontbutton.c
index 135e7c9a02..6600c2e27c 100644
--- a/gtk/gtkfontbutton.c
+++ b/gtk/gtkfontbutton.c
@@ -96,13 +96,13 @@ struct _GtkFontButton
   Pango2FontFamily      *font_family;
   Pango2FontFace        *font_face;
   Pango2FontMap         *font_map;
-  char                 *font_features;
+  char                  *font_features;
+  char                  *palette;
   Pango2Language        *language;
   char                 *preview_text;
   GtkFontFilterFunc     font_filter;
   gpointer              font_filter_data;
   GDestroyNotify        font_filter_data_destroy;
-  GtkCssProvider       *provider;
 };
 
 struct _GtkFontButtonClass
@@ -200,6 +200,7 @@ clear_font_data (GtkFontButton *font_button)
   g_clear_pointer (&font_button->font_desc, pango2_font_description_free);
   g_clear_pointer (&font_button->fontname, g_free);
   g_clear_pointer (&font_button->font_features, g_free);
+  g_clear_pointer (&font_button->palette, g_free);
 }
 
 static void
@@ -623,8 +624,6 @@ gtk_font_button_finalize (GObject *object)
 
   g_free (font_button->preview_text);
 
-  g_clear_object (&font_button->provider);
-
   gtk_widget_unparent (font_button->button);
 
   G_OBJECT_CLASS (gtk_font_button_parent_class)->finalize (object);
@@ -704,6 +703,9 @@ gtk_font_button_get_property (GObject    *object,
     case GTK_FONT_CHOOSER_PROP_FONT_FEATURES:
       g_value_set_string (value, font_button->font_features);
       break;
+    case GTK_FONT_CHOOSER_PROP_PALETTE:
+      g_value_set_string (value, font_button->palette);
+      break;
     case GTK_FONT_CHOOSER_PROP_LANGUAGE:
       g_value_set_string (value, pango2_language_to_string (font_button->language));
       break;
@@ -1044,6 +1046,8 @@ response_cb (GtkDialog *dialog,
   font_button->font_size = gtk_font_chooser_get_font_size (font_chooser);
   g_free (font_button->font_features);
   font_button->font_features = gtk_font_chooser_get_font_features (font_chooser);
+  g_free (font_button->palette);
+  font_button->palette = gtk_font_chooser_get_palette (font_chooser);
   font_button->language = pango2_language_from_string (gtk_font_chooser_get_language (font_chooser));
 
   /* Set label font */
@@ -1052,6 +1056,7 @@ response_cb (GtkDialog *dialog,
   g_object_notify (G_OBJECT (font_button), "font");
   g_object_notify (G_OBJECT (font_button), "font-desc");
   g_object_notify (G_OBJECT (font_button), "font-features");
+  g_object_notify (G_OBJECT (font_button), "palette");
 
   g_object_thaw_notify (object);
 
@@ -1069,260 +1074,35 @@ dialog_destroy (GtkWidget *widget,
   font_button->font_dialog = NULL;
 }
 
-static void
-add_css_variations (GString    *s,
-                    const char *variations)
-{
-  const char *p;
-  const char *sep = "";
-
-  if (variations == NULL || variations[0] == '\0')
-    {
-      g_string_append (s, "normal");
-      return;
-    }
-
-  p = variations;
-  while (p && *p)
-    {
-      const char *start;
-      const char *end, *end2;
-      double value;
-      char name[5];
-
-      while (g_ascii_isspace (*p)) p++;
-
-      start = p;
-      end = strchr (p, ',');
-      if (end && (end - p < 6))
-        goto skip;
-
-      name[0] = p[0];
-      name[1] = p[1];
-      name[2] = p[2];
-      name[3] = p[3];
-      name[4] = '\0';
-
-      p += 4;
-      while (g_ascii_isspace (*p)) p++;
-      if (*p == '=') p++;
-
-      if (p - start < 5)
-        goto skip;
-
-      value = g_ascii_strtod (p, (char **) &end2);
-
-      while (end2 && g_ascii_isspace (*end2)) end2++;
-
-      if (end2 && (*end2 != ',' && *end2 != '\0'))
-        goto skip;
-
-      g_string_append_printf (s, "%s\"%s\" %g", sep, name, value);
-      sep = ", ";
-
-skip:
-      p = end ? end + 1 : NULL;
-    }
-}
-
-static char *
-pango2_font_description_to_css (Pango2FontDescription *desc,
-                               const char           *features,
-                               const char           *language)
-{
-  GString *s;
-  Pango2FontMask set;
-
-  s = g_string_new ("* { ");
-
-  set = pango2_font_description_get_set_fields (desc);
-  if (set & PANGO2_FONT_MASK_FAMILY)
-    {
-      g_string_append (s, "font-family: \"");
-      g_string_append (s, pango2_font_description_get_family (desc));
-      g_string_append (s, "\"; ");
-    }
-  if (set & PANGO2_FONT_MASK_STYLE)
-    {
-      switch (pango2_font_description_get_style (desc))
-        {
-        case PANGO2_STYLE_NORMAL:
-          g_string_append (s, "font-style: normal; ");
-          break;
-        case PANGO2_STYLE_OBLIQUE:
-          g_string_append (s, "font-style: oblique; ");
-          break;
-        case PANGO2_STYLE_ITALIC:
-          g_string_append (s, "font-style: italic; ");
-          break;
-        default:
-          break;
-        }
-    }
-  if (set & PANGO2_FONT_MASK_VARIANT)
-    {
-      switch (pango2_font_description_get_variant (desc))
-        {
-        case PANGO2_VARIANT_NORMAL:
-          g_string_append (s, "font-variant: normal; ");
-          break;
-        case PANGO2_VARIANT_SMALL_CAPS:
-          g_string_append (s, "font-variant: small-caps; ");
-          break;
-        case PANGO2_VARIANT_ALL_SMALL_CAPS:
-          g_string_append (s, "font-variant: all-small-caps; ");
-          break;
-        case PANGO2_VARIANT_PETITE_CAPS:
-          g_string_append (s, "font-variant: petite-caps; ");
-          break;
-        case PANGO2_VARIANT_ALL_PETITE_CAPS:
-          g_string_append (s, "font-variant: all-petite-caps; ");
-          break;
-        case PANGO2_VARIANT_UNICASE:
-          g_string_append (s, "font-variant: unicase; ");
-          break;
-        case PANGO2_VARIANT_TITLE_CAPS:
-          g_string_append (s, "font-variant: titling-caps; ");
-          break;
-        default:
-          break;
-        }
-    }
-  if (set & PANGO2_FONT_MASK_WEIGHT)
-    {
-      switch (pango2_font_description_get_weight (desc))
-        {
-        case PANGO2_WEIGHT_THIN:
-          g_string_append (s, "font-weight: 100; ");
-          break;
-        case PANGO2_WEIGHT_ULTRALIGHT:
-          g_string_append (s, "font-weight: 200; ");
-          break;
-        case PANGO2_WEIGHT_LIGHT:
-        case PANGO2_WEIGHT_SEMILIGHT:
-          g_string_append (s, "font-weight: 300; ");
-          break;
-        case PANGO2_WEIGHT_BOOK:
-        case PANGO2_WEIGHT_NORMAL:
-          g_string_append (s, "font-weight: 400; ");
-          break;
-        case PANGO2_WEIGHT_MEDIUM:
-          g_string_append (s, "font-weight: 500; ");
-          break;
-        case PANGO2_WEIGHT_SEMIBOLD:
-          g_string_append (s, "font-weight: 600; ");
-          break;
-        case PANGO2_WEIGHT_BOLD:
-          g_string_append (s, "font-weight: 700; ");
-          break;
-        case PANGO2_WEIGHT_ULTRABOLD:
-          g_string_append (s, "font-weight: 800; ");
-          break;
-        case PANGO2_WEIGHT_HEAVY:
-        case PANGO2_WEIGHT_ULTRAHEAVY:
-          g_string_append (s, "font-weight: 900; ");
-          break;
-        default:
-          break;
-        }
-    }
-  if (set & PANGO2_FONT_MASK_STRETCH)
-    {
-      switch (pango2_font_description_get_stretch (desc))
-        {
-        case PANGO2_STRETCH_ULTRA_CONDENSED:
-          g_string_append (s, "font-stretch: ultra-condensed; ");
-          break;
-        case PANGO2_STRETCH_EXTRA_CONDENSED:
-          g_string_append (s, "font-stretch: extra-condensed; ");
-          break;
-        case PANGO2_STRETCH_CONDENSED:
-          g_string_append (s, "font-stretch: condensed; ");
-          break;
-        case PANGO2_STRETCH_SEMI_CONDENSED:
-          g_string_append (s, "font-stretch: semi-condensed; ");
-          break;
-        case PANGO2_STRETCH_NORMAL:
-          g_string_append (s, "font-stretch: normal; ");
-          break;
-        case PANGO2_STRETCH_SEMI_EXPANDED:
-          g_string_append (s, "font-stretch: semi-expanded; ");
-          break;
-        case PANGO2_STRETCH_EXPANDED:
-          g_string_append (s, "font-stretch: expanded; ");
-          break;
-        case PANGO2_STRETCH_EXTRA_EXPANDED:
-          break;
-        case PANGO2_STRETCH_ULTRA_EXPANDED:
-          g_string_append (s, "font-stretch: ultra-expanded; ");
-          break;
-        default:
-          break;
-        }
-    }
-  if (set & PANGO2_FONT_MASK_SIZE)
-    {
-      g_string_append_printf (s, "font-size: %dpt; ", pango2_font_description_get_size (desc) / 
PANGO2_SCALE);
-    }
-
-  if (set & PANGO2_FONT_MASK_VARIATIONS)
-    {
-      const char *variations;
-
-      g_string_append (s, "font-variation-settings: ");
-      variations = pango2_font_description_get_variations (desc);
-      add_css_variations (s, variations);
-      g_string_append (s, "; ");
-    }
-  if (features)
-    {
-      g_string_append_printf (s, "font-feature-settings: %s;", features);
-    }
-
-  g_string_append (s, "}");
-
-  return g_string_free (s, FALSE);
-}
-
 static void
 gtk_font_button_label_use_font (GtkFontButton *font_button)
 {
-  GtkStyleContext *context;
-
-  context = gtk_widget_get_style_context (font_button->font_label);
-
   if (!font_button->use_font)
     {
-      if (font_button->provider)
-        {
-          gtk_style_context_remove_provider (context, GTK_STYLE_PROVIDER (font_button->provider));
-          g_clear_object (&font_button->provider);
-        }
+      gtk_label_set_attributes (GTK_LABEL (font_button->font_label), NULL);
     }
   else
     {
       Pango2FontDescription *desc;
-      char *data;
-
-      if (!font_button->provider)
-        {
-          font_button->provider = gtk_css_provider_new ();
-          gtk_style_context_add_provider (context,
-                                          GTK_STYLE_PROVIDER (font_button->provider),
-                                          GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
-        }
 
       desc = pango2_font_description_copy (font_button->font_desc);
 
       if (!font_button->use_size)
         pango2_font_description_unset_fields (desc, PANGO2_FONT_MASK_SIZE);
 
-      data = pango2_font_description_to_css (desc,
-                                            font_button->font_features,
-                                            pango2_language_to_string (font_button->language));
-      gtk_css_provider_load_from_data (font_button->provider, data, -1);
+      Pango2AttrList *attrs = pango2_attr_list_new ();
+
+      if ((font_button->level & GTK_FONT_CHOOSER_LEVEL_FEATURES) != 0 &&
+          font_button->font_features != NULL)
+        pango2_attr_list_insert (attrs, pango2_attr_font_features_new (font_button->font_features));
+
+      if ((font_button->level & GTK_FONT_CHOOSER_LEVEL_PALETTE) != 0 && font_button->palette != NULL)
+        pango2_attr_list_insert (attrs, pango2_attr_palette_new (font_button->palette));
+
+      pango2_attr_list_insert (attrs, pango2_attr_font_desc_new (desc));
+      gtk_label_set_attributes (GTK_LABEL (font_button->font_label), attrs);
+      pango2_attr_list_unref (attrs);
 
-      g_free (data);
       pango2_font_description_free (desc);
     }
 }
diff --git a/gtk/gtkfontchooser.c b/gtk/gtkfontchooser.c
index b569dfe9de..1ced14b7f3 100644
--- a/gtk/gtkfontchooser.c
+++ b/gtk/gtkfontchooser.c
@@ -123,6 +123,17 @@ gtk_font_chooser_default_init (GtkFontChooserInterface *iface)
                           "",
                           GTK_PARAM_READABLE));
 
+  /**
+   * GtkFontChooser:palette: (attributes org.gtk.Property.get=gtk_font_chooser_get_palette)
+   *
+   * The selected palette.
+   */
+  g_object_interface_install_property
+     (iface,
+      g_param_spec_string ("palette", NULL, NULL,
+                           "default",
+                           GTK_PARAM_READABLE));
+
   /**
    * GtkFontChooser:language: (attributes org.gtk.Property.get=gtk_font_chooser_get_language 
org.gtk.Property.set=gtk_font_chooser_set_language)
    *
@@ -538,6 +549,26 @@ gtk_font_chooser_get_font_features (GtkFontChooser *fontchooser)
   return text;
 }
 
+/**
+ * gtk_font_chooser_get_palette: (attributes org.gtk.Method.get_property=palette)
+ * @fontchooser: a `GtkFontChooser`
+ *
+ * Gets the currently-selected palette.
+ *
+ * Returns: the currently selected palette
+ */
+char *
+gtk_font_chooser_get_palette (GtkFontChooser *fontchooser)
+{
+  char *text;
+
+  g_return_val_if_fail (GTK_IS_FONT_CHOOSER (fontchooser), NULL);
+
+  g_object_get (fontchooser, "palette", &text, NULL);
+
+  return text;
+}
+
 /**
  * gtk_font_chooser_get_language: (attributes org.gtk.Method.get_property=language)
  * @fontchooser: a `GtkFontChooser`
diff --git a/gtk/gtkfontchooser.h b/gtk/gtkfontchooser.h
index 44027951a9..d61efed40b 100644
--- a/gtk/gtkfontchooser.h
+++ b/gtk/gtkfontchooser.h
@@ -53,6 +53,7 @@ typedef gboolean (*GtkFontFilterFunc) (const Pango2FontFamily *family,
  * @GTK_FONT_CHOOSER_LEVEL_SIZE: Allow selecting a specific font size
  * @GTK_FONT_CHOOSER_LEVEL_VARIATIONS: Allow changing OpenType font variation axes
  * @GTK_FONT_CHOOSER_LEVEL_FEATURES: Allow selecting specific OpenType font features
+ * @GTK_FONT_CHOOSER_LEVEL_PALETTE: Allow selecting a color palette
  *
  * Specifies the granularity of font selection
  * that is desired in a `GtkFontChooser`.
@@ -65,7 +66,8 @@ typedef enum {
   GTK_FONT_CHOOSER_LEVEL_STYLE      = 1 << 0,
   GTK_FONT_CHOOSER_LEVEL_SIZE       = 1 << 1,
   GTK_FONT_CHOOSER_LEVEL_VARIATIONS = 1 << 2,
-  GTK_FONT_CHOOSER_LEVEL_FEATURES   = 1 << 3
+  GTK_FONT_CHOOSER_LEVEL_FEATURES   = 1 << 3,
+  GTK_FONT_CHOOSER_LEVEL_PALETTE    = 1 << 4,
 } GtkFontChooserLevel;
 
 #define GTK_TYPE_FONT_CHOOSER                  (gtk_font_chooser_get_type ())
@@ -156,6 +158,8 @@ GtkFontChooserLevel
 GDK_AVAILABLE_IN_ALL
 char *           gtk_font_chooser_get_font_features        (GtkFontChooser   *fontchooser);
 GDK_AVAILABLE_IN_ALL
+char *           gtk_font_chooser_get_palette              (GtkFontChooser   *fontchooser);
+GDK_AVAILABLE_IN_ALL
 char *           gtk_font_chooser_get_language             (GtkFontChooser   *fontchooser);
 GDK_AVAILABLE_IN_ALL
 void             gtk_font_chooser_set_language             (GtkFontChooser   *fontchooser,
diff --git a/gtk/gtkfontchooserdialog.c b/gtk/gtkfontchooserdialog.c
index 014091159c..d6c6fa2fa7 100644
--- a/gtk/gtkfontchooserdialog.c
+++ b/gtk/gtkfontchooserdialog.c
@@ -150,7 +150,9 @@ update_tweak_button (GtkFontChooserDialog *dialog)
     return;
 
   g_object_get (dialog->fontchooser, "level", &level, NULL);
-  if ((level & (GTK_FONT_CHOOSER_LEVEL_FEATURES | GTK_FONT_CHOOSER_LEVEL_VARIATIONS)) != 0)
+  if ((level & (GTK_FONT_CHOOSER_LEVEL_FEATURES |
+                GTK_FONT_CHOOSER_LEVEL_VARIATIONS |
+                GTK_FONT_CHOOSER_LEVEL_PALETTE)) != 0)
     gtk_widget_show (dialog->tweak_button);
   else
     gtk_widget_hide (dialog->tweak_button);
diff --git a/gtk/gtkfontchooserutils.c b/gtk/gtkfontchooserutils.c
index 2d8cc19fae..6da6946810 100644
--- a/gtk/gtkfontchooserutils.c
+++ b/gtk/gtkfontchooserutils.c
@@ -141,6 +141,9 @@ _gtk_font_chooser_install_properties (GObjectClass *klass)
   g_object_class_override_property (klass,
                                     GTK_FONT_CHOOSER_PROP_FONT_FEATURES,
                                     "font-features");
+  g_object_class_override_property (klass,
+                                    GTK_FONT_CHOOSER_PROP_PALETTE,
+                                    "palette");
   g_object_class_override_property (klass,
                                     GTK_FONT_CHOOSER_PROP_LANGUAGE,
                                     "language");
diff --git a/gtk/gtkfontchooserutils.h b/gtk/gtkfontchooserutils.h
index ac7bf18558..7efb33e22e 100644
--- a/gtk/gtkfontchooserutils.h
+++ b/gtk/gtkfontchooserutils.h
@@ -39,6 +39,7 @@ typedef enum {
   GTK_FONT_CHOOSER_PROP_SHOW_PREVIEW_ENTRY,
   GTK_FONT_CHOOSER_PROP_LEVEL,
   GTK_FONT_CHOOSER_PROP_FONT_FEATURES,
+  GTK_FONT_CHOOSER_PROP_PALETTE,
   GTK_FONT_CHOOSER_PROP_LANGUAGE,
   GTK_FONT_CHOOSER_PROP_LAST
 } GtkFontChooserProp;
diff --git a/gtk/gtkfontchooserwidget.c b/gtk/gtkfontchooserwidget.c
index 3370272757..e54e70c2a3 100644
--- a/gtk/gtkfontchooserwidget.c
+++ b/gtk/gtkfontchooserwidget.c
@@ -62,6 +62,7 @@
 #include "gtklistview.h"
 #include "gtksortlistmodel.h"
 #include "gtkstringsorter.h"
+#include "gtkcolorswatchprivate.h"
 
 #include <hb-ot.h>
 
@@ -122,6 +123,7 @@ struct _GtkFontChooserWidget
 
   GtkWidget       *axis_grid;
   GtkWidget       *feature_box;
+  GtkWidget       *palette_grid;
 
   GtkFrame          *language_button;
   GtkFrame          *language_frame;
@@ -136,7 +138,8 @@ struct _GtkFontChooserWidget
   Pango2FontMap         *font_map;
 
   Pango2FontDescription *font_desc;
-  char                 *font_features;
+  char                  *font_features;
+  char                  *palette;
   Pango2Language        *language;
 
   GtkFontFilterFunc filter_func;
@@ -276,6 +279,9 @@ gtk_font_chooser_widget_get_property (GObject         *object,
     case GTK_FONT_CHOOSER_PROP_FONT_FEATURES:
       g_value_set_string (value, fontchooser->font_features);
       break;
+    case GTK_FONT_CHOOSER_PROP_PALETTE:
+      g_value_set_string (value, fontchooser->palette);
+      break;
     case GTK_FONT_CHOOSER_PROP_LANGUAGE:
       g_value_set_string (value, pango2_language_to_string (fontchooser->language));
       break;
@@ -718,6 +724,8 @@ gtk_font_chooser_widget_update_preview_attributes (GtkFontChooserWidget *fontcho
   pango2_attr_list_insert (attrs, pango2_attr_font_desc_new (fontchooser->font_desc));
   if (fontchooser->font_features)
     pango2_attr_list_insert (attrs, pango2_attr_font_features_new (fontchooser->font_features));
+  if (fontchooser->palette)
+    pango2_attr_list_insert (attrs, pango2_attr_palette_new (fontchooser->palette));
   if (fontchooser->language)
     pango2_attr_list_insert (attrs, pango2_attr_language_new (fontchooser->language));
 
@@ -884,6 +892,7 @@ gtk_font_chooser_widget_class_init (GtkFontChooserWidgetClass *klass)
   gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, grid);
   gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, font_name_label);
   gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, feature_box);
+  gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, palette_grid);
   gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, axis_grid);
   gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, language_button);
   gtk_widget_class_bind_template_child (widget_class, GtkFontChooserWidget, language_frame);
@@ -1285,6 +1294,7 @@ gtk_font_chooser_widget_finalize (GObject *object)
   g_hash_table_unref (fontchooser->axes);
 
   g_free (fontchooser->font_features);
+  g_free (fontchooser->palette);
 
   G_OBJECT_CLASS (gtk_font_chooser_widget_parent_class)->finalize (object);
 }
@@ -2069,18 +2079,11 @@ font_feature_toggled_cb (GtkCheckButton *check_button,
   update_font_features (fontchooser);
 }
 
-static void
-add_check_group (GtkFontChooserWidget *fontchooser,
-                 const char  *title,
-                 const char **tags)
+static GtkWidget *
+make_title_label (const char *title)
 {
   GtkWidget *label;
-  GtkWidget *group;
   Pango2AttrList *attrs;
-  int i;
-
-  group = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-  gtk_widget_set_halign (group, GTK_ALIGN_FILL);
 
   label = gtk_label_new (title);
   gtk_label_set_xalign (GTK_LABEL (label), 0.0);
@@ -2090,7 +2093,22 @@ add_check_group (GtkFontChooserWidget *fontchooser,
   pango2_attr_list_insert (attrs, pango2_attr_weight_new (PANGO2_WEIGHT_BOLD));
   gtk_label_set_attributes (GTK_LABEL (label), attrs);
   pango2_attr_list_unref (attrs);
-  gtk_box_append (GTK_BOX (group), label);
+
+  return label;
+}
+
+static void
+add_check_group (GtkFontChooserWidget *fontchooser,
+                 const char  *title,
+                 const char **tags)
+{
+  GtkWidget *group;
+  int i;
+
+  group = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+  gtk_widget_set_halign (group, GTK_ALIGN_FILL);
+
+  gtk_box_append (GTK_BOX (group), make_title_label (title));
 
   for (i = 0; tags[i]; i++)
     {
@@ -2144,24 +2162,14 @@ add_radio_group (GtkFontChooserWidget *fontchooser,
                  const char  *title,
                  const char **tags)
 {
-  GtkWidget *label;
   GtkWidget *group;
   int i;
   GtkWidget *group_button = NULL;
-  Pango2AttrList *attrs;
 
   group = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
   gtk_widget_set_halign (group, GTK_ALIGN_FILL);
 
-  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);
-  attrs = pango2_attr_list_new ();
-  pango2_attr_list_insert (attrs, pango2_attr_weight_new (PANGO2_WEIGHT_BOLD));
-  gtk_label_set_attributes (GTK_LABEL (label), attrs);
-  pango2_attr_list_unref (attrs);
-  gtk_box_append (GTK_BOX (group), label);
+  gtk_box_append (GTK_BOX (group), make_title_label (title));
 
   for (i = 0; tags[i]; i++)
     {
@@ -2386,6 +2394,160 @@ update_font_features (GtkFontChooserWidget *fontchooser)
   gtk_font_chooser_widget_update_preview_attributes (fontchooser);
 }
 
+static void
+palette_changed (GtkCheckButton *button,
+                 gpointer        data)
+{
+  GtkFontChooserWidget *fontchooser = data;
+  const char *palette;
+
+  palette = (const char *) g_object_get_data (G_OBJECT (button), "palette");
+
+  if (g_strcmp0 (fontchooser->palette, palette) != 0)
+    {
+      g_free (fontchooser->palette);
+      fontchooser->palette = g_strdup (palette);
+      g_object_notify (G_OBJECT (fontchooser), "palette");
+    }
+
+  gtk_font_chooser_widget_update_preview_attributes (fontchooser);
+}
+
+static gboolean
+gtk_font_chooser_widget_update_palettes (GtkFontChooserWidget *fontchooser)
+{
+  GtkWidget *child;
+  Pango2Font *font;
+  hb_font_t *hb_font;
+  hb_face_t *hb_face;
+
+  if ((fontchooser->level & GTK_FONT_CHOOSER_LEVEL_PALETTE) == 0)
+    return FALSE;
+
+  while ((child = gtk_widget_get_first_child (fontchooser->palette_grid)))
+    gtk_grid_remove (GTK_GRID (fontchooser->palette_grid), child);
+
+  font = pango2_context_load_font (gtk_widget_get_pango_context (GTK_WIDGET (fontchooser)),
+                                   fontchooser->font_desc);
+  hb_font = pango2_font_get_hb_font (font);
+  hb_face = hb_font_get_face (hb_font);
+
+  if (hb_ot_color_has_palettes (hb_face))
+    {
+      GtkWidget *first_palette = NULL;
+      GtkWidget *toggle;
+      char *palette_name;
+
+      gtk_grid_attach (GTK_GRID (fontchooser->palette_grid),
+                                 make_title_label (_("Color Palettes")),
+                                 0, -2, 3, 1);
+
+     toggle = gtk_check_button_new_with_label (_("Default"));
+     g_object_set_data (G_OBJECT (toggle), "palette", (gpointer) "default");
+     g_signal_connect (toggle, "toggled", G_CALLBACK (palette_changed), fontchooser);
+     if (fontchooser->palette == NULL ||
+         g_strcmp0 (fontchooser->palette, "default") == 0)
+       gtk_check_button_set_active (GTK_CHECK_BUTTON (toggle), TRUE);
+     gtk_grid_attach (GTK_GRID (fontchooser->palette_grid), toggle, 0, -1, 1, 1);
+     first_palette = toggle;
+
+     toggle = gtk_check_button_new_with_label (_("Light"));
+     g_object_set_data (G_OBJECT (toggle), "palette", (gpointer) "light");
+     g_signal_connect (toggle, "toggled", G_CALLBACK (palette_changed), fontchooser);
+     if (g_strcmp0 (fontchooser->palette, "light") == 0)
+       gtk_check_button_set_active (GTK_CHECK_BUTTON (toggle), TRUE);
+     gtk_check_button_set_group (GTK_CHECK_BUTTON (toggle), GTK_CHECK_BUTTON (first_palette));
+     gtk_grid_attach (GTK_GRID (fontchooser->palette_grid), toggle, 1, -1, 1, 1);
+
+     toggle = gtk_check_button_new_with_label (_("Dark"));
+     g_object_set_data (G_OBJECT (toggle), "palette", (gpointer) "dark");
+     g_signal_connect (toggle, "toggled", G_CALLBACK (palette_changed), fontchooser);
+     if (g_strcmp0 (fontchooser->palette, "dark") == 0)
+       gtk_check_button_set_active (GTK_CHECK_BUTTON (toggle), TRUE);
+     gtk_check_button_set_group (GTK_CHECK_BUTTON (toggle), GTK_CHECK_BUTTON (first_palette));
+     gtk_grid_attach (GTK_GRID (fontchooser->palette_grid), toggle, 2, -1, 1, 1);
+
+      for (unsigned int i = 0; i < hb_ot_color_palette_get_count (hb_face); i++)
+        {
+          hb_ot_name_id_t name_id;
+          char *name;
+          unsigned int n_colors;
+          hb_color_t *colors;
+          GtkWidget *palette;
+          GtkWidget *swatch;
+
+          name_id = hb_ot_color_palette_get_name_id (hb_face, i);
+          if (name_id != HB_OT_NAME_ID_INVALID)
+            {
+              unsigned int len;
+              char buf[80];
+
+              len = sizeof (buf);
+              hb_ot_name_get_utf8 (hb_face, name_id, HB_LANGUAGE_INVALID, &len, buf);
+              name = g_strdup (buf);
+            }
+          else
+            name = g_strdup_printf ("Palette %d", i);
+
+          toggle = gtk_check_button_new_with_label (name);
+
+          palette_name = g_strdup_printf ("palette%d", i);
+
+          if (g_strcmp0 (fontchooser->palette, palette_name) == 0)
+            gtk_check_button_set_active (GTK_CHECK_BUTTON (toggle), TRUE);
+
+          g_object_set_data_full (G_OBJECT (toggle), "palette", palette_name, g_free);
+          g_signal_connect (toggle, "toggled", G_CALLBACK (palette_changed), fontchooser);
+
+          gtk_check_button_set_group (GTK_CHECK_BUTTON (toggle), GTK_CHECK_BUTTON (first_palette));
+
+          g_free (name);
+
+          gtk_grid_attach (GTK_GRID (fontchooser->palette_grid), toggle, 0, i, 1, 1);
+
+#if 0
+          hb_ot_color_palette_flags_t flags;
+          const char *str;
+          flags = hb_ot_color_palette_get_flags (hb_face, i);
+          if ((flags & (HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND |
+                        HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND)) ==
+                        (HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND |
+                         HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND))
+            str = _("(light, dark)");
+          else if (flags & HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND)
+            str = _("(light)");
+          else if (flags & HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND)
+            str = _("(dark)");
+          else
+            str = NULL;
+          if (str)
+            gtk_grid_attach (GTK_GRID (fontchooser->palette_grid), gtk_label_new (str), 1, i, 1, 1);
+#endif
+
+          n_colors = hb_ot_color_palette_get_colors (hb_face, i, 0, NULL, NULL);
+          colors = g_new (hb_color_t, n_colors);
+          n_colors = hb_ot_color_palette_get_colors (hb_face, i, 0, &n_colors, colors);
+
+          palette = gtk_grid_new ();
+          gtk_grid_attach (GTK_GRID (fontchooser->palette_grid), palette, 2, i, 1, 1);
+
+          for (int k = 0; k < n_colors; k++)
+            {
+              swatch = gtk_color_swatch_new ();
+              gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (swatch),
+                                         &(GdkRGBA){ hb_color_get_red (colors[k])/255.,
+                                                     hb_color_get_green (colors[k])/255.,
+                                                     hb_color_get_blue (colors[k])/255.,
+                                                     hb_color_get_alpha (colors[k])/255.});
+              gtk_widget_set_size_request (swatch, 16, 16);
+              gtk_grid_attach (GTK_GRID (palette), swatch, k % 8, k / 8, 1, 1);
+            }
+        }
+    }
+
+  return TRUE;
+}
+
 static void
 gtk_font_chooser_widget_merge_font_desc (GtkFontChooserWidget       *fontchooser,
                                          const Pango2FontDescription *font_desc)
@@ -2424,6 +2586,8 @@ gtk_font_chooser_widget_merge_font_desc (GtkFontChooserWidget       *fontchooser
         has_tweak = TRUE;
       if (gtk_font_chooser_widget_update_font_variations (fontchooser))
         has_tweak = TRUE;
+      if (gtk_font_chooser_widget_update_palettes (fontchooser))
+        has_tweak = TRUE;
 
       g_simple_action_set_enabled (G_SIMPLE_ACTION (fontchooser->tweak_action), has_tweak);
     }
diff --git a/gtk/ui/gtkfontchooserwidget.ui b/gtk/ui/gtkfontchooserwidget.ui
index c7079a1201..1efa9cbb91 100644
--- a/gtk/ui/gtkfontchooserwidget.ui
+++ b/gtk/ui/gtkfontchooserwidget.ui
@@ -387,6 +387,12 @@
                             <property name="spacing">12</property>
                           </object>
                         </child>
+                        <child>
+                          <object class="GtkGrid" id="palette_grid">
+                            <property name="row-spacing">12</property>
+                            <property name="column-spacing">12</property>
+                          </object>
+                        </child>
                       </object>
                     </child>
                   </object>
diff --git a/tests/testfontchooserdialog.c b/tests/testfontchooserdialog.c
index 7a40d14df1..aa7d4929fe 100644
--- a/tests/testfontchooserdialog.c
+++ b/tests/testfontchooserdialog.c
@@ -134,6 +134,11 @@ main (int argc, char *argv[])
 #endif
 
   gtk_font_button_set_use_font (GTK_FONT_BUTTON (font_button), TRUE);
+  gtk_font_chooser_set_level (GTK_FONT_CHOOSER (font_button), GTK_FONT_CHOOSER_LEVEL_STYLE |
+                                                              GTK_FONT_CHOOSER_LEVEL_SIZE |
+                                                              GTK_FONT_CHOOSER_LEVEL_VARIATIONS |
+                                                              GTK_FONT_CHOOSER_LEVEL_PALETTE |
+                                                              GTK_FONT_CHOOSER_LEVEL_FEATURES);
 
   window = gtk_window_new ();
   box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);


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