[gnome-software/1392-unify-lozenge-styling: 5/13] Introduce GsLozenge




commit eaf7cbb97ac112c3305ee0ad647b895837a4e701
Author: Milan Crha <mcrha redhat com>
Date:   Tue May 3 20:42:44 2022 +0200

    Introduce GsLozenge
    
    This provides a widget to show a lozenge either with an icon or with
    a text.

 src/gnome-software.gresource.xml |   1 +
 src/gs-lozenge.c                 | 415 +++++++++++++++++++++++++++++++++++++++
 src/gs-lozenge.h                 |  38 ++++
 src/gs-lozenge.ui                |  33 ++++
 src/meson.build                  |   1 +
 5 files changed, 488 insertions(+)
---
diff --git a/src/gnome-software.gresource.xml b/src/gnome-software.gresource.xml
index 6b58f2e61..60277a600 100644
--- a/src/gnome-software.gresource.xml
+++ b/src/gnome-software.gresource.xml
@@ -24,6 +24,7 @@
   <file preprocess="xml-stripblanks">gs-installed-page.ui</file>
   <file preprocess="xml-stripblanks">gs-license-tile.ui</file>
   <file preprocess="xml-stripblanks">gs-loading-page.ui</file>
+  <file preprocess="xml-stripblanks">gs-lozenge.ui</file>
   <file preprocess="xml-stripblanks">gs-metered-data-dialog.ui</file>
   <file preprocess="xml-stripblanks">gs-moderate-page.ui</file>
   <file preprocess="xml-stripblanks">gs-overview-page.ui</file>
diff --git a/src/gs-lozenge.c b/src/gs-lozenge.c
new file mode 100644
index 000000000..39886cf73
--- /dev/null
+++ b/src/gs-lozenge.c
@@ -0,0 +1,415 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ * vi:set noexpandtab tabstop=8 shiftwidth=8:
+ *
+ * Copyright (C) 2022 Red Hat (www.redhat.com)
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include "config.h"
+
+#include "gs-lozenge.h"
+#include "gs-lozenge-layout.h"
+
+struct _GsLozenge
+{
+       GtkBox           parent_instance;
+
+       GtkWidget       *image; /* (unowned) */
+       GtkWidget       *label; /* (unowned) */
+
+       gchar           *icon_name;
+       gchar           *text;
+       gchar           *markup;
+       gboolean         circular;
+       gint             pixel_size;
+};
+
+G_DEFINE_TYPE (GsLozenge, gs_lozenge, GTK_TYPE_BOX)
+
+typedef enum {
+       PROP_CIRCULAR = 1,
+       PROP_ICON_NAME,
+       PROP_PIXEL_SIZE,
+       PROP_TEXT,
+       PROP_MARKUP
+} GsLozengeProperty;
+
+static GParamSpec *obj_props[PROP_MARKUP + 1] = { NULL, };
+
+static void
+gs_lozenge_get_property (GObject    *object,
+                        guint       prop_id,
+                        GValue     *value,
+                        GParamSpec *pspec)
+{
+       GsLozenge *self = GS_LOZENGE (object);
+
+       switch ((GsLozengeProperty) prop_id) {
+       case PROP_CIRCULAR:
+               g_value_set_boolean (value, gs_lozenge_get_circular (self));
+               break;
+       case PROP_ICON_NAME:
+               g_value_set_string (value, gs_lozenge_get_icon_name (self));
+               break;
+       case PROP_PIXEL_SIZE:
+               g_value_set_int (value, gs_lozenge_get_pixel_size (self));
+               break;
+       case PROP_TEXT:
+               g_value_set_string (value, gs_lozenge_get_text (self));
+               break;
+       case PROP_MARKUP:
+               g_value_set_string (value, gs_lozenge_get_markup (self));
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+gs_lozenge_set_property (GObject      *object,
+                        guint         prop_id,
+                        const GValue *value,
+                        GParamSpec   *pspec)
+{
+       GsLozenge *self = GS_LOZENGE (object);
+
+       switch ((GsLozengeProperty) prop_id) {
+       case PROP_CIRCULAR:
+               gs_lozenge_set_circular (self, g_value_get_boolean (value));
+               break;
+       case PROP_ICON_NAME:
+               gs_lozenge_set_icon_name (self, g_value_get_string (value));
+               break;
+       case PROP_PIXEL_SIZE:
+               gs_lozenge_set_pixel_size (self, g_value_get_int (value));
+               break;
+       case PROP_TEXT:
+               gs_lozenge_set_text (self, g_value_get_string (value));
+               break;
+       case PROP_MARKUP:
+               gs_lozenge_set_markup (self, g_value_get_string (value));
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+gs_lozenge_dispose (GObject *object)
+{
+       GsLozenge *self = GS_LOZENGE (object);
+
+       g_clear_pointer (&self->icon_name, g_free);
+       g_clear_pointer (&self->text, g_free);
+       g_clear_pointer (&self->markup, g_free);
+
+       G_OBJECT_CLASS (gs_lozenge_parent_class)->dispose (object);
+}
+
+static void
+gs_lozenge_class_init (GsLozengeClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+       object_class->get_property = gs_lozenge_get_property;
+       object_class->set_property = gs_lozenge_set_property;
+       object_class->dispose = gs_lozenge_dispose;
+
+       /**
+        * GsLozenge:circular:
+        *
+        * Whether the lozenge should be circular/square widget.
+        *
+        * Since: 43
+        */
+       obj_props[PROP_CIRCULAR] =
+               g_param_spec_boolean ("circular", NULL, NULL,
+                                     FALSE,
+                                     G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+       /**
+        * GsLozenge:icon-name:
+        *
+        * An icon name for the lozenge. Setting this property turns
+        * the lozenge into the icon mode, which mean showing the icon,
+        * not the markup.
+        *
+        * Since: 43
+        */
+       obj_props[PROP_ICON_NAME] =
+               g_param_spec_string ("icon-name", NULL, NULL,
+                                     NULL,
+                                     G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+       /**
+        * GsLozenge:pixel-size:
+        *
+        * An icon pixel size for the lozenge.
+        *
+        * Since: 43
+        */
+       obj_props[PROP_PIXEL_SIZE] =
+               g_param_spec_int ("pixel-size", NULL, NULL,
+                                 0, G_MAXINT, 16,
+                                 G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+       /**
+        * GsLozenge:text:
+        *
+        * A plain text for the lozenge. Setting this property turns
+        * the lozenge into the text mode, which mean showing the text,
+        * not the icon.
+        *
+        * Since: 43
+        */
+       obj_props[PROP_TEXT] =
+               g_param_spec_string ("text", NULL, NULL,
+                                     NULL,
+                                     G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+       /**
+        * GsLozenge:markup:
+        *
+        * A markup text for the lozenge. Setting this property turns
+        * the lozenge into the text mode, which mean showing the markup,
+        * not the icon.
+        *
+        * Since: 43
+        */
+       obj_props[PROP_MARKUP] =
+               g_param_spec_string ("markup", NULL, NULL,
+                                     NULL,
+                                     G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+       g_object_class_install_properties (object_class, G_N_ELEMENTS (obj_props), obj_props);
+
+       gtk_widget_class_set_layout_manager_type (widget_class, GS_TYPE_LOZENGE_LAYOUT);
+       gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Software/gs-lozenge.ui");
+
+       gtk_widget_class_bind_template_child (widget_class, GsLozenge, image);
+       gtk_widget_class_bind_template_child (widget_class, GsLozenge, label);
+}
+
+static void
+gs_lozenge_init (GsLozenge *self)
+{
+       gtk_widget_init_template (GTK_WIDGET (self));
+
+       self->pixel_size = 16;
+}
+
+/**
+ * gs_lozenge_new:
+ *
+ * Returns: (transfer full): a new #GsLozenge
+ *
+ * Since: 43
+ **/
+GtkWidget *
+gs_lozenge_new (void)
+{
+       return g_object_new (GS_TYPE_LOZENGE, NULL);
+}
+
+const gchar *
+gs_lozenge_get_icon_name (GsLozenge *self)
+{
+       g_return_val_if_fail (GS_IS_LOZENGE (self), NULL);
+
+       return self->icon_name;
+}
+
+gboolean
+gs_lozenge_get_circular (GsLozenge *self)
+{
+       g_return_val_if_fail (GS_IS_LOZENGE (self), FALSE);
+
+       return self->circular;
+}
+
+void
+gs_lozenge_set_circular (GsLozenge *self,
+                        gboolean value)
+{
+       GtkLayoutManager *layout_manager;
+
+       g_return_if_fail (GS_IS_LOZENGE (self));
+
+       if ((!self->circular) == (!value))
+               return;
+
+       self->circular = value;
+
+       layout_manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
+       gs_lozenge_layout_set_circular (GS_LOZENGE_LAYOUT (layout_manager), self->circular);
+
+       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CIRCULAR]);
+}
+
+void
+gs_lozenge_set_icon_name (GsLozenge *self,
+                         const gchar *value)
+{
+       g_return_if_fail (GS_IS_LOZENGE (self));
+
+       if (value != NULL && *value == '\0')
+               value = NULL;
+
+       if (g_strcmp0 (self->icon_name, value) == 0)
+               return;
+
+       g_clear_pointer (&self->icon_name, g_free);
+       self->icon_name = g_strdup (value);
+
+       if (self->icon_name == NULL) {
+               gtk_widget_hide (self->image);
+               gtk_widget_show (self->label);
+       } else {
+               gtk_image_set_from_icon_name (GTK_IMAGE (self->image), self->icon_name);
+               gtk_widget_hide (self->label);
+               gtk_widget_show (self->image);
+       }
+
+       /* Clean up the other properties before notifying of the changed property name */
+
+       if (self->text != NULL) {
+               g_clear_pointer (&self->text, g_free);
+               g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT]);
+       }
+
+       if (self->markup != NULL) {
+               g_clear_pointer (&self->markup, g_free);
+               g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARKUP]);
+       }
+
+       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ICON_NAME]);
+}
+
+gint
+gs_lozenge_get_pixel_size (GsLozenge *self)
+{
+       g_return_val_if_fail (GS_IS_LOZENGE (self), 0);
+
+       return self->pixel_size;
+}
+
+void
+gs_lozenge_set_pixel_size (GsLozenge *self,
+                          gint value)
+{
+       g_return_if_fail (GS_IS_LOZENGE (self));
+
+       if (self->pixel_size == value)
+               return;
+
+       self->pixel_size = value;
+
+       gtk_image_set_pixel_size (GTK_IMAGE (self->image), self->pixel_size);
+
+       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_PIXEL_SIZE]);
+}
+
+gboolean
+gs_lozenge_get_use_markup (GsLozenge *self)
+{
+       g_return_val_if_fail (GS_IS_LOZENGE (self), FALSE);
+       return gtk_label_get_use_markup (GTK_LABEL (self->label));
+}
+
+const gchar *
+gs_lozenge_get_text (GsLozenge *self)
+{
+       g_return_val_if_fail (GS_IS_LOZENGE (self), NULL);
+
+       return self->text;
+}
+
+void
+gs_lozenge_set_text (GsLozenge *self,
+                    const gchar *value)
+{
+       g_return_if_fail (GS_IS_LOZENGE (self));
+
+       if (value != NULL && *value == '\0')
+               value = NULL;
+
+       if (g_strcmp0 (self->text, value) == 0)
+               return;
+
+       g_clear_pointer (&self->text, g_free);
+       self->text = g_strdup (value);
+
+       if (self->text == NULL) {
+               gtk_widget_hide (self->label);
+               gtk_widget_show (self->image);
+       } else {
+               gtk_label_set_text (GTK_LABEL (self->label), self->text);
+               gtk_widget_hide (self->image);
+               gtk_widget_show (self->label);
+       }
+
+       /* Clean up the other properties before notifying of the changed property name */
+
+       if (self->icon_name != NULL) {
+               g_clear_pointer (&self->icon_name, g_free);
+               g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ICON_NAME]);
+       }
+
+       if (self->markup != NULL) {
+               g_clear_pointer (&self->markup, g_free);
+               g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARKUP]);
+       }
+
+       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT]);
+}
+
+const gchar *
+gs_lozenge_get_markup (GsLozenge *self)
+{
+       g_return_val_if_fail (GS_IS_LOZENGE (self), NULL);
+
+       return self->markup;
+}
+
+void
+gs_lozenge_set_markup (GsLozenge *self,
+                      const gchar *value)
+{
+       g_return_if_fail (GS_IS_LOZENGE (self));
+
+       if (value != NULL && *value == '\0')
+               value = NULL;
+
+       if (g_strcmp0 (self->markup, value) == 0)
+               return;
+
+       g_clear_pointer (&self->markup, g_free);
+       self->markup = g_strdup (value);
+
+       if (self->markup == NULL) {
+               gtk_widget_hide (self->label);
+               gtk_widget_show (self->image);
+       } else {
+               gtk_label_set_markup (GTK_LABEL (self->label), self->markup);
+               gtk_widget_hide (self->image);
+               gtk_widget_show (self->label);
+       }
+
+       /* Clean up the other properties before notifying of the changed property name */
+
+       if (self->icon_name != NULL) {
+               g_clear_pointer (&self->icon_name, g_free);
+               g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ICON_NAME]);
+       }
+
+       if (self->text != NULL) {
+               g_clear_pointer (&self->text, g_free);
+               g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT]);
+       }
+
+       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARKUP]);
+}
diff --git a/src/gs-lozenge.h b/src/gs-lozenge.h
new file mode 100644
index 000000000..d33197672
--- /dev/null
+++ b/src/gs-lozenge.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ * vi:set noexpandtab tabstop=8 shiftwidth=8:
+ *
+ * Copyright (C) 2022 Red Hat (www.redhat.com)
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#pragma once
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_LOZENGE (gs_lozenge_get_type ())
+G_DECLARE_FINAL_TYPE (GsLozenge, gs_lozenge, GS, LOZENGE, GtkBox)
+
+GtkWidget *    gs_lozenge_new                  (void);
+gboolean       gs_lozenge_get_circular         (GsLozenge *self);
+void           gs_lozenge_set_circular         (GsLozenge *self,
+                                                gboolean value);
+const gchar *  gs_lozenge_get_icon_name        (GsLozenge *self);
+void           gs_lozenge_set_icon_name        (GsLozenge *self,
+                                                const gchar *value);
+gint           gs_lozenge_get_pixel_size       (GsLozenge *self);
+void           gs_lozenge_set_pixel_size       (GsLozenge *self,
+                                                gint value);
+gboolean       gs_lozenge_get_use_markup       (GsLozenge *self);
+const gchar *  gs_lozenge_get_text             (GsLozenge *self);
+void           gs_lozenge_set_text             (GsLozenge *self,
+                                                const gchar *value);
+const gchar *  gs_lozenge_get_markup           (GsLozenge *self);
+void           gs_lozenge_set_markup           (GsLozenge *self,
+                                                const gchar *value);
+
+G_END_DECLS
diff --git a/src/gs-lozenge.ui b/src/gs-lozenge.ui
new file mode 100644
index 000000000..545d803f4
--- /dev/null
+++ b/src/gs-lozenge.ui
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.10"/>
+  <template class="GsLozenge" parent="GtkBox">
+    <property name="halign">center</property>
+    <property name="hexpand">False</property>
+    <property name="valign">center</property>
+    <style>
+      <class name="context-tile-lozenge"/>
+    </style>
+    <child>
+      <object class="GtkImage" id="image">
+        <property name="halign">center</property>
+        <property name="hexpand">True</property>
+        <!-- this is a placeholder: the icon is actually set in code -->
+        <property name="icon-name">safety-symbolic</property>
+        <property name="pixel-size">16</property>
+        <property name="visible">False</property>
+      </object>
+    </child>
+    <child>
+      <object class="GtkLabel" id="label">
+        <property name="halign">center</property>
+        <property name="hexpand">True</property>
+        <!-- this is a placeholder: the text is actually set in code -->
+        <property name="label">20 MB</property>
+        <property name="visible">False</property>
+        <property name="xalign">0.5</property>
+        <property name="visible">False</property>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/meson.build b/src/meson.build
index e4e03c004..1b5858691 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -53,6 +53,7 @@ gnome_software_sources = [
   'gs-layout-manager.c',
   'gs-license-tile.c',
   'gs-loading-page.c',
+  'gs-lozenge.c',
   'gs-lozenge-layout.c',
   'gs-main.c',
   'gs-metered-data-dialog.c',


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