[gnome-software] Break out the popular tile as separate widget



commit a306cd89c5132a272bb9ef5cebc2e288cd8ccafd
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Sep 7 00:12:00 2013 -0400

    Break out the popular tile as separate widget
    
    At the same time, move all the construction code to a template.

 src/Makefile.am                  |    2 +
 src/gnome-software.gresource.xml |    1 +
 src/gs-popular-tile.c            |  174 ++++++++++++++++++++++++++++++++++++++
 src/gs-popular-tile.h            |   64 ++++++++++++++
 src/gs-shell-overview.c          |  101 ++--------------------
 src/popular-tile.ui              |   87 +++++++++++++++++++
 6 files changed, 338 insertions(+), 91 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index e248f4f..d6c089f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -39,6 +39,8 @@ gnome_software_SOURCES =                              \
        gs-category.h                                   \
        gs-app-widget.c                                 \
        gs-app-widget.h                                 \
+       gs-popular-tile.c                               \
+       gs-popular-tile.h                               \
        gs-box.h                                        \
        gs-box.c                                        \
        gs-plugin.c                                     \
diff --git a/src/gnome-software.gresource.xml b/src/gnome-software.gresource.xml
index 2c67dd9..c7964ad 100644
--- a/src/gnome-software.gresource.xml
+++ b/src/gnome-software.gresource.xml
@@ -3,6 +3,7 @@
  <gresource prefix="/org/gnome/software">
   <file preprocess="xml-stripblanks">gnome-software.ui</file>
   <file preprocess="xml-stripblanks">app-menu.ui</file>
+  <file preprocess="xml-stripblanks">popular-tile.ui</file>
   <file>gtk-style.css</file>
   <file>shadow.png</file>
   <file>shadow-active.png</file>
diff --git a/src/gs-popular-tile.c b/src/gs-popular-tile.c
new file mode 100644
index 0000000..fa73ab2
--- /dev/null
+++ b/src/gs-popular-tile.c
@@ -0,0 +1,174 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "gs-popular-tile.h"
+
+struct _GsPopularTilePrivate
+{
+       GsApp           *app;
+       GtkWidget       *button;
+       GtkWidget       *label;
+       GtkWidget       *image;
+       GtkWidget       *eventbox;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GsPopularTile, gs_popular_tile, GTK_TYPE_BIN)
+
+enum {
+       SIGNAL_CLICKED,
+       SIGNAL_LAST
+};
+
+static guint signals [SIGNAL_LAST] = { 0 };
+
+GsApp *
+gs_popular_tile_get_app (GsPopularTile *tile)
+{
+        GsPopularTilePrivate *priv;
+
+       g_return_val_if_fail (GS_IS_POPULAR_TILE (tile), NULL);
+
+        priv = gs_popular_tile_get_instance_private (tile);
+       return priv->app;
+}
+
+static gboolean
+transform_state_func (GBinding *binding,
+                      const GValue *source,
+                      GValue *target,
+                      gpointer user_data)
+{
+        GsAppState state;
+        gboolean installed;
+
+        state = g_value_get_uint (source);
+
+        switch (state) {
+        case GS_APP_STATE_INSTALLED:
+        case GS_APP_STATE_INSTALLING:
+        case GS_APP_STATE_REMOVING:
+        case GS_APP_STATE_UPDATABLE:
+                installed = TRUE;
+                break;
+        case GS_APP_STATE_AVAILABLE:
+        default:
+                installed = FALSE;
+                break;
+        }
+        g_value_set_boolean (target, installed);
+
+        return TRUE;
+}
+
+void
+gs_popular_tile_set_app (GsPopularTile *tile, GsApp *app)
+{
+        GsPopularTilePrivate *priv;
+
+       g_return_if_fail (GS_IS_POPULAR_TILE (tile));
+       g_return_if_fail (GS_IS_APP (app));
+
+        priv = gs_popular_tile_get_instance_private (tile);
+
+        g_clear_object (&priv->app);
+       priv->app = g_object_ref (app);
+
+        g_object_bind_property_full (priv->app, "state",
+                                     priv->eventbox, "visible",
+                                     G_BINDING_SYNC_CREATE,
+                                     transform_state_func,
+                                     NULL, NULL, NULL);
+
+        gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), gs_app_get_pixbuf (priv->app));
+
+        gtk_label_set_label (GTK_LABEL (priv->label), gs_app_get_name (app));
+}
+
+static void
+gs_popular_tile_destroy (GtkWidget *widget)
+{
+       GsPopularTile *tile = GS_POPULAR_TILE (widget);
+       GsPopularTilePrivate *priv;
+
+        priv = gs_popular_tile_get_instance_private (tile);
+
+       g_clear_object (&priv->app);
+
+       GTK_WIDGET_CLASS (gs_popular_tile_parent_class)->destroy (widget);
+}
+
+static void
+button_clicked (GsPopularTile *tile)
+{
+        g_signal_emit (tile, signals[SIGNAL_CLICKED], 0);
+}
+
+static void
+gs_popular_tile_init (GsPopularTile *tile)
+{
+        GsPopularTilePrivate *priv;
+
+        gtk_widget_set_has_window (GTK_WIDGET (tile), FALSE);
+        gtk_widget_init_template (GTK_WIDGET (tile));
+        priv = gs_popular_tile_get_instance_private (tile);
+        g_signal_connect_swapped (priv->button, "clicked",
+                                  G_CALLBACK (button_clicked), tile);
+}
+
+static void
+gs_popular_tile_class_init (GsPopularTileClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+       widget_class->destroy = gs_popular_tile_destroy;
+
+       signals [SIGNAL_CLICKED] =
+               g_signal_new ("clicked",
+                             G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+                             G_STRUCT_OFFSET (GsPopularTileClass, clicked),
+                             NULL, NULL, g_cclosure_marshal_VOID__VOID,
+                             G_TYPE_NONE, 0);
+
+        gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/software/popular-tile.ui");
+
+        gtk_widget_class_bind_template_child_private (widget_class, GsPopularTile, button);
+        gtk_widget_class_bind_template_child_private (widget_class, GsPopularTile, label);
+        gtk_widget_class_bind_template_child_private (widget_class, GsPopularTile, image);
+        gtk_widget_class_bind_template_child_private (widget_class, GsPopularTile, eventbox);
+}
+
+GtkWidget *
+gs_popular_tile_new (GsApp *app)
+{
+        GsPopularTile *tile;
+
+        tile = g_object_new (GS_TYPE_POPULAR_TILE, NULL);
+        gs_popular_tile_set_app (tile, app);
+
+        return GTK_WIDGET (tile);
+}
+
diff --git a/src/gs-popular-tile.h b/src/gs-popular-tile.h
new file mode 100644
index 0000000..b9afcc3
--- /dev/null
+++ b/src/gs-popular-tile.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef GS_POPULAR_TILE_H
+#define GS_POPULAR_TILE_H
+
+#include <gtk/gtk.h>
+
+#include "gs-app.h"
+
+#define GS_TYPE_POPULAR_TILE           (gs_popular_tile_get_type())
+#define GS_POPULAR_TILE(obj)           (G_TYPE_CHECK_INSTANCE_CAST((obj), GS_TYPE_POPULAR_TILE, 
GsPopularTile))
+#define GS_POPULAR_TILE_CLASS(cls)     (G_TYPE_CHECK_CLASS_CAST((cls), GS_TYPE_POPULAR_TILE, 
GsPopularTileClass))
+#define GS_IS_POPULAR_TILE(obj)                (G_TYPE_CHECK_INSTANCE_TYPE((obj), GS_TYPE_POPULAR_TILE))
+#define GS_IS_POPULAR_TILE_CLASS(cls)  (G_TYPE_CHECK_CLASS_TYPE((cls), GS_TYPE_POPULAR_TILE))
+#define GS_POPULAR_TILE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GS_TYPE_POPULAR_TILE, 
GsPopularTileClass))
+
+G_BEGIN_DECLS
+
+typedef struct _GsPopularTile                  GsPopularTile;
+typedef struct _GsPopularTileClass             GsPopularTileClass;
+typedef struct _GsPopularTilePrivate           GsPopularTilePrivate;
+
+struct _GsPopularTile
+{
+       GtkBin                   parent;
+       GsPopularTilePrivate    *priv;
+};
+
+struct _GsPopularTileClass
+{
+       GtkBinClass              parent_class;
+
+       void                    (*clicked)      (GsPopularTile  *popular_tile);
+};
+
+GType           gs_popular_tile_get_type               (void);
+GtkWidget      *gs_popular_tile_new                    (GsApp *app);
+GsApp          *gs_popular_tile_get_app                (GsPopularTile  *popular_tile);
+void            gs_popular_tile_set_app                (GsPopularTile  *popular_tile,
+                                                        GsApp          *app);
+
+G_END_DECLS
+
+#endif /* GS_POPULAR_TILE_H */
+
diff --git a/src/gs-shell-overview.c b/src/gs-shell-overview.c
index 771b068..6aa7a18 100644
--- a/src/gs-shell-overview.c
+++ b/src/gs-shell-overview.c
@@ -27,7 +27,7 @@
 #include "gs-shell-overview.h"
 #include "gs-app.h"
 #include "gs-category.h"
-#include "gs-app-widget.h"
+#include "gs-popular-tile.h"
 #include "gs-utils.h"
 
 static void    gs_shell_overview_finalize      (GObject        *object);
@@ -83,97 +83,14 @@ app_tile_clicked (GtkButton *button, gpointer data)
         gs_shell_show_app (shell_overview->priv->shell, app);
 }
 
-static gboolean
-transform_state_func (GBinding *binding,
-                      const GValue *source,
-                      GValue *target,
-                      gpointer user_data)
-{
-        GsAppState state;
-        gboolean installed;
-
-        state = g_value_get_uint (source);
-
-        switch (state) {
-        case GS_APP_STATE_INSTALLED:
-        case GS_APP_STATE_INSTALLING:
-        case GS_APP_STATE_REMOVING:
-        case GS_APP_STATE_UPDATABLE:
-                installed = TRUE;
-                break;
-        case GS_APP_STATE_AVAILABLE:
-        default:
-                installed = FALSE;
-                break;
-        }
-        g_value_set_boolean (target, installed);
-
-        return TRUE;
-}
-
-static GtkWidget *
-create_popular_tile (GsShellOverview *shell_overview, GsApp *app)
+static void
+popular_tile_clicked (GsPopularTile *tile, gpointer data)
 {
-       GtkWidget *button, *frame, *box, *image, *label;
-       GtkWidget *overlay, *ebox;
-
-       frame = gtk_aspect_frame_new (NULL, 0.5, 0, 1, FALSE);
-       gtk_widget_set_valign (frame, GTK_ALIGN_START);
-       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
-        gtk_widget_set_size_request (frame, -1, 180);
-       button = gtk_button_new ();
-       gtk_style_context_add_class (gtk_widget_get_style_context (button), "view");
-       gtk_style_context_add_class (gtk_widget_get_style_context (button), "tile");
-       gtk_widget_set_halign (button, GTK_ALIGN_FILL);
-       gtk_widget_set_valign (button, GTK_ALIGN_FILL);
-        overlay = gtk_overlay_new ();
-       gtk_widget_set_halign (overlay, GTK_ALIGN_FILL);
-       gtk_widget_set_valign (overlay, GTK_ALIGN_FILL);
-        ebox = gtk_event_box_new ();
-        gtk_widget_set_no_show_all (ebox, TRUE);
-        g_object_bind_property_full (app, "state",
-                                     ebox, "visible",
-                                     G_BINDING_SYNC_CREATE,
-                                     transform_state_func,
-                                     NULL, NULL, NULL);
-        gtk_overlay_add_overlay (GTK_OVERLAY (overlay), ebox);
-        gtk_event_box_set_visible_window (GTK_EVENT_BOX (ebox), TRUE);
-        gtk_style_context_add_class (gtk_widget_get_style_context (ebox), "installed-overlay-box");
-        gtk_widget_set_halign (ebox, GTK_ALIGN_END);
-        gtk_widget_set_valign (ebox, GTK_ALIGN_END);
-        gtk_widget_set_margin_bottom (ebox, 35);
-
-        label = gtk_label_new (_("Installed"));
-        gtk_widget_show (label);
-        gtk_container_add (GTK_CONTAINER (ebox), label);
-        gtk_style_context_add_class (gtk_widget_get_style_context (label), "installed-overlay-label");
-        gtk_widget_set_margin_left (label, 16);
-        gtk_widget_set_margin_right (label, 16);
-        gtk_widget_set_margin_top (label, 4);
-        gtk_widget_set_margin_bottom (label, 4);
-
-       gtk_container_add (GTK_CONTAINER (button), overlay);
-       box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-       gtk_container_add (GTK_CONTAINER (overlay), box);
-       gtk_widget_set_valign (box, GTK_ALIGN_FILL);
-       image = gtk_image_new_from_pixbuf (gs_app_get_pixbuf (app));
-       gtk_widget_set_valign (image, GTK_ALIGN_CENTER);
-       g_object_set (box, "margin", 12, NULL);
-       gtk_box_pack_start (GTK_BOX (box), image, TRUE, TRUE, 0);
-       label = gtk_label_new (gs_app_get_name (app));
-        gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
-        gtk_label_set_width_chars (GTK_LABEL (label), 10);
-        gtk_label_set_max_width_chars (GTK_LABEL (label), 15);
-       gtk_widget_set_valign (label, GTK_ALIGN_END);
-       g_object_set (label, "margin", 6, NULL);
-       gtk_box_pack_start (GTK_BOX (box), label, FALSE, TRUE, 0);
-       gtk_container_add (GTK_CONTAINER (frame), button);
-       gtk_widget_show_all (frame);
-       g_object_set_data_full (G_OBJECT (button), "app", g_object_ref (app), g_object_unref);
-       g_signal_connect (button, "clicked",
-                         G_CALLBACK (app_tile_clicked), shell_overview);
+       GsShellOverview *shell = GS_SHELL_OVERVIEW (data);
+       GsApp *app;
 
-       return frame;
+       app = gs_popular_tile_get_app (tile);
+        gs_shell_show_app (shell->priv->shell, app);
 }
 
 /**
@@ -208,7 +125,9 @@ gs_shell_overview_get_popular_cb (GObject *source_object,
        grid = GTK_WIDGET (gtk_builder_get_object (priv->builder, "box_popular"));
        for (l = list, i = 0; l != NULL && i < 6; l = l->next, i++) {
                app = GS_APP (l->data);
-               tile = create_popular_tile (shell_overview, app);
+               tile = gs_popular_tile_new (app);
+               g_signal_connect (tile, "clicked",
+                         G_CALLBACK (popular_tile_clicked), shell_overview);
                 gtk_box_pack_start (GTK_BOX (grid), tile, TRUE, TRUE, 0);
        }
 out:
diff --git a/src/popular-tile.ui b/src/popular-tile.ui
new file mode 100644
index 0000000..a2d7f81
--- /dev/null
+++ b/src/popular-tile.ui
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.10 -->
+  <template class="GsPopularTile" parent="GtkBin">
+    <property name="visible">True</property>
+    <child>
+      <object class="GtkAspectFrame" id="frame">
+        <property name="visible">True</property>
+        <property name="valign">start</property>
+        <property name="shadow_type">none</property>
+        <property name="height_request">180</property>
+        <child>
+          <object class="GtkButton" id="button">
+            <property name="visible">True</property>
+            <property name="halign">fill</property>
+            <property name="valign">fill</property>
+            <style>
+              <class name="view"/>
+              <class name="tile"/>
+            </style>
+            <child>
+              <object class="GtkOverlay" id="overlay">
+                <property name="visible">True</property>
+                <property name="halign">fill</property>
+                <property name="valign">fill</property>
+                <child type="overlay">
+                  <object class="GtkEventBox" id="eventbox">
+                    <property name="no_show_all">True</property>
+                    <property name="visible_window">True</property>
+                    <property name="halign">end</property>
+                    <property name="valign">end</property>
+                    <property name="margin-bottom">35</property>
+                    <style>
+                      <class name="installed-overlay-box"/>
+                    </style>
+                    <child>
+                      <object class="GtkLabel" id="installed-label">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Installed</property>
+                        <property name="margin-left">16</property>
+                        <property name="margin-right">16</property>
+                        <property name="margin-top">4</property>
+                        <property name="margin-bottom">4</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkBox" id="box">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <property name="valign">fill</property>
+                    <property name="margin">12</property>
+                    <child>
+                      <object class="GtkImage" id="image">
+                        <property name="visible">True</property>
+                        <property name="valign">center</property>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label">
+                        <property name="visible">True</property>
+                        <property name="valign">end</property>
+                        <property name="margin">6</property>
+                        <property name="ellipsize">end</property>
+                        <property name="width_chars">10</property>
+                        <property name="max_width_chars">15</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>


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