[gnome-software/1205-reviews-ratings-are-rounded-to-integer-stars: 3/6] Reviews: Ratings are rounded to integer stars




commit aeddb0cd7518e166666f9052cc0076338d3396bb
Author: Milan Crha <mcrha redhat com>
Date:   Tue May 25 12:29:42 2021 +0200

    Reviews: Ratings are rounded to integer stars
    
    Introduce and use a new GsStarImage widget, which can show partial ratings.
    
    Closes https://gitlab.gnome.org/GNOME/gnome-software/-/issues/1205

 src/gs-details-page.ui |   1 +
 src/gs-star-image.c    | 191 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/gs-star-image.h    |  37 ++++++++++
 src/gs-star-widget.c   |  35 +++++----
 src/meson.build        |   1 +
 5 files changed, 250 insertions(+), 15 deletions(-)
---
diff --git a/src/gs-details-page.ui b/src/gs-details-page.ui
index bafb11d15..b30ea9f04 100644
--- a/src/gs-details-page.ui
+++ b/src/gs-details-page.ui
@@ -144,6 +144,7 @@
                                         <property name="visible">True</property>
                                         <property name="halign">start</property>
                                         <property name="valign">center</property>
+                                        <property name="icon-size">16</property>
                                       </object>
                                     </child>
                                   </object>
diff --git a/src/gs-star-image.c b/src/gs-star-image.c
new file mode 100644
index 000000000..05a66fb99
--- /dev/null
+++ b/src/gs-star-image.c
@@ -0,0 +1,191 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ * vi:set noexpandtab tabstop=8 shiftwidth=8:
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include "config.h"
+
+#include "gs-star-image.h"
+
+struct _GsStarImagePrivate {
+       gdouble fraction;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GsStarImage, gs_star_image, GTK_TYPE_WIDGET)
+
+enum {
+       PROP_FRACTION = 1
+};
+
+static void
+gs_star_image_outline_star (cairo_t *cr,
+                           gint x,
+                           gint y,
+                           gint radius)
+{
+       const struct _points {
+               gdouble x, y;
+       } points[] = {
+               {  0.000000, -1.000000 },
+               { -0.224513, -0.309017 },
+               { -0.951057, -0.309017 },
+               { -0.363271,  0.118034 },
+               { -0.587785,  0.809017 },
+               {  0.0,       0.381966 },
+               {  0.587785,  0.809017 },
+               {  0.363271,  0.118034 },
+               {  0.951057, -0.309017 },
+               {  0.224513, -0.309017 }
+       };
+       gint ii, nn = G_N_ELEMENTS (points);
+
+       if (radius <= 0)
+               return;
+
+       cairo_translate (cr, radius, radius);
+       cairo_move_to (cr, points[0].x * radius, points[0].y * radius);
+
+       for (ii = 1; ii <= nn; ii++) {
+               cairo_line_to (cr, points[ii % nn].x * radius, points[ii % nn].y * radius);
+       }
+}
+
+static void
+gs_star_image_get_property (GObject *object,
+                           guint param_id,
+                           GValue *value,
+                           GParamSpec *pspec)
+{
+       switch (param_id) {
+       case PROP_FRACTION:
+               g_value_set_double (value, gs_star_image_get_fraction (GS_STAR_IMAGE (object)));
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+               break;
+       }
+}
+
+static void
+gs_star_image_set_property (GObject *object,
+                           guint param_id,
+                           const GValue *value,
+                           GParamSpec *pspec)
+{
+       switch (param_id) {
+       case PROP_FRACTION:
+               gs_star_image_set_fraction (GS_STAR_IMAGE (object), g_value_get_double (value));
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+               break;
+       }
+}
+
+static gboolean
+gs_star_image_draw (GtkWidget *widget,
+                   cairo_t *cr)
+{
+       GtkAllocation allocation;
+       gdouble fraction;
+       gint radius;
+
+       fraction = gs_star_image_get_fraction (GS_STAR_IMAGE (widget));
+
+       gtk_widget_get_allocation (widget, &allocation);
+
+       radius = MIN (allocation.width, allocation.height) / 2;
+
+       if (radius > 0) {
+               GtkStyleContext *style_context;
+               GdkRGBA rgba;
+
+               style_context = gtk_widget_get_style_context (widget);
+               gtk_style_context_get_color (style_context,
+                                            gtk_style_context_get_state (style_context),
+                                            &rgba);
+
+               cairo_save (cr);
+               gdk_cairo_set_source_rgba (cr, &rgba);
+
+               cairo_save (cr);
+               gs_star_image_outline_star (cr, allocation.x, allocation.y, radius);
+               cairo_clip (cr);
+               cairo_rectangle (cr, -radius, -radius, 2 * radius * fraction, 2 * radius);
+               cairo_fill (cr);
+               cairo_restore (cr);
+
+               cairo_save (cr);
+               gs_star_image_outline_star (cr, allocation.x, allocation.y, radius);
+               cairo_set_antialias (cr, CAIRO_ANTIALIAS_SUBPIXEL);
+               cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
+               cairo_set_line_width (cr, 1);
+               cairo_stroke (cr);
+               cairo_restore (cr);
+
+               cairo_restore (cr);
+       }
+
+       return FALSE;
+}
+
+static void
+gs_star_image_class_init (GsStarImageClass *klass)
+{
+       GObjectClass *object_class;
+       GtkWidgetClass *widget_class;
+
+       object_class = G_OBJECT_CLASS (klass);
+       object_class->get_property = gs_star_image_get_property;
+       object_class->set_property = gs_star_image_set_property;
+
+       widget_class = GTK_WIDGET_CLASS (klass);
+       widget_class->draw = gs_star_image_draw;
+
+       g_object_class_install_property (object_class,
+                                        PROP_FRACTION,
+                                        g_param_spec_double ("fraction", NULL, NULL,
+                                                             0.0, 1.0, 1.0,
+                                                             G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
+}
+
+static void
+gs_star_image_init (GsStarImage *self)
+{
+       self->priv = gs_star_image_get_instance_private (self);
+       self->priv->fraction = 1.0;
+
+       gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
+       gtk_widget_set_size_request (GTK_WIDGET (self), 16, 16);
+}
+
+GtkWidget *
+gs_star_image_new (void)
+{
+       return g_object_new (GS_TYPE_STAR_IMAGE, NULL);
+}
+
+void
+gs_star_image_set_fraction (GsStarImage *self,
+                           gdouble fraction)
+{
+       g_return_if_fail (GS_IS_STAR_IMAGE (self));
+
+       if (self->priv->fraction == fraction)
+               return;
+
+       self->priv->fraction = fraction;
+
+       g_object_notify (G_OBJECT (self), "fraction");
+
+       gtk_widget_queue_draw (GTK_WIDGET (self));
+}
+
+gdouble
+gs_star_image_get_fraction (GsStarImage *self)
+{
+       g_return_val_if_fail (GS_IS_STAR_IMAGE (self), -1.0);
+
+       return self->priv->fraction;
+}
diff --git a/src/gs-star-image.h b/src/gs-star-image.h
new file mode 100644
index 000000000..b3c6d04a5
--- /dev/null
+++ b/src/gs-star-image.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ * vi:set noexpandtab tabstop=8 shiftwidth=8:
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_STAR_IMAGE             (gs_star_image_get_type ())
+#define GS_STAR_IMAGE(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GS_TYPE_STAR_IMAGE, GsStarImage))
+#define GS_STAR_IMAGE_CLASS(obj)       (G_TYPE_CHECK_CLASS_CAST ((obj), GS_TYPE_STAR_IMAGE,  
GsStarImageClass))
+#define GS_IS_STAR_IMAGE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GS_TYPE_STAR_IMAGE))
+#define GS_IS_STAR_IMAGE_CLASS(obj)    (G_TYPE_CHECK_CLASS_TYPE ((obj), GS_TYPE_STAR_IMAGE))
+#define GS_STAR_IMAGE_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GS_TYPE_STAR_IMAGE, 
GsStarImageClass))
+
+typedef struct _GsStarImagePrivate GsStarImagePrivate;
+
+typedef struct _GsStarImageClass {
+       GtkWidgetClass parent_class;
+} GsStarImageClass;
+
+typedef struct _GsStarImage {
+       GtkWidget parent;
+       GsStarImagePrivate *priv;
+} GsStarImage;
+
+GType          gs_star_image_get_type          (void) G_GNUC_CONST;
+GtkWidget *    gs_star_image_new               (void);
+void           gs_star_image_set_fraction      (GsStarImage *self,
+                                                gdouble fraction);
+gdouble                gs_star_image_get_fraction      (GsStarImage *self);
+
+G_END_DECLS
diff --git a/src/gs-star-widget.c b/src/gs-star-widget.c
index 4485af12f..560c40e19 100644
--- a/src/gs-star-widget.c
+++ b/src/gs-star-widget.c
@@ -12,6 +12,7 @@
 #include <math.h>
 
 #include "gs-common.h"
+#include "gs-star-image.h"
 #include "gs-star-widget.h"
 
 typedef struct
@@ -20,7 +21,7 @@ typedef struct
        gint             rating;
        guint            icon_size;
        GtkWidget       *box1;
-       GtkImage        *images[5];
+       GtkWidget       *images[5];
 } GsStarWidgetPrivate;
 
 G_DEFINE_TYPE_WITH_PRIVATE (GsStarWidget, gs_star_widget, GTK_TYPE_BIN)
@@ -94,15 +95,18 @@ gs_star_widget_refresh_rating (GsStarWidget *star)
 
        for (guint i = 0; i < G_N_ELEMENTS (priv->images); i++) {
                GtkWidget *im = GTK_WIDGET (priv->images[i]);
-               gboolean enabled;
-
-               /* add fudge factor so we can actually get 5 stars in reality */
-               enabled = priv->rating >= rate_to_star[i] - 10;
-
-               gtk_style_context_add_class (gtk_widget_get_style_context (im),
-                                            enabled ? "star-enabled" : "star-disabled");
-               gtk_style_context_remove_class (gtk_widget_get_style_context (im),
-                                               enabled ? "star-disabled" : "star-enabled");
+               gdouble fraction;
+
+               if (priv->rating >= rate_to_star[i])
+                       fraction = 1.0;
+               else if (!i)
+                       fraction = priv->rating / 20.0;
+               else if (priv->rating > rate_to_star[i - 1])
+                       fraction = (priv->rating - rate_to_star[i - 1]) / 20.0;
+               else
+                       fraction = 0.0;
+
+               gs_star_image_set_fraction (GS_STAR_IMAGE (im), fraction);
        }
 }
 
@@ -122,10 +126,11 @@ gs_star_widget_refresh (GsStarWidget *star)
                GtkWidget *im;
 
                /* create image */
-               im = gtk_image_new_from_icon_name ("starred-symbolic",
-                                                  GTK_ICON_SIZE_DIALOG);
-               gtk_image_set_pixel_size (GTK_IMAGE (im), (gint) priv->icon_size);
-               priv->images[i] = GTK_IMAGE (im);
+               im = gs_star_image_new ();
+               gtk_widget_set_size_request (im, (gint) priv->icon_size, (gint) priv->icon_size);
+               gtk_style_context_add_class (gtk_widget_get_style_context (im), "star-enabled");
+
+               priv->images[i] = im;
 
                /* create button */
                if (priv->interactive) {
@@ -274,7 +279,7 @@ gs_star_widget_class_init (GsStarWidgetClass *klass)
                                    "Icon Size",
                                    "Size of icons to use, in pixels",
                                    0, G_MAXUINT, 12,
-                                   G_PARAM_READWRITE);
+                                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
 
        /**
         * GsStarWidget:interactive:
diff --git a/src/meson.build b/src/meson.build
index 430eb0c4b..1ffd665b4 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -63,6 +63,7 @@ gnome_software_sources = [
   'gs-shell.c',
   'gs-shell-search-provider.c',
   'gs-sidebar.c',
+  'gs-star-image.c',
   'gs-star-widget.c',
   'gs-summary-tile.c',
   'gs-third-party-repo-row.c',


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