1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3
* Copyright (C) 2001-2007 Philip Withnall <philip@tecnocode.co.uk>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
* The Totem project hereby grant permission for non-gpl compatible GStreamer
20
* plugins to be used and distributed together with GStreamer and Totem. This
21
* permission are above and beyond the permissions granted by the GPL license
22
* Totem is covered by.
24
* Monday 7th February 2005: Christian Schaller: Add exception clause.
25
* See license_change file for details.
30
* SECTION:totem-cell-renderer-video
31
* @short_description: a #GtkCellRenderer widget for listing videos
32
* @stability: Unstable
33
* @include: totem-cell-renderer-video.h
34
* @see_also: #TotemVideoList
36
* #TotemCellRendererVideo is a #GtkCellRenderer for rendering video thumbnails, typically in a #TotemVideoList.
37
* It supports drawing a video thumbnail, and the video's title underneath.
43
#include <glib/gi18n.h>
47
#include "totem-cell-renderer-video.h"
48
#include "totem-private.h"
50
struct _TotemCellRendererVideoPrivate {
53
PangoAlignment alignment;
54
gboolean use_placeholder;
57
#define TOTEM_CELL_RENDERER_VIDEO_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TOTEM_TYPE_CELL_RENDERER_VIDEO, TotemCellRendererVideoPrivate))
66
static void totem_cell_renderer_video_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
67
static void totem_cell_renderer_video_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
68
static void totem_cell_renderer_video_dispose (GObject *object);
69
static void totem_cell_renderer_video_finalize (GObject *object);
70
static void totem_cell_renderer_video_get_size (GtkCellRenderer *cell, GtkWidget *widget, const GdkRectangle *cell_area, gint *x_offset, gint *y_offset, gint *width, gint *height);
71
static void totem_cell_renderer_video_render (GtkCellRenderer *cell, cairo_t *cr, GtkWidget *widget, const GdkRectangle *background_area, const GdkRectangle *cell_area, GtkCellRendererState flags);
73
G_DEFINE_TYPE (TotemCellRendererVideo, totem_cell_renderer_video, GTK_TYPE_CELL_RENDERER)
76
* totem_cell_renderer_video_new:
77
* @use_placeholder: if %TRUE, use a placeholder thumbnail
79
* Creates a new #TotemCellRendererVideo with its #TotemCellRendererVideo:use-placeholder
80
* property set to @use_placeholder. If @use_placeholder is %TRUE,
81
* the renderer will display a generic placeholder thumbnail if a
82
* proper one is not available.
84
* Return value: a new #TotemCellRendererVideo
86
TotemCellRendererVideo *
87
totem_cell_renderer_video_new (gboolean use_placeholder)
89
return g_object_new (TOTEM_TYPE_CELL_RENDERER_VIDEO,
90
"use-placeholder", use_placeholder,
95
totem_cell_renderer_video_class_init (TotemCellRendererVideoClass *klass)
97
GObjectClass *object_class = G_OBJECT_CLASS (klass);
98
GtkCellRendererClass *renderer_class = GTK_CELL_RENDERER_CLASS (klass);
100
g_type_class_add_private (klass, sizeof (TotemCellRendererVideoPrivate));
102
object_class->set_property = totem_cell_renderer_video_set_property;
103
object_class->get_property = totem_cell_renderer_video_get_property;
104
object_class->dispose = totem_cell_renderer_video_dispose;
105
object_class->finalize = totem_cell_renderer_video_finalize;
106
renderer_class->get_size = totem_cell_renderer_video_get_size;
107
renderer_class->render = totem_cell_renderer_video_render;
110
* TotemCellRendererVideo:thumbnail:
112
* A #GdkPixbuf of a thumbnail of the video to display. When rendered, it will scale to the width of the parent #GtkTreeView,
113
* so can be as large as reasonable.
115
g_object_class_install_property (object_class, PROP_THUMBNAIL,
116
g_param_spec_object ("thumbnail", "Thumbnail", "A GdkPixbuf of a thumbnail of the video to display.",
117
GDK_TYPE_PIXBUF, G_PARAM_READWRITE));
120
* TotemCellRendererVideo:title:
122
* The title of the video, as it should be displayed.
124
g_object_class_install_property (object_class, PROP_TITLE,
125
g_param_spec_string ("title", "Title", "The title of the video, as it should be displayed.",
126
_("Unknown video"), G_PARAM_READWRITE));
129
* TotemCellRendererVideo:alignment:
131
* A #PangoAlignment giving the text alignment for the video title.
133
g_object_class_install_property (object_class, PROP_ALIGNMENT,
134
g_param_spec_enum ("alignment", "Alignment", "A PangoAlignment giving the text alignment for the video title.",
135
PANGO_TYPE_ALIGNMENT,
140
* TotemCellRendererVideo:use-placeholder:
142
* If %TRUE, a placeholder image should be used for the video thumbnail if a #TotemCellRendererVideo:thumbnail isn't provided.
144
g_object_class_install_property (object_class, PROP_USE_PLACEHOLDER,
145
g_param_spec_boolean ("use-placeholder", "Use placeholder?",
146
"Whether a placeholder image should be used for the video thumbnail.",
147
FALSE, G_PARAM_READWRITE));
151
totem_cell_renderer_video_init (TotemCellRendererVideo *self)
153
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TOTEM_TYPE_CELL_RENDERER_VIDEO, TotemCellRendererVideoPrivate);
154
self->priv->title = NULL;
155
self->priv->thumbnail = NULL;
156
self->priv->alignment = PANGO_ALIGN_CENTER;
157
self->priv->use_placeholder = FALSE;
159
/* Make sure we're in the right mode */
160
g_object_set ((gpointer) self, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);
164
totem_cell_renderer_video_dispose (GObject *object)
166
TotemCellRendererVideo *self = TOTEM_CELL_RENDERER_VIDEO (object);
168
if (self->priv->thumbnail != NULL)
169
g_object_unref (self->priv->thumbnail);
170
self->priv->thumbnail = NULL;
172
/* Chain up to the parent class */
173
G_OBJECT_CLASS (totem_cell_renderer_video_parent_class)->dispose (object);
177
totem_cell_renderer_video_finalize (GObject *object)
179
TotemCellRendererVideo *self = TOTEM_CELL_RENDERER_VIDEO (object);
181
g_free (self->priv->title);
183
/* Chain up to the parent class */
184
G_OBJECT_CLASS (totem_cell_renderer_video_parent_class)->finalize (object);
188
totem_cell_renderer_video_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
190
TotemCellRendererVideoPrivate *priv = TOTEM_CELL_RENDERER_VIDEO_GET_PRIVATE (object);
195
if (priv->thumbnail != NULL)
196
g_object_unref (priv->thumbnail);
197
priv->thumbnail = GDK_PIXBUF (g_value_dup_object (value));
200
g_free (priv->title);
201
priv->title = g_value_dup_string (value);
204
priv->alignment = g_value_get_enum (value);
206
case PROP_USE_PLACEHOLDER:
207
priv->use_placeholder = g_value_get_boolean (value);
210
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
215
totem_cell_renderer_video_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
217
TotemCellRendererVideoPrivate *priv = TOTEM_CELL_RENDERER_VIDEO_GET_PRIVATE (object);
222
g_value_set_object (value, G_OBJECT (priv->thumbnail));
225
g_value_set_string (value, priv->title);
228
g_value_set_enum (value, priv->alignment);
230
case PROP_USE_PLACEHOLDER:
231
g_value_set_boolean (value, priv->use_placeholder);
234
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
239
get_size (GtkCellRenderer *cell,
241
const GdkRectangle *cell_area,
242
GdkRectangle *draw_area,
243
GdkRectangle *title_area,
244
GdkRectangle *thumbnail_area)
246
TotemCellRendererVideoPrivate *priv = TOTEM_CELL_RENDERER_VIDEO (cell)->priv;
247
GtkStyleContext *style_context;
248
guint pixbuf_width = 0;
249
guint pixbuf_height = 0;
250
guint title_width, title_height;
251
guint calc_width, calc_height;
253
guint cell_xpad, cell_ypad;
254
gfloat cell_xalign, cell_yalign;
255
PangoContext *context;
256
PangoFontMetrics *metrics;
257
PangoFontDescription *font_desc;
260
"width", &cell_width,
263
"xalign", &cell_xalign,
264
"yalign", &cell_yalign,
267
/* Calculate thumbnail dimensions */
268
if (priv->thumbnail != NULL) {
269
pixbuf_width = gdk_pixbuf_get_width (priv->thumbnail);
270
pixbuf_height = gdk_pixbuf_get_height (priv->thumbnail);
271
} else if (priv->use_placeholder == TRUE) {
272
gint width, height; /* Sort out signedness weirdness (damn GTK+) */
274
if (gtk_icon_size_lookup (GTK_ICON_SIZE_DIALOG, &width, &height) == TRUE) {
275
pixbuf_width = width;
276
pixbuf_height = height;
278
pixbuf_width = cell_width;
279
pixbuf_height = cell_width;
283
/* Calculate title dimensions */
284
style_context = gtk_widget_get_style_context (widget);
285
gtk_style_context_get (style_context, GTK_STATE_FLAG_ACTIVE, "font", &font_desc, NULL);
286
if (priv->thumbnail != NULL)
287
pango_font_description_set_weight (font_desc, PANGO_WEIGHT_BOLD);
288
context = gtk_widget_get_pango_context (widget);
289
metrics = pango_context_get_metrics (context, font_desc, pango_context_get_language (context));
292
title_width = cell_area->width;
293
else if (cell_width != -1)
294
title_width = cell_width;
296
title_width = pixbuf_width;
298
title_height = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent (metrics));
300
pango_font_metrics_unref (metrics);
301
pango_font_description_free (font_desc);
303
/* Calculate the total final size */
304
calc_width = cell_xpad * 2 + MAX (pixbuf_width, title_width);
305
calc_height = cell_ypad * 3 + pixbuf_height + title_height;
308
if (cell_area && calc_width > 0 && calc_height > 0) {
309
draw_area->x = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
310
(1.0 - cell_xalign) : cell_xalign) * (cell_area->width - calc_width));
311
draw_area->x = MAX (draw_area->x, 0);
312
draw_area->y = (cell_yalign * (cell_area->height - calc_height));
313
draw_area->y = MAX (draw_area->y, 0);
319
draw_area->x += cell_xpad;
320
draw_area->y += cell_ypad;
321
draw_area->width = calc_width;
322
draw_area->height = calc_height;
326
title_area->width = cell_area->width;
327
title_area->x = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ? 1.0 : 0.0;
329
title_area->width = calc_width;
330
title_area->x = draw_area->x;
333
title_area->height = title_height;
334
if (pixbuf_height > 0)
335
title_area->y = draw_area->y + pixbuf_height + cell_ypad;
337
title_area->y = draw_area->y;
340
if (pixbuf_height > 0 && thumbnail_area) {
341
thumbnail_area->x = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
342
(1.0 - cell_xalign) : cell_xalign) *
343
(cell_area->width - pixbuf_width));
344
thumbnail_area->x = MAX (thumbnail_area->x, 0);
345
thumbnail_area->y = draw_area->y;
346
thumbnail_area->width = cell_xpad * 2 + pixbuf_width;
347
thumbnail_area->height = pixbuf_height;
353
totem_cell_renderer_video_get_size (GtkCellRenderer *cell,
355
const GdkRectangle *cell_area,
361
GdkRectangle draw_area;
363
get_size (cell, widget, cell_area, &draw_area, NULL, NULL);
366
*x_offset = draw_area.x;
368
*y_offset = draw_area.y;
370
*width = draw_area.width;
372
*height = draw_area.height;
376
totem_cell_renderer_video_render (GtkCellRenderer *cell,
379
const GdkRectangle *background_area,
380
const GdkRectangle *cell_area,
381
GtkCellRendererState flags)
383
TotemCellRendererVideoPrivate *priv = TOTEM_CELL_RENDERER_VIDEO (cell)->priv;
385
GdkRectangle draw_rect;
386
GdkRectangle draw_area;
387
GdkRectangle title_area;
388
GdkRectangle thumbnail_area;
391
guint cell_xpad, cell_ypad;
392
gboolean cell_is_expander;
393
GtkStyleContext *context;
398
"is_expander", &cell_is_expander,
401
get_size (cell, widget, cell_area, &draw_area, &title_area, &thumbnail_area);
403
draw_area.x += cell_area->x;
404
draw_area.y += cell_area->y;
405
draw_area.width -= cell_xpad * 2;
406
draw_area.height -= cell_ypad * 2;
408
if (!gdk_rectangle_intersect (cell_area, &draw_area, &draw_rect))
411
/* Sort out the thumbnail */
412
if (priv->thumbnail != NULL)
413
pixbuf = priv->thumbnail;
414
else if (priv->use_placeholder == TRUE)
415
pixbuf = gtk_widget_render_icon_pixbuf (widget, GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_DIALOG);
419
if (cell_is_expander)
422
/* Sort out the title */
423
if (!gtk_cell_renderer_get_sensitive (cell)) {
424
state = GTK_STATE_INSENSITIVE;
425
} else if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED) {
426
if (gtk_widget_has_focus (widget))
427
state = GTK_STATE_SELECTED;
429
state = GTK_STATE_ACTIVE;
430
} else if ((flags & GTK_CELL_RENDERER_PRELIT) == GTK_CELL_RENDERER_PRELIT &&
431
gtk_widget_get_state (widget) == GTK_STATE_PRELIGHT) {
432
state = GTK_STATE_PRELIGHT;
434
if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
435
state = GTK_STATE_INSENSITIVE;
437
state = GTK_STATE_NORMAL;
441
context = gtk_widget_get_style_context (widget);
442
layout = gtk_widget_create_pango_layout (widget, priv->title);
443
if (pixbuf != NULL) {
444
PangoFontDescription *desc;
445
gtk_style_context_get (context, state, "font", &desc, NULL);
446
pango_font_description_set_weight (desc, PANGO_WEIGHT_BOLD);
447
pango_layout_set_font_description (layout, desc);
448
pango_font_description_free (desc);
451
pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
452
pango_layout_set_width (layout, title_area.width * PANGO_SCALE);
453
pango_layout_set_alignment (layout, priv->alignment);
455
gtk_style_context_set_state (context, state);
456
gtk_render_layout (context, cr,
457
cell_area->x + title_area.x,
458
cell_area->y + title_area.y,
461
g_object_unref (layout);
463
/* Draw the thumbnail */
464
if (pixbuf != NULL) {
465
gdk_cairo_set_source_pixbuf (cr, pixbuf, cell_area->x + thumbnail_area.x, cell_area->y + thumbnail_area.y);
466
gdk_cairo_rectangle (cr, &draw_rect);