[gnome-todo] Add a dark / light theme switcher
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-todo] Add a dark / light theme switcher
- Date: Fri, 2 Jul 2021 17:08:48 +0000 (UTC)
commit ba6d0315f2b0ce8fe4655f2e14f2bad4c602a791
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date: Fri Jul 2 14:07:19 2021 -0300
Add a dark / light theme switcher
https://gitlab.gnome.org/GNOME/gnome-todo/-/issues/397
data/org.gnome.todo.gschema.xml | 9 ++
src/gui/gtd-theme-selector.c | 214 +++++++++++++++++++++++++++++++++++
src/gui/gtd-theme-selector.h | 37 ++++++
src/gui/gtd-theme-selector.ui | 42 +++++++
src/gui/gtd-window.c | 6 +
src/gui/gui.gresource.xml | 1 +
src/gui/menus.ui | 6 +
src/meson.build | 1 +
src/themes/Adwaita-themeselector.css | 25 ++++
src/themes/Adwaita.css | 1 +
src/todo.gresource.xml | 1 +
11 files changed, 343 insertions(+)
---
diff --git a/data/org.gnome.todo.gschema.xml b/data/org.gnome.todo.gschema.xml
index 1daa7410..52119669 100644
--- a/data/org.gnome.todo.gschema.xml
+++ b/data/org.gnome.todo.gschema.xml
@@ -31,5 +31,14 @@
<summary>Sidebar revealed</summary>
<description>Whether the sidebar is revealed or not</description>
</key>
+ <key name="style-variant" type="s">
+ <choices>
+ <choice value="light"/>
+ <choice value="dark"/>
+ </choices>
+ <default>'light'</default>
+ <summary>Style Variant</summary>
+ <description>Use the light or dark variant of the GTK theme and/or GtkSourceView style
scheme.</description>
+ </key>
</schema>
</schemalist>
diff --git a/src/gui/gtd-theme-selector.c b/src/gui/gtd-theme-selector.c
new file mode 100644
index 00000000..dd95df4c
--- /dev/null
+++ b/src/gui/gtd-theme-selector.c
@@ -0,0 +1,214 @@
+/* gtd-theme-selector.c
+ *
+ * Copyright 2021 Georges Basile Stavracas Neto <georges stavracas gmail 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
+ */
+
+#include "gtd-manager.h"
+#include "gtd-theme-selector.h"
+
+struct _GtdThemeSelector
+{
+ GtkWidget parent;
+
+ GtkToggleButton *dark;
+ GtkToggleButton *light;
+
+ gchar *theme;
+};
+
+G_DEFINE_TYPE (GtdThemeSelector, gtd_theme_selector, GTK_TYPE_WIDGET)
+
+enum
+{
+ PROP_0,
+ PROP_THEME,
+ N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+/*
+ * Auxiliary methods
+ */
+
+static gboolean
+style_variant_to_boolean (GValue *value,
+ GVariant *variant,
+ gpointer user_data)
+{
+ gboolean is_dark = g_strcmp0 (g_variant_get_string (variant, NULL), "dark") == 0;
+
+ g_value_set_boolean (value, is_dark);
+
+ return TRUE;
+}
+
+static void
+setup_action (GtdThemeSelector *self)
+{
+ g_autoptr (GSimpleActionGroup) group = NULL;
+ g_autoptr (GAction) action = NULL;
+ GtkSettings *gtk_settings;
+ GtdManager *manager;
+ GSettings *settings;
+ gboolean is_dark;
+
+ manager = gtd_manager_get_default ();
+ settings = gtd_manager_get_settings (manager);
+
+ self->theme = g_settings_get_string (settings, "style-variant");
+ is_dark = g_strcmp0 (self->theme, "dark") == 0;
+ gtk_settings = gtk_settings_get_default ();
+ g_object_set (gtk_settings,
+ "gtk-application-prefer-dark-theme", is_dark,
+ NULL);
+
+ group = g_simple_action_group_new ();
+ action = g_settings_create_action (settings, "style-variant");
+ g_action_map_add_action (G_ACTION_MAP (group), action);
+
+ gtk_widget_insert_action_group (GTK_WIDGET (self),
+ "settings",
+ G_ACTION_GROUP (group));
+
+ g_settings_bind_with_mapping (settings,
+ "style-variant",
+ gtk_settings,
+ "gtk-application-prefer-dark-theme",
+ G_SETTINGS_BIND_GET,
+ style_variant_to_boolean,
+ NULL, NULL, NULL);
+}
+
+/*
+ * GObject overrides
+ */
+static void
+gtd_theme_selector_dispose (GObject *object)
+{
+ GtdThemeSelector *self = (GtdThemeSelector *)object;
+
+ g_clear_pointer (&self->theme, g_free);
+
+ G_OBJECT_CLASS (gtd_theme_selector_parent_class)->dispose (object);
+}
+
+static void
+gtd_theme_selector_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtdThemeSelector *self = GTD_THEME_SELECTOR (object);
+
+ switch (prop_id)
+ {
+ case PROP_THEME:
+ g_value_set_string (value, gtd_theme_selector_get_theme (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtd_theme_selector_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtdThemeSelector *self = GTD_THEME_SELECTOR (object);
+
+ switch (prop_id)
+ {
+ case PROP_THEME:
+ gtd_theme_selector_set_theme (self, g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtd_theme_selector_class_init (GtdThemeSelectorClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->dispose = gtd_theme_selector_dispose;
+ object_class->get_property = gtd_theme_selector_get_property;
+ object_class->set_property = gtd_theme_selector_set_property;
+
+ properties [PROP_THEME] =
+ g_param_spec_string ("theme",
+ "Theme",
+ "Theme",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+
+ gtk_widget_class_install_property_action (widget_class, "theme.mode", "theme");
+
+ gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/todo/ui/gtd-theme-selector.ui");
+
+ gtk_widget_class_bind_template_child (widget_class, GtdThemeSelector, dark);
+ gtk_widget_class_bind_template_child (widget_class, GtdThemeSelector, light);
+
+ gtk_widget_class_set_css_name (widget_class, "themeselector");
+
+ gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
+}
+
+static void
+gtd_theme_selector_init (GtdThemeSelector *self)
+{
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ setup_action (self);
+}
+
+GtkWidget *
+gtd_theme_selector_new (void)
+{
+ return g_object_new (GTD_TYPE_THEME_SELECTOR, NULL);
+}
+
+const gchar *
+gtd_theme_selector_get_theme (GtdThemeSelector *self)
+{
+ g_return_val_if_fail (GTD_IS_THEME_SELECTOR (self), NULL);
+
+ return self->theme;
+}
+
+void
+gtd_theme_selector_set_theme (GtdThemeSelector *self,
+ const gchar *theme)
+{
+ g_return_if_fail (GTD_IS_THEME_SELECTOR (self));
+
+ if (g_strcmp0 (theme, self->theme) == 0)
+ return;
+
+ g_clear_pointer (&self->theme, g_free);
+ self->theme = g_strdup (theme);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_THEME]);
+}
diff --git a/src/gui/gtd-theme-selector.h b/src/gui/gtd-theme-selector.h
new file mode 100644
index 00000000..0a731d6f
--- /dev/null
+++ b/src/gui/gtd-theme-selector.h
@@ -0,0 +1,37 @@
+/* gtd-theme-selector.h
+ *
+ * Copyright 2021 Georges Basile Stavracas Neto <georges stavracas gmail 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 GTD_TYPE_THEME_SELECTOR (gtd_theme_selector_get_type())
+G_DECLARE_FINAL_TYPE (GtdThemeSelector, gtd_theme_selector, GTD, THEME_SELECTOR, GtkWidget)
+
+GtkWidget * gtd_theme_selector_new (void);
+
+const gchar * gtd_theme_selector_get_theme (GtdThemeSelector *self);
+
+void gtd_theme_selector_set_theme (GtdThemeSelector *self,
+ const gchar *theme);
+
+G_END_DECLS
diff --git a/src/gui/gtd-theme-selector.ui b/src/gui/gtd-theme-selector.ui
new file mode 100644
index 00000000..364a2463
--- /dev/null
+++ b/src/gui/gtd-theme-selector.ui
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GtdThemeSelector" parent="GtkWidget">
+
+ <child>
+ <object class="GtkBox" id="box">
+ <property name="halign">center</property>
+ <property name="orientation">horizontal</property>
+ <property name="margin-start">24</property>
+ <property name="margin-end">24</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <object class="GtkCheckButton" id="light">
+ <style>
+ <class name="light"/>
+ </style>
+ <property name="focus-on-click">false</property>
+ <property name="action-name">settings.style-variant</property>
+ <property name="action-target">'light'</property>
+ <property name="tooltip-text" translatable="yes">Light style</property>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkCheckButton" id="dark">
+ <style>
+ <class name="dark"/>
+ </style>
+ <property name="group">light</property>
+ <property name="focus-on-click">false</property>
+ <property name="action-name">settings.style-variant</property>
+ <property name="action-target">'dark'</property>
+ <property name="tooltip-text" translatable="yes">Dark style</property>
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ </template>
+</interface>
diff --git a/src/gui/gtd-window.c b/src/gui/gtd-window.c
index 96f337a6..cd9dcff5 100644
--- a/src/gui/gtd-window.c
+++ b/src/gui/gtd-window.c
@@ -35,6 +35,7 @@
#include "gtd-panel.h"
#include "gtd-task.h"
#include "gtd-task-list.h"
+#include "gtd-theme-selector.h"
#include "gtd-window.h"
#include "gtd-workspace.h"
@@ -577,6 +578,7 @@ static void
gtd_window_init (GtdWindow *self)
{
GtkApplication *application;
+ GtkPopover *popover;
GMenu *primary_menu;
static const GActionEntry entries[] = {
@@ -604,6 +606,10 @@ gtd_window_init (GtdWindow *self)
primary_menu = gtk_application_get_menu_by_id (application, "primary-menu");
gtk_menu_button_set_menu_model (self->primary_menu_button, G_MENU_MODEL (primary_menu));
+ popover = gtk_menu_button_get_popover (self->primary_menu_button);
+ gtk_popover_menu_add_child (GTK_POPOVER_MENU (popover),
+ gtd_theme_selector_new (),
+ "theme");
/* Development build */
if (is_development_build ())
setup_development_build (self);
diff --git a/src/gui/gui.gresource.xml b/src/gui/gui.gresource.xml
index bb7161f7..60ddb00a 100644
--- a/src/gui/gui.gresource.xml
+++ b/src/gui/gui.gresource.xml
@@ -13,6 +13,7 @@
<file compressed="true" preprocess="xml-stripblanks">gtd-task-list-popover.ui</file>
<file compressed="true" preprocess="xml-stripblanks">gtd-task-list-view.ui</file>
<file compressed="true" preprocess="xml-stripblanks">gtd-task-row.ui</file>
+ <file compressed="true" preprocess="xml-stripblanks">gtd-theme-selector.ui</file>
<file compressed="true" preprocess="xml-stripblanks">gtd-window.ui</file>
<!-- Assets -->
diff --git a/src/gui/menus.ui b/src/gui/menus.ui
index f90d756b..18e57ee0 100644
--- a/src/gui/menus.ui
+++ b/src/gui/menus.ui
@@ -2,6 +2,12 @@
<interface>
<menu id="primary-menu">
+ <section>
+ <item>
+ <attribute name="custom">theme</attribute>
+ </item>
+ </section>
+
<section>
<item>
<attribute name="label" translatable="yes">_About To Do</attribute>
diff --git a/src/meson.build b/src/meson.build
index 9ab95215..ebafc5fd 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -152,6 +152,7 @@ sources += files(
'gui/gtd-omni-area.c',
'gui/gtd-omni-area-addin.c',
'gui/gtd-theme-manager.c',
+ 'gui/gtd-theme-selector.c',
'gui/gtd-widget.c',
'gui/gtd-window.c',
'models/gtd-list-model-filter.c',
diff --git a/src/themes/Adwaita-themeselector.css b/src/themes/Adwaita-themeselector.css
new file mode 100644
index 00000000..a7676b6e
--- /dev/null
+++ b/src/themes/Adwaita-themeselector.css
@@ -0,0 +1,25 @@
+themeselector checkbutton radio {
+ -gtk-icon-source: none;
+ background: none;
+ box-shadow: none;
+ padding: 12px;
+ min-height: 24px;
+ min-width: 24px;
+ border-width: 3px;
+ border-style: solid;
+ border-color: transparent;
+}
+
+themeselector checkbutton radio:checked {
+ border-color: @theme_selected_bg_color;
+ -gtk-icon-source: -gtk-scaled(-gtk-icontheme("object-select-symbolic"));
+}
+
+themeselector checkbutton.light radio {
+ color: #2e3436;
+ background-color: #fff;
+}
+themeselector checkbutton.dark radio {
+ color: #fff;
+ background-color: #2e3436;
+}
diff --git a/src/themes/Adwaita.css b/src/themes/Adwaita.css
index c2d8c904..5552c06e 100644
--- a/src/themes/Adwaita.css
+++ b/src/themes/Adwaita.css
@@ -1,6 +1,7 @@
@import url("resource:///org/gnome/todo/themes/Adwaita-omniarea.css");
@import url("resource:///org/gnome/todo/themes/Adwaita-tasklistview.css");
@import url("resource:///org/gnome/todo/themes/Adwaita-taskrow.css");
+@import url("resource:///org/gnome/todo/themes/Adwaita-themeselector.css");
@import url("resource:///org/gnome/todo/themes/Adwaita-widgets.css");
.transparent {
diff --git a/src/todo.gresource.xml b/src/todo.gresource.xml
index a754744c..98085beb 100644
--- a/src/todo.gresource.xml
+++ b/src/todo.gresource.xml
@@ -6,6 +6,7 @@
<file compressed="true">themes/Adwaita-omniarea.css</file>
<file compressed="true">themes/Adwaita-tasklistview.css</file>
<file compressed="true">themes/Adwaita-taskrow.css</file>
+ <file compressed="true">themes/Adwaita-themeselector.css</file>
<file compressed="true">themes/Adwaita-widgets.css</file>
</gresource>
</gresources>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]