summaryrefslogtreecommitdiffstats
path: root/subprojects/libhandy/src/hdy-preferences-group.c
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/libhandy/src/hdy-preferences-group.c')
-rw-r--r--subprojects/libhandy/src/hdy-preferences-group.c449
1 files changed, 449 insertions, 0 deletions
diff --git a/subprojects/libhandy/src/hdy-preferences-group.c b/subprojects/libhandy/src/hdy-preferences-group.c
new file mode 100644
index 0000000..8000627
--- /dev/null
+++ b/subprojects/libhandy/src/hdy-preferences-group.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2019 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#include "hdy-preferences-group-private.h"
+
+#include "hdy-preferences-row.h"
+
+/**
+ * SECTION:hdy-preferences-group
+ * @short_description: A group gathering preferences rows.
+ * @Title: HdyPreferencesGroup
+ *
+ * A #HdyPreferencesGroup represents a group or tightly related preferences,
+ * which in turn are represented by HdyPreferencesRow.
+ *
+ * To summarize the role of the preferences it gathers, a group can have both a
+ * title and a description. The title will be used by #HdyPreferencesWindow to
+ * let the user look for a preference.
+ *
+ * # CSS nodes
+ *
+ * #HdyPreferencesGroup has a single CSS node with name preferencesgroup.
+ *
+ * Since: 0.0.10
+ */
+
+typedef struct
+{
+ GtkBox *box;
+ GtkLabel *description;
+ GtkListBox *listbox;
+ GtkBox *listbox_box;
+ GtkLabel *title;
+} HdyPreferencesGroupPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (HdyPreferencesGroup, hdy_preferences_group, GTK_TYPE_BIN)
+
+enum {
+ PROP_0,
+ PROP_DESCRIPTION,
+ PROP_TITLE,
+ LAST_PROP,
+};
+
+static GParamSpec *props[LAST_PROP];
+
+static void
+update_title_visibility (HdyPreferencesGroup *self)
+{
+ HdyPreferencesGroupPrivate *priv = hdy_preferences_group_get_instance_private (self);
+
+ /* Show the listbox only if it has children to avoid having showing the
+ * listbox as an empty frame, parasiting the look of non-GtkListBoxRow
+ * children.
+ */
+ gtk_widget_set_visible (GTK_WIDGET (priv->title),
+ gtk_label_get_text (priv->title) != NULL &&
+ g_strcmp0 (gtk_label_get_text (priv->title), "") != 0);
+}
+
+static void
+update_description_visibility (HdyPreferencesGroup *self)
+{
+ HdyPreferencesGroupPrivate *priv = hdy_preferences_group_get_instance_private (self);
+
+ gtk_widget_set_visible (GTK_WIDGET (priv->description),
+ gtk_label_get_text (priv->description) != NULL &&
+ g_strcmp0 (gtk_label_get_text (priv->description), "") != 0);
+}
+
+static void
+update_listbox_visibility (HdyPreferencesGroup *self)
+{
+ HdyPreferencesGroupPrivate *priv = hdy_preferences_group_get_instance_private (self);
+ g_autoptr(GList) children = NULL;
+
+ /* We must wait until listob has been built and added. */
+ if (priv->listbox == NULL)
+ return;
+
+ children = gtk_container_get_children (GTK_CONTAINER (priv->listbox));
+
+ gtk_widget_set_visible (GTK_WIDGET (priv->listbox), children != NULL);
+}
+
+typedef struct {
+ HdyPreferencesGroup *group;
+ GtkCallback callback;
+ gpointer callback_data;
+} ForallData;
+
+static void
+for_non_internal_child (GtkWidget *widget,
+ gpointer callback_data)
+{
+ ForallData *data = callback_data;
+ HdyPreferencesGroupPrivate *priv = hdy_preferences_group_get_instance_private (data->group);
+
+ if (widget != (GtkWidget *) priv->listbox)
+ data->callback (widget, data->callback_data);
+}
+
+static void
+hdy_preferences_group_forall (GtkContainer *container,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer callback_data)
+{
+ HdyPreferencesGroup *self = HDY_PREFERENCES_GROUP (container);
+ HdyPreferencesGroupPrivate *priv = hdy_preferences_group_get_instance_private (self);
+ ForallData data;
+
+ if (include_internals) {
+ GTK_CONTAINER_CLASS (hdy_preferences_group_parent_class)->forall (GTK_CONTAINER (self), include_internals, callback, callback_data);
+
+ return;
+ }
+
+ data.group = self;
+ data.callback = callback;
+ data.callback_data = callback_data;
+
+ if (priv->listbox)
+ GTK_CONTAINER_GET_CLASS (priv->listbox)->forall (GTK_CONTAINER (priv->listbox), include_internals, callback, callback_data);
+ if (priv->listbox_box)
+ GTK_CONTAINER_GET_CLASS (priv->listbox_box)->forall (GTK_CONTAINER (priv->listbox_box), include_internals, for_non_internal_child, &data);
+}
+
+static void
+hdy_preferences_group_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ HdyPreferencesGroup *self = HDY_PREFERENCES_GROUP (object);
+
+ switch (prop_id) {
+ case PROP_DESCRIPTION:
+ g_value_set_string (value, hdy_preferences_group_get_description (self));
+ break;
+ case PROP_TITLE:
+ g_value_set_string (value, hdy_preferences_group_get_title (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+hdy_preferences_group_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ HdyPreferencesGroup *self = HDY_PREFERENCES_GROUP (object);
+
+ switch (prop_id) {
+ case PROP_DESCRIPTION:
+ hdy_preferences_group_set_description (self, g_value_get_string (value));
+ break;
+ case PROP_TITLE:
+ hdy_preferences_group_set_title (self, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+hdy_preferences_group_dispose (GObject *object)
+{
+ HdyPreferencesGroup *self = HDY_PREFERENCES_GROUP (object);
+ HdyPreferencesGroupPrivate *priv = hdy_preferences_group_get_instance_private (self);
+
+ /*
+ * Since we overload forall(), the inherited destroy() won't work as normal.
+ * Remove internal widgets ourself.
+ */
+ g_clear_pointer ((GtkWidget **) &priv->description, gtk_widget_destroy);
+ g_clear_pointer ((GtkWidget **) &priv->listbox, gtk_widget_destroy);
+ g_clear_pointer ((GtkWidget **) &priv->listbox_box, gtk_widget_destroy);
+ g_clear_pointer ((GtkWidget **) &priv->title, gtk_widget_destroy);
+
+ G_OBJECT_CLASS (hdy_preferences_group_parent_class)->dispose (object);
+}
+
+static void
+hdy_preferences_group_add (GtkContainer *container,
+ GtkWidget *child)
+{
+ HdyPreferencesGroup *self = HDY_PREFERENCES_GROUP (container);
+ HdyPreferencesGroupPrivate *priv = hdy_preferences_group_get_instance_private (self);
+
+ if (priv->title == NULL || priv->description == NULL || priv->listbox_box == NULL) {
+ GTK_CONTAINER_CLASS (hdy_preferences_group_parent_class)->add (container, child);
+
+ return;
+ }
+
+ if (HDY_IS_PREFERENCES_ROW (child))
+ gtk_container_add (GTK_CONTAINER (priv->listbox), child);
+ else
+ gtk_container_add (GTK_CONTAINER (priv->listbox_box), child);
+}
+
+static void
+hdy_preferences_group_remove (GtkContainer *container,
+ GtkWidget *child)
+{
+ HdyPreferencesGroup *self = HDY_PREFERENCES_GROUP (container);
+ HdyPreferencesGroupPrivate *priv = hdy_preferences_group_get_instance_private (self);
+
+ if (child == GTK_WIDGET (priv->box))
+ GTK_CONTAINER_CLASS (hdy_preferences_group_parent_class)->remove (container, child);
+ else if (HDY_IS_PREFERENCES_ROW (child))
+ gtk_container_remove (GTK_CONTAINER (priv->listbox), child);
+ else if (child != GTK_WIDGET (priv->listbox))
+ gtk_container_remove (GTK_CONTAINER (priv->listbox_box), child);
+}
+
+static void
+hdy_preferences_group_class_init (HdyPreferencesGroupClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+ object_class->get_property = hdy_preferences_group_get_property;
+ object_class->set_property = hdy_preferences_group_set_property;
+ object_class->dispose = hdy_preferences_group_dispose;
+
+ container_class->add = hdy_preferences_group_add;
+ container_class->remove = hdy_preferences_group_remove;
+ container_class->forall = hdy_preferences_group_forall;
+
+ /**
+ * HdyPreferencesGroup:description:
+ *
+ * The description for this group of preferences.
+ *
+ * Since: 0.0.10
+ */
+ props[PROP_DESCRIPTION] =
+ g_param_spec_string ("description",
+ _("Description"),
+ _("Description"),
+ "",
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * HdyPreferencesGroup:title:
+ *
+ * The title for this group of preferences.
+ *
+ * Since: 0.0.10
+ */
+ props[PROP_TITLE] =
+ g_param_spec_string ("title",
+ _("Title"),
+ _("Title"),
+ "",
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, LAST_PROP, props);
+
+ gtk_widget_class_set_css_name (widget_class, "preferencesgroup");
+ gtk_widget_class_set_template_from_resource (widget_class,
+ "/sm/puri/handy/ui/hdy-preferences-group.ui");
+ gtk_widget_class_bind_template_child_private (widget_class, HdyPreferencesGroup, box);
+ gtk_widget_class_bind_template_child_private (widget_class, HdyPreferencesGroup, description);
+ gtk_widget_class_bind_template_child_private (widget_class, HdyPreferencesGroup, listbox);
+ gtk_widget_class_bind_template_child_private (widget_class, HdyPreferencesGroup, listbox_box);
+ gtk_widget_class_bind_template_child_private (widget_class, HdyPreferencesGroup, title);
+ gtk_widget_class_bind_template_callback (widget_class, update_listbox_visibility);
+}
+
+static void
+hdy_preferences_group_init (HdyPreferencesGroup *self)
+{
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ update_description_visibility (self);
+ update_title_visibility (self);
+ update_listbox_visibility (self);
+}
+
+/**
+ * hdy_preferences_group_new:
+ *
+ * Creates a new #HdyPreferencesGroup.
+ *
+ * Returns: a new #HdyPreferencesGroup
+ *
+ * Since: 0.0.10
+ */
+GtkWidget *
+hdy_preferences_group_new (void)
+{
+ return g_object_new (HDY_TYPE_PREFERENCES_GROUP, NULL);
+}
+
+/**
+ * hdy_preferences_group_get_title:
+ * @self: a #HdyPreferencesGroup
+ *
+ * Gets the title of @self.
+ *
+ * Returns: the title of @self.
+ *
+ * Since: 0.0.10
+ */
+const gchar *
+hdy_preferences_group_get_title (HdyPreferencesGroup *self)
+{
+ HdyPreferencesGroupPrivate *priv;
+
+ g_return_val_if_fail (HDY_IS_PREFERENCES_GROUP (self), NULL);
+
+ priv = hdy_preferences_group_get_instance_private (self);
+
+ return gtk_label_get_text (priv->title);
+}
+
+/**
+ * hdy_preferences_group_set_title:
+ * @self: a #HdyPreferencesGroup
+ * @title: the title
+ *
+ * Sets the title for @self.
+ *
+ * Since: 0.0.10
+ */
+void
+hdy_preferences_group_set_title (HdyPreferencesGroup *self,
+ const gchar *title)
+{
+ HdyPreferencesGroupPrivate *priv;
+
+ g_return_if_fail (HDY_IS_PREFERENCES_GROUP (self));
+
+ priv = hdy_preferences_group_get_instance_private (self);
+
+ if (g_strcmp0 (gtk_label_get_label (priv->title), title) == 0)
+ return;
+
+ gtk_label_set_label (priv->title, title);
+ update_title_visibility (self);
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TITLE]);
+}
+
+/**
+ * hdy_preferences_group_get_description:
+ * @self: a #HdyPreferencesGroup
+ *
+ *
+ * Returns: the description of @self.
+ *
+ * Since: 0.0.10
+ */
+const gchar *
+hdy_preferences_group_get_description (HdyPreferencesGroup *self)
+{
+ HdyPreferencesGroupPrivate *priv;
+
+ g_return_val_if_fail (HDY_IS_PREFERENCES_GROUP (self), NULL);
+
+ priv = hdy_preferences_group_get_instance_private (self);
+
+ return gtk_label_get_text (priv->description);
+}
+
+/**
+ * hdy_preferences_group_set_description:
+ * @self: a #HdyPreferencesGroup
+ * @description: the description
+ *
+ * Sets the description for @self.
+ *
+ * Since: 0.0.10
+ */
+void
+hdy_preferences_group_set_description (HdyPreferencesGroup *self,
+ const gchar *description)
+{
+ HdyPreferencesGroupPrivate *priv;
+
+ g_return_if_fail (HDY_IS_PREFERENCES_GROUP (self));
+
+ priv = hdy_preferences_group_get_instance_private (self);
+
+ if (g_strcmp0 (gtk_label_get_label (priv->description), description) == 0)
+ return;
+
+ gtk_label_set_label (priv->description, description);
+ update_description_visibility (self);
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DESCRIPTION]);
+}
+
+static void
+add_preferences_to_model (HdyPreferencesRow *row,
+ GListStore *model)
+{
+ const gchar *title;
+
+ g_assert (HDY_IS_PREFERENCES_ROW (row));
+ g_assert (G_IS_LIST_STORE (model));
+
+ if (!gtk_widget_get_visible (GTK_WIDGET (row)))
+ return;
+
+ title = hdy_preferences_row_get_title (row);
+
+ if (!title || !*title)
+ return;
+
+ g_list_store_append (model, row);
+}
+
+/**
+ * hdy_preferences_group_add_preferences_to_model: (skip)
+ * @self: a #HdyPreferencesGroup
+ * @model: the model
+ *
+ * Add preferences from @self to the model.
+ *
+ * Since: 0.0.10
+ */
+void
+hdy_preferences_group_add_preferences_to_model (HdyPreferencesGroup *self,
+ GListStore *model)
+{
+ HdyPreferencesGroupPrivate *priv = hdy_preferences_group_get_instance_private (self);
+
+ g_return_if_fail (HDY_IS_PREFERENCES_GROUP (self));
+ g_return_if_fail (G_IS_LIST_STORE (model));
+
+ if (!gtk_widget_get_visible (GTK_WIDGET (self)))
+ return;
+
+ gtk_container_foreach (GTK_CONTAINER (priv->listbox), (GtkCallback) add_preferences_to_model, model);
+}