Logo Search packages:      
Sourcecode: nautilus version File versions  Download package

nautilus-cell-renderer-pixbuf-emblem.c

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-

   nautilus-cell-renderer-pixbuf-emblem.c: cell renderer which can render
   an emblem on top of a pixbuf (for use in FMListView and FMTreeView)
 
   Copyright (C) 2003 Juerg Billeter
  
   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., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
  
   This is based on GtkCellRendererPixbuf written by
   Jonathan Blandford <jrb@redhat.com>
  
   Author: Juerg Billeter <j@bitron.ch>
*/

#include "nautilus-cell-renderer-pixbuf-emblem.h"

static void nautilus_cell_renderer_pixbuf_emblem_get_property (GObject *object,
                                          guint       param_id,
                                          GValue            *value,
                                          GParamSpec  *pspec);
static void nautilus_cell_renderer_pixbuf_emblem_set_property (GObject *object,
                                          guint       param_id,
                                          const GValue      *value,
                                          GParamSpec  *pspec);
static void nautilus_cell_renderer_pixbuf_emblem_init       (NautilusCellRendererPixbufEmblem *cellpixbuf);
static void nautilus_cell_renderer_pixbuf_emblem_class_init  (NautilusCellRendererPixbufEmblemClass *klass);
static void nautilus_cell_renderer_pixbuf_emblem_finalize (GObject *object);
static void nautilus_cell_renderer_pixbuf_emblem_create_stock_pixbuf (NautilusCellRendererPixbufEmblem *cellpixbuf,
                                                          GtkWidget             *widget);
static void nautilus_cell_renderer_pixbuf_emblem_get_size   (GtkCellRenderer            *cell,
                                                 GtkWidget                  *widget,
                                                 GdkRectangle               *rectangle,
                                                 gint                       *x_offset,
                                                 gint                       *y_offset,
                                                 gint                       *width,
                                                 gint                       *height);
static void     nautilus_cell_renderer_pixbuf_emblem_render     (GtkCellRenderer            *cell,
                                                          GdkWindow                  *window,
                                                          GtkWidget                  *widget,
                                                          GdkRectangle               *background_area,
                                                          GdkRectangle               *cell_area,
                                                          GdkRectangle               *expose_area,
                                                          GtkCellRendererState                       flags);

enum {
      PROP_ZERO,
      PROP_PIXBUF,
      PROP_PIXBUF_EXPANDER_OPEN,
      PROP_PIXBUF_EXPANDER_CLOSED,
      PROP_STOCK_ID,
      PROP_STOCK_SIZE,
      PROP_STOCK_DETAIL,
      PROP_PIXBUF_EMBLEM
};

#define CELLINFO_KEY "nautilus-cell-renderer-pixbuf-emblem-info"

typedef struct _NautilusCellRendererPixbufEmblemInfo NautilusCellRendererPixbufEmblemInfo;
struct _NautilusCellRendererPixbufEmblemInfo
{
      gchar *stock_id;
      GtkIconSize stock_size;
      gchar *stock_detail;
};

G_DEFINE_TYPE (NautilusCellRendererPixbufEmblem, nautilus_cell_renderer_pixbuf_emblem, GTK_TYPE_CELL_RENDERER);

static void
nautilus_cell_renderer_pixbuf_emblem_init (NautilusCellRendererPixbufEmblem *cellpixbuf)
{
      NautilusCellRendererPixbufEmblemInfo *cellinfo;
      
      cellinfo = g_new0 (NautilusCellRendererPixbufEmblemInfo, 1);
      cellinfo->stock_size = GTK_ICON_SIZE_MENU;
      g_object_set_data (G_OBJECT (cellpixbuf), CELLINFO_KEY, cellinfo);
}

static void
nautilus_cell_renderer_pixbuf_emblem_class_init (NautilusCellRendererPixbufEmblemClass *klass)
{
      GObjectClass *object_class = G_OBJECT_CLASS (klass);
      GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);

      object_class->finalize = nautilus_cell_renderer_pixbuf_emblem_finalize;

      object_class->get_property = nautilus_cell_renderer_pixbuf_emblem_get_property;
      object_class->set_property = nautilus_cell_renderer_pixbuf_emblem_set_property;

      cell_class->get_size = nautilus_cell_renderer_pixbuf_emblem_get_size;
      cell_class->render = nautilus_cell_renderer_pixbuf_emblem_render;

      g_object_class_install_property (object_class,
                           PROP_PIXBUF,
                           g_param_spec_object ("pixbuf",
                                          "Pixbuf Object",
                                          "The pixbuf to render",
                                          GDK_TYPE_PIXBUF,
                                          G_PARAM_READABLE |
                                          G_PARAM_WRITABLE));

      g_object_class_install_property (object_class,
                           PROP_PIXBUF_EXPANDER_OPEN,
                           g_param_spec_object ("pixbuf_expander_open",
                                          "Pixbuf Expander Open",
                                          "Pixbuf for open expander",
                                          GDK_TYPE_PIXBUF,
                                          G_PARAM_READABLE |
                                          G_PARAM_WRITABLE));

      g_object_class_install_property (object_class,
                           PROP_PIXBUF_EXPANDER_CLOSED,
                           g_param_spec_object ("pixbuf_expander_closed",
                                          "Pixbuf Expander Closed",
                                          "Pixbuf for closed expander",
                                          GDK_TYPE_PIXBUF,
                                          G_PARAM_READABLE |
                                          G_PARAM_WRITABLE));

      g_object_class_install_property (object_class,
                           PROP_STOCK_ID,
                           g_param_spec_string ("stock_id",
                                          "Stock ID",
                                          "The stock ID of the stock icon to render",
                                          NULL,
                                          G_PARAM_READWRITE));

      g_object_class_install_property (object_class,
                           PROP_STOCK_SIZE,
                           g_param_spec_enum ("stock_size",
                                          "Size",
                                          "The size of the rendered icon",
                                          GTK_TYPE_ICON_SIZE,
                                          GTK_ICON_SIZE_MENU,
                                          G_PARAM_READWRITE));

      g_object_class_install_property (object_class,
                           PROP_STOCK_DETAIL,
                           g_param_spec_string ("stock_detail",
                                          "Detail",
                                          "Render detail to pass to the theme engine",
                                          NULL,
                                          G_PARAM_READWRITE));

      g_object_class_install_property (object_class,
                               PROP_PIXBUF_EMBLEM,
                               g_param_spec_object ("pixbuf_emblem",
                                                "Pixbuf Emblem Object",
                                                "The emblem to overlay",
                                                GDK_TYPE_PIXBUF,
                                                G_PARAM_READABLE |
                                                G_PARAM_WRITABLE));
}

static void
nautilus_cell_renderer_pixbuf_emblem_finalize (GObject *object)
{
      NautilusCellRendererPixbufEmblem *cellpixbuf = NAUTILUS_CELL_RENDERER_PIXBUF_EMBLEM (object);
      NautilusCellRendererPixbufEmblemInfo *cellinfo = g_object_get_data (object, CELLINFO_KEY);
      
      if (cellpixbuf->pixbuf && cellinfo->stock_id) {
            g_object_unref (cellpixbuf->pixbuf);
      }
      
      if (cellinfo->stock_id) {
            g_free (cellinfo->stock_id);
      }
      
      if (cellinfo->stock_detail) {
            g_free (cellinfo->stock_detail);
      }
      
      g_free (cellinfo);
      g_object_set_data (object, CELLINFO_KEY, NULL);

      (* G_OBJECT_CLASS (nautilus_cell_renderer_pixbuf_emblem_parent_class)->finalize) (object);
}

static void
nautilus_cell_renderer_pixbuf_emblem_get_property (GObject        *object,
                                       guint           param_id,
                                       GValue         *value,
                                       GParamSpec     *pspec)
{
      NautilusCellRendererPixbufEmblem *cellpixbuf = NAUTILUS_CELL_RENDERER_PIXBUF_EMBLEM (object);
      NautilusCellRendererPixbufEmblemInfo *cellinfo = g_object_get_data (object, CELLINFO_KEY);
                                                                            
      switch (param_id)
      {
            case PROP_PIXBUF:
                  g_value_set_object (value,
                                  cellpixbuf->pixbuf ? G_OBJECT (cellpixbuf->pixbuf) : NULL);
                  break;
            case PROP_PIXBUF_EXPANDER_OPEN:
                  g_value_set_object (value,
                                  cellpixbuf->pixbuf_expander_open ? G_OBJECT (cellpixbuf->pixbuf_expander_open) : NULL);
                  break;
            case PROP_PIXBUF_EXPANDER_CLOSED:
                  g_value_set_object (value,
                                  cellpixbuf->pixbuf_expander_closed ? G_OBJECT (cellpixbuf->pixbuf_expander_closed) : NULL);
                  break;
            case PROP_STOCK_ID:
                  g_value_set_string (value, cellinfo->stock_id);
                  break;
            case PROP_STOCK_SIZE:
                  g_value_set_enum (value, cellinfo->stock_size);
                  break;
            case PROP_STOCK_DETAIL:
                  g_value_set_string (value, cellinfo->stock_detail);
                  break;
            case PROP_PIXBUF_EMBLEM:
                  g_value_set_object (value,
                                  cellpixbuf->pixbuf_emblem ? G_OBJECT (cellpixbuf->pixbuf_emblem) : NULL);
                  break;

            default:
                  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
                  break;
      }
}
                                                                                                                                                                       
static void
nautilus_cell_renderer_pixbuf_emblem_set_property (GObject      *object,
                                       guint         param_id,
                                       const GValue *value,
                                       GParamSpec   *pspec)
{
      GdkPixbuf *pixbuf;
      NautilusCellRendererPixbufEmblem *cellpixbuf = NAUTILUS_CELL_RENDERER_PIXBUF_EMBLEM (object);
      NautilusCellRendererPixbufEmblemInfo *cellinfo = g_object_get_data (object, CELLINFO_KEY);
                                                                            
      switch (param_id)
      {
            case PROP_PIXBUF:
                  pixbuf = (GdkPixbuf*) g_value_get_object (value);
                  if (pixbuf) {
                        g_object_ref (pixbuf);
                  }
                  if (cellpixbuf->pixbuf) {
                        g_object_unref (cellpixbuf->pixbuf);
                  }
                  cellpixbuf->pixbuf = pixbuf;
                  break;
            case PROP_PIXBUF_EXPANDER_OPEN:
                  pixbuf = (GdkPixbuf*) g_value_get_object (value);
                  if (pixbuf) {
                        g_object_ref (pixbuf);
                  }
                  if (cellpixbuf->pixbuf_expander_open) {
                        g_object_unref (cellpixbuf->pixbuf_expander_open);
                  }
                  cellpixbuf->pixbuf_expander_open = pixbuf;
                  break;
            case PROP_PIXBUF_EXPANDER_CLOSED:
                  pixbuf = (GdkPixbuf*) g_value_get_object (value);
                  if (pixbuf) {
                        g_object_ref (pixbuf);
                  }
                  if (cellpixbuf->pixbuf_expander_closed) {
                        g_object_unref (cellpixbuf->pixbuf_expander_closed);
                  }
                  cellpixbuf->pixbuf_expander_closed = pixbuf;
                  break;
            case PROP_STOCK_ID:
                  if (cellinfo->stock_id) {
                        g_free (cellinfo->stock_id);
                  }
                  cellinfo->stock_id = g_strdup (g_value_get_string (value));
                  break;
            case PROP_STOCK_SIZE:
                  cellinfo->stock_size = g_value_get_enum (value);
                  break;
            case PROP_STOCK_DETAIL:
                  if (cellinfo->stock_detail) {
                        g_free (cellinfo->stock_detail);
                  }
                  cellinfo->stock_detail = g_strdup (g_value_get_string (value));
                  break;
            case PROP_PIXBUF_EMBLEM:
                  pixbuf = (GdkPixbuf *) g_value_get_object (value);
                  if (pixbuf) {
                        g_object_ref (pixbuf);
                  }
                  if (cellpixbuf->pixbuf_emblem) {
                        g_object_unref (cellpixbuf->pixbuf_emblem);
                  }
                  cellpixbuf->pixbuf_emblem = pixbuf;
                  break;

            default:
                  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
                  break;
      }
}

GtkCellRenderer *
nautilus_cell_renderer_pixbuf_emblem_new (void)
{
      return g_object_new (NAUTILUS_TYPE_CELL_RENDERER_PIXBUF_EMBLEM, NULL);
}

static void
nautilus_cell_renderer_pixbuf_emblem_create_stock_pixbuf (NautilusCellRendererPixbufEmblem *cellpixbuf,
                                            GtkWidget             *widget)
{
      NautilusCellRendererPixbufEmblemInfo *cellinfo = g_object_get_data (G_OBJECT (cellpixbuf), CELLINFO_KEY);

      if (cellpixbuf->pixbuf) {
            g_object_unref (cellpixbuf->pixbuf);
      }

      cellpixbuf->pixbuf = gtk_widget_render_icon (widget,
                                     cellinfo->stock_id,
                                     cellinfo->stock_size,
                                     cellinfo->stock_detail);
}

static void
nautilus_cell_renderer_pixbuf_emblem_get_size (GtkCellRenderer *cell,
                           GtkWidget       *widget,
                           GdkRectangle    *cell_area,
                           gint            *x_offset,
                           gint            *y_offset,
                           gint            *width,
                           gint            *height)
{
      NautilusCellRendererPixbufEmblem *cellpixbuf = (NautilusCellRendererPixbufEmblem *) cell;
      NautilusCellRendererPixbufEmblemInfo *cellinfo = g_object_get_data (G_OBJECT (cell), CELLINFO_KEY);
      gint pixbuf_width  = 0;
      gint pixbuf_height = 0;
      gint calc_width;
      gint calc_height;
      gint xpad, ypad;

      if (!cellpixbuf->pixbuf && cellinfo->stock_id)
            nautilus_cell_renderer_pixbuf_emblem_create_stock_pixbuf (cellpixbuf, widget);

      if (cellpixbuf->pixbuf) {
            pixbuf_width  = gdk_pixbuf_get_width (cellpixbuf->pixbuf);
            pixbuf_height = gdk_pixbuf_get_height (cellpixbuf->pixbuf);
      }
      if (cellpixbuf->pixbuf_expander_open) {
            pixbuf_width  = MAX (pixbuf_width, gdk_pixbuf_get_width (cellpixbuf->pixbuf_expander_open));
            pixbuf_height = MAX (pixbuf_height, gdk_pixbuf_get_height (cellpixbuf->pixbuf_expander_open));
      }
      if (cellpixbuf->pixbuf_expander_closed) {
            pixbuf_width  = MAX (pixbuf_width, gdk_pixbuf_get_width (cellpixbuf->pixbuf_expander_closed));
            pixbuf_height = MAX (pixbuf_height, gdk_pixbuf_get_height (cellpixbuf->pixbuf_expander_closed));
      }

      gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
      calc_width  = xpad * 2 + pixbuf_width;
      calc_height = ypad * 2 + pixbuf_height;
  
      if (x_offset) *x_offset = 0;
      if (y_offset) *y_offset = 0;

      if (cell_area && pixbuf_width > 0 && pixbuf_height > 0) {
            gfloat xalign, yalign;

            gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
            if (x_offset) {
                  *x_offset = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
                        1.0 - xalign : xalign) * 
                        (cell_area->width - calc_width - 2 * xpad));
                  *x_offset = MAX (*x_offset, 0) + xpad;
            }
            if (y_offset) {
                  *y_offset = (yalign *
                        (cell_area->height - calc_height - 2 * ypad));
                  *y_offset = MAX (*y_offset, 0) + ypad;
            }
      }

      if (width)
            *width = calc_width;
  
      if (height)
            *height = calc_height;
}

static void
nautilus_cell_renderer_pixbuf_emblem_render (GtkCellRenderer      *cell,
                                 GdkWindow            *window,
                                 GtkWidget            *widget,
                                 GdkRectangle         *background_area,
                                 GdkRectangle         *cell_area,
                                 GdkRectangle         *expose_area,
                                 GtkCellRendererState  flags)
 
{
      NautilusCellRendererPixbufEmblem *cellpixbuf = (NautilusCellRendererPixbufEmblem *) cell;
      NautilusCellRendererPixbufEmblemInfo *cellinfo = g_object_get_data (G_OBJECT (cell), CELLINFO_KEY);
      GdkPixbuf *pixbuf;
      GdkRectangle pix_rect;
      GdkRectangle pix_emblem_rect;
      GdkRectangle draw_rect;
      gboolean stock_pixbuf = FALSE;
      gint xpad, ypad;
      gboolean is_expander, is_expanded;

      pixbuf = cellpixbuf->pixbuf;
      g_object_get (cell,
                  "is-expander", &is_expander,
                  "is-expanded", &is_expanded,
                  NULL);
      if (is_expander) {
            if (is_expanded &&
                cellpixbuf->pixbuf_expander_open != NULL) {
                  pixbuf = cellpixbuf->pixbuf_expander_open;
            } else if (!is_expanded &&
                     cellpixbuf->pixbuf_expander_closed != NULL) {
                  pixbuf = cellpixbuf->pixbuf_expander_closed;
            }
      }

      if (!pixbuf && !cellinfo->stock_id) {
            return;
      } else if (!pixbuf && cellinfo->stock_id) {
            stock_pixbuf = TRUE;
      }

      nautilus_cell_renderer_pixbuf_emblem_get_size (cell, widget, cell_area,
                             &pix_rect.x,
                             &pix_rect.y,
                             &pix_rect.width,
                             &pix_rect.height);

      if (stock_pixbuf)
            pixbuf = cellpixbuf->pixbuf;

      gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
      pix_rect.x += cell_area->x;
      pix_rect.y += cell_area->y;
      pix_rect.width  -= xpad * 2;
      pix_rect.height -= ypad * 2;

      if (gdk_rectangle_intersect (cell_area, &pix_rect, &draw_rect) &&
          gdk_rectangle_intersect (expose_area, &draw_rect, &draw_rect)) {
            gdk_draw_pixbuf (window,
                  gtk_widget_get_style (widget)->black_gc,
                  pixbuf,
                  /* pixbuf 0, 0 is at pix_rect.x, pix_rect.y */
                  draw_rect.x - pix_rect.x,
                  draw_rect.y - pix_rect.y,
                  draw_rect.x,
                  draw_rect.y,
                  draw_rect.width,
                  draw_rect.height,
                  GDK_RGB_DITHER_NORMAL,
                  0, 0);
      }

      if (cellpixbuf->pixbuf_emblem) {
            pix_emblem_rect.width = gdk_pixbuf_get_width (cellpixbuf->pixbuf_emblem);
            pix_emblem_rect.height = gdk_pixbuf_get_height (cellpixbuf->pixbuf_emblem);
            pix_emblem_rect.x = pix_rect.x;
            pix_emblem_rect.y = pix_rect.y + pix_rect.height - pix_emblem_rect.height;
            if (gdk_rectangle_intersect (cell_area, &pix_emblem_rect, &draw_rect) &&
                gdk_rectangle_intersect (expose_area, &draw_rect, &draw_rect)) {
                  gdk_draw_pixbuf (window,
                        gtk_widget_get_style (widget)->black_gc,
                        cellpixbuf->pixbuf_emblem,
                        /* pixbuf 0, 0 is at pix_emblem_rect.x, pix_emblem_rect.y */
                        draw_rect.x - pix_emblem_rect.x,
                        draw_rect.y - pix_emblem_rect.y,
                        draw_rect.x,
                        draw_rect.y,
                        draw_rect.width,
                        draw_rect.height,
                        GDK_RGB_DITHER_NORMAL,
                        0, 0);
            }
      }
}

Generated by  Doxygen 1.6.0   Back to index