From 178dcc788892a216b346d4937970efa351bc4863 Mon Sep 17 00:00:00 2001 From: Alan F Date: Fri, 28 Feb 2014 09:54:43 +0000 Subject: a cell renderer for RSS items --- src/Makefile.am | 1 + src/torrent-cell-renderer.c | 2 - src/trg-rss-cell-renderer.c | 414 ++++++++++++++++++++++++++++++++++++++++++++ src/trg-rss-cell-renderer.h | 55 ++++++ src/trg-rss-model.c | 1 + src/trg-rss-model.h | 1 + src/trg-rss-window.c | 11 +- src/trg-toolbar.h | 1 - src/util.h | 1 + 9 files changed, 481 insertions(+), 6 deletions(-) create mode 100644 src/trg-rss-cell-renderer.c create mode 100644 src/trg-rss-cell-renderer.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index fc4902e..7cb7801 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -107,6 +107,7 @@ transmission_remote_gtk_SOURCES = \ main.c \ trg-rss-model.c \ trg-rss-window.c \ + trg-rss-cell-renderer.c \ upload.c \ $(NULL) diff --git a/src/torrent-cell-renderer.c b/src/torrent-cell-renderer.c index 654d7bd..5c6abd2 100644 --- a/src/torrent-cell-renderer.c +++ b/src/torrent-cell-renderer.c @@ -445,8 +445,6 @@ get_size_compact(TorrentCellRenderer * cell, g_object_unref(icon); } -#define MAX3(a,b,c) MAX(a,MAX(b,c)) - static void get_size_full(TorrentCellRenderer * cell, GtkWidget * widget, gint * width, gint * height) diff --git a/src/trg-rss-cell-renderer.c b/src/trg-rss-cell-renderer.c new file mode 100644 index 0000000..5cae5c7 --- /dev/null +++ b/src/trg-rss-cell-renderer.c @@ -0,0 +1,414 @@ +#include "config.h" + +#ifdef HAVE_RSSGLIB + +#include +#include +#include + +#include "icons.h" +#include "hig.h" +#include "util.h" +#include "trg-rss-cell-renderer.h" + +enum { + PROP_TITLE = 1, + PROP_FEED, + PROP_PUBLISHED +}; + +#define SMALL_SCALE 0.9 +#define COMPACT_ICON_SIZE GTK_ICON_SIZE_MENU +#define FULL_ICON_SIZE GTK_ICON_SIZE_DND + +#define FOREGROUND_COLOR_KEY "foreground-rgba" +typedef GdkRGBA GtrColor; +typedef cairo_t GtrDrawable; +typedef GtkRequisition GtrRequisition; + +struct TrgRssCellRendererPrivate { + GtkCellRenderer *text_renderer; + GtkCellRenderer *icon_renderer; + GString *gstr1; + GString *gstr2; + gchar *title; + gchar *published; + gchar *feed; +}; + +static void +trg_rss_cell_renderer_render(GtkCellRenderer * cell, + GtrDrawable * window, GtkWidget * widget, + const GdkRectangle * background_area, + const GdkRectangle * cell_area, + GtkCellRendererState flags); + +static void +gtr_cell_renderer_render(GtkCellRenderer * renderer, + GtrDrawable * drawable, + GtkWidget * widget, + const GdkRectangle * area, + GtkCellRendererState flags) +{ + gtk_cell_renderer_render(renderer, drawable, widget, area, area, + flags); +} + +static void trg_rss_cell_renderer_set_property(GObject * object, + guint property_id, + const GValue * v, + GParamSpec * pspec) +{ + TrgRssCellRenderer *self = TRG_RSS_CELL_RENDERER(object); + struct TrgRssCellRendererPrivate *p = self->priv; + + switch (property_id) { + case PROP_TITLE: + g_free(p->title); + p->title = g_value_dup_string(v); + break; + case PROP_PUBLISHED: + g_free(p->published); + p->published = g_value_dup_string(v); + break; + case PROP_FEED: + g_free(p->feed); + p->feed = g_value_dup_string(v); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void +trg_rss_cell_renderer_get_property(GObject * object, + guint property_id, + GValue * v, GParamSpec * pspec) +{ + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); +} + +G_DEFINE_TYPE(TrgRssCellRenderer, trg_rss_cell_renderer, + GTK_TYPE_CELL_RENDERER) + +static void trg_rss_cell_renderer_dispose(GObject * o) +{ + TrgRssCellRenderer *r = TRG_RSS_CELL_RENDERER(o); + + if (r && r->priv) { + struct TrgRssCellRendererPrivate *priv = r->priv; + + g_string_free(priv->gstr1, TRUE); + g_free(priv->feed); + g_free(priv->published); + g_free(priv->title); + g_object_unref(G_OBJECT(priv->text_renderer)); + g_object_unref(G_OBJECT(priv->icon_renderer)); + r->priv = NULL; + } + + G_OBJECT_CLASS(trg_rss_cell_renderer_parent_class)->dispose(o); +} + +static GdkPixbuf *get_icon(TrgRssCellRenderer * r, GtkIconSize icon_size, + GtkWidget * for_widget) +{ + const char *mime_type = "file"; + + return gtr_get_mime_type_icon(mime_type, icon_size, for_widget); +} + +static void +trg_rss_cell_renderer_get_size(GtkCellRenderer * cell, GtkWidget * widget, + const GdkRectangle * cell_area, + gint * x_offset, + gint * y_offset, + gint * width, gint * height) +{ + TrgRssCellRenderer *self = TRG_RSS_CELL_RENDERER(cell); + + if (self) { + struct TrgRssCellRendererPrivate *p = self->priv; + int xpad, ypad; + int h, w; + GtkRequisition icon_size; + GtkRequisition name_size; + GtkRequisition stat_size; + GtkRequisition prog_size; + GdkPixbuf *icon; + + icon = get_icon(self, FULL_ICON_SIZE, widget); + + gtk_cell_renderer_get_padding(cell, &xpad, &ypad); + + /* get the idealized cell dimensions */ + g_object_set(p->icon_renderer, "pixbuf", icon, NULL); + gtk_cell_renderer_get_preferred_size(p->icon_renderer, widget, NULL, + &icon_size); + g_object_set(p->text_renderer, "text", p->title, + "weight", PANGO_WEIGHT_BOLD, "scale", 1.0, "ellipsize", + PANGO_ELLIPSIZE_NONE, NULL); + gtk_cell_renderer_get_preferred_size(p->text_renderer, widget, NULL, + &name_size); + g_object_set(p->text_renderer, "text", p->feed, "weight", + PANGO_WEIGHT_NORMAL, "scale", SMALL_SCALE, NULL); + gtk_cell_renderer_get_preferred_size(p->text_renderer, widget, NULL, + &prog_size); + g_object_set(p->text_renderer, "text", p->published, NULL); + gtk_cell_renderer_get_preferred_size(p->text_renderer, widget, NULL, + &stat_size); + + /** + *** LAYOUT + **/ + + if (width != NULL) + *width = w = + xpad * 2 + icon_size.width + GUI_PAD + MAX3(name_size.width, + prog_size.width, + stat_size.width); + if (height != NULL) + *height = h = + ypad * 2 + name_size.height + prog_size.height + + GUI_PAD_SMALL + stat_size.height; + + /* cleanup */ + g_object_unref(icon); + + if (x_offset) + *x_offset = cell_area ? cell_area->x : 0; + + if (y_offset) { + int xpad, ypad; + gtk_cell_renderer_get_padding(cell, &xpad, &ypad); + *y_offset = + cell_area ? (int) ((cell_area->height - (ypad * 2 + h)) / + 2.0) : 0; + } + } +} + +static void +trg_rss_cell_renderer_class_init(TrgRssCellRendererClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS(klass); + + g_type_class_add_private(klass, + sizeof(struct TrgRssCellRendererPrivate)); + + cell_class->render = trg_rss_cell_renderer_render; + cell_class->get_size = trg_rss_cell_renderer_get_size; + gobject_class->set_property = trg_rss_cell_renderer_set_property; + gobject_class->get_property = trg_rss_cell_renderer_get_property; + gobject_class->dispose = trg_rss_cell_renderer_dispose; + + g_object_class_install_property(gobject_class, + PROP_TITLE, + g_param_spec_string("title", + "title", + "Title", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME + | + G_PARAM_STATIC_NICK + | + G_PARAM_STATIC_BLURB)); + + g_object_class_install_property(gobject_class, + PROP_PUBLISHED, + g_param_spec_string("published", + "published", + "Published", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME + | + G_PARAM_STATIC_NICK + | + G_PARAM_STATIC_BLURB)); + + g_object_class_install_property(gobject_class, + PROP_FEED, + g_param_spec_string("feed", + "feed", + "Feed", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME + | + G_PARAM_STATIC_NICK + | + G_PARAM_STATIC_BLURB)); + + /*g_object_class_install_property(gobject_class, P_BAR_HEIGHT, + g_param_spec_int("bar-height", NULL, + "Bar Height", + 1, INT_MAX, + DEFAULT_BAR_HEIGHT, + G_PARAM_READWRITE));*/ + +} + +static void trg_rss_cell_renderer_init(TrgRssCellRenderer * self) +{ + struct TrgRssCellRendererPrivate *p; + + p = self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, + TRG_RSS_CELL_RENDERER_TYPE, + struct + TrgRssCellRendererPrivate); + + p->gstr1 = g_string_new(NULL); + p->gstr2 = g_string_new(NULL); + p->text_renderer = gtk_cell_renderer_text_new(); + g_object_set(p->text_renderer, "xpad", 0, "ypad", 0, NULL); + p->icon_renderer = gtk_cell_renderer_pixbuf_new(); + g_object_ref_sink(p->text_renderer); + g_object_ref_sink(p->icon_renderer); +} + + +GtkCellRenderer *trg_rss_cell_renderer_new(void) +{ + return (GtkCellRenderer *) g_object_new(TRG_RSS_CELL_RENDERER_TYPE, + NULL); +} + +static void +get_text_color(TrgRssCellRenderer * r, GtkWidget * widget, + GtrColor * setme) +{ + /*struct TrgRssCellRendererPrivate *p = r->priv; + static const GdkRGBA red = { 1.0, 0, 0, 0 }; + + if (p->error) + *setme = red; + else if (p->flags & TORRENT_FLAG_PAUSED) + gtk_style_context_get_color(gtk_widget_get_style_context(widget), + GTK_STATE_FLAG_INSENSITIVE, setme); + else*/ + gtk_style_context_get_color(gtk_widget_get_style_context(widget), + GTK_STATE_FLAG_NORMAL, setme); +} + +static void +trg_rss_cell_renderer_render(GtkCellRenderer * cell, + GtrDrawable * window, GtkWidget * widget, + const GdkRectangle * background_area, + const GdkRectangle * cell_area, + GtkCellRendererState flags) +{ + TrgRssCellRenderer *self = TRG_RSS_CELL_RENDERER(cell); + int xpad, ypad; + GtkRequisition size; + GdkRectangle fill_area; + GdkRectangle icon_area; + GdkRectangle name_area; + GdkRectangle stat_area; + GdkRectangle prog_area; + GdkRectangle prct_area; + GdkPixbuf *icon; + GtrColor text_color; + struct TrgRssCellRendererPrivate *p; + + if (!self) + return; + + p = self->priv; + + icon = get_icon(self, FULL_ICON_SIZE, widget); + gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(cell), &xpad, &ypad); + get_text_color(self, widget, &text_color); + + /* get the idealized cell dimensions */ + g_object_set(p->icon_renderer, "pixbuf", icon, NULL); + gtk_cell_renderer_get_preferred_size(p->icon_renderer, widget, NULL, + &size); + icon_area.width = size.width; + icon_area.height = size.height; + g_object_set(p->text_renderer, "text", p->title, + "weight", PANGO_WEIGHT_BOLD, "ellipsize", + PANGO_ELLIPSIZE_NONE, "scale", 1.0, NULL); + gtk_cell_renderer_get_preferred_size(p->text_renderer, widget, NULL, + &size); + name_area.width = size.width; + name_area.height = size.height; + g_object_set(p->text_renderer, "text", p->feed, "weight", + PANGO_WEIGHT_NORMAL, "scale", SMALL_SCALE, NULL); + gtk_cell_renderer_get_preferred_size(p->text_renderer, widget, NULL, + &size); + prog_area.width = size.width; + prog_area.height = size.height; + g_object_set(p->text_renderer, "text", p->published, NULL); + gtk_cell_renderer_get_preferred_size(p->text_renderer, widget, NULL, + &size); + stat_area.width = size.width; + stat_area.height = size.height; + + /** + *** LAYOUT + **/ + + fill_area = *background_area; + fill_area.x += xpad; + fill_area.y += ypad; + fill_area.width -= xpad * 2; + fill_area.height -= ypad * 2; + + /* icon */ + icon_area.x = fill_area.x; + icon_area.y = fill_area.y + (fill_area.height - icon_area.height) / 2; + + /* name */ + name_area.x = icon_area.x + icon_area.width + GUI_PAD; + name_area.y = fill_area.y; + name_area.width = + fill_area.width - GUI_PAD - icon_area.width - GUI_PAD_SMALL; + + /* prog */ + prog_area.x = name_area.x; + prog_area.y = name_area.y + name_area.height; + prog_area.width = name_area.width; + + /* progressbar */ + prct_area.x = prog_area.x; + prct_area.y = prog_area.y + prog_area.height + GUI_PAD_SMALL; + prct_area.width = prog_area.width; + prct_area.height = 0; + + /* status */ + stat_area.x = prct_area.x; + stat_area.y = prct_area.y + prct_area.height + GUI_PAD_SMALL; + stat_area.width = prct_area.width; + + /** + *** RENDER + **/ + + g_object_set(p->icon_renderer, "pixbuf", icon, "sensitive", TRUE, + NULL); + gtr_cell_renderer_render(p->icon_renderer, window, widget, &icon_area, + flags); + g_object_set(p->text_renderer, "text", p->title, + "scale", 1.0, FOREGROUND_COLOR_KEY, &text_color, + "ellipsize", PANGO_ELLIPSIZE_END, "weight", + PANGO_WEIGHT_BOLD, NULL); + gtr_cell_renderer_render(p->text_renderer, window, widget, &name_area, + flags); + g_object_set(p->text_renderer, "text", p->feed, "scale", + SMALL_SCALE, "weight", PANGO_WEIGHT_NORMAL, NULL); + gtr_cell_renderer_render(p->text_renderer, window, widget, &prog_area, + flags); + g_object_set(p->text_renderer, "text", p->published, + FOREGROUND_COLOR_KEY, &text_color, NULL); + gtr_cell_renderer_render(p->text_renderer, window, widget, &stat_area, + flags); + + /* cleanup */ + g_object_unref(icon); +} + +#endif diff --git a/src/trg-rss-cell-renderer.h b/src/trg-rss-cell-renderer.h new file mode 100644 index 0000000..a255d90 --- /dev/null +++ b/src/trg-rss-cell-renderer.h @@ -0,0 +1,55 @@ +/* + * transmission-remote-gtk - A GTK RPC client to Transmission + * Copyright (C) 2011-2013 Alan Fitton + + * 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 TRG_RSS_CELL_RENDERER_H +#define TRG_RSS_CELL_RENDERER_H + +#include "config.h" + +#ifdef HAVE_RSSGLIB + +#include + +#define TRG_RSS_CELL_RENDERER_TYPE ( trg_rss_cell_renderer_get_type( ) ) + +#define TRG_RSS_CELL_RENDERER( o ) \ + ( G_TYPE_CHECK_INSTANCE_CAST( ( o ), \ + TRG_RSS_CELL_RENDERER_TYPE, \ + TrgRssCellRenderer ) ) + +typedef struct TrgRssCellRenderer TrgRssCellRenderer; + +typedef struct TrgRssCellRendererClass TrgRssCellRendererClass; + +struct TrgRssCellRenderer { + GtkCellRenderer parent; + struct TrgRssCellRendererPrivate *priv; +}; + +struct TrgRssCellRendererClass { + GtkCellRendererClass parent; +}; + +GType trg_rss_cell_renderer_get_type(void) G_GNUC_CONST; + +GtkCellRenderer *trg_rss_cell_renderer_new(void); + +#endif + +#endif /* TRG_RSS_CELL_RENDERER_H */ diff --git a/src/trg-rss-model.c b/src/trg-rss-model.c index 813652f..b6ee229 100644 --- a/src/trg-rss-model.c +++ b/src/trg-rss-model.c @@ -245,6 +245,7 @@ static void trg_rss_model_init(TrgRssModel * self) { column_types[RSSCOL_LINK] = G_TYPE_STRING; column_types[RSSCOL_FEED] = G_TYPE_STRING; column_types[RSSCOL_PUBDATE] = G_TYPE_STRING; + column_types[RSSCOL_SENSITIVE] = G_TYPE_BOOLEAN; gtk_list_store_set_column_types(GTK_LIST_STORE(self), RSSCOL_COLUMNS, column_types); diff --git a/src/trg-rss-model.h b/src/trg-rss-model.h index a931c37..8ddddd4 100644 --- a/src/trg-rss-model.h +++ b/src/trg-rss-model.h @@ -77,6 +77,7 @@ enum { RSSCOL_LINK, RSSCOL_FEED, RSSCOL_PUBDATE, + RSSCOL_SENSITIVE, RSSCOL_COLUMNS }; diff --git a/src/trg-rss-window.c b/src/trg-rss-window.c index 224cbb7..c4091a5 100644 --- a/src/trg-rss-window.c +++ b/src/trg-rss-window.c @@ -27,6 +27,7 @@ #include "trg-rss-window.h" #include "trg-rss-model.h" +#include "trg-rss-cell-renderer.h" #include "trg-torrent-add-dialog.h" #include "trg-client.h" #include "upload.h" @@ -189,7 +190,7 @@ static GObject *trg_rss_window_constructor(GType type, TrgRssModel *model; GtkTreeView *view; GtkWidget *vbox; - GtkToolItem *item; + //GtkToolItem *item; object = G_OBJECT_CLASS (trg_rss_window_parent_class)->constructor(type, @@ -207,11 +208,13 @@ static GObject *trg_rss_window_constructor(GType type, trg_rss_model_update(model); view = GTK_TREE_VIEW(gtk_tree_view_new()); + gtk_tree_view_set_headers_visible(view, FALSE); gtk_tree_view_set_model(view, GTK_TREE_MODEL(model)); - gtk_tree_view_insert_column_with_attributes(view, -1, "Title", gtk_cell_renderer_text_new(), "text", RSSCOL_TITLE, NULL); + /*gtk_tree_view_insert_column_with_attributes(view, -1, "Title", gtk_cell_renderer_text_new(), "text", RSSCOL_TITLE, NULL); gtk_tree_view_insert_column_with_attributes(view, -1, "Feed", gtk_cell_renderer_text_new(), "text", RSSCOL_FEED, NULL); gtk_tree_view_insert_column_with_attributes(view, -1, "Published", gtk_cell_renderer_text_new(), "text", RSSCOL_PUBDATE, NULL); - gtk_tree_view_insert_column_with_attributes(view, -1, "URL", gtk_cell_renderer_text_new(), "text", RSSCOL_LINK, NULL); + gtk_tree_view_insert_column_with_attributes(view, -1, "URL", gtk_cell_renderer_text_new(), "text", RSSCOL_LINK, NULL);*/ + gtk_tree_view_insert_column_with_attributes(view, -1, NULL, trg_rss_cell_renderer_new(), "title", RSSCOL_TITLE, "feed", RSSCOL_FEED, "published", RSSCOL_PUBDATE, NULL); g_signal_connect(view, "row-activated", G_CALLBACK(rss_item_activated), object); @@ -237,6 +240,8 @@ static GObject *trg_rss_window_constructor(GType type, /*g_signal_connect(object, "response", G_CALLBACK(trg_rss_window_response_cb), NULL);*/ + gtk_widget_set_size_request(GTK_WIDGET(object), 500, 300); + return object; } diff --git a/src/trg-toolbar.h b/src/trg-toolbar.h index 7d12b2d..6887a16 100644 --- a/src/trg-toolbar.h +++ b/src/trg-toolbar.h @@ -17,7 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - #ifndef TRG_TOOLBAR_H_ #define TRG_TOOLBAR_H_ diff --git a/src/util.h b/src/util.h index 351f565..8134952 100644 --- a/src/util.h +++ b/src/util.h @@ -32,6 +32,7 @@ #define trg_strlpercent(a, b) tr_strlpercent(a, b, sizeof(a)) #define trg_strlsize(a, b) tr_formatter_size_B(a, b, sizeof(a)) #define trg_strlratio(a, b) tr_strlratio(a, b, sizeof(a)) +#define MAX3(a,b,c) MAX(a,MAX(b,c)) #define TR_RATIO_NA -1 #define TR_RATIO_INF -2 -- cgit v1.2.3