[gnome-builder] plugins/editorui: create scheme selector widget



commit 2283bbc20338519df7ea356a863c02f042f6bf7f
Author: Christian Hergert <chergert redhat com>
Date:   Fri Aug 12 14:41:54 2022 -0700

    plugins/editorui: create scheme selector widget
    
    This has a lot of the color/sorting stuff from g-t-e copied over as well,
    which will eventually fix #1747 when the new IdeTweaks engine lands.

 src/plugins/editorui/editorui.gresource.xml        |   1 +
 .../editorui/gbp-editorui-scheme-selector.c        | 294 +++++++++++++++++++++
 .../editorui/gbp-editorui-scheme-selector.h        |  31 +++
 .../editorui/gbp-editorui-scheme-selector.ui       |  20 ++
 src/plugins/editorui/gbp-editorui-tweaks-addin.c   |  41 ++-
 src/plugins/editorui/meson.build                   |   1 +
 src/plugins/editorui/style.css                     |   3 +
 src/plugins/editorui/tweaks.ui                     |   5 +
 8 files changed, 382 insertions(+), 14 deletions(-)
---
diff --git a/src/plugins/editorui/editorui.gresource.xml b/src/plugins/editorui/editorui.gresource.xml
index d9f1fd160..990567891 100644
--- a/src/plugins/editorui/editorui.gresource.xml
+++ b/src/plugins/editorui/editorui.gresource.xml
@@ -6,6 +6,7 @@
     <file>gtk/keybindings.json</file>
     <file preprocess="xml-stripblanks">gtk/menus.ui</file>
     <file preprocess="xml-stripblanks">gbp-editorui-position-label.ui</file>
+    <file preprocess="xml-stripblanks">gbp-editorui-scheme-selector.ui</file>
     <file preprocess="xml-stripblanks">tweaks.ui</file>
   </gresource>
 </gresources>
diff --git a/src/plugins/editorui/gbp-editorui-scheme-selector.c 
b/src/plugins/editorui/gbp-editorui-scheme-selector.c
new file mode 100644
index 000000000..7f968117c
--- /dev/null
+++ b/src/plugins/editorui/gbp-editorui-scheme-selector.c
@@ -0,0 +1,294 @@
+/* gbp-editorui-scheme-selector.c
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-editorui-scheme-selector"
+
+#include "config.h"
+
+#include <libide-gui.h>
+#include <libide-sourceview.h>
+
+#include "gbp-editorui-scheme-selector.h"
+
+struct _GbpEditoruiSchemeSelector
+{
+  GtkWidget   parent_instance;
+
+  GtkFlowBox *flow_box;
+  GSettings  *settings;
+};
+
+enum {
+  PROP_0,
+  N_PROPS
+};
+
+G_DEFINE_FINAL_TYPE (GbpEditoruiSchemeSelector, gbp_editorui_scheme_selector, GTK_TYPE_WIDGET)
+
+static GParamSpec *properties [N_PROPS];
+
+typedef struct
+{
+  const char           *id;
+  const char           *sort_key;
+  GtkSourceStyleScheme *scheme;
+  guint                 has_alt : 1;
+  guint                 is_dark : 1;
+} SchemeInfo;
+
+static int
+sort_schemes_cb (gconstpointer a,
+                 gconstpointer b)
+{
+  const SchemeInfo *info_a = a;
+  const SchemeInfo *info_b = b;
+
+  /* Light schemes first */
+  if (!info_a->is_dark && info_b->is_dark)
+    return -1;
+  else if (info_a->is_dark && !info_b->is_dark)
+    return 1;
+
+  /* Items with variants first */
+  if (info_a->has_alt && !info_b->has_alt)
+    return -1;
+  else if (!info_a->has_alt && info_b->has_alt)
+    return 1;
+
+  return g_utf8_collate (info_a->sort_key, info_b->sort_key);
+}
+
+static void
+update_style_scheme_selection (GtkFlowBox *flow_box)
+{
+  const char *id;
+
+  g_assert (GTK_IS_FLOW_BOX (flow_box));
+
+  id = ide_application_get_style_scheme (IDE_APPLICATION_DEFAULT);
+
+  for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (flow_box));
+       child;
+       child = gtk_widget_get_next_sibling (child))
+    {
+      GtkFlowBoxChild *intermediate = GTK_FLOW_BOX_CHILD (child);
+      GtkSourceStyleSchemePreview *preview = GTK_SOURCE_STYLE_SCHEME_PREVIEW (gtk_flow_box_child_get_child 
(intermediate));
+      GtkSourceStyleScheme *scheme = gtk_source_style_scheme_preview_get_scheme (preview);
+      const char *scheme_id = gtk_source_style_scheme_get_id (scheme);
+      gboolean selected = g_strcmp0 (scheme_id, id) == 0;
+
+      gtk_source_style_scheme_preview_set_selected (preview, selected);
+    }
+}
+
+static void
+update_style_schemes (GtkFlowBox *flow_box)
+{
+  GtkSourceStyleSchemeManager *sm;
+  const char * const *scheme_ids;
+  g_autoptr(GArray) schemes = NULL;
+  const char *current_scheme;
+  gboolean is_dark;
+  guint j = 0;
+  GtkWidget *child;
+
+  g_assert (GTK_IS_FLOW_BOX (flow_box));
+
+  schemes = g_array_new (FALSE, FALSE, sizeof (SchemeInfo));
+  is_dark = adw_style_manager_get_dark (adw_style_manager_get_default ());
+  current_scheme = ide_application_get_style_scheme (IDE_APPLICATION_DEFAULT);
+
+  /* Populate schemes for preferences */
+  sm = gtk_source_style_scheme_manager_get_default ();
+  scheme_ids = gtk_source_style_scheme_manager_get_scheme_ids (sm);
+
+  for (guint i = 0; scheme_ids[i]; i++)
+    {
+      SchemeInfo info;
+
+      /* Ignore our printing scheme */
+      if (g_strcmp0 (scheme_ids[i], "printing") == 0)
+        continue;
+
+      info.scheme = gtk_source_style_scheme_manager_get_scheme (sm, scheme_ids[i]);
+      info.id = gtk_source_style_scheme_get_id (info.scheme);
+      info.sort_key = gtk_source_style_scheme_get_name (info.scheme);
+      info.has_alt = FALSE;
+      info.is_dark = FALSE;
+
+      if (ide_source_style_scheme_is_dark (info.scheme))
+        {
+          GtkSourceStyleScheme *alt = ide_source_style_scheme_get_variant (info.scheme, "light");
+
+          g_assert (GTK_SOURCE_IS_STYLE_SCHEME (alt));
+
+          if (alt != info.scheme)
+            {
+              info.sort_key = gtk_source_style_scheme_get_id (alt);
+              info.has_alt = TRUE;
+            }
+
+          info.is_dark = TRUE;
+        }
+      else
+        {
+          GtkSourceStyleScheme *alt = ide_source_style_scheme_get_variant (info.scheme, "dark");
+
+          g_assert (GTK_SOURCE_IS_STYLE_SCHEME (alt));
+
+          if (alt != info.scheme)
+            info.has_alt = TRUE;
+        }
+
+      g_array_append_val (schemes, info);
+    }
+
+  g_array_sort (schemes, sort_schemes_cb);
+
+  while ((child = gtk_widget_get_first_child (GTK_WIDGET (flow_box))))
+    gtk_flow_box_remove (flow_box, child);
+
+  for (guint i = 0; i < schemes->len; i++)
+    {
+      const SchemeInfo *info = &g_array_index (schemes, SchemeInfo, i);
+      GtkWidget *preview;
+
+      /* Ignore if not matching light/dark variant for app, unless it is
+       * the current scheme and it has no alternate.
+       */
+      if (is_dark != ide_source_style_scheme_is_dark (info->scheme) &&
+          (g_strcmp0 (info->id, current_scheme) != 0 || info->has_alt))
+        continue;
+
+      preview = gtk_source_style_scheme_preview_new (info->scheme);
+      gtk_actionable_set_action_name (GTK_ACTIONABLE (preview), "app.style-scheme-name");
+      gtk_actionable_set_action_target (GTK_ACTIONABLE (preview), "s", info->id);
+      gtk_flow_box_insert (flow_box, preview, -1);
+
+      j++;
+    }
+
+  update_style_scheme_selection (flow_box);
+}
+
+static void
+style_scheme_activated_cb (GbpEditoruiSchemeSelector *self,
+                           GtkFlowBoxChild           *child,
+                           GtkFlowBox                *flow_box)
+{
+  GtkWidget *preview;
+
+  g_assert (GBP_IS_EDITORUI_SCHEME_SELECTOR (self));
+  g_assert (GTK_IS_FLOW_BOX_CHILD (child));
+  g_assert (GTK_IS_FLOW_BOX (flow_box));
+
+  if ((preview = gtk_flow_box_child_get_child (child)))
+    gtk_widget_activate (preview);
+}
+
+static void
+gbp_editorui_scheme_selector_constructed (GObject *object)
+{
+  GbpEditoruiSchemeSelector *self = (GbpEditoruiSchemeSelector *)object;
+
+  G_OBJECT_CLASS (gbp_editorui_scheme_selector_parent_class)->constructed (object);
+
+  update_style_schemes (self->flow_box);
+}
+
+static void
+gbp_editorui_scheme_selector_dispose (GObject *object)
+{
+  GbpEditoruiSchemeSelector *self = (GbpEditoruiSchemeSelector *)object;
+
+  g_clear_pointer ((GtkWidget **)&self->flow_box, gtk_widget_unparent);
+
+  G_OBJECT_CLASS (gbp_editorui_scheme_selector_parent_class)->dispose (object);
+}
+
+static void
+gbp_editorui_scheme_selector_get_property (GObject    *object,
+                                           guint       prop_id,
+                                           GValue     *value,
+                                           GParamSpec *pspec)
+{
+  GbpEditoruiSchemeSelector *self = GBP_EDITORUI_SCHEME_SELECTOR (object);
+
+  switch (prop_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_editorui_scheme_selector_set_property (GObject      *object,
+                                           guint         prop_id,
+                                           const GValue *value,
+                                           GParamSpec   *pspec)
+{
+  GbpEditoruiSchemeSelector *self = GBP_EDITORUI_SCHEME_SELECTOR (object);
+
+  switch (prop_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_editorui_scheme_selector_class_init (GbpEditoruiSchemeSelectorClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->constructed = gbp_editorui_scheme_selector_constructed;
+  object_class->dispose = gbp_editorui_scheme_selector_dispose;
+  object_class->get_property = gbp_editorui_scheme_selector_get_property;
+  object_class->set_property = gbp_editorui_scheme_selector_set_property;
+
+  gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
+  gtk_widget_class_set_template_from_resource (widget_class, 
"/plugins/editorui/gbp-editorui-scheme-selector.ui");
+  gtk_widget_class_bind_template_child (widget_class, GbpEditoruiSchemeSelector, flow_box);
+  gtk_widget_class_bind_template_child (widget_class, GbpEditoruiSchemeSelector, settings);
+  gtk_widget_class_bind_template_callback (widget_class, style_scheme_activated_cb);
+  gtk_widget_class_bind_template_callback (widget_class, update_style_scheme_selection);
+}
+
+static void
+gbp_editorui_scheme_selector_init (GbpEditoruiSchemeSelector *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+  g_signal_connect_object (IDE_APPLICATION_DEFAULT,
+                           "notify::style-scheme",
+                           G_CALLBACK (update_style_scheme_selection),
+                           self->flow_box,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (adw_style_manager_get_default (),
+                           "notify::dark",
+                           G_CALLBACK (update_style_schemes),
+                           self->flow_box,
+                           G_CONNECT_SWAPPED);
+
+  /* Ensure we've queried style-scheme-name once */
+  g_variant_unref (g_settings_get_value (self->settings, "style-scheme-name"));
+}
diff --git a/src/plugins/editorui/gbp-editorui-scheme-selector.h 
b/src/plugins/editorui/gbp-editorui-scheme-selector.h
new file mode 100644
index 000000000..139536f4d
--- /dev/null
+++ b/src/plugins/editorui/gbp-editorui-scheme-selector.h
@@ -0,0 +1,31 @@
+/* gbp-editorui-scheme-selector.h
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_EDITORUI_SCHEME_SELECTOR (gbp_editorui_scheme_selector_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpEditoruiSchemeSelector, gbp_editorui_scheme_selector, GBP, 
EDITORUI_SCHEME_SELECTOR, GtkWidget)
+
+G_END_DECLS
diff --git a/src/plugins/editorui/gbp-editorui-scheme-selector.ui 
b/src/plugins/editorui/gbp-editorui-scheme-selector.ui
new file mode 100644
index 000000000..26011f795
--- /dev/null
+++ b/src/plugins/editorui/gbp-editorui-scheme-selector.ui
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GbpEditoruiSchemeSelector" parent="GtkWidget">
+    <child>
+      <object class="GtkFlowBox" id="flow_box">
+        <signal name="child-activated" handler="style_scheme_activated_cb" swapped="true" 
object="GbpEditoruiSchemeSelector"/>
+        <property name="hexpand">true</property>
+        <property name="column-spacing">8</property>
+        <property name="row-spacing">8</property>
+        <property name="max-children-per-line">4</property>
+        <property name="max-children-per-line">4</property>
+        <property name="selection-mode">none</property>
+      </object>
+    </child>
+  </template>
+  <object class="GSettings" id="settings">
+    <property name="schema-id">org.gnome.builder.editor</property>
+    <signal name="changed::style-scheme-name" handler="update_style_scheme_selection" object="flow_box" 
swapped="true"/>
+  </object>
+</interface>
diff --git a/src/plugins/editorui/gbp-editorui-tweaks-addin.c 
b/src/plugins/editorui/gbp-editorui-tweaks-addin.c
index 230b80773..b74cd3ea0 100644
--- a/src/plugins/editorui/gbp-editorui-tweaks-addin.c
+++ b/src/plugins/editorui/gbp-editorui-tweaks-addin.c
@@ -22,7 +22,10 @@
 
 #include "config.h"
 
+#include <libide-gui.h>
+
 #include "gbp-editorui-preview.h"
+#include "gbp-editorui-scheme-selector.h"
 #include "gbp-editorui-tweaks-addin.h"
 
 struct _GbpEditoruiTweaksAddin
@@ -32,27 +35,35 @@ struct _GbpEditoruiTweaksAddin
 
 G_DEFINE_FINAL_TYPE (GbpEditoruiTweaksAddin, gbp_editorui_tweaks_addin, IDE_TYPE_TWEAKS_ADDIN)
 
+static GtkWidget *
+editorui_create_style_scheme_preview (GbpEditoruiTweaksAddin *self,
+                                      IdeTweaksWidget        *widget)
+{
+  g_assert (GBP_IS_EDITORUI_TWEAKS_ADDIN (self));
+  g_assert (IDE_IS_TWEAKS_WIDGET (widget));
+
+  return g_object_new (GBP_TYPE_EDITORUI_PREVIEW,
+                       "bottom-margin", 8,
+                       "css-classes", IDE_STRV_INIT ("card"),
+                       "cursor-visible", FALSE,
+                       "left-margin", 12,
+                       "monospace", TRUE,
+                       "right-margin", 12,
+                       "right-margin-position", 30,
+                       "top-margin", 8,
+                       NULL);
+}
+
 static GtkWidget *
 editorui_create_style_scheme_selector (GbpEditoruiTweaksAddin *self,
                                        IdeTweaksWidget        *widget)
 {
-  GbpEditoruiPreview *preview;
-  GtkBox *box;
-
   g_assert (GBP_IS_EDITORUI_TWEAKS_ADDIN (self));
   g_assert (IDE_IS_TWEAKS_WIDGET (widget));
 
-  box = g_object_new (GTK_TYPE_BOX,
-                      "orientation", GTK_ORIENTATION_VERTICAL,
-                      "spacing", 12,
-                      "margin-bottom", 12,
-                      NULL);
-  preview = g_object_new (GBP_TYPE_EDITORUI_PREVIEW,
-                          "css-classes", IDE_STRV_INIT ("card"),
-                          NULL);
-  gtk_box_append (box, GTK_WIDGET (preview));
-
-  return GTK_WIDGET (box);
+  return g_object_new (GBP_TYPE_EDITORUI_SCHEME_SELECTOR,
+                       "margin-top", 18,
+                       NULL);
 }
 
 static void
@@ -65,6 +76,8 @@ gbp_editorui_tweaks_addin_init (GbpEditoruiTweaksAddin *self)
 {
   ide_tweaks_addin_set_resource_path (IDE_TWEAKS_ADDIN (self),
                                       "/plugins/editorui/tweaks.ui");
+  ide_tweaks_addin_bind_callback (IDE_TWEAKS_ADDIN (self),
+                                  editorui_create_style_scheme_preview);
   ide_tweaks_addin_bind_callback (IDE_TWEAKS_ADDIN (self),
                                   editorui_create_style_scheme_selector);
 }
diff --git a/src/plugins/editorui/meson.build b/src/plugins/editorui/meson.build
index 6444f5cb0..5c1888237 100644
--- a/src/plugins/editorui/meson.build
+++ b/src/plugins/editorui/meson.build
@@ -4,6 +4,7 @@ plugins_sources += files([
   'gbp-editorui-position-label.c',
   'gbp-editorui-preferences-addin.c',
   'gbp-editorui-preview.c',
+  'gbp-editorui-scheme-selector.c',
   'gbp-editorui-tweaks-addin.c',
   'gbp-editorui-workbench-addin.c',
   'gbp-editorui-workspace-addin.c',
diff --git a/src/plugins/editorui/style.css b/src/plugins/editorui/style.css
index 2bce7c332..b26fe22da 100644
--- a/src/plugins/editorui/style.css
+++ b/src/plugins/editorui/style.css
@@ -1,12 +1,15 @@
+.IdeTweaksWindow preferencesgroup flowbox.style-schemes flowboxchild,
 window.preferences preferencesgroup flowbox.style-schemes flowboxchild {
   outline-offset: 2px;
   border-radius: 12px;
   outline-width: 2px;
   padding: 0;
 }
+.IdeTweaksWindow preferencesgroup flowbox.style-schemes flowboxchild GtkSourceStyleSchemePreview,
 window.preferences preferencesgroup flowbox.style-schemes flowboxchild GtkSourceStyleSchemePreview {
   margin: 0;
 }
+.IdeTweaksWindow preferencesgroup flowbox.style-schemes flowboxchild 
GtkSourceStyleSchemePreview:not(.selected),
 window.preferences preferencesgroup flowbox.style-schemes flowboxchild 
GtkSourceStyleSchemePreview:not(.selected) {
   box-shadow: 0 0 0 1px alpha(black, 0.03),
               0 1px 3px 1px alpha(black, .07),
diff --git a/src/plugins/editorui/tweaks.ui b/src/plugins/editorui/tweaks.ui
index 46370bd80..c723feb76 100644
--- a/src/plugins/editorui/tweaks.ui
+++ b/src/plugins/editorui/tweaks.ui
@@ -8,6 +8,11 @@
             <child>
               <object class="IdeTweaksGroup" id="appearance_page_color_group">
                 <property name="title" translatable="yes">Color</property>
+                <child>
+                  <object class="IdeTweaksWidget" id="style_scheme_preview">
+                    <signal name="create" handler="editorui_create_style_scheme_preview" 
object="GbpEditoruiTweaksAddin" swapped="true"/>
+                  </object>
+                </child>
                 <child>
                   <object class="IdeTweaksWidget" id="style_scheme_selector">
                     <signal name="create" handler="editorui_create_style_scheme_selector" 
object="GbpEditoruiTweaksAddin" swapped="true"/>


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