[gnome-software] Make the GsAppTile an abstract class
- From: Joaquim Manuel Pereira Rocha <jrocha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Make the GsAppTile an abstract class
- Date: Thu, 23 Jun 2016 13:48:41 +0000 (UTC)
commit 5dc0a4e7df88ada338c0a07c4bd47cb4f3ebb8c6
Author: Joaquim Rocha <jrocha endlessm com>
Date: Thu Jun 23 13:31:15 2016 +0200
Make the GsAppTile an abstract class
These changes make the GsAppTile an abstract class and move its former
functionality to a new class called GsSummaryTile.
The reason for the change is that all app tiles should extend this
class, allowing for a more more abstract code which simplifies the use
of different app tiles in the future.
src/Makefile.am | 4 +-
src/gnome-software.gresource.xml | 2 +-
src/gs-app-tile.c | 271 ++------------------------------
src/gs-app-tile.h | 13 ++-
src/gs-popular-tile.c | 21 ++-
src/gs-shell-category.c | 6 +-
src/gs-summary-tile.c | 321 ++++++++++++++++++++++++++++++++++++++
src/gs-summary-tile.h | 42 +++++
src/gs-summary-tile.ui | 131 ++++++++++++++++
9 files changed, 543 insertions(+), 268 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 86e2e7b..dae7135 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -48,7 +48,7 @@ UI_FILES = \
gs-app-addon-row.ui \
gs-app-folder-dialog.ui \
gs-app-row.ui \
- gs-app-tile.ui \
+ gs-summary-tile.ui \
gs-auth-dialog.ui \
gs-category-tile.ui \
gs-feature-tile.ui \
@@ -166,6 +166,8 @@ gnome_software_SOURCES = \
gs-category-tile.h \
gs-app-tile.c \
gs-app-tile.h \
+ gs-summary-tile.c \
+ gs-summary-tile.h \
gs-app-folder-dialog.c \
gs-app-folder-dialog.h \
gs-first-run-dialog.c \
diff --git a/src/gnome-software.gresource.xml b/src/gnome-software.gresource.xml
index 23a127a..d3a9391 100644
--- a/src/gnome-software.gresource.xml
+++ b/src/gnome-software.gresource.xml
@@ -6,7 +6,7 @@
<file preprocess="xml-stripblanks">gs-app-addon-row.ui</file>
<file preprocess="xml-stripblanks">gs-app-folder-dialog.ui</file>
<file preprocess="xml-stripblanks">gs-app-row.ui</file>
- <file preprocess="xml-stripblanks">gs-app-tile.ui</file>
+ <file preprocess="xml-stripblanks">gs-summary-tile.ui</file>
<file preprocess="xml-stripblanks">gs-auth-dialog.ui</file>
<file preprocess="xml-stripblanks">gs-category-tile.ui</file>
<file preprocess="xml-stripblanks">gs-feature-tile.ui</file>
diff --git a/src/gs-app-tile.c b/src/gs-app-tile.c
index 4841c22..81912cd 100644
--- a/src/gs-app-tile.c
+++ b/src/gs-app-tile.c
@@ -28,285 +28,50 @@
#include "gs-star-widget.h"
#include "gs-common.h"
-struct _GsAppTile
-{
- GtkButton parent_instance;
-
- GsApp *app;
- GtkWidget *image;
- GtkWidget *name;
- GtkWidget *summary;
- GtkWidget *eventbox;
- GtkWidget *stack;
- gint preferred_width;
-};
-
-G_DEFINE_TYPE (GsAppTile, gs_app_tile, GTK_TYPE_BUTTON)
-
-enum {
- PROP_0,
- PROP_PREFERRED_WIDTH
-};
+G_DEFINE_ABSTRACT_TYPE (GsAppTile, gs_app_tile, GTK_TYPE_BUTTON)
GsApp *
gs_app_tile_get_app (GsAppTile *tile)
{
- g_return_val_if_fail (GS_IS_APP_TILE (tile), NULL);
-
- return tile->app;
-}
-
-static gboolean
-app_state_changed_idle (gpointer user_data)
-{
- GsAppTile *tile = GS_APP_TILE (user_data);
- AtkObject *accessible;
- GtkWidget *label;
- gboolean installed;
- g_autofree gchar *name = NULL;
-
- accessible = gtk_widget_get_accessible (GTK_WIDGET (tile));
-
- label = gtk_bin_get_child (GTK_BIN (tile->eventbox));
- switch (gs_app_get_state (tile->app)) {
- case AS_APP_STATE_INSTALLED:
- case AS_APP_STATE_UPDATABLE:
- case AS_APP_STATE_UPDATABLE_LIVE:
- installed = TRUE;
- name = g_strdup_printf ("%s (%s)",
- gs_app_get_name (tile->app),
- _("Installed"));
- /* TRANSLATORS: this is the small blue label on the tile
- * that tells the user the application is installed */
- gtk_label_set_label (GTK_LABEL (label), _("Installed"));
- break;
- case AS_APP_STATE_INSTALLING:
- installed = TRUE;
- name = g_strdup_printf ("%s (%s)",
- gs_app_get_name (tile->app),
- _("Installing"));
- /* TRANSLATORS: this is the small blue label on the tile
- * that tells the user the application is being installed */
- gtk_label_set_label (GTK_LABEL (label), _("Installing"));
- break;
- case AS_APP_STATE_REMOVING:
- installed = TRUE;
- name = g_strdup_printf ("%s (%s)",
- gs_app_get_name (tile->app),
- _("Removing"));
- /* TRANSLATORS: this is the small blue label on the tile
- * that tells the user the application is being removed */
- gtk_label_set_label (GTK_LABEL (label), _("Removing"));
- break;
- case AS_APP_STATE_QUEUED_FOR_INSTALL:
- case AS_APP_STATE_AVAILABLE:
- default:
- installed = FALSE;
- name = g_strdup (gs_app_get_name (tile->app));
- break;
- }
+ GsAppTileClass *klass;
- gtk_widget_set_visible (tile->eventbox, installed);
+ g_return_val_if_fail (GS_IS_APP_TILE (tile), NULL);
- if (GTK_IS_ACCESSIBLE (accessible)) {
- atk_object_set_name (accessible, name);
- atk_object_set_description (accessible, gs_app_get_summary (tile->app));
- }
+ klass = GS_APP_TILE_GET_CLASS (tile);
+ g_assert (klass->get_app);
- g_object_unref (tile);
- return G_SOURCE_REMOVE;
-}
-
-static void
-app_state_changed (GsApp *app, GParamSpec *pspec, GsAppTile *tile)
-{
- g_idle_add (app_state_changed_idle, g_object_ref (tile));
+ return klass->get_app(tile);
}
void
gs_app_tile_set_app (GsAppTile *tile, GsApp *app)
{
- const GdkPixbuf *pixbuf;
- g_autofree gchar *text = NULL;
+ GsAppTileClass *klass;
g_return_if_fail (GS_IS_APP_TILE (tile));
- g_return_if_fail (GS_IS_APP (app) || app == NULL);
-
- gtk_image_clear (GTK_IMAGE (tile->image));
- gtk_image_set_pixel_size (GTK_IMAGE (tile->image), 64);
-
- if (tile->app)
- g_signal_handlers_disconnect_by_func (tile->app, app_state_changed, tile);
-
- g_set_object (&tile->app, app);
- if (!app)
- return;
-
- gtk_stack_set_visible_child_name (GTK_STACK (tile->stack), "content");
-
- g_signal_connect (tile->app, "notify::state",
- G_CALLBACK (app_state_changed), tile);
- app_state_changed (tile->app, NULL, tile);
-
- pixbuf = gs_app_get_pixbuf (app);
- if (pixbuf != NULL)
- gs_image_set_from_pixbuf (GTK_IMAGE (tile->image), pixbuf);
- gtk_label_set_label (GTK_LABEL (tile->name), gs_app_get_name (app));
-
- /* perhaps set custom css */
- gs_utils_widget_set_css_app (app, GTK_WIDGET (tile),
- "GnomeSoftware::AppTile-css");
-
- /* some kinds have boring summaries */
- switch (gs_app_get_kind (app)) {
- case AS_APP_KIND_SHELL_EXTENSION:
- text = g_strdup (gs_app_get_description (app));
- g_strdelimit (text, "\n\t", ' ');
- break;
- default:
- text = g_strdup (gs_app_get_summary (app));
- break;
- }
-
- gtk_label_set_label (GTK_LABEL (tile->summary), text);
- gtk_widget_set_visible (tile->summary, text && text[0]);
-}
-
-static void
-gs_app_tile_destroy (GtkWidget *widget)
-{
- GsAppTile *tile = GS_APP_TILE (widget);
+ g_return_if_fail (!app || GS_IS_APP (app));
- if (tile->app)
- g_signal_handlers_disconnect_by_func (tile->app, app_state_changed, tile);
- g_clear_object (&tile->app);
+ klass = GS_APP_TILE_GET_CLASS (tile);
+ g_assert (klass->get_app);
- GTK_WIDGET_CLASS (gs_app_tile_parent_class)->destroy (widget);
+ klass->set_app(tile, app);
}
-static void
-gs_app_tile_init (GsAppTile *tile)
-{
- gtk_widget_set_has_window (GTK_WIDGET (tile), FALSE);
- tile->preferred_width = -1;
- gtk_widget_init_template (GTK_WIDGET (tile));
-}
-
-static void
-gs_app_tile_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- GsAppTile *app_tile = GS_APP_TILE (object);
-
- switch (prop_id) {
- case PROP_PREFERRED_WIDTH:
- g_value_set_int (value, app_tile->preferred_width);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gs_app_tile_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- GsAppTile *app_tile = GS_APP_TILE (object);
-
- switch (prop_id) {
- case PROP_PREFERRED_WIDTH:
- app_tile->preferred_width = g_value_get_int (value);
- gtk_widget_queue_resize (GTK_WIDGET (app_tile));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gs_app_get_preferred_width (GtkWidget *widget,
- gint *min, gint *nat)
-{
-#if GTK_CHECK_VERSION(3,20,0)
- gint m;
-#else
- gint m, n;
-#endif
- GsAppTile *app_tile = GS_APP_TILE (widget);
-
- if (app_tile->preferred_width < 0) {
- /* Just retrieve the default values */
- GTK_WIDGET_CLASS (gs_app_tile_parent_class)->get_preferred_width (widget, min, nat);
- return;
- }
-
-/* It's because of some bugs in gtkbutton.c 3.18 and before.
- * We can remove this when we branch for 3.20 *and* require GTK 3.20. */
-#if GTK_CHECK_VERSION(3,20,0)
- GTK_WIDGET_CLASS (gs_app_tile_parent_class)->get_preferred_width (widget, &m, NULL);
-#else
- GTK_WIDGET_CLASS (gs_app_tile_parent_class)->get_preferred_width (widget, &m, &n);
-#endif
-
- if (min != NULL)
- *min = m;
- if (nat != NULL)
- *nat = MAX (m, app_tile->preferred_width);
-}
-
-static void
+void
gs_app_tile_class_init (GsAppTileClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-
- object_class->get_property = gs_app_tile_get_property;
- object_class->set_property = gs_app_tile_set_property;
+{}
- widget_class->destroy = gs_app_tile_destroy;
- widget_class->get_preferred_width = gs_app_get_preferred_width;
-
- /**
- * GsAppTile:preferred-width:
- *
- * The only purpose of this property is to be retrieved as the
- * natural width by gtk_widget_get_preferred_width() fooling the
- * parent #GtkFlowBox container and making it switch to more columns
- * (children per row) if it is able to place n+1 children in a row
- * having this specified width. If this value is less than a minimum
- * width of this app tile then the minimum is returned instead. Set
- * this property to -1 to turn off this feature and return the default
- * natural width instead.
- */
- g_object_class_install_property (object_class, PROP_PREFERRED_WIDTH,
- g_param_spec_int ("preferred-width",
- "Preferred width",
- "The preferred width of this widget, its only purpose is to trick the
parent container",
- -1, G_MAXINT, -1,
- G_PARAM_READWRITE));
-
- gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Software/gs-app-tile.ui");
-
- gtk_widget_class_bind_template_child (widget_class, GsAppTile, image);
- gtk_widget_class_bind_template_child (widget_class, GsAppTile, name);
- gtk_widget_class_bind_template_child (widget_class, GsAppTile, summary);
- gtk_widget_class_bind_template_child (widget_class, GsAppTile, eventbox);
- gtk_widget_class_bind_template_child (widget_class, GsAppTile, stack);
-}
+void
+gs_app_tile_init (GsAppTile *tile)
+{}
GtkWidget *
-gs_app_tile_new (GsApp *cat)
+gs_app_tile_new (GsApp *app)
{
GsAppTile *tile;
tile = g_object_new (GS_TYPE_APP_TILE, NULL);
- gs_app_tile_set_app (tile, cat);
+ gs_app_tile_set_app (tile, app);
return GTK_WIDGET (tile);
}
diff --git a/src/gs-app-tile.h b/src/gs-app-tile.h
index e089275..8b22aff 100644
--- a/src/gs-app-tile.h
+++ b/src/gs-app-tile.h
@@ -30,9 +30,18 @@ G_BEGIN_DECLS
#define GS_TYPE_APP_TILE (gs_app_tile_get_type ())
-G_DECLARE_FINAL_TYPE (GsAppTile, gs_app_tile, GS, APP_TILE, GtkButton)
+G_DECLARE_DERIVABLE_TYPE (GsAppTile, gs_app_tile, GS, APP_TILE, GtkButton)
-GtkWidget *gs_app_tile_new (GsApp *app);
+struct _GsAppTileClass
+{
+ GtkButtonClass parent_class;
+
+ void (*set_app) (GsAppTile *tile,
+ GsApp *app);
+ GsApp *(*get_app) (GsAppTile *tile);
+};
+
+GtkWidget *gs_app_tile_new (GsApp *app);
GsApp *gs_app_tile_get_app (GsAppTile *tile);
void gs_app_tile_set_app (GsAppTile *tile,
GsApp *cat);
diff --git a/src/gs-popular-tile.c b/src/gs-popular-tile.c
index 5a5e893..341251f 100644
--- a/src/gs-popular-tile.c
+++ b/src/gs-popular-tile.c
@@ -40,12 +40,12 @@ struct _GsPopularTile
GtkWidget *stars;
};
-G_DEFINE_TYPE (GsPopularTile, gs_popular_tile, GTK_TYPE_BUTTON)
+G_DEFINE_TYPE (GsPopularTile, gs_popular_tile, GS_TYPE_APP_TILE)
-GsApp *
-gs_popular_tile_get_app (GsPopularTile *tile)
+static GsApp *
+gs_popular_tile_get_app (GsAppTile *app_tile)
{
- g_return_val_if_fail (GS_IS_POPULAR_TILE (tile), NULL);
+ GsPopularTile *tile = GS_POPULAR_TILE (app_tile);
return tile->app;
}
@@ -100,10 +100,11 @@ app_state_changed (GsApp *app, GParamSpec *pspec, GsPopularTile *tile)
g_idle_add (app_state_changed_idle, g_object_ref (tile));
}
-void
-gs_popular_tile_set_app (GsPopularTile *tile, GsApp *app)
+static void
+gs_popular_tile_set_app (GsAppTile *app_tile, GsApp *app)
{
- g_return_if_fail (GS_IS_POPULAR_TILE (tile));
+ GsPopularTile *tile = GS_POPULAR_TILE (app_tile);
+
g_return_if_fail (GS_IS_APP (app) || app == NULL);
if (tile->app)
@@ -160,9 +161,13 @@ static void
gs_popular_tile_class_init (GsPopularTileClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GsAppTileClass *app_tile_class = GS_APP_TILE_CLASS (klass);
widget_class->destroy = gs_popular_tile_destroy;
+ app_tile_class->set_app = gs_popular_tile_set_app;
+ app_tile_class->get_app = gs_popular_tile_get_app;
+
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Software/gs-popular-tile.ui");
gtk_widget_class_bind_template_child (widget_class, GsPopularTile, label);
@@ -178,7 +183,7 @@ gs_popular_tile_new (GsApp *app)
GsPopularTile *tile;
tile = g_object_new (GS_TYPE_POPULAR_TILE, NULL);
- gs_popular_tile_set_app (tile, app);
+ gs_app_tile_set_app (GS_APP_TILE (tile), app);
return GTK_WIDGET (tile);
}
diff --git a/src/gs-shell-category.c b/src/gs-shell-category.c
index 92cb1e9..c40bc14 100644
--- a/src/gs-shell-category.c
+++ b/src/gs-shell-category.c
@@ -26,7 +26,7 @@
#include <glib/gi18n.h>
#include "gs-common.h"
-#include "gs-app-tile.h"
+#include "gs-summary-tile.h"
#include "gs-shell-category.h"
struct _GsShellCategory
@@ -101,7 +101,7 @@ gs_shell_category_get_apps_cb (GObject *source_object,
for (i = 0; i < gs_app_list_length (list); i++) {
app = gs_app_list_index (list, i);
- tile = gs_app_tile_new (app);
+ tile = gs_summary_tile_new (app);
g_signal_connect (tile, "clicked",
G_CALLBACK (app_tile_clicked), self);
gtk_container_add (GTK_CONTAINER (self->category_detail_box), tile);
@@ -140,7 +140,7 @@ gs_shell_category_reload (GsPage *page)
gs_container_remove_all (GTK_CONTAINER (self->category_detail_box));
count = MIN(30, gs_category_get_size (self->subcategory));
for (i = 0; i < count; i++) {
- tile = gs_app_tile_new (NULL);
+ tile = gs_summary_tile_new (NULL);
gtk_container_add (GTK_CONTAINER (self->category_detail_box), tile);
gtk_widget_set_can_focus (gtk_widget_get_parent (tile), FALSE);
}
diff --git a/src/gs-summary-tile.c b/src/gs-summary-tile.c
new file mode 100644
index 0000000..4454655
--- /dev/null
+++ b/src/gs-summary-tile.c
@@ -0,0 +1,321 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Matthias Clasen <mclasen redhat 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-summary-tile.h"
+#include "gs-star-widget.h"
+#include "gs-common.h"
+
+struct _GsSummaryTile
+{
+ GsAppTile parent_instance;
+
+ GsApp *app;
+ GtkWidget *image;
+ GtkWidget *name;
+ GtkWidget *summary;
+ GtkWidget *eventbox;
+ GtkWidget *stack;
+ gint preferred_width;
+};
+
+G_DEFINE_TYPE (GsSummaryTile, gs_summary_tile, GS_TYPE_APP_TILE)
+
+enum {
+ PROP_0,
+ PROP_PREFERRED_WIDTH
+};
+
+static GsApp *
+gs_summary_tile_get_app (GsAppTile *tile)
+{
+ return GS_SUMMARY_TILE (tile)->app;
+}
+
+static gboolean
+app_state_changed_idle (gpointer user_data)
+{
+ GsSummaryTile *tile = GS_SUMMARY_TILE (user_data);
+ AtkObject *accessible;
+ GtkWidget *label;
+ gboolean installed;
+ g_autofree gchar *name = NULL;
+
+ accessible = gtk_widget_get_accessible (GTK_WIDGET (tile));
+
+ label = gtk_bin_get_child (GTK_BIN (tile->eventbox));
+ switch (gs_app_get_state (tile->app)) {
+ case AS_APP_STATE_INSTALLED:
+ case AS_APP_STATE_UPDATABLE:
+ case AS_APP_STATE_UPDATABLE_LIVE:
+ installed = TRUE;
+ name = g_strdup_printf ("%s (%s)",
+ gs_app_get_name (tile->app),
+ _("Installed"));
+ /* TRANSLATORS: this is the small blue label on the tile
+ * that tells the user the application is installed */
+ gtk_label_set_label (GTK_LABEL (label), _("Installed"));
+ break;
+ case AS_APP_STATE_INSTALLING:
+ installed = TRUE;
+ name = g_strdup_printf ("%s (%s)",
+ gs_app_get_name (tile->app),
+ _("Installing"));
+ /* TRANSLATORS: this is the small blue label on the tile
+ * that tells the user the application is being installed */
+ gtk_label_set_label (GTK_LABEL (label), _("Installing"));
+ break;
+ case AS_APP_STATE_REMOVING:
+ installed = TRUE;
+ name = g_strdup_printf ("%s (%s)",
+ gs_app_get_name (tile->app),
+ _("Removing"));
+ /* TRANSLATORS: this is the small blue label on the tile
+ * that tells the user the application is being removed */
+ gtk_label_set_label (GTK_LABEL (label), _("Removing"));
+ break;
+ case AS_APP_STATE_QUEUED_FOR_INSTALL:
+ case AS_APP_STATE_AVAILABLE:
+ default:
+ installed = FALSE;
+ name = g_strdup (gs_app_get_name (tile->app));
+ break;
+ }
+
+ gtk_widget_set_visible (tile->eventbox, installed);
+
+ if (GTK_IS_ACCESSIBLE (accessible)) {
+ atk_object_set_name (accessible, name);
+ atk_object_set_description (accessible, gs_app_get_summary (tile->app));
+ }
+
+ g_object_unref (tile);
+ return G_SOURCE_REMOVE;
+}
+
+static void
+app_state_changed (GsApp *app, GParamSpec *pspec, GsSummaryTile *tile)
+{
+ g_idle_add (app_state_changed_idle, g_object_ref (tile));
+}
+
+static void
+gs_summary_tile_set_app (GsAppTile *app_tile, GsApp *app)
+{
+ const GdkPixbuf *pixbuf;
+ GsSummaryTile *tile = GS_SUMMARY_TILE (app_tile);
+ g_autofree gchar *text = NULL;
+
+ g_return_if_fail (GS_IS_APP (app) || app == NULL);
+
+ gtk_image_clear (GTK_IMAGE (tile->image));
+ gtk_image_set_pixel_size (GTK_IMAGE (tile->image), 64);
+
+ if (tile->app)
+ g_signal_handlers_disconnect_by_func (tile->app, app_state_changed, tile);
+
+ g_set_object (&tile->app, app);
+ if (!app)
+ return;
+
+ gtk_stack_set_visible_child_name (GTK_STACK (tile->stack), "content");
+
+ g_signal_connect (tile->app, "notify::state",
+ G_CALLBACK (app_state_changed), tile);
+ app_state_changed (tile->app, NULL, tile);
+
+ pixbuf = gs_app_get_pixbuf (app);
+ if (pixbuf != NULL)
+ gs_image_set_from_pixbuf (GTK_IMAGE (tile->image), pixbuf);
+ gtk_label_set_label (GTK_LABEL (tile->name), gs_app_get_name (app));
+
+ /* perhaps set custom css */
+ gs_utils_widget_set_css_app (app, GTK_WIDGET (tile),
+ "GnomeSoftware::AppTile-css");
+
+ /* some kinds have boring summaries */
+ switch (gs_app_get_kind (app)) {
+ case AS_APP_KIND_SHELL_EXTENSION:
+ text = g_strdup (gs_app_get_description (app));
+ g_strdelimit (text, "\n\t", ' ');
+ break;
+ default:
+ text = g_strdup (gs_app_get_summary (app));
+ break;
+ }
+
+ gtk_label_set_label (GTK_LABEL (tile->summary), text);
+ gtk_widget_set_visible (tile->summary, text && text[0]);
+}
+
+static void
+gs_summary_tile_destroy (GtkWidget *widget)
+{
+ GsSummaryTile *tile = GS_SUMMARY_TILE (widget);
+
+ if (tile->app)
+ g_signal_handlers_disconnect_by_func (tile->app, app_state_changed, tile);
+ g_clear_object (&tile->app);
+
+ GTK_WIDGET_CLASS (gs_summary_tile_parent_class)->destroy (widget);
+}
+
+static void
+gs_summary_tile_init (GsSummaryTile *tile)
+{
+ gtk_widget_set_has_window (GTK_WIDGET (tile), FALSE);
+ tile->preferred_width = -1;
+ gtk_widget_init_template (GTK_WIDGET (tile));
+}
+
+static void
+gs_summary_tile_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GsSummaryTile *app_tile = GS_SUMMARY_TILE (object);
+
+ switch (prop_id) {
+ case PROP_PREFERRED_WIDTH:
+ g_value_set_int (value, app_tile->preferred_width);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gs_summary_tile_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GsSummaryTile *app_tile = GS_SUMMARY_TILE (object);
+
+ switch (prop_id) {
+ case PROP_PREFERRED_WIDTH:
+ app_tile->preferred_width = g_value_get_int (value);
+ gtk_widget_queue_resize (GTK_WIDGET (app_tile));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gs_app_get_preferred_width (GtkWidget *widget,
+ gint *min, gint *nat)
+{
+#if GTK_CHECK_VERSION(3,20,0)
+ gint m;
+#else
+ gint m, n;
+#endif
+ GsSummaryTile *app_tile = GS_SUMMARY_TILE (widget);
+
+ if (app_tile->preferred_width < 0) {
+ /* Just retrieve the default values */
+ GTK_WIDGET_CLASS (gs_summary_tile_parent_class)->get_preferred_width (widget, min, nat);
+ return;
+ }
+
+ /* It's because of some bugs in gtkbutton.c 3.18 and before.
+ * We can remove this when we branch for 3.20 *and* require GTK 3.20. */
+#if GTK_CHECK_VERSION(3,20,0)
+ GTK_WIDGET_CLASS (gs_summary_tile_parent_class)->get_preferred_width (widget, &m, NULL);
+#else
+ GTK_WIDGET_CLASS (gs_summary_tile_parent_class)->get_preferred_width (widget, &m, &n);
+#endif
+
+ if (min != NULL)
+ *min = m;
+ if (nat != NULL)
+ *nat = MAX (m, app_tile->preferred_width);
+}
+
+static void
+gs_summary_tile_class_init (GsSummaryTileClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GsAppTileClass *tile_class = GS_APP_TILE_CLASS (klass);
+
+ object_class->get_property = gs_summary_tile_get_property;
+ object_class->set_property = gs_summary_tile_set_property;
+
+ widget_class->destroy = gs_summary_tile_destroy;
+ widget_class->get_preferred_width = gs_app_get_preferred_width;
+
+ tile_class->set_app = gs_summary_tile_set_app;
+ tile_class->get_app = gs_summary_tile_get_app;
+
+ /**
+ * GsAppTile:preferred-width:
+ *
+ * The only purpose of this property is to be retrieved as the
+ * natural width by gtk_widget_get_preferred_width() fooling the
+ * parent #GtkFlowBox container and making it switch to more columns
+ * (children per row) if it is able to place n+1 children in a row
+ * having this specified width. If this value is less than a minimum
+ * width of this app tile then the minimum is returned instead. Set
+ * this property to -1 to turn off this feature and return the default
+ * natural width instead.
+ */
+ g_object_class_install_property (object_class, PROP_PREFERRED_WIDTH,
+ g_param_spec_int ("preferred-width",
+ "Preferred width",
+ "The preferred width of this widget, its only
purpose is to trick the parent container",
+ -1, G_MAXINT, -1,
+ G_PARAM_READWRITE));
+
+ gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Software/gs-summary-tile.ui");
+
+ gtk_widget_class_bind_template_child (widget_class, GsSummaryTile,
+ image);
+ gtk_widget_class_bind_template_child (widget_class, GsSummaryTile,
+ name);
+ gtk_widget_class_bind_template_child (widget_class, GsSummaryTile,
+ summary);
+ gtk_widget_class_bind_template_child (widget_class, GsSummaryTile,
+ eventbox);
+ gtk_widget_class_bind_template_child (widget_class, GsSummaryTile,
+ stack);
+}
+
+GtkWidget *
+gs_summary_tile_new (GsApp *cat)
+{
+ GsAppTile *tile;
+
+ tile = g_object_new (GS_TYPE_SUMMARY_TILE, NULL);
+ gs_summary_tile_set_app (tile, cat);
+
+ return GTK_WIDGET (tile);
+}
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-summary-tile.h b/src/gs-summary-tile.h
new file mode 100644
index 0000000..cd5c421
--- /dev/null
+++ b/src/gs-summary-tile.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Matthias Clasen <mclasen redhat 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_SUMMARY_TILE_H
+#define GS_SUMMARY_TILE_H
+
+#include <gtk/gtk.h>
+
+#include "gs-app.h"
+#include "gs-app-tile.h"
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_SUMMARY_TILE (gs_summary_tile_get_type ())
+
+G_DECLARE_FINAL_TYPE (GsSummaryTile, gs_summary_tile, GS, SUMMARY_TILE, GsAppTile)
+
+GtkWidget *gs_summary_tile_new (GsApp *app);
+
+G_END_DECLS
+
+#endif /* GS_SUMMARY_TILE_H */
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-summary-tile.ui b/src/gs-summary-tile.ui
new file mode 100644
index 0000000..06c615d
--- /dev/null
+++ b/src/gs-summary-tile.ui
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.10 -->
+ <template class="GsSummaryTile" parent="GsAppTile">
+ <property name="visible">True</property>
+ <property name="hexpand">True</property>
+ <!-- This is the minimum (sic!) width of a tile when the GtkFlowBox parent container switches to 3
columns -->
+ <property name="preferred-width">270</property>
+ <style>
+ <class name="view"/>
+ <class name="tile"/>
+ </style>
+ <child>
+ <object class="GtkStack" id="stack">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkImage" id="waiting">
+ <property name="visible">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="pixel-size">16</property>
+ <property name="icon-name">content-loading-symbolic</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="name">waiting</property>
+ </packing>
+ </child>
+ <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">start</property>
+ <property name="valign">start</property>
+ <property name="margin-top">58</property>
+ <property name="margin-start">12</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-start">16</property>
+ <property name="margin-end">16</property>
+ <property name="margin-top">4</property>
+ <property name="margin-bottom">4</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkGrid" id="grid">
+ <property name="visible">True</property>
+ <property name="margin-top">14</property>
+ <property name="margin-bottom">15</property>
+ <property name="margin-start">17</property>
+ <property name="margin-end">17</property>
+ <property name="row-spacing">3</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkImage" id="image">
+ <property name="visible">True</property>
+ <property name="width-request">64</property>
+ <property name="height-request">64</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ <property name="width">1</property>
+ <property name="height">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="name">
+ <property name="visible">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0.0</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ <style>
+ <class name="app-tile-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary">
+ <property name="visible">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0.0</property>
+ <property name="yalign">0.0</property>
+ <property name="lines">2</property>
+ <property name="vexpand">True</property>
+ <property name="single-line-mode">True</property>
+ <style>
+ <class name="app-tile-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">content</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]